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