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