add hotplug events
[project/mountd.git] / mount.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <fcntl.h>
8 #include <sys/ioctl.h>
9 #include <linux/hdreg.h>
10 #include <scsi/sg.h>
11 #include <dirent.h>
12 #include <sys/wait.h>
13 #include <sys/inotify.h>
14 #include <sys/stat.h>
15 #include <sys/types.h>
16 #include <glob.h>
17 #include <libgen.h>
18 #include <poll.h>
19 #include <dirent.h>
20 #include <syslog.h>
21
22 #include "include/log.h"
23 #include "include/list.h"
24 #include "include/sys.h"
25 #include "include/signal.h"
26 #include "include/timer.h"
27 #include "include/autofs.h"
28 #include "include/ucix.h"
29 #include "include/fs.h"
30 #include "include/mount.h"
31
32 int mount_new(char *path, char *dev);
33
34 struct list_head mounts;
35
36 struct mount {
37         struct list_head list;
38         char name[64];
39         char dev[64];
40         char serial[64];
41         char vendor[64];
42         char model[64];
43         char rev[64];
44         int mounted;
45         int ignore;
46         char size[64];
47         char sector_size[64];
48         int fs;
49 };
50
51 char *fs_names[] = {
52         "",
53         "",
54         "MBR",
55         "EXT2",
56         "EXT3",
57         "FAT",
58         "HFSPLUS",
59         "",
60         "NTFS",
61         "",
62         "EXFAT",
63         "EXT4"
64 };
65
66 #define MAX_MOUNTED             32
67 #define MAX_MOUNT_NAME  32
68
69 char mounted[MAX_MOUNTED][3][MAX_MOUNT_NAME];
70 int mounted_count = 0;
71 extern char uci_path[32];
72
73 static void mount_dump_uci_state(void)
74 {
75         struct uci_context *ctx;
76         struct list_head *p;
77         char mountd[] = {"mountd"};
78         char type[] = {"mountd_disc"};
79         int mounted = 0;
80         unsigned long long int size = 0;
81         unlink("/var/state/mountd");
82         ctx = ucix_init("mountd");
83         uci_set_savedir(ctx, "/var/state/");
84         ucix_add_option_int(ctx, mountd, mountd, "count", list_count(&mounts));
85         list_for_each(p, &mounts)
86         {
87                 struct mount *q = container_of(p, struct mount, list);
88                 char t[64];
89                 if(q->fs == EXTENDED)
90                         continue;
91                 ucix_add_section(ctx, mountd, q->serial, type);
92                 strcpy(t, q->dev);
93                 t[3] = '\0';
94                 ucix_add_option(ctx, mountd, q->serial, "disc", t);
95                 ucix_add_option(ctx, mountd, q->serial, "sector_size", q->sector_size);
96                 snprintf(t, 64, "part%dmounted", atoi(&q->dev[3]));
97                 ucix_add_option(ctx, mountd, q->serial, t, (q->mounted)?("1"):("0"));
98                 ucix_add_option(ctx, mountd, q->serial, "vendor", q->vendor);
99                 ucix_add_option(ctx, mountd, q->serial, "model", q->model);
100                 ucix_add_option(ctx, mountd, q->serial, "rev", q->rev);
101                 snprintf(t, 64, "size%d", atoi(&q->dev[3]));
102                 ucix_add_option(ctx, mountd, q->serial, t, q->size);
103                 if(q->fs > MBR && q->fs <= EXT4)
104                 {
105                         snprintf(t, 64, "fs%d", atoi(&q->dev[3]));
106                         ucix_add_option(ctx, mountd, q->serial, t, fs_names[q->fs]);
107                 }
108                 if(q->mounted)
109                         mounted++;
110                 if((!q->ignore) && q->size && q->sector_size)
111                         size = size + (((unsigned long long int)atoi(q->size)) * ((unsigned long long int)atoi(q->sector_size)));
112         }
113         ucix_add_option_int(ctx, mountd, mountd, "mounted", mounted);
114         ucix_add_option_int(ctx, mountd, mountd, "total", size);
115         system_printf("echo -n %llu > /tmp/run/mountd_size", size);
116         ucix_save_state(ctx, "mountd");
117         ucix_cleanup(ctx);
118 }
119
120 static struct mount* mount_find(char *name, char *dev)
121 {
122         struct list_head *p;
123         list_for_each(p, &mounts)
124         {
125                 struct mount *q = container_of(p, struct mount, list);
126                 if(name)
127                         if(!strcmp(q->name, name))
128                                 return q;
129                 if(dev)
130                         if(!strcmp(q->dev, dev))
131                                 return q;
132         }
133         return 0;
134 }
135
136 static void mount_add_list(char *name, char *dev, char *serial,
137         char *vendor, char *model, char *rev, int ignore, char *size, char *sector_size, int fs)
138 {
139         struct mount *mount;
140         char tmp[64], tmp2[64];
141         if(fs <= MBR || fs > EXT4)
142                 return;
143         mount  = malloc(sizeof(struct mount));
144         INIT_LIST_HEAD(&mount->list);
145         strncpy(mount->vendor, vendor, 64);
146         strncpy(mount->model, model, 64);
147         strncpy(mount->rev, rev, 64);
148         strncpy(mount->name, name, 64);
149         strncpy(mount->dev, dev, 64);
150         strncpy(mount->serial, serial, 64);
151         strncpy(mount->size, size, 64);
152         strncpy(mount->sector_size, sector_size, 64);
153         mount->ignore = ignore;
154         mount->mounted = 0;
155         mount->fs = fs;
156         list_add(&mount->list, &mounts);
157         if((!mount->ignore) && (mount->fs > MBR) && (mount->fs <= EXT4))
158         {
159                 log_printf("new mount : %s -> %s (%s)\n", name, dev, fs_names[mount->fs]);
160                 snprintf(tmp, 64, "%s%s", uci_path, name);
161                 snprintf(tmp2, 64, "/tmp/run/mountd/%s", dev);
162                 symlink(tmp2, tmp);
163                 mount_new("/tmp/run/mountd/", dev);
164                 system_printf("ACTION=add DEVICE=%s NAME=%s /sbin/hotplug-call mount", dev, name);
165         }
166 }
167
168 static int mount_check_disc(char *disc)
169 {
170         FILE *fp = fopen("/proc/mounts", "r");
171         char tmp[256];
172         int avail = -1;
173         if(!fp)
174         {
175                 log_printf("error reading /proc/mounts");
176                 fclose(fp);
177                 return avail;
178         }
179         while((fgets(tmp, 256, fp) > 0) && (avail == -1))
180         {
181                 char *t;
182                 char tmp2[32];
183                 t = strstr(tmp, " ");
184                 if(t)
185                 {
186                         int l;
187                         *t = '\0';
188                         l = snprintf(tmp2, 31, "/dev/%s", disc);
189
190                         if(!strncmp(tmp, tmp2, l))
191                                 avail = 0;
192                 }
193         }
194         fclose(fp);
195         return avail;
196 }
197
198 static int mount_wait_for_disc(char *disc)
199 {
200         int i = 10;
201         while(i--)
202         {
203                 int ret = mount_check_disc(disc);
204                 if(!ret)
205                         return ret;
206                 poll(0, 0, 100);
207         }
208         return -1;
209 }
210
211 int mount_new(char *path, char *dev)
212 {
213         struct mount *mount;
214         char tmp[256];
215         int ret = 1;
216         pid_t pid;
217         mount = mount_find(0, dev);
218         if(!mount)
219         {
220                 log_printf("request for invalid path %s%s\n", path, dev);
221                 return -1;
222         }
223         if(mount->ignore || mount->mounted || mount->fs == EXTENDED)
224                 return -1;
225         snprintf(tmp, 256, "%s%s", path, mount->dev);
226         log_printf("mounting %s\n", tmp);
227         mkdir(tmp, 777);
228
229         pid = autofs_safe_fork();
230         if(!pid)
231         {
232                 if(mount->fs == EXFAT)
233                 {
234                         log_printf("mount -t exfat -o rw,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
235                         ret = system_printf("mount -t exfat -o rw,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
236                 }
237                 if(mount->fs == FAT)
238                 {
239                         log_printf("mount -t vfat -o rw,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
240                         ret = system_printf("mount -t vfat -o rw,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
241                 }
242                 if(mount->fs == EXT4)
243                 {
244                         log_printf("mount -t ext4 -o rw,defaults /dev/%s %s", mount->dev, tmp);
245                         ret = system_printf("mount -t ext4 -o rw,defaults /dev/%s %s", mount->dev, tmp);
246                 }
247                 if(mount->fs == EXT3)
248                 {
249                         log_printf("mount -t ext3 -o rw,defaults /dev/%s %s", mount->dev, tmp);
250                         ret = system_printf("mount -t ext3 -o rw,defaults /dev/%s %s", mount->dev, tmp);
251                 }
252                 if(mount->fs == EXT2)
253                 {
254                         log_printf("mount -t ext2 -o rw,defaults /dev/%s %s", mount->dev, tmp);
255                         ret = system_printf("mount -t ext2 -o rw,defaults /dev/%s %s", mount->dev, tmp);
256                 }
257                 if(mount->fs == HFSPLUS)
258                 {
259                         log_printf("mount -t hfsplus -o rw,defaults,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
260                         ret = system_printf("mount -t hfsplus -o rw,defaults,uid=1000,gid=1000 /dev/%s %s", mount->dev, tmp);
261                 }
262                 if(mount->fs == NTFS)
263                 {
264                         log_printf("ntfs-3g /dev/%s %s -o force", mount->dev, tmp);
265                         ret = system_printf("ntfs-3g /dev/%s %s -o force", mount->dev, tmp);
266                 }
267                 exit(WEXITSTATUS(ret));
268         }
269         pid = waitpid(pid, &ret, 0);
270         ret = WEXITSTATUS(ret);
271         log_printf("----------> mount ret = %d\n", ret);
272         if(ret && (ret != 0xff))
273                 return -1;
274         if(mount_wait_for_disc(mount->dev) == 0)
275         {
276                 mount->mounted = 1;
277                 mount_dump_uci_state();
278         } else return -1;
279         return 0;
280 }
281
282 int mount_remove(char *path, char *dev)
283 {
284         struct mount *mount;
285         char tmp[256];
286         int ret;
287         snprintf(tmp, 256, "%s%s", path, dev);
288         log_printf("%s has expired... unmounting\n", tmp);
289         ret = system_printf("/bin/umount %s", tmp);
290         if(ret != 0)
291                 return 0;
292         rmdir(tmp);
293         mount = mount_find(0, dev);
294         if(mount)
295                 mount->mounted = 0;
296         log_printf("finished unmounting\n");
297         mount_dump_uci_state();
298         return 0;
299 }
300
301 static int dir_sort(const struct dirent **a, const struct dirent **b)
302 {
303         return 0;
304 }
305
306 static int dir_filter(const struct dirent *a)
307 {
308         if(strstr(a->d_name, ":"))
309                 return 1;
310         return 0;
311 }
312
313 static char* mount_get_serial(char *dev)
314 {
315         static char tmp[64];
316         static char tmp2[64];
317         int disc;
318         static struct hd_driveid hd;
319         int i;
320         static char *serial;
321         static char disc_id[13];
322         snprintf(tmp, 64, "/dev/%s", dev);
323         disc = open(tmp, O_RDONLY);
324         if(!disc)
325         {
326                 log_printf("Trying to open unknown disc\n");
327                 return 0;
328         }
329         i = ioctl(disc, HDIO_GET_IDENTITY, &hd);
330         close(disc);
331         if(!i)
332                 serial = (char*)hd.serial_no;
333         /* if we failed, it probably a usb storage device */
334         /* there must be a better way for this */
335         if(i)
336         {
337                 struct dirent **namelist;
338                 int n = scandir("/sys/bus/scsi/devices/", &namelist, dir_filter, dir_sort);
339                 if(n > 0)
340                 {
341                         while(n--)
342                         {
343                                 char *t = strstr(namelist[n]->d_name, ":");
344                                 if(t)
345                                 {
346                                         int id;
347                                         struct stat buf;
348                                         char tmp3[64];
349                                         int ret;
350                                         *t = 0;
351                                         id = atoi(namelist[n]->d_name);
352                                         *t = ':';
353                                         sprintf(tmp3, "/sys/bus/scsi/devices/%s/block:%s/", namelist[n]->d_name, dev);
354                                         ret = stat(tmp3, &buf);
355                                         if(ret)
356                                         {
357                                                 sprintf(tmp3, "/sys/bus/scsi/devices/%s/block/%s/", namelist[n]->d_name, dev);
358                                                 ret = stat(tmp3, &buf);
359                                         }
360                                         if(!ret)
361                                         {
362                                                 FILE *fp;
363                                                 snprintf(tmp2, 64, "/proc/scsi/usb-storage/%d", id);
364                                                 fp = fopen(tmp2, "r");
365                                                 if(fp)
366                                                 {
367                                                         while(fgets(tmp2, 64, fp) > 0)
368                                                         {
369                                                                 serial = strstr(tmp2, "Serial Number:");
370                                                                 if(serial)
371                                                                 {
372                                                                         serial += strlen("Serial Number: ");
373                                                                         serial[strlen(serial) - 1] = '\0';
374                                                                         i = 0;
375                                                                         break;
376                                                                 }
377                                                         }
378                                                         fclose(fp);
379                                                 }
380                                         }
381                                 }
382                                 free(namelist[n]);
383                         }
384                         free(namelist);
385                 }
386         }
387         if(i)
388         {
389                 log_printf("could not find a serial number for the device %s\n", dev);
390         } else {
391                 /* serial string id is cheap, but makes the discs anonymous */
392                 unsigned char uniq[6];
393                 unsigned int *u = (unsigned int*) uniq;
394                 int l = strlen(serial);
395                 int i;
396                 memset(disc_id, 0, 13);
397                 memset(uniq, 0, 6);
398                 for(i = 0; i < l; i++)
399                 {
400                         uniq[i%6] += serial[i];
401                 }
402                 sprintf(disc_id, "%08X%02X%02X", *u, uniq[4], uniq[5]);
403                 //log_printf("Serial number - %s %s\n", serial, disc_id);
404                 return disc_id;
405         }
406         sprintf(disc_id, "000000000000");
407         return disc_id;
408 }
409
410 static void mount_dev_add(char *dev)
411 {
412         struct mount *mount = mount_find(0, dev);
413         if(!mount)
414         {
415                 char node[64];
416                 char name[64];
417                 int ignore = 0;
418                 char *s;
419                 char tmp[64];
420                 char tmp2[64];
421                 char *p;
422                 struct uci_context *ctx;
423                 char vendor[64];
424                 char model[64];
425                 char rev[64];
426                 char size[64];
427                 char sector_size[64];
428                 FILE *fp;
429                 int offset = 3;
430
431                 strcpy(name, dev);
432                 if (!strncmp(name, "mmcblk", 6))
433                         offset = 7;
434                 name[offset] = '\0';
435                 s = mount_get_serial(name);
436                 if(!s) {
437                         return;
438                 }
439                 if (!strncmp(name, "mmcblk", 6)) {
440                         snprintf(tmp, 64, "part%s", &dev[8]);
441                         snprintf(node, 64, "SD-P%s", &dev[8]);
442
443                 } else {
444                         snprintf(tmp, 64, "part%s", &dev[3]);
445                         snprintf(node, 64, "USB-%s", &dev[2]);
446                 }
447                 if(node[4] >= 'a' && node[4] <= 'z')
448                 {
449                         node[4] -= 'a';
450                         node[4] += 'A';
451                 }
452                 ctx = ucix_init("mountd");
453                 p = ucix_get_option(ctx, "mountd", s, tmp);
454                 ucix_cleanup(ctx);
455                 if(p)
456                 {
457                         if(strlen(p) == 1)
458                         {
459                                 if(*p == '0')
460                                         ignore = 1;
461                         } else {
462                                 snprintf(node, 64, "%s", p);
463                         }
464                 }
465                 strcpy(name, dev);
466                 name[3] = '\0';
467                 snprintf(tmp, 64, "/sys/class/block/%s/device/model", name);
468                 fp = fopen(tmp, "r");
469                 if(!fp)
470                 {
471                         snprintf(tmp, 64, "/sys/block/%s/device/model", name);
472                         fp = fopen(tmp, "r");
473                 }
474                 if(!fp)
475                         snprintf(model, 64, "unknown");
476                 else {
477                         fgets(model, 64, fp);
478                         model[strlen(model) - 1] = '\0';;
479                         fclose(fp);
480                 }
481                 snprintf(tmp, 64, "/sys/class/block/%s/device/vendor", name);
482                 fp = fopen(tmp, "r");
483                 if(!fp)
484                 {
485                         snprintf(tmp, 64, "/sys/block/%s/device/vendor", name);
486                         fp = fopen(tmp, "r");
487                 }
488                 if(!fp)
489                         snprintf(vendor, 64, "unknown");
490                 else {
491                         fgets(vendor, 64, fp);
492                         vendor[strlen(vendor) - 1] = '\0';
493                         fclose(fp);
494                 }
495                 snprintf(tmp, 64, "/sys/class/block/%s/device/rev", name);
496                 fp = fopen(tmp, "r");
497                 if(!fp)
498                 {
499                         snprintf(tmp, 64, "/sys/block/%s/device/rev", name);
500                         fp = fopen(tmp, "r");
501                 }
502                 if(!fp)
503                         snprintf(rev, 64, "unknown");
504                 else {
505                         fgets(rev, 64, fp);
506                         rev[strlen(rev) - 1] = '\0';
507                         fclose(fp);
508                 }
509                 snprintf(tmp, 64, "/sys/class/block/%s/size", dev);
510                 fp = fopen(tmp, "r");
511                 if(!fp)
512                 {
513                         snprintf(tmp, 64, "/sys/block/%s/%s/size", name, dev);
514                         fp = fopen(tmp, "r");
515                 }
516                 if(!fp)
517                         snprintf(size, 64, "unknown");
518                 else {
519                         fgets(size, 64, fp);
520                         size[strlen(size) - 1] = '\0';
521                         fclose(fp);
522                 }
523                 strcpy(tmp2, dev);
524                 tmp2[3] = '\0';
525                 snprintf(tmp, 64, "/sys/block/%s/queue/hw_sector_size", tmp2);
526                 fp = fopen(tmp, "r");
527                 if(!fp)
528                         snprintf(sector_size, 64, "unknown");
529                 else {
530                         fgets(sector_size, 64, fp);
531                         sector_size[strlen(sector_size) - 1] = '\0';
532                         fclose(fp);
533                 }
534                 snprintf(tmp, 64, "/dev/%s", dev);
535                 mount_add_list(node, dev, s, vendor, model, rev, ignore, size, sector_size, detect_fs(tmp));
536                 mount_dump_uci_state();
537         }
538 }
539
540 static void mount_dev_del(char *dev)
541 {
542         struct mount *mount = mount_find(0, dev);
543         char tmp[256];
544         if(mount)
545         {
546                 if(mount->mounted)
547                 {
548                         snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->name);
549                         log_printf("%s has dissappeared ... unmounting\n", tmp);
550                         snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->dev);
551                         system_printf("/bin/umount %s", tmp);
552                         rmdir(tmp);
553                         snprintf(tmp, 64, "%s%s", uci_path, mount->name);
554                         unlink(tmp);
555                         mount_dump_uci_state();
556                 }
557         }
558 }
559
560 void mount_dump_list(void)
561 {
562         struct list_head *p;
563         list_for_each(p, &mounts)
564         {
565                 struct mount *q = container_of(p, struct mount, list);
566                 log_printf("* %s %s %d\n", q->name, q->dev, q->mounted);
567         }
568 }
569
570 char* is_mounted(char *block, char *path)
571 {
572         int i;
573         for(i = 0; i < mounted_count; i++)
574         {
575                 if(block)
576                         if(!strncmp(&mounted[i][0][0], block, strlen(&mounted[i][0][0])))
577                                 return &mounted[i][0][0];
578                 if(path)
579                         if(!strncmp(&mounted[i][1][1], &path[1], strlen(&mounted[i][1][0])))
580                                 return &mounted[i][0][0];
581         }
582         return 0;
583 }
584
585 static void mount_check_mount_list(void)
586 {
587         FILE *fp = fopen("/proc/mounts", "r");
588         char tmp[256];
589
590         if(!fp)
591         {
592                 log_printf("error reading /proc/mounts");
593                 fclose(fp);
594                 return;
595         }
596         mounted_count = 0;
597         while(fgets(tmp, 256, fp) > 0)
598         {
599                 char *t, *t2;
600                 t = strstr(tmp, " ");
601                 if(t)
602                 {
603                         *t = '\0';
604                         t++;
605                 } else t = tmp;
606                 strncpy(&mounted[mounted_count][0][0], tmp, MAX_MOUNT_NAME);
607                 t2 = strstr(t, " ");
608                 if(t2)
609                 {
610                         *t2 = '\0';
611                         t2++;
612                 } else t2 = t;
613                 strncpy(&mounted[mounted_count][1][0], t, MAX_MOUNT_NAME);
614                 t = strstr(t2, " ");
615                 if(t)
616                 {
617                         *t = '\0';
618                         t++;
619                 } else t = tmp;
620                 strncpy(&mounted[mounted_count][2][0], t2, MAX_MOUNT_NAME);
621         /*      printf("%s %s %s\n",
622                         mounted[mounted_count][0],
623                         mounted[mounted_count][1],
624                         mounted[mounted_count][2]);*/
625                 if(mounted_count < MAX_MOUNTED - 1)
626                         mounted_count++;
627                 else
628                         log_printf("found more than %d mounts \n", MAX_MOUNTED);
629         }
630         fclose(fp);
631 }
632
633 /* FIXME: we need more intelligence here */
634 static int dir_filter2(const struct dirent *a)
635 {
636         if(!strncmp(a->d_name, "mmcblk", 6) || !strncmp(a->d_name, "sd", 2))
637                 return 1;
638         return 0;
639 }
640 #define MAX_BLOCK       64
641 char block[MAX_BLOCK][MAX_BLOCK];
642 int blk_cnt = 0;
643
644 static int check_block(char *b)
645 {
646         int i;
647         for(i = 0; i < blk_cnt; i++)
648         {
649                 if(!strcmp(block[i], b))
650                         return 1;
651         }
652         return 0;
653 }
654
655 static void mount_enum_drives(void)
656 {
657         struct dirent **namelist, **namelist2;
658         int i, n = scandir("/sys/block/", &namelist, dir_filter2, dir_sort);
659         struct list_head *p;
660         blk_cnt = 0;
661         if(n > 0)
662         {
663                 while(n--)
664                 {
665                         if(blk_cnt < MAX_BLOCK)
666                         {
667                                 int m;
668                                 char tmp[64];
669                                 snprintf(tmp, 64, "/sys/block/%s/", namelist[n]->d_name);
670                                 m = scandir(tmp, &namelist2, dir_filter2, dir_sort);
671                                 while(m--)
672                                 {
673                                         strncpy(&block[blk_cnt][0], namelist2[m]->d_name, MAX_BLOCK);
674                                         blk_cnt++;
675                                         free(namelist2[m]);
676                                 }
677                                 free(namelist2);
678                         }
679                         free(namelist[n]);
680                 }
681                 free(namelist);
682         }
683         p = mounts.next;
684         while(p != &mounts)
685         {
686                 struct mount *q = container_of(p, struct mount, list);
687                 char tmp[64];
688                 struct uci_context *ctx;
689                 int del = 0;
690                 char *t;
691                 snprintf(tmp, 64, "part%s", &q->dev[3]);
692                 ctx = ucix_init("mountd");
693                 t = ucix_get_option(ctx, "mountd", q->serial, tmp);
694                 ucix_cleanup(ctx);
695                 if(t && !q->mounted)
696                 {
697                         if(!strcmp(t, "0"))
698                         {
699                                 if(!q->ignore)
700                                         del = 1;
701                         } else if(!strcmp(t, "1"))
702                         {
703                                 if(strncmp(q->name, "Disc-", 5))
704                                         del = 1;
705                         } else if(strcmp(q->name, t))
706                         {
707                                 del = 1;
708                         }
709                 }
710                 if(!check_block(q->dev)||del)
711                 {
712                         mount_dev_del(q->dev);
713                         p->prev->next = p->next;
714                         p->next->prev = p->prev;
715                         p = p->next;
716                         log_printf("removing %s\n", q->dev);
717                         snprintf(tmp, 64, "%s%s", uci_path, q->name);
718                         unlink(tmp);
719                         system_printf("ACTION=remove DEVICE=%s NAME=%s /sbin/hotplug-call mount", q->dev, q->name);
720                         free(q);
721                         mount_dump_uci_state();
722                         system_printf("/etc/fonstated/ReloadSamba");
723                 } else p = p->next;
724         }
725
726         for(i = 0; i < blk_cnt; i++)
727                 mount_dev_add(block[i]);
728 }
729
730 static void mount_check_enum(void)
731 {
732         waitpid(-1, 0, WNOHANG);
733         mount_enum_drives();
734 }
735
736 void mount_init(void)
737 {
738         INIT_LIST_HEAD(&mounts);
739         timer_add(mount_check_mount_list, 2);
740         timer_add(mount_check_enum, 1);
741         mount_check_mount_list();
742 }