source: src/router/services/services/usb_hotplug.c @ 18609

Last change on this file since 18609 was 18609, checked in by BrainSlayer, 16 months ago

small hack

File size: 13.8 KB
Line 
1/*
2 * USB hotplug service    Copyright 2007, Broadcom Corporation  All Rights
3 * Reserved.    THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO
4 * WARRANTIES OF ANY  KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR
5 * OTHERWISE. BROADCOM  SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF
6 * MERCHANTABILITY, FITNESS  FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT
7 * CONCERNING THIS SOFTWARE.    $Id$ 
8 */
9
10#include <stdio.h>
11#include <stdlib.h>
12#include <string.h>
13#include <errno.h>
14#include <dirent.h>
15#include <sys/stat.h>
16#include <typedefs.h>
17#include <shutils.h>
18#include <bcmnvram.h>
19
20static bool usb_ufd_connected(char *str);
21static int usb_process_path(char *path, char *fs, char *target);
22static void usb_unmount(char *dev);
23int usb_add_ufd(char *dev);
24
25#define DUMPFILE        "/tmp/disktype.dump"
26
27#ifdef HAVE_X86
28static char *getdisc(void)      // works only for squashfs
29{
30        int i;
31        static char ret[4];
32        unsigned char *disks[] =
33            { "sda2", "sdb2", "sdc2", "sdd2", "sde2", "sdf2", "sdg2", "sdh2",
34                "sdi2"
35        };
36        for (i = 0; i < 9; i++) {
37                char dev[64];
38
39                sprintf(dev, "/dev/%s", disks[i]);
40                FILE *in = fopen(dev, "rb");
41
42                if (in == NULL)
43                        continue;       // no second partition or disc does not
44                // exist, skipping
45                char buf[4];
46
47                fread(buf, 4, 1, in);
48                if (buf[0] == 'h' && buf[1] == 's' && buf[2] == 'q'
49                    && buf[3] == 't') {
50                        fclose(in);
51                        // filesystem detected
52                        strncpy(ret, disks[i], 3);
53                        return ret;
54                }
55                fclose(in);
56        }
57        return NULL;
58}
59#endif
60void start_hotplug_usb(void)
61{
62        char *device, *interface;
63        char *action;
64        int class, subclass, protocol;
65
66        if (!(nvram_match("usb_automnt", "1")))
67                return;
68
69        if (!(action = getenv("ACTION")) || !(device = getenv("TYPE")))
70                return;
71        //sysprintf("echo action %s type %s >> /tmp/hotplugs", action, device);
72
73        sscanf(device, "%d/%d/%d", &class, &subclass, &protocol);
74
75        if (class == 0) {
76                if (!(interface = getenv("INTERFACE")))
77                        goto skip;
78                sscanf(interface, "%d/%d/%d", &class, &subclass, &protocol);
79        }
80      skip:;
81        //sysprintf("echo action %d type %d >> /tmp/hotplugs", class, subclass);
82
83        /*
84         * If a new USB device is added and it is of storage class
85         */
86        if (class == 8 && subclass == 6) {
87                if (!strcmp(action, "add"))
88                        usb_add_ufd(NULL);
89                if (!strcmp(action, "remove"))
90                        usb_unmount(NULL);
91        }
92
93        if (class == 0 && subclass == 0) {
94                if (!strcmp(action, "add"))
95                        usb_add_ufd(NULL);
96                if (!strcmp(action, "remove"))
97                        usb_unmount(NULL);
98        }
99
100        return;
101}
102
103void start_hotplug_block(void)
104{
105        char *devpath;
106        char *action;
107
108        if (!(nvram_match("usb_automnt", "1")))
109                return;
110
111        if (!(action = getenv("ACTION")))
112                return;
113        if (!(devpath = getenv("DEVPATH")))
114                return;
115        char *slash = strrchr(devpath, '/');
116        //sysprintf("echo action %s devpath %s >> /tmp/hotplugs", action,
117        //        devpath);
118
119        char devname[64];
120        sprintf(devname, "/dev/%s", slash + 1);
121        char sysdev[128];
122        sprintf(sysdev, "/sys%s/partition", devpath);
123        FILE *fp = fopen(sysdev, "rb");
124        if (fp) {
125                fclose(fp);     // skip partitions
126                return;
127        }
128        sprintf(sysdev, "/sys%s/dev", devpath);
129        fp = fopen(sysdev, "rb");
130        if (fp) {
131                int major;
132                int minor;
133                fscanf(fp, "%d:%d", &major, &minor);
134                sysprintf("mknod %s b %d %d\n", devname, major, minor);
135                fclose(fp);     // skip partitions
136        }
137        //sysprintf("echo add devname %s >> /tmp/hotplugs", devname);
138        if (!strcmp(action, "add"))
139                usb_add_ufd(devname);
140        if (!strcmp(action, "remove"))
141                usb_unmount(devname);
142
143        return;
144}
145
146    /*
147     *   Check if the UFD is still connected because the links created in
148     * /dev/discs are not removed when the UFD is  unplugged. 
149     */
150static bool usb_ufd_connected(char *str)
151{
152        uint host_no;
153        char proc_file[128];
154        FILE *fp;
155        char line[256];
156        int i;
157
158        /*
159         * Host no. assigned by scsi driver for this UFD
160         */
161        host_no = atoi(str);
162        sprintf(proc_file, "/proc/scsi/usb-storage-%d/%d", host_no, host_no);
163
164        if ((fp = fopen(proc_file, "r"))) {
165                while (fgets(line, sizeof(line), fp) != NULL) {
166                        if (strstr(line, "Attached: Yes")) {
167                                fclose(fp);
168                                return TRUE;
169                        }
170                }
171                fclose(fp);
172        }
173        //in 2.6 kernels its a little bit different; find 1st
174        for (i = 0; i < 16; i++) {
175                sprintf(proc_file, "/proc/scsi/usb-storage/%d", i);
176                if (f_exists(proc_file)) {
177                        return TRUE;
178                }
179        }
180        return FALSE;
181
182}
183
184    /*
185     *   Mount the path and look for the WCN configuration file.  If it
186     * exists launch wcnparse to process the configuration. 
187     */
188static int usb_process_path(char *path, char *fs, char *target)
189{
190        int ret = ENOENT;
191        char mount_point[32];
192        eval("stopservice", "samba3");
193        eval("stopservice", "ftpsrv");
194
195        if (nvram_match("usb_mntpoint", "mnt") && target)
196                sprintf(mount_point, "/mnt/%s", target);
197        else
198                sprintf(mount_point, "/%s",
199                        nvram_default_get("usb_mntpoint", "mnt"));
200#ifdef HAVE_NTFS3G
201        if (!strcmp(fs, "ntfs"))
202                insmod("fuse");
203#endif
204        if (!strcmp(fs, "ext2")) {
205                insmod("mbcache");
206                insmod("ext2");
207        }
208#ifdef HAVE_USB_ADVANCED
209        if (!strcmp(fs, "ext3")) {
210                insmod("mbcache");
211                insmod("ext2");
212                insmod("jbd");
213                insmod("ext3");
214        }
215        if (!strcmp(fs, "ext4")) {
216                insmod("crc16");
217                insmod("mbcache");
218                insmod("jbd2");
219                insmod("ext4");
220        }
221        if (!strcmp(fs, "btrfs")) {
222                insmod("libcrc32c");
223                insmod("lzo_compress");
224                insmod("lzo_decompress");
225                insmod("btrfs");
226        }
227#endif
228        if (!strcmp(fs, "vfat")) {
229                insmod("nls_base");
230                insmod("nls_cp932");
231                insmod("nls_cp936");
232                insmod("nls_cp950");
233                insmod("nls_cp437");
234                insmod("nls_iso8859-1");
235                insmod("nls_iso8859-2");
236                insmod("nls_utf8");
237                insmod("fat");
238                insmod("vfat");
239                insmod("msdos");
240        }
241        if (!strcmp(fs, "xfs")) {
242                insmod("xfs");
243        }
244        if (!strcmp(fs, "udf")) {
245                insmod("crc-itu-t");
246                insmod("udf");
247        }
248        if (!strcmp(fs, "iso9660")) {
249                insmod("isofs");
250        }
251        if (target)
252                sysprintf("mkdir -p /tmp/mnt/%s", target);
253        else
254                sysprintf("mkdir -p /tmp/mnt");
255#ifdef HAVE_NTFS3G
256        if (!strcmp(fs, "ntfs")) {
257                ret = eval("ntfs-3g", path, mount_point);
258        } else
259#endif
260                ret =
261                    eval("/bin/mount", "-t", fs, "-o", "iocharset=utf8", path,
262                         mount_point);
263
264        if (ret != 0) {         //give it another try
265#ifdef HAVE_NTFS3G
266                if (!strcmp(fs, "ntfs")) {
267                        ret = eval("ntfs-3g", path, mount_point);
268                } else
269#endif
270                        ret = eval("/bin/mount", path, mount_point);    //guess fs
271        }
272        system("echo 4096 > /proc/sys/vm/min_free_kbytes");     // avoid out of memory problems which could lead to broken wireless, so we limit the minimum free ram to 4096. everything else can be used for fs cache
273        eval("startservice", "samba3");
274        eval("startservice", "ftpsrv");
275        return ret;
276}
277
278static void usb_unmount(char *path)
279{
280        char mount_point[32];
281        eval("stopservice", "samba3");
282        eval("stopservice", "ftpsrv");
283        system("echo 1 > /proc/sys/vm/drop_caches");    // flush fs cache
284/* todo: how to unmount correct drive */
285        if (!path)
286                sprintf(mount_point, "/%s",
287                        nvram_default_get("usb_mntpoint", "mnt"));
288        else
289                strcpy(mount_point, path);
290        eval("/bin/umount", mount_point);
291        eval("rm", "-f", DUMPFILE);
292        eval("startservice", "samba3");
293        eval("startservice", "ftpsrv");
294        return;
295}
296
297    /*
298     * Handle hotplugging of UFD
299     */
300int usb_add_ufd(char *devpath)
301{
302        DIR *dir = NULL;
303        FILE *fp = NULL;
304        char line[256];
305        struct dirent *entry;
306        char path[128];
307        char *fs = NULL;
308        int is_part = 0;
309        char part[10], *partitions, *next;
310        struct stat tmp_stat;
311        int i, found = 0;
312        int mounted[16];
313        memset(mounted, 0, sizeof(mounted));
314
315        if (devpath) {
316                int rcnt = 0;
317              retry:;
318                fp = fopen(devpath, "rb");
319                if (!fp && rcnt < 10) {
320//                      sysprintf("echo not available, try again %s >> /tmp/hotplugs",devpath);
321                        sleep(1);
322                        rcnt++;
323                        goto retry;
324                }
325//              sysprintf("echo open devname %s>> /tmp/hotplugs", devpath);
326        } else {
327                for (i = 1; i < 16; i++) {      //it needs some time for disk to settle down and /dev/discs is created
328                        if ((dir = opendir("/dev/discs")) != NULL
329                            || (fp = fopen("/dev/sda", "rb")) != NULL
330                            || (fp = fopen("/dev/sdb", "rb")) != NULL
331                            || (fp = fopen("/dev/sdc", "rb")) != NULL
332                            || (fp = fopen("/dev/sr0", "rb")) != NULL
333                            || (fp = fopen("/dev/sr1", "rb")) != NULL
334                            || (fp = fopen("/dev/sdd", "rb")) != NULL) {
335                                break;
336                        } else {
337                                sleep(1);
338                        }
339                }
340        }
341        int new = 0;
342        if (fp) {
343                fclose(fp);
344                new = 1;
345                if (dir)
346                        closedir(dir);
347        }
348
349        /*
350         * Scan through entries in the directories
351         */
352
353        for (i = 1; i < 16; i++) {      //it needs some time for disk to settle down and /dev/discs/discs%d is created
354                if (new) {
355                        dir = opendir("/dev");
356                }
357                if (dir == NULL)        // i is 16 here and not 15 if timeout happens
358                        return EINVAL;
359                while ((entry = readdir(dir)) != NULL) {
360                        int is_mounted = 0;
361                        if (mounted[i])
362                                continue;
363
364#ifdef HAVE_X86
365                        char check[32];
366                        strcpy(check, getdisc());
367                        if (!strncmp(entry->d_name, check, 5)) {
368                                fprintf(stderr,
369                                        "skip %s, since its the system drive\n",
370                                        check);
371                                continue;
372                        }
373#endif
374                        if (devpath) {
375                                char devname[64];
376                                sprintf(devname, "/dev/%s", entry->d_name);
377                                //sysprintf
378                                //  ("echo cmp devname %s >> /tmp/hotplugs"
379                                //   ,entry->d_name);
380                                if (strcmp(devname, devpath))
381                                        continue;       // skip all non matching devices
382                                //  sysprintf
383                                //      ("echo take devname %s >> /tmp/hotplugs",
384                                //       devname);
385                        }
386                        if (!new && (strncmp(entry->d_name, "disc", 4)))
387                                continue;
388                        if (new && (strncmp(entry->d_name, "sd", 2))
389                            && (strncmp(entry->d_name, "sr", 2))
390                            && (strncmp(entry->d_name, "mmcblk", 6)))
391                                continue;
392                        mounted[i] = 1;
393
394                        /*
395                         * Files created when the UFD is inserted are not removed when
396                         * it is removed. Verify the device  is still inserted.  Strip
397                         * the "disc" and pass the rest of the string. 
398                         */
399                        if (new) {
400                                //everything else would cause a memory fault
401                                if ((strncmp(entry->d_name, "mmcblk", 6))
402                                    && usb_ufd_connected(entry->d_name) ==
403                                    FALSE)
404                                        continue;
405                        } else {
406                                if (usb_ufd_connected(entry->d_name + 4) ==
407                                    FALSE)
408                                        continue;
409                        }
410                        if (new) {
411                                //              sysprintf("echo test %s >> /tmp/hotplugs",entry->d_name);
412                                if (strlen(entry->d_name) != 3
413                                    && (strncmp(entry->d_name, "mmcblk", 6)))
414                                        continue;
415                                if (strlen(entry->d_name) != 7
416                                    && !(strncmp(entry->d_name, "mmcblk", 6)))
417                                        continue;
418                                //              sysprintf("echo test success %s >> /tmp/hotplugs",entry->d_name);
419                                sprintf(path, "/dev/%s", entry->d_name);
420                        } else {
421                                sprintf(path, "/dev/discs/%s/disc",
422                                        entry->d_name);
423                        }
424                        sysprintf("/usr/sbin/disktype %s > %s", path, DUMPFILE);
425                        //set spindown time
426                        sysprintf("hdparm -S 120 %s", path);
427
428                        /*
429                         * Check if it has file system
430                         */
431                        fs = NULL;
432                        if ((fp = fopen(DUMPFILE, "r"))) {
433                                while (fgets(line, sizeof(line), fp) != NULL) {
434                                        if (strstr(line, "Partition"))
435                                                is_part = 1;
436                                        fprintf(stderr,
437                                                "[USB Device] partition: %s\n",
438                                                line);
439
440                                        if (strstr(line, "file system")) {
441                                                fprintf(stderr,
442                                                        "[USB Device] file system: %s\n",
443                                                        line);
444                                                if (strstr(line, "FAT")) {
445                                                        fs = "vfat";
446                                                        break;
447                                                } else if (strstr(line, "Ext2")) {
448                                                        fs = "ext2";
449                                                        break;
450                                                } else if (strstr(line, "XFS")) {
451                                                        fs = "xfs";
452                                                        break;
453                                                } else if (strstr(line, "UDF")) {
454                                                        fs = "udf";
455                                                        break;
456                                                } else
457                                                    if (strstr(line, "ISO9660"))
458                                                {
459                                                        fs = "iso9660";
460                                                        break;
461                                                } else if (strstr(line, "Ext3")) {
462#ifdef HAVE_USB_ADVANCED
463                                                        fs = "ext3";
464#else
465                                                        fs = "ext2";
466#endif
467                                                        break;
468                                                }
469#ifdef HAVE_USB_ADVANCED
470                                                else if (strstr(line, "Ext4")) {
471                                                        fs = "ext4";
472                                                        break;
473                                                } else
474                                                    if (strstr(line, "Btrfs")) {
475                                                        fs = "btrfs";
476                                                        break;
477                                                }
478#endif
479#ifdef HAVE_NTFS3G
480                                                else if (strstr(line, "NTFS")) {
481                                                        fs = "ntfs";
482                                                        break;
483                                                }
484#endif
485                                        }
486
487                                }
488                                fclose(fp);
489                        }
490
491                        char targetname[64];
492                        if (fs) {
493                                /*
494                                 * If it is partioned, mount first partition else raw disk
495                                 */
496                                if (is_part && !new) {
497                                        partitions =
498                                            "part1 part2 part3 part4 part5 part6";
499                                        foreach(part, partitions, next) {
500                                                sprintf(path,
501                                                        "/dev/discs/%s/%s",
502                                                        entry->d_name, part);
503                                                if (stat(path, &tmp_stat))
504                                                        continue;
505                                                sprintf(targetname, "%s_%s",
506                                                        entry->d_name, part);
507
508                                                if (usb_process_path
509                                                    (path, fs, targetname)
510                                                    == 0) {
511                                                        is_mounted = 1;
512                                                        break;
513                                                }
514                                        }
515                                }
516                                if (is_part && new) {
517                                        partitions = "1 2 3 4 5 6";
518                                        foreach(part, partitions, next) {
519                                                sprintf(path, "/dev/%s%s",
520                                                        entry->d_name, part);
521                                                if (stat(path, &tmp_stat))
522                                                        continue;
523                                                sprintf(targetname, "%s_part%s",
524                                                        entry->d_name, part);
525                                                if (usb_process_path
526                                                    (path, fs, targetname)
527                                                    == 0) {
528                                                        is_mounted = 1;
529                                                        break;
530                                                }
531                                        }
532                                } else {
533                                        if (new)
534                                                sprintf(targetname, "disc%s",
535                                                        entry->d_name);
536                                        else
537                                                sprintf(targetname, "%s",
538                                                        entry->d_name);
539                                        if (usb_process_path
540                                            (path, fs, targetname) == 0)
541                                                is_mounted = 1;
542                                }
543
544                        }
545
546                        if ((fp = fopen(DUMPFILE, "a"))) {
547                                if (fs && is_mounted) {
548                                        fprintf(fp,
549                                                "Status: <b>Mounted on /%s</b>\n",
550                                                nvram_safe_get("usb_mntpoint"));
551                                        i = 16;
552                                } else if (fs)
553                                        fprintf(fp,
554                                                "Status: <b>Not mounted</b>\n");
555                                else
556                                        fprintf(fp,
557                                                "Status: <b>Not mounted - Unsupported file system or disk not formated</b>\n");
558                                fclose(fp);
559                        }
560
561                        if (is_mounted && !nvram_match("usb_runonmount", "")) {
562                                sprintf(path, "%s",
563                                        nvram_safe_get("usb_runonmount"));
564                                if (stat(path, &tmp_stat) == 0) //file exists
565                                {
566                                        setenv("PATH",
567                                               "/sbin:/bin:/usr/sbin:/usr/bin:/jffs/sbin:/jffs/bin:/jffs/usr/sbin:/jffs/usr/bin:/mmc/sbin:/mmc/bin:/mmc/usr/sbin:/mmc/usr/bin:/opt/bin:/opt/sbin:/opt/usr/bin:/opt/usr/sbin",
568                                               1);
569                                        setenv("LD_LIBRARY_PATH",
570                                               "/lib:/usr/lib:/jffs/lib:/jffs/usr/lib:/mmc/lib:/mmc/usr/lib:/opt/lib:/opt/usr/lib",
571                                               1);
572
573                                        system(path);
574                                }
575                        }
576                }
577                if (i < 4)
578                        sleep(1);
579                if (new)
580                        closedir(dir);
581        }
582        return 0;
583}
Note: See TracBrowser for help on using the repository browser.