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

Last change on this file since 17206 was 17206, checked in by BrainSlayer, 2 years ago

new x86 code

File size: 9.7 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);
22static void usb_unmount(void);
23int usb_add_ufd(void);
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[]={"sda2","sdb2","sdc2","sdd2","sde2","sdf2","sdg2","sdh2","sdi2"};
33        for (i = 0; i < 9; i++) {
34                char dev[64];
35
36                sprintf(dev, "/dev/%s", disks[i]);
37                FILE *in = fopen(dev, "rb");
38
39                if (in == NULL)
40                        continue;       // no second partition or disc does not
41                // exist, skipping
42                char buf[4];
43
44                fread(buf, 4, 1, in);
45                if (buf[0] == 'h' && buf[1] == 's' && buf[2] == 'q'
46                    && buf[3] == 't') {
47                        fclose(in);
48                        // filesystem detected
49                        strncpy(ret,disks[i],3);
50                        return ret;
51                }
52                fclose(in);
53        }
54        return NULL;
55}
56#endif
57void start_hotplug_usb(void)
58{
59        char *device, *interface;
60        char *action;
61        int class, subclass, protocol;
62
63        if (!(nvram_match("usb_automnt", "1")))
64                return;
65
66        if (!(action = getenv("ACTION")) || !(device = getenv("TYPE")))
67                return;
68
69        sscanf(device, "%d/%d/%d", &class, &subclass, &protocol);
70
71        if (class == 0) {
72                if (!(interface = getenv("INTERFACE")))
73                        return;
74                sscanf(interface, "%d/%d/%d", &class, &subclass, &protocol);
75        }
76
77        /*
78         * If a new USB device is added and it is of storage class
79         */
80        if (class == 8 && subclass == 6) {
81                if (!strcmp(action, "add"))
82                        usb_add_ufd();
83                if (!strcmp(action, "remove"))
84                        usb_unmount();
85        }
86
87        return;
88}
89
90    /*
91     *   Check if the UFD is still connected because the links created in
92     * /dev/discs are not removed when the UFD is  unplugged. 
93     */
94static bool usb_ufd_connected(char *str)
95{
96        uint host_no;
97        char proc_file[128];
98        FILE *fp;
99        char line[256];
100        int i;
101
102        /*
103         * Host no. assigned by scsi driver for this UFD
104         */
105        host_no = atoi(str);
106        sprintf(proc_file, "/proc/scsi/usb-storage-%d/%d", host_no, host_no);
107
108        if ((fp = fopen(proc_file, "r"))) {
109                while (fgets(line, sizeof(line), fp) != NULL) {
110                        if (strstr(line, "Attached: Yes")) {
111                                fclose(fp);
112                                return TRUE;
113                        }
114                }
115                fclose(fp);
116        }
117        //in 2.6 kernels its a little bit different; find 1st
118        for (i = 0; i < 16; i++) {
119                sprintf(proc_file, "/proc/scsi/usb-storage/%d", i);
120                if (f_exists(proc_file)) {
121                        return TRUE;
122                }
123        }
124        return FALSE;
125
126}
127
128    /*
129     *   Mount the path and look for the WCN configuration file.  If it
130     * exists launch wcnparse to process the configuration. 
131     */
132static int usb_process_path(char *path, char *fs)
133{
134        int ret = ENOENT;
135        char mount_point[32];
136        eval("stopservice", "samba3");
137        eval("stopservice", "ftpsrv");
138
139        sprintf(mount_point, "/%s", nvram_default_get("usb_mntpoint", "mnt"));
140#ifdef HAVE_NTFS3G
141        if (!strcmp(fs, "ntfs"))
142                insmod("fuse");
143#endif
144        if (!strcmp(fs, "ext2")) {
145                insmod("mbcache");
146                insmod("ext2");
147        }
148#ifdef HAVE_USB_ADVANCED
149        if (!strcmp(fs, "ext3")) {
150                insmod("mbcache");
151                insmod("ext2");
152                insmod("jbd");
153                insmod("ext3");
154        }
155#endif
156        if (!strcmp(fs, "vfat")) {
157                insmod("nls_base");
158                insmod("nls_cp437");
159                insmod("nls_iso8859-1");
160                insmod("nls_iso8859-2");
161                insmod("nls_utf8");
162                insmod("fat");
163                insmod("vfat");
164                insmod("msdos");
165        }
166        if (!strcmp(fs, "xfs")) {
167                insmod("xfs");
168        }
169#ifdef HAVE_NTFS3G
170        if (!strcmp(fs, "ntfs")) {
171                ret = eval("ntfs-3g", path, mount_point);
172        } else
173#endif
174                ret = eval("/bin/mount", "-t", fs, path, mount_point);
175
176        if (ret != 0) {         //give it another try
177#ifdef HAVE_NTFS3G
178                if (!strcmp(fs, "ntfs")) {
179                        ret = eval("ntfs-3g", path, mount_point);
180                } else
181#endif
182                        ret = eval("/bin/mount", path, mount_point);    //guess fs
183        }
184        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
185        eval("startservice", "samba3");
186        eval("startservice", "ftpsrv");
187        return ret;
188}
189
190static void usb_unmount(void)
191{
192        char mount_point[32];
193        eval("stopservice", "samba3");
194        eval("stopservice", "ftpsrv");
195        system("echo 1 > /proc/sys/vm/drop_caches");    // flush fs cache
196        sprintf(mount_point, "/%s", nvram_default_get("usb_mntpoint", "mnt"));
197        eval("/bin/umount", mount_point);
198        eval("rm", "-f", DUMPFILE);
199        eval("startservice", "samba3");
200        eval("startservice", "ftpsrv");
201        return;
202}
203
204    /*
205     * Handle hotplugging of UFD
206     */
207int usb_add_ufd(void)
208{
209        DIR *dir = NULL;
210        FILE *fp = NULL;
211        char line[256];
212        struct dirent *entry;
213        char path[128];
214        char *fs = NULL;
215        int is_part = 0;
216        int is_mounted = 0;
217        char part[10], *partitions, *next;
218        struct stat tmp_stat;
219        int i, found = 0;
220
221        for (i = 1; i < 16; i++) {      //it needs some time for disk to settle down and /dev/discs is created
222                if ((dir = opendir("/dev/discs")) != NULL
223                    || (fp = fopen("/dev/sda", "rb")) != NULL
224                    || (fp = fopen("/dev/sdb", "rb")) != NULL
225                    || (fp = fopen("/dev/sdc", "rb")) != NULL
226                    || (fp = fopen("/dev/sdd", "rb")) != NULL) {
227                        break;
228                } else {
229                        sleep(1);
230                }
231        }
232        int new = 0;
233        if (fp) {
234                fclose(fp);
235                new = 1;
236                if (dir)
237                        closedir(dir);
238                dir = opendir("/dev");
239        }
240        if (dir == NULL)        // i is 16 here and not 15 if timeout happens
241                return EINVAL;
242
243        /*
244         * Scan through entries in the directories
245         */
246
247        for (i = 1; i < 16; i++) {      //it needs some time for disk to settle down and /dev/discs/discs%d is created
248                while ((entry = readdir(dir)) != NULL) {
249
250#ifdef HAVE_X86
251                        char check[32];
252                        strcpy(check, getdisc());
253                        if (!strncmp(entry->d_name, check, 5)) {
254                                fprintf(stderr,
255                                        "skip %s, since its the system drive\n",
256                                        check);
257                                continue;
258                        }
259#endif
260                        if (!new && (strncmp(entry->d_name, "disc", 4)))
261                                continue;
262                        if (new && (strncmp(entry->d_name, "sd", 2)))
263                                continue;
264                        found = 1;
265
266                        /*
267                         * Files created when the UFD is inserted are not removed when
268                         * it is removed. Verify the device  is still inserted.  Strip
269                         * the "disc" and pass the rest of the string. 
270                         */
271                        if (new) {
272                                //everything else would cause a memory fault
273                                if (usb_ufd_connected(entry->d_name) == FALSE)
274                                        continue;
275                        } else {
276                                if (usb_ufd_connected(entry->d_name + 4) ==
277                                    FALSE)
278                                        continue;
279                        }
280                        if (new) {
281                                if (strlen(entry->d_name) != 3)
282                                        continue;
283                                sprintf(path, "/dev/%s", entry->d_name);
284                        } else {
285                                sprintf(path, "/dev/discs/%s/disc",
286                                        entry->d_name);
287                        }
288                        sysprintf("/usr/sbin/disktype %s > %s", path, DUMPFILE);
289                        //set spindown time
290                        sysprintf("hdparm -S 120 %s",path);
291
292                        /*
293                         * Check if it has file system
294                         */
295                        if ((fp = fopen(DUMPFILE, "r"))) {
296                                while (fgets(line, sizeof(line), fp) != NULL) {
297                                        if (strstr(line, "Partition"))
298                                                is_part = 1;
299                                        fprintf(stderr,
300                                                "[USB Device] partition: %s\n",
301                                                line);
302
303                                        if (strstr(line, "file system")) {
304                                                fprintf(stderr,
305                                                        "[USB Device] file system: %s\n",
306                                                        line);
307                                                if (strstr(line, "FAT")) {
308                                                        fs = "vfat";
309                                                        break;
310                                                } else if (strstr(line, "Ext2")) {
311                                                        fs = "ext2";
312                                                        break;
313                                                } else if (strstr(line, "XFS")) {
314                                                        fs = "xfs";
315                                                        break;
316                                                } else if (strstr(line, "Ext3")) {
317#ifdef HAVE_USB_ADVANCED
318                                                        fs = "ext3";
319#else
320                                                        fs = "ext2";
321#endif
322                                                        break;
323                                                }
324#ifdef HAVE_NTFS3G
325                                                else if (strstr(line, "NTFS")) {
326                                                        fs = "ntfs";
327                                                        break;
328                                                }
329#endif
330                                        }
331
332                                }
333                                fclose(fp);
334                        }
335
336                        if (fs) {
337                                /*
338                                 * If it is partioned, mount first partition else raw disk
339                                 */
340                                if (is_part && !new) {
341                                        partitions =
342                                            "part1 part2 part3 part4 part5 part6";
343                                        foreach(part, partitions, next) {
344                                                sprintf(path,
345                                                        "/dev/discs/%s/%s",
346                                                        entry->d_name, part);
347                                                if (stat(path, &tmp_stat))
348                                                        continue;
349                                                if (usb_process_path(path, fs)
350                                                    == 0) {
351                                                        is_mounted = 1;
352                                                        break;
353                                                }
354                                        }
355                                }
356                                if (is_part && new) {
357                                        partitions = "1 2 3 4 5 6";
358                                        foreach(part, partitions, next) {
359                                                sprintf(path, "/dev/%s%s",
360                                                        entry->d_name, part);
361                                                if (stat(path, &tmp_stat))
362                                                        continue;
363                                                if (usb_process_path(path, fs)
364                                                    == 0) {
365                                                        is_mounted = 1;
366                                                        break;
367                                                }
368                                        }
369                                } else {
370                                        if (usb_process_path(path, fs) == 0)
371                                                is_mounted = 1;
372                                }
373
374                        }
375
376                        if ((fp = fopen(DUMPFILE, "a"))) {
377                                if (fs && is_mounted)
378                                        fprintf(fp,
379                                                "Status: <b>Mounted on /%s</b>\n",
380                                                nvram_safe_get("usb_mntpoint"));
381                                else if (fs)
382                                        fprintf(fp,
383                                                "Status: <b>Not mounted</b>\n");
384                                else
385                                        fprintf(fp,
386                                                "Status: <b>Not mounted - Unsupported file system or disk not formated</b>\n");
387                                fclose(fp);
388                        }
389
390                        if (is_mounted && !nvram_match("usb_runonmount", "")) {
391                                sprintf(path, "%s",
392                                        nvram_safe_get("usb_runonmount"));
393                                if (stat(path, &tmp_stat) == 0) //file exists
394                                {
395                                        setenv("PATH",
396                                               "/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",
397                                               1);
398                                        setenv("LD_LIBRARY_PATH",
399                                               "/lib:/usr/lib:/jffs/lib:/jffs/usr/lib:/mmc/lib:/mmc/usr/lib:/opt/lib:/opt/usr/lib",
400                                               1);
401
402                                        system(path);
403                                }
404                        }
405
406                        if (is_mounted) {       //temp. fix: only mount 1st mountable part, then exit
407                                closedir(dir);
408                                return 0;
409                        }
410                }
411                if (!found)
412                        sleep(1);
413                else
414                        break;
415        }
416        closedir(dir);
417        return 0;
418}
Note: See TracBrowser for help on using the repository browser.