filesystem mount options in uci as optional parameter
[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                 char *options, *fstype;
233                 if(mount->fs == EXFAT)
234                 {
235                         options = "rw,uid=1000,gid=1000";
236                         fstype = "exfat";
237                 }
238                 if(mount->fs == FAT)
239                 {
240                         options = "rw,uid=1000,gid=1000";
241                         fstype = "vfat";
242                 }
243                 if(mount->fs == EXT4)
244                 {
245                         options = "rw,defaults";
246                         fstype = "ext4";
247                 }
248                 if(mount->fs == EXT3)
249                 {
250                         options = "rw,defaults";
251                         fstype = "ext3";
252                 }
253                 if(mount->fs == EXT2)
254                 {
255                         options = "rw,defaults";
256                         fstype = "ext2";
257                 }
258                 if(mount->fs == HFSPLUS)
259                 {
260                         options = "rw,defaults,uid=1000,gid=1000";
261                         fstype = "hfsplus";
262                 }
263                 if(mount->fs == NTFS)
264                 {
265                         options = "force";
266                         fstype = "ntfs-3g";
267                 }
268                 if(mount->fs > MBR && mount->fs <= EXT4)
269                 {
270                         struct uci_context *ctx;
271                         char *uci_options, *uci_fstype;
272                         ctx = ucix_init("mountd");
273                         if(fs_names[mount->fs])
274                         {
275                                 uci_options = ucix_get_option(ctx, "mountd", fs_names[mount->fs], "options");
276                                 uci_fstype = ucix_get_option(ctx, "mountd", fs_names[mount->fs], "fstype");
277                                 if(uci_options)
278                                         options = uci_options;
279                                 if(uci_fstype)
280                                         fstype = uci_fstype;
281                                 log_printf("mount -t %s -o %s /dev/%s %s", fstype, options, mount->dev, tmp);
282                                 ret = system_printf("mount -t %s -o %s /dev/%s %s", fstype, options, mount->dev, tmp);
283                         }
284                         ucix_cleanup(ctx);
285                 }
286                 exit(WEXITSTATUS(ret));
287         }
288         pid = waitpid(pid, &ret, 0);
289         ret = WEXITSTATUS(ret);
290         log_printf("----------> mount ret = %d\n", ret);
291         if(ret && (ret != 0xff))
292                 return -1;
293         if(mount_wait_for_disc(mount->dev) == 0)
294         {
295                 mount->mounted = 1;
296                 mount_dump_uci_state();
297         } else return -1;
298         return 0;
299 }
300
301 int mount_remove(char *path, char *dev)
302 {
303         struct mount *mount;
304         char tmp[256];
305         int ret;
306         snprintf(tmp, 256, "%s%s", path, dev);
307         log_printf("%s has expired... unmounting\n", tmp);
308         ret = system_printf("/bin/umount %s", tmp);
309         if(ret != 0)
310                 return 0;
311         rmdir(tmp);
312         mount = mount_find(0, dev);
313         if(mount)
314                 mount->mounted = 0;
315         log_printf("finished unmounting\n");
316         mount_dump_uci_state();
317         return 0;
318 }
319
320 static int dir_sort(const struct dirent **a, const struct dirent **b)
321 {
322         return 0;
323 }
324
325 static int dir_filter(const struct dirent *a)
326 {
327         if(strstr(a->d_name, ":"))
328                 return 1;
329         return 0;
330 }
331
332 static char* mount_get_serial(char *dev)
333 {
334         static char tmp[64];
335         static char tmp2[64];
336         int disc;
337         static struct hd_driveid hd;
338         int i;
339         static char *serial;
340         static char disc_id[13];
341         snprintf(tmp, 64, "/dev/%s", dev);
342         disc = open(tmp, O_RDONLY);
343         if(!disc)
344         {
345                 log_printf("Trying to open unknown disc\n");
346                 return 0;
347         }
348         i = ioctl(disc, HDIO_GET_IDENTITY, &hd);
349         close(disc);
350         if(!i)
351                 serial = (char*)hd.serial_no;
352         /* if we failed, it probably a usb storage device */
353         /* there must be a better way for this */
354         if(i)
355         {
356                 struct dirent **namelist;
357                 int n = scandir("/sys/bus/scsi/devices/", &namelist, dir_filter, dir_sort);
358                 if(n > 0)
359                 {
360                         while(n--)
361                         {
362                                 char *t = strstr(namelist[n]->d_name, ":");
363                                 if(t)
364                                 {
365                                         int id;
366                                         struct stat buf;
367                                         char tmp3[64];
368                                         int ret;
369                                         *t = 0;
370                                         id = atoi(namelist[n]->d_name);
371                                         *t = ':';
372                                         sprintf(tmp3, "/sys/bus/scsi/devices/%s/block:%s/", namelist[n]->d_name, dev);
373                                         ret = stat(tmp3, &buf);
374                                         if(ret)
375                                         {
376                                                 sprintf(tmp3, "/sys/bus/scsi/devices/%s/block/%s/", namelist[n]->d_name, dev);
377                                                 ret = stat(tmp3, &buf);
378                                         }
379                                         if(!ret)
380                                         {
381                                                 FILE *fp;
382                                                 snprintf(tmp2, 64, "/proc/scsi/usb-storage/%d", id);
383                                                 fp = fopen(tmp2, "r");
384                                                 if(fp)
385                                                 {
386                                                         while(fgets(tmp2, 64, fp) > 0)
387                                                         {
388                                                                 serial = strstr(tmp2, "Serial Number:");
389                                                                 if(serial)
390                                                                 {
391                                                                         serial += strlen("Serial Number: ");
392                                                                         serial[strlen(serial) - 1] = '\0';
393                                                                         i = 0;
394                                                                         break;
395                                                                 }
396                                                         }
397                                                         fclose(fp);
398                                                 }
399                                         }
400                                 }
401                                 free(namelist[n]);
402                         }
403                         free(namelist);
404                 }
405         }
406         if(i)
407         {
408                 log_printf("could not find a serial number for the device %s\n", dev);
409         } else {
410                 /* serial string id is cheap, but makes the discs anonymous */
411                 unsigned char uniq[6];
412                 unsigned int *u = (unsigned int*) uniq;
413                 int l = strlen(serial);
414                 int i;
415                 memset(disc_id, 0, 13);
416                 memset(uniq, 0, 6);
417                 for(i = 0; i < l; i++)
418                 {
419                         uniq[i%6] += serial[i];
420                 }
421                 sprintf(disc_id, "%08X%02X%02X", *u, uniq[4], uniq[5]);
422                 //log_printf("Serial number - %s %s\n", serial, disc_id);
423                 return disc_id;
424         }
425         sprintf(disc_id, "000000000000");
426         return disc_id;
427 }
428
429 static void mount_dev_add(char *dev)
430 {
431         struct mount *mount = mount_find(0, dev);
432         if(!mount)
433         {
434                 char node[64];
435                 char name[64];
436                 int ignore = 0;
437                 char *s;
438                 char tmp[64];
439                 char tmp2[64];
440                 char *p;
441                 struct uci_context *ctx;
442                 char vendor[64];
443                 char model[64];
444                 char rev[64];
445                 char size[64];
446                 char sector_size[64];
447                 FILE *fp;
448                 int offset = 3;
449
450                 strcpy(name, dev);
451                 if (!strncmp(name, "mmcblk", 6))
452                         offset = 7;
453                 name[offset] = '\0';
454                 s = mount_get_serial(name);
455                 if(!s) {
456                         return;
457                 }
458                 if (!strncmp(name, "mmcblk", 6)) {
459                         snprintf(tmp, 64, "part%s", &dev[8]);
460                         snprintf(node, 64, "SD-P%s", &dev[8]);
461
462                 } else {
463                         snprintf(tmp, 64, "part%s", &dev[3]);
464                         snprintf(node, 64, "USB-%s", &dev[2]);
465                 }
466                 if(node[4] >= 'a' && node[4] <= 'z')
467                 {
468                         node[4] -= 'a';
469                         node[4] += 'A';
470                 }
471                 ctx = ucix_init("mountd");
472                 p = ucix_get_option(ctx, "mountd", s, tmp);
473                 ucix_cleanup(ctx);
474                 if(p)
475                 {
476                         if(strlen(p) == 1)
477                         {
478                                 if(*p == '0')
479                                         ignore = 1;
480                         } else {
481                                 snprintf(node, 64, "%s", p);
482                         }
483                 }
484                 strcpy(name, dev);
485                 name[3] = '\0';
486                 snprintf(tmp, 64, "/sys/class/block/%s/device/model", name);
487                 fp = fopen(tmp, "r");
488                 if(!fp)
489                 {
490                         snprintf(tmp, 64, "/sys/block/%s/device/model", name);
491                         fp = fopen(tmp, "r");
492                 }
493                 if(!fp)
494                         snprintf(model, 64, "unknown");
495                 else {
496                         fgets(model, 64, fp);
497                         model[strlen(model) - 1] = '\0';;
498                         fclose(fp);
499                 }
500                 snprintf(tmp, 64, "/sys/class/block/%s/device/vendor", name);
501                 fp = fopen(tmp, "r");
502                 if(!fp)
503                 {
504                         snprintf(tmp, 64, "/sys/block/%s/device/vendor", name);
505                         fp = fopen(tmp, "r");
506                 }
507                 if(!fp)
508                         snprintf(vendor, 64, "unknown");
509                 else {
510                         fgets(vendor, 64, fp);
511                         vendor[strlen(vendor) - 1] = '\0';
512                         fclose(fp);
513                 }
514                 snprintf(tmp, 64, "/sys/class/block/%s/device/rev", name);
515                 fp = fopen(tmp, "r");
516                 if(!fp)
517                 {
518                         snprintf(tmp, 64, "/sys/block/%s/device/rev", name);
519                         fp = fopen(tmp, "r");
520                 }
521                 if(!fp)
522                         snprintf(rev, 64, "unknown");
523                 else {
524                         fgets(rev, 64, fp);
525                         rev[strlen(rev) - 1] = '\0';
526                         fclose(fp);
527                 }
528                 snprintf(tmp, 64, "/sys/class/block/%s/size", dev);
529                 fp = fopen(tmp, "r");
530                 if(!fp)
531                 {
532                         snprintf(tmp, 64, "/sys/block/%s/%s/size", name, dev);
533                         fp = fopen(tmp, "r");
534                 }
535                 if(!fp)
536                         snprintf(size, 64, "unknown");
537                 else {
538                         fgets(size, 64, fp);
539                         size[strlen(size) - 1] = '\0';
540                         fclose(fp);
541                 }
542                 strcpy(tmp2, dev);
543                 tmp2[3] = '\0';
544                 snprintf(tmp, 64, "/sys/block/%s/queue/hw_sector_size", tmp2);
545                 fp = fopen(tmp, "r");
546                 if(!fp)
547                         snprintf(sector_size, 64, "unknown");
548                 else {
549                         fgets(sector_size, 64, fp);
550                         sector_size[strlen(sector_size) - 1] = '\0';
551                         fclose(fp);
552                 }
553                 snprintf(tmp, 64, "/dev/%s", dev);
554                 mount_add_list(node, dev, s, vendor, model, rev, ignore, size, sector_size, detect_fs(tmp));
555                 mount_dump_uci_state();
556         }
557 }
558
559 static void mount_dev_del(char *dev)
560 {
561         struct mount *mount = mount_find(0, dev);
562         char tmp[256];
563         if(mount)
564         {
565                 if(mount->mounted)
566                 {
567                         snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->name);
568                         log_printf("%s has dissappeared ... unmounting\n", tmp);
569                         snprintf(tmp, 256, "%s%s", "/tmp/run/mountd/", mount->dev);
570                         system_printf("/bin/umount %s", tmp);
571                         rmdir(tmp);
572                         snprintf(tmp, 64, "%s%s", uci_path, mount->name);
573                         unlink(tmp);
574                         mount_dump_uci_state();
575                 }
576         }
577 }
578
579 void mount_dump_list(void)
580 {
581         struct list_head *p;
582         list_for_each(p, &mounts)
583         {
584                 struct mount *q = container_of(p, struct mount, list);
585                 log_printf("* %s %s %d\n", q->name, q->dev, q->mounted);
586         }
587 }
588
589 char* is_mounted(char *block, char *path)
590 {
591         int i;
592         for(i = 0; i < mounted_count; i++)
593         {
594                 if(block)
595                         if(!strncmp(&mounted[i][0][0], block, strlen(&mounted[i][0][0])))
596                                 return &mounted[i][0][0];
597                 if(path)
598                         if(!strncmp(&mounted[i][1][1], &path[1], strlen(&mounted[i][1][0])))
599                                 return &mounted[i][0][0];
600         }
601         return 0;
602 }
603
604 static void mount_check_mount_list(void)
605 {
606         FILE *fp = fopen("/proc/mounts", "r");
607         char tmp[256];
608
609         if(!fp)
610         {
611                 log_printf("error reading /proc/mounts");
612                 fclose(fp);
613                 return;
614         }
615         mounted_count = 0;
616         while(fgets(tmp, 256, fp) > 0)
617         {
618                 char *t, *t2;
619                 t = strstr(tmp, " ");
620                 if(t)
621                 {
622                         *t = '\0';
623                         t++;
624                 } else t = tmp;
625                 strncpy(&mounted[mounted_count][0][0], tmp, MAX_MOUNT_NAME);
626                 t2 = strstr(t, " ");
627                 if(t2)
628                 {
629                         *t2 = '\0';
630                         t2++;
631                 } else t2 = t;
632                 strncpy(&mounted[mounted_count][1][0], t, MAX_MOUNT_NAME);
633                 t = strstr(t2, " ");
634                 if(t)
635                 {
636                         *t = '\0';
637                         t++;
638                 } else t = tmp;
639                 strncpy(&mounted[mounted_count][2][0], t2, MAX_MOUNT_NAME);
640         /*      printf("%s %s %s\n",
641                         mounted[mounted_count][0],
642                         mounted[mounted_count][1],
643                         mounted[mounted_count][2]);*/
644                 if(mounted_count < MAX_MOUNTED - 1)
645                         mounted_count++;
646                 else
647                         log_printf("found more than %d mounts \n", MAX_MOUNTED);
648         }
649         fclose(fp);
650 }
651
652 /* FIXME: we need more intelligence here */
653 static int dir_filter2(const struct dirent *a)
654 {
655         if(!strncmp(a->d_name, "mmcblk", 6) || !strncmp(a->d_name, "sd", 2))
656                 return 1;
657         return 0;
658 }
659 #define MAX_BLOCK       64
660 char block[MAX_BLOCK][MAX_BLOCK];
661 int blk_cnt = 0;
662
663 static int check_block(char *b)
664 {
665         int i;
666         for(i = 0; i < blk_cnt; i++)
667         {
668                 if(!strcmp(block[i], b))
669                         return 1;
670         }
671         return 0;
672 }
673
674 static void mount_enum_drives(void)
675 {
676         struct dirent **namelist, **namelist2;
677         int i, n = scandir("/sys/block/", &namelist, dir_filter2, dir_sort);
678         struct list_head *p;
679         blk_cnt = 0;
680         if(n > 0)
681         {
682                 while(n--)
683                 {
684                         if(blk_cnt < MAX_BLOCK)
685                         {
686                                 int m;
687                                 char tmp[64];
688                                 snprintf(tmp, 64, "/sys/block/%s/", namelist[n]->d_name);
689                                 m = scandir(tmp, &namelist2, dir_filter2, dir_sort);
690                                 while(m--)
691                                 {
692                                         strncpy(&block[blk_cnt][0], namelist2[m]->d_name, MAX_BLOCK);
693                                         blk_cnt++;
694                                         free(namelist2[m]);
695                                 }
696                                 free(namelist2);
697                         }
698                         free(namelist[n]);
699                 }
700                 free(namelist);
701         }
702         p = mounts.next;
703         while(p != &mounts)
704         {
705                 struct mount *q = container_of(p, struct mount, list);
706                 char tmp[64];
707                 struct uci_context *ctx;
708                 int del = 0;
709                 char *t;
710                 snprintf(tmp, 64, "part%s", &q->dev[3]);
711                 ctx = ucix_init("mountd");
712                 t = ucix_get_option(ctx, "mountd", q->serial, tmp);
713                 ucix_cleanup(ctx);
714                 if(t && !q->mounted)
715                 {
716                         if(!strcmp(t, "0"))
717                         {
718                                 if(!q->ignore)
719                                         del = 1;
720                         } else if(!strcmp(t, "1"))
721                         {
722                                 if(strncmp(q->name, "Disc-", 5))
723                                         del = 1;
724                         } else if(strcmp(q->name, t))
725                         {
726                                 del = 1;
727                         }
728                 }
729                 if(!check_block(q->dev)||del)
730                 {
731                         mount_dev_del(q->dev);
732                         p->prev->next = p->next;
733                         p->next->prev = p->prev;
734                         p = p->next;
735                         log_printf("removing %s\n", q->dev);
736                         snprintf(tmp, 64, "%s%s", uci_path, q->name);
737                         unlink(tmp);
738                         system_printf("ACTION=remove DEVICE=%s NAME=%s /sbin/hotplug-call mount", q->dev, q->name);
739                         free(q);
740                         mount_dump_uci_state();
741                         system_printf("/etc/fonstated/ReloadSamba");
742                 } else p = p->next;
743         }
744
745         for(i = 0; i < blk_cnt; i++)
746                 mount_dev_add(block[i]);
747 }
748
749 static void mount_check_enum(void)
750 {
751         waitpid(-1, 0, WNOHANG);
752         mount_enum_drives();
753 }
754
755 void mount_init(void)
756 {
757         INIT_LIST_HEAD(&mounts);
758         timer_add(mount_check_mount_list, 2);
759         timer_add(mount_check_enum, 1);
760         mount_check_mount_list();
761 }