Revert "Do not use UTF8 charset for FAT"
[tomato.git] / release / src / router / rc / usb.c
blob9033a627ab5f1d880c090304dbcd388c25e2ecb1
1 /*
3 USB Support
5 */
6 #include "rc.h"
8 #include <sys/types.h>
9 #include <unistd.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <arpa/inet.h>
13 #include <time.h>
14 #include <sys/time.h>
15 #include <errno.h>
17 #include <sys/mount.h>
18 #include <mntent.h>
19 #include <dirent.h>
20 #include <sys/file.h>
21 #include <sys/swap.h>
23 /* Adjust bdflush parameters.
24 * Do this here, because Tomato doesn't have the sysctl command.
25 * With these values, a disk block should be written to disk within 2 seconds.
27 #ifdef LINUX26
28 void tune_bdflush(void)
30 f_write_string("/proc/sys/vm/dirty_expire_centisecs", "200", 0, 0);
31 //f_write_string("/proc/sys/vm/dirty_writeback_centisecs", "100", 0, 0);
33 #else
34 #include <sys/kdaemon.h>
35 #define SET_PARM(n) (n * 2 | 1)
36 void tune_bdflush(void)
38 bdflush(SET_PARM(5), 100);
39 bdflush(SET_PARM(6), 100);
40 bdflush(SET_PARM(8), 0);
42 #endif // LINUX26
44 #define USBCORE_MOD "usbcore"
45 #define USB20_MOD "ehci-hcd"
46 #define USBSTORAGE_MOD "usb-storage"
47 #define SCSI_MOD "scsi_mod"
48 #define SD_MOD "sd_mod"
49 #ifdef LINUX26
50 #define USBOHCI_MOD "ohci-hcd"
51 #define USBUHCI_MOD "uhci"
52 #define USBPRINTER_MOD "usblp"
53 #define SCSI_WAIT_MOD "scsi_wait_scan"
54 #define USBFS "usbfs"
55 #else
56 #define USBOHCI_MOD "usb-ohci"
57 #define USBUHCI_MOD "usb-uhci"
58 #define USBPRINTER_MOD "printer"
59 #define USBFS "usbdevfs"
60 #endif
63 void start_usb(void)
65 _dprintf("%s\n", __FUNCTION__);
66 tune_bdflush();
68 if (nvram_get_int("usb_enable")) {
69 // led(LED_AOSS, LED_ON);
70 modprobe(USBCORE_MOD);
72 /* mount usb device filesystem */
73 mount(USBFS, "/proc/bus/usb", USBFS, MS_MGC_VAL, NULL);
75 if (nvram_get_int("usb_storage")) {
76 /* insert scsi and storage modules before usb drivers */
77 modprobe(SCSI_MOD);
78 #ifdef LINUX26
79 modprobe(SCSI_WAIT_MOD);
80 #endif
81 modprobe(SD_MOD);
82 modprobe(USBSTORAGE_MOD);
84 if (nvram_get_int("usb_fs_ext3")) {
85 #ifdef LINUX26
86 modprobe("mbcache"); // used by ext2/ext3
87 #endif
88 /* insert ext3 first so that lazy mount tries ext3 before ext2 */
89 modprobe("jbd");
90 modprobe("ext3");
91 modprobe("ext2");
94 if (nvram_get_int("usb_fs_fat")) {
95 modprobe("fat");
96 modprobe("vfat");
100 /* if enabled, force USB2 before USB1.1 */
101 if (nvram_get_int("usb_usb2")) {
102 modprobe(USB20_MOD);
105 if (nvram_get_int("usb_uhci")) {
106 modprobe(USBUHCI_MOD);
109 if (nvram_get_int("usb_ohci")) {
110 modprobe(USBOHCI_MOD);
113 if (nvram_get_int("usb_printer")) {
114 symlink("/dev/usb", "/dev/printers");
115 modprobe(USBPRINTER_MOD);
117 /* start printer server */
118 xstart("p910nd",
119 nvram_get_int("usb_printer_bidirect") ? "-b" : "", //bidirectional
120 "-f", "/dev/usb/lp0", // device
121 "0" // listen port
125 else {
126 // led(LED_AOSS, LED_OFF);
130 void stop_usb(void)
132 // stop printing service
133 int i;
134 char s[32];
135 char pid[] = "/var/run/p9100d.pid";
137 // only find and kill the printer server we started (port 0)
138 if (f_read_string(pid, s, sizeof(s)) > 0) {
139 if ((i = atoi(s)) > 1) {
140 kill(i, SIGTERM);
141 sleep(1);
142 unlink(pid);
145 modprobe_r(USBPRINTER_MOD);
147 // only stop storage services if disabled
148 if (!nvram_get_int("usb_enable") || !nvram_get_int("usb_storage")) {
149 // Unmount all partitions
150 remove_storage_main(0);
152 // Stop storage services
153 modprobe_r("ext2");
154 modprobe_r("ext3");
155 modprobe_r("jbd");
156 #ifdef LINUX26
157 modprobe_r("mbcache");
158 #endif
159 modprobe_r("vfat");
160 modprobe_r("fat");
161 modprobe_r("fuse");
162 sleep(1);
163 #ifdef TCONFIG_SAMBASRV
164 modprobe_r("nls_cp437");
165 modprobe_r("nls_cp850");
166 modprobe_r("nls_cp852");
167 modprobe_r("nls_cp866");
168 #ifdef LINUX26
169 modprobe_r("nls_cp932");
170 modprobe_r("nls_cp936");
171 modprobe_r("nls_cp949");
172 modprobe_r("nls_cp950");
173 #endif
174 #endif
175 modprobe_r(USBSTORAGE_MOD);
176 modprobe_r(SD_MOD);
177 #ifdef LINUX26
178 modprobe_r(SCSI_WAIT_MOD);
179 #endif
180 modprobe_r(SCSI_MOD);
183 // only unload core modules if usb is disabled
184 if (!nvram_get_int("usb_enable")) {
185 umount("/proc/bus/usb"); // unmount usb device filesystem
186 modprobe_r(USBOHCI_MOD);
187 modprobe_r(USBUHCI_MOD);
188 modprobe_r(USB20_MOD);
189 modprobe_r(USBCORE_MOD);
194 #define MOUNT_VAL_FAIL 0
195 #define MOUNT_VAL_RONLY 1
196 #define MOUNT_VAL_RW 2
197 #define MOUNT_VAL_EXIST 3
199 int mount_r(char *mnt_dev, char *mnt_dir, char *type)
201 struct mntent *mnt;
202 int ret;
203 char options[80];
204 char flagfn[128];
205 int dir_made;
207 if ((mnt = findmntents(mnt_dev, 0, NULL, 0))) {
208 syslog(LOG_INFO, "USB partition at %s already mounted on %s",
209 mnt_dev, mnt->mnt_dir);
210 return MOUNT_VAL_EXIST;
213 options[0] = 0;
215 if (type) {
216 unsigned long flags = MS_NOATIME | MS_NODEV;
218 if (strcmp(type, "swap") == 0 || strcmp(type, "mbr") == 0) {
219 /* not a mountable partition */
220 flags = 0;
222 else if (strcmp(type, "ext2") == 0 || strcmp(type, "ext3") == 0) {
224 #ifdef TCONFIG_SAMBASRV
225 else if (strcmp(type, "vfat") == 0) {
226 if (nvram_invmatch("smbd_cset", ""))
227 sprintf(options, "iocharset=%s%s",
228 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
229 nvram_get("smbd_cset"));
230 if (nvram_invmatch("smbd_cpage", "")) {
231 char *cp = nvram_safe_get("smbd_cpage");
232 sprintf(options + strlen(options), ",codepage=%s" + (options[0] ? 0 : 1), cp);
233 sprintf(flagfn, "nls_cp%s", cp);
235 cp = nvram_get("smbd_nlsmod");
236 if ((cp) && (*cp != 0) && (strcmp(cp, flagfn) != 0))
237 modprobe_r(cp);
239 modprobe(flagfn);
240 nvram_set("smbd_nlsmod", flagfn);
242 sprintf(options + strlen(options), ",shortname=winnt" + (options[0] ? 0 : 1));
243 #ifdef LINUX26
244 sprintf(options + strlen(options), ",flush" + (options[0] ? 0 : 1));
245 #endif
247 else if (strncmp(type, "ntfs", 4) == 0) {
248 if (nvram_invmatch("smbd_cset", ""))
249 sprintf(options, "iocharset=%s%s",
250 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
251 nvram_get("smbd_cset"));
253 #endif
255 if (flags) {
256 if ((dir_made = mkdir_if_none(mnt_dir))) {
257 /* Create the flag file for remove the directory on dismount. */
258 sprintf(flagfn, "%s/.autocreated-dir", mnt_dir);
259 f_write(flagfn, NULL, 0, 0, 0);
262 ret = mount(mnt_dev, mnt_dir, type, flags, options[0] ? options : "");
264 /* try ntfs-3g in case it's installed */
265 if (ret != 0 && strncmp(type, "ntfs", 4) == 0) {
266 sprintf(options + strlen(options), ",noatime,nodev" + (options[0] ? 0 : 1));
267 #ifdef TCONFIG_NTFS
268 if (nvram_get_int("usb_fs_ntfs"))
269 #endif
270 ret = eval("ntfs-3g", "-o", options, mnt_dev, mnt_dir);
272 if (ret != 0) /* give it another try - guess fs */
273 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
275 if (ret == 0) {
276 syslog(LOG_INFO, "USB %s%s fs at %s mounted on %s",
277 type, (flags & MS_RDONLY) ? " (ro)" : "", mnt_dev, mnt_dir);
278 return (flags & MS_RDONLY) ? MOUNT_VAL_RONLY : MOUNT_VAL_RW;
281 if (dir_made) {
282 unlink(flagfn);
283 rmdir(mnt_dir);
287 return MOUNT_VAL_FAIL;
291 struct mntent *mount_fstab(char *dev_name, char *type, char *label, char *uuid)
293 struct mntent *mnt = NULL;
294 #if 0
295 if (eval("mount", "-a") == 0)
296 mnt = findmntents(dev_name, 0, NULL, 0);
297 #else
298 char spec[PATH_MAX+1];
300 if (label && *label) {
301 sprintf(spec, "LABEL=%s", label);
302 if (eval("mount", spec) == 0)
303 mnt = findmntents(dev_name, 0, NULL, 0);
306 if (!mnt && uuid && *uuid) {
307 sprintf(spec, "UUID=%s", uuid);
308 if (eval("mount", spec) == 0)
309 mnt = findmntents(dev_name, 0, NULL, 0);
312 if (!mnt) {
313 if (eval("mount", dev_name) == 0)
314 mnt = findmntents(dev_name, 0, NULL, 0);
317 if (!mnt) {
318 /* Still did not find what we are looking for, try absolute path */
319 if (realpath(dev_name, spec)) {
320 if (eval("mount", spec) == 0)
321 mnt = findmntents(dev_name, 0, NULL, 0);
324 #endif
326 if (mnt)
327 syslog(LOG_INFO, "USB %s fs at %s mounted on %s", type, dev_name, mnt->mnt_dir);
328 return (mnt);
332 /* Check if the UFD is still connected because the links created in /dev/discs
333 * are not removed when the UFD is unplugged.
334 * The file to read is: /proc/scsi/usb-storage-#/#, where # is the host no.
335 * We are looking for "Attached: Yes".
337 static int usb_ufd_connected(int host_no)
339 char proc_file[128];
340 #ifndef LINUX26
341 char line[256];
342 #endif
343 FILE *fp;
345 sprintf(proc_file, "%s/%s-%d/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no, host_no);
346 fp = fopen(proc_file, "r");
348 if (!fp) {
349 /* try the way it's implemented in newer kernels: /proc/scsi/usb-storage/[host] */
350 sprintf(proc_file, "%s/%s/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no);
351 fp = fopen(proc_file, "r");
354 if (fp) {
355 #ifdef LINUX26
356 fclose(fp);
357 return 1;
358 #else
359 while (fgets(line, sizeof(line), fp) != NULL) {
360 if (strstr(line, "Attached: Yes")) {
361 fclose(fp);
362 return 1;
365 fclose(fp);
366 #endif
369 return 0;
373 #ifndef MNT_DETACH
374 #define MNT_DETACH 0x00000002 /* from linux/fs.h - just detach from the tree */
375 #endif
376 int umount_mountpoint(struct mntent *mnt, uint flags);
377 int uswap_mountpoint(struct mntent *mnt, uint flags);
379 /* Unmount this partition from all its mountpoints. Note that it may
380 * actually be mounted several times, either with different names or
381 * with "-o bind" flag.
382 * If the special flagfile is now revealed, delete it and [attempt to] delete
383 * the directory.
385 int umount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
387 sync(); /* This won't matter if the device is unplugged, though. */
389 if (flags & EFH_HUNKNOWN) {
390 /* EFH_HUNKNOWN flag is passed if the host was unknown.
391 * Only unmount disconnected drives in this case.
393 if (usb_ufd_connected(host_num))
394 return(0);
397 /* Find all the active swaps that are on this device and stop them. */
398 findmntents(dev_name, 1, uswap_mountpoint, flags);
400 /* Find all the mountpoints that are for this device and unmount them. */
401 findmntents(dev_name, 0, umount_mountpoint, flags);
402 return 0;
405 int uswap_mountpoint(struct mntent *mnt, uint flags)
407 swapoff(mnt->mnt_fsname);
408 return 0;
411 int umount_mountpoint(struct mntent *mnt, uint flags)
413 int ret = 1, count;
414 char flagfn[128];
416 /* Kill all NAS applications here so they are not keeping the device busy,
417 * unless it's an unmount request from the Web GUI.
419 if ((flags & EFH_USER) == 0) {
420 restart_nas_services(1, 0);
423 sprintf(flagfn, "%s/.autocreated-dir", mnt->mnt_dir);
424 run_nvscript("script_autostop", mnt->mnt_dir, 5);
425 count = 0;
426 while ((ret = umount(mnt->mnt_dir)) && (count < 2)) {
427 count++;
428 sleep(1);
431 if (!ret)
432 syslog(LOG_INFO, "USB partition unmounted from %s", mnt->mnt_dir);
434 if (ret && ((flags & EFH_SHUTDN) != 0)) {
435 /* If system is stopping (not restarting), and we couldn't unmount the
436 * partition, try to remount it as read-only. Ignore the return code -
437 * we can still try to do a lazy unmount.
439 eval("mount", "-o", "remount,ro", mnt->mnt_dir);
442 if (ret && ((flags & EFH_USER) == 0)) {
443 /* Make one more try to do a lazy unmount unless it's an unmount
444 * request from the Web GUI.
445 * MNT_DETACH will expose the underlying mountpoint directory to all
446 * except whatever has cd'ed to the mountpoint (thereby making it busy).
447 * So the unmount can't actually fail. It disappears from the ken of
448 * everyone else immediately, and from the ken of whomever is keeping it
449 * busy until they move away from it. And then it disappears for real.
451 ret = umount2(mnt->mnt_dir, MNT_DETACH);
452 syslog(LOG_INFO, "USB partition busy - will unmount ASAP from %s", mnt->mnt_dir);
455 if (!ret) {
456 if ((unlink(flagfn) == 0)) {
457 // Only delete the directory if it was auto-created
458 rmdir(mnt->mnt_dir);
461 return(!ret);
465 /* Mount this partition on this disc.
466 * If the device is already mounted on any mountpoint, don't mount it again.
467 * If this is a swap partition, try swapon -a.
468 * If this is a regular partition, try mount -a.
470 * Before we mount any partitions:
471 * If the type is swap and /etc/fstab exists, do "swapon -a"
472 * If /etc/fstab exists, try mounting using fstab.
473 * We delay invoking mount because mount will probe all the partitions
474 * to read the labels, and we don't want it to do that early on.
475 * We don't invoke swapon until we actually find a swap partition.
477 * If the mount succeeds, execute the *.autorun scripts in the top
478 * directory of the newly mounted partition.
479 * Returns NZ for success, 0 if we did not mount anything.
481 int mount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
483 char the_label[128], mountpoint[128], uuid[40];
484 int ret;
485 char *type;
486 static char *swp_argv[] = { "swapon", "-a", NULL };
487 struct mntent *mnt;
489 if ((type = detect_fs_type(dev_name)) == NULL)
490 return(0);
491 find_label_or_uuid(dev_name, the_label, uuid);
493 if (f_exists("/etc/fstab")) {
494 if (strcmp(type, "swap") == 0) {
495 _eval(swp_argv, NULL, 0, NULL);
496 return(0);
499 if (mount_r(dev_name, NULL, NULL) == MOUNT_VAL_EXIST)
500 return(0);
502 if ((mnt = mount_fstab(dev_name, type, the_label, uuid))) {
503 run_userfile(mnt->mnt_dir, ".autorun", mnt->mnt_dir, 3);
504 return(1);
508 if (*the_label != 0) {
509 char *p;
510 for (p = the_label; *p; p++) {
511 if (*p == ' ') *p = '_';
513 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, the_label);
514 if ((ret = mount_r(dev_name, mountpoint, type))) {
515 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
516 run_userfile(mountpoint, ".autorun", mountpoint, 3);
517 return(ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
521 /* Can't mount to /mnt/LABEL, so try mounting to /mnt/discDN_PN */
522 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, pt_name);
523 ret = mount_r(dev_name, mountpoint, type);
524 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
525 run_userfile(mountpoint, ".autorun", mountpoint, 3);
526 return (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
530 #if 0 /* LINUX26 */
533 * Finds SCSI Host number. Returns the host number >=0 if found, or (-1) otherwise.
534 * The name and host number of scsi block device in kernel 2.6 (for attached devices) can be found as
535 * /sys($DEVPATH)/host<host_no>/target<*>/<id>/block:[sda|sdb|...]
536 * where $DEVPATH is passed to hotplug events, and looks like
537 * /devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.2
539 * For printers this function finds a minor assigned to a printer
540 * /sys($DEVPATH)/usb:lp[0|1|2|...]
542 int find_dev_host(const char *devpath)
544 DIR *usb_devpath;
545 struct dirent *dp;
546 char buf[256];
547 int host = -1; /* Scsi Host */
549 sprintf(buf, "/sys%s", devpath);
550 if ((usb_devpath = opendir(buf))) {
551 while ((dp = readdir(usb_devpath))) {
552 errno = 0;
553 if (strncmp(dp->d_name, "host", 4) == 0) {
554 host = strtol(dp->d_name + 4, (char **)NULL, 10);
555 if (errno)
556 host = -1;
557 else
558 break;
560 else if (strncmp(dp->d_name, "usb:lp", 6) == 0) {
561 host = strtol(dp->d_name + 6, (char **)NULL, 10);
562 if (errno)
563 host = -1;
564 else
565 break;
567 else
568 continue;
570 closedir(usb_devpath);
572 return (host);
575 #endif /* LINUX26 */
578 /* Mount or unmount all partitions on this controller.
579 * Parameter: action_add:
580 * 0 = unmount
581 * >0 = mount only if automount config option is enabled.
582 * <0 = mount regardless of config option.
584 void hotplug_usb_storage_device(int host_no, int action_add, uint flags)
586 if (!nvram_get_int("usb_enable"))
587 return;
588 _dprintf("%s: host %d action: %d\n", __FUNCTION__, host_no, action_add);
590 if (action_add) {
591 if (nvram_get_int("usb_storage") && (nvram_get_int("usb_automount") || action_add < 0)) {
592 /* Do not probe the device here. It's either initiated by user,
593 * or hotplug_usb() already did.
595 if (exec_for_host(host_no, 0x00, flags, mount_partition)) {
596 restart_nas_services(0, 1); // restart all NAS applications
597 run_nvscript("script_usbmount", NULL, 3);
601 else {
602 if (nvram_get_int("usb_storage") || ((flags & EFH_USER) == 0)) {
603 /* When unplugged, unmount the device even if
604 * usb storage is disabled in the GUI.
606 if (flags & EFH_USER) {
607 /* Unmount from Web. Run user pre-unmount script if any.
609 run_nvscript("script_usbumount", NULL, 3);
611 exec_for_host(host_no, (flags & EFH_USER) ? 0x00 : 0x02, flags, umount_partition);
612 /* Restart NAS applications (they could be killed by umount_mountpoint),
613 * or just re-read the configuration.
615 restart_nas_services(0, 1);
621 /* This gets called at reboot or upgrade. The system is stopping. */
622 void remove_storage_main(int shutdn)
624 if (nvram_get_int("usb_enable") && nvram_get_int("usb_storage")) {
625 if (nvram_get_int("usb_automount")) {
626 // run pre-unmount script if any
627 run_nvscript("script_usbumount", NULL, 3);
630 if (shutdn)
631 restart_nas_services(1, 0);
632 /* Unmount all partitions */
633 exec_for_host(-1, 0x02, shutdn ? EFH_SHUTDN : 0, umount_partition);
637 /*******
638 * All the complex locking & checking code was removed when the kernel USB-storage
639 * bugs were fixed.
640 * The crash bug was with overlapped I/O to different USB drives, not specifically
641 * with mount processing.
643 * And for USB devices that are slow to come up. The kernel now waits until the
644 * USB drive has settled, and it correctly reads the partition table before calling
645 * the hotplug agent.
647 * The kernel patch was cleaning up data structures on an unplug. It
648 * needs to wait until the disk is unmounted. We have 20 seconds to do
649 * the unmounts.
650 *******/
653 /* Plugging or removing usb device
655 * On an occurrance, multiple hotplug events may be fired off.
656 * For example, if a hub is plugged or unplugged, an event
657 * will be generated for everything downstream of it, plus one for
658 * the hub itself. These are fired off simultaneously, not serially.
659 * This means that many many hotplug processes will be running at
660 * the same time.
662 * The hotplug event generated by the kernel gives us several pieces
663 * of information:
664 * PRODUCT is vendorid/productid/rev#.
665 * DEVICE is /proc/bus/usb/bus#/dev#
666 * ACTION is add or remove
667 * SCSI_HOST is the host (controller) number (this relies on the custom kernel patch)
669 * Note that when we get a hotplug add event, the USB susbsystem may
670 * or may not have yet tried to read the partition table of the
671 * device. For a new controller that has never been seen before,
672 * generally yes. For a re-plug of a controller that has been seen
673 * before, generally no.
675 * On a remove, the partition info has not yet been expunged. The
676 * partitions show up as /dev/discs/disc#/part#, and /proc/partitions.
677 * It appears that doing a "stat" for a non-existant partition will
678 * causes the kernel to re-validate the device and update the
679 * partition table info. However, it won't re-validate if the disc is
680 * mounted--you'll get a "Device busy for revalidation (usage=%d)" in
681 * syslog.
683 * The $INTERFACE is "class/subclass/protocol"
684 * Some interesting classes:
685 * 8 = mass storage
686 * 7 = printer
687 * 3 = HID. 3/1/2 = mouse.
688 * 6 = still image (6/1/1 = Digital camera Camera)
689 * 9 = Hub
690 * 255 = scanner (255/255/255)
692 * Observed:
693 * Hub seems to have no INTERFACE (null), and TYPE of "9/0/0"
694 * Flash disk seems to have INTERFACE of "8/6/80", and TYPE of "0/0/0"
696 * When a hub is unplugged, a hotplug event is generated for it and everything
697 * downstream from it. You cannot depend on getting these events in any
698 * particular order, since there will be many hotplug programs all fired off
699 * at almost the same time.
700 * On a remove, don't try to access the downstream devices right away, give the
701 * kernel time to finish cleaning up all the data structures, which will be
702 * in the process of being torn down.
704 * On the initial plugin, the first time the kernel usb-storage subsystem sees
705 * the host (identified by GUID), it automatically reads the partition table.
706 * On subsequent plugins, it does not.
708 * Special values for Web Administration to unmount or remount
709 * all partitions of the host:
710 * INTERFACE=TOMATO/...
711 * ACTION=add/remove
712 * SCSI_HOST=<host_no>
713 * If host_no is negative, we unmount all partions of *all* hosts.
715 void hotplug_usb(void)
717 int add;
718 int host = -1;
719 char *interface = getenv("INTERFACE");
720 char *action = getenv("ACTION");
721 char *product = getenv("PRODUCT");
722 #ifdef LINUX26
723 char *device = getenv("DEVICENAME");
724 int is_block = strcmp(getenv("SUBSYSTEM") ? : "", "block") == 0;
725 #else
726 char *device = getenv("DEVICE");
727 #endif
728 char *scsi_host = getenv("SCSI_HOST");
730 _dprintf("%s hotplug INTERFACE=%s ACTION=%s PRODUCT=%s HOST=%s DEVICE=%s\n",
731 getenv("SUBSYSTEM") ? : "USB", interface, action, product, scsi_host, device);
733 if (!nvram_get_int("usb_enable")) return;
734 #ifdef LINUX26
735 if (!action || ((!interface || !product) && !is_block))
736 #else
737 if (!interface || !action || !product) /* Hubs bail out here. */
738 #endif
739 return;
741 if (scsi_host)
742 host = atoi(scsi_host);
744 if (!wait_action_idle(10)) return;
746 add = (strcmp(action, "add") == 0);
747 if (add && (strncmp(interface ? : "", "TOMATO/", 7) != 0)) {
748 #ifdef LINUX26
749 if (!is_block && device)
750 #endif
751 syslog(LOG_DEBUG, "Attached USB device %s [INTERFACE=%s PRODUCT=%s]",
752 device, interface, product);
753 #ifdef LINUX26
754 if (is_block)
755 #endif
756 file_unlock(file_lock("usb")); /* To allow automount to be blocked on startup. */
759 if (strncmp(interface ? : "", "TOMATO/", 7) == 0) { /* web admin */
760 if (scsi_host == NULL)
761 host = atoi(product); // for backward compatibility
762 /* If host is negative, unmount all partitions of *all* hosts.
763 * This feature can be used in custom scripts as following:
765 * # INTERFACE=TOMATO/1 ACTION=remove PRODUCT=-1 SCSI_HOST=-1 hotplug usb
767 * PRODUCT is required to pass the env variables verification.
769 /* Unmount or remount all partitions of the host. */
770 hotplug_usb_storage_device(host, add ? -1 : 0, EFH_USER);
772 #ifdef LINUX26
773 else if (is_block && strcmp(getenv("MAJOR") ? : "", "8") == 0 && strcmp(getenv("PHYSDEVBUS") ? : "", "scsi") == 0) {
774 /* scsi partition */
775 char devname[64];
776 sprintf(devname, "/dev/%s", device);
777 if (add) {
778 if (nvram_get_int("usb_storage") && nvram_get_int("usb_automount")) {
779 int minor = atoi(getenv("MINOR") ? : "0");
780 if ((minor % 16) == 0 && !is_no_partition(device)) {
781 /* This is a disc, and not a "no-partition" device,
782 * like APPLE iPOD shuffle. We can't mount it.
784 return;
786 if (mount_partition(devname, host, NULL, device, EFH_HP_ADD)) {
787 restart_nas_services(0, 1); // restart all NAS applications
788 run_nvscript("script_usbmount", NULL, 3);
792 else {
793 /* When unplugged, unmount the device even if usb storage is disabled in the GUI */
794 umount_partition(devname, host, NULL, device, EFH_HP_REMOVE);
795 /* Restart NAS applications (they could be killed by umount_mountpoint),
796 * or just re-read the configuration.
798 restart_nas_services(0, 1);
801 #endif
802 else if (strncmp(interface ? : "", "8/", 2) == 0) { /* usb storage */
803 run_nvscript("script_usbhotplug", NULL, 2);
804 #ifndef LINUX26
805 hotplug_usb_storage_device(host, add, (add ? EFH_HP_ADD : EFH_HP_REMOVE) | (host < 0 ? EFH_HUNKNOWN : 0));
806 #endif
808 else { /* It's some other type of USB device, not storage. */
809 #ifdef LINUX26
810 if (is_block) return;
811 #endif
812 /* Do nothing. The user's hotplug script must do it all. */
813 run_nvscript("script_usbhotplug", NULL, 2);