New routers supported
[tomato.git] / release / src / router / rc / usb.c
blob9e1cecc091e1d9d1b102ef863b216182190f0734
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", "200", 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-hcd"
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
62 static int p9100d_sig(int sig)
64 const char p910pid[] = "/var/run/p9100d.pid";
65 char s[32];
66 int pid;
68 if (f_read_string(p910pid, s, sizeof(s)) > 0) {
69 if ((pid = atoi(s)) > 1) {
70 if (kill(pid, sig) == 0) {
71 if (sig == SIGTERM) {
72 sleep(1);
73 unlink(p910pid);
75 return 0;
79 return -1;
82 void start_usb(void)
84 char param[32];
85 int i;
87 if (nvram_match("boardtype", "0x052b")) { // Netgear WNR3500L v2 - initialize USB port
88 xstart("gpio", "enable", "20");
91 _dprintf("%s\n", __FUNCTION__);
92 tune_bdflush();
94 if (nvram_get_int("usb_enable")) {
95 modprobe(USBCORE_MOD);
97 /* mount usb device filesystem */
98 mount(USBFS, "/proc/bus/usb", USBFS, MS_MGC_VAL, NULL);
100 #ifdef LINUX26
101 i = do_led(LED_USB, LED_PROBE);
102 if (i != 255) {
103 modprobe("ledtrig-usbdev");
104 modprobe("leds-usb");
105 sprintf(param, "%d", i);
106 f_write_string("/proc/leds-usb/gpio_pin", param, 0, 0);
108 #endif
109 #ifdef TCONFIG_USBAP
110 char instance[20];
111 /* From Asus QTD cache params */
112 char arg1[20] = {0};
113 char arg2[20] = {0};
114 char arg3[20] = {0};
115 char arg4[20] = {0};
116 char arg5[20] = {0};
117 char arg6[20] = {0};
118 char arg7[20] = {0};
119 /* Save QTD cache params in nvram */
120 sprintf(arg1, "log2_irq_thresh=%d", nvram_get_int("ehciirqt"));
121 sprintf(arg2, "qtdc_pid=%d", nvram_get_int("qtdc_pid"));
122 sprintf(arg3, "qtdc_vid=%d", nvram_get_int("qtdc_vid"));
123 sprintf(arg4, "qtdc0_ep=%d", nvram_get_int("qtdc0_ep"));
124 sprintf(arg5, "qtdc0_sz=%d", nvram_get_int("qtdc0_sz"));
125 sprintf(arg6, "qtdc1_ep=%d", nvram_get_int("qtdc1_ep"));
126 sprintf(arg7, "qtdc1_sz=%d", nvram_get_int("qtdc1_sz"));
128 modprobe("ehci-hcd", arg1, arg2, arg3, arg4, arg5, arg6, arg7);
130 sprintf(instance, "instance_base=1");
131 modprobe("wl_high", instance );
132 #endif
134 if (nvram_get_int("usb_storage")) {
135 /* insert scsi and storage modules before usb drivers */
136 modprobe(SCSI_MOD);
137 #ifdef LINUX26
138 modprobe(SCSI_WAIT_MOD);
139 #endif
140 modprobe(SD_MOD);
141 modprobe(USBSTORAGE_MOD);
143 if (nvram_get_int("usb_fs_ext3")) {
144 #ifdef LINUX26
145 modprobe("mbcache"); // used by ext2/ext3
146 #endif
147 /* insert ext3 first so that lazy mount tries ext3 before ext2 */
148 modprobe("jbd");
149 modprobe("ext3");
150 modprobe("ext2");
153 if (nvram_get_int("usb_fs_fat")) {
154 modprobe("fat");
155 modprobe("vfat");
157 #ifdef TCONFIG_HFS
158 if (nvram_get_int("usb_fs_hfs")) {
159 modprobe("hfs");
160 modprobe("hfsplus");
162 #endif
164 #if defined(LINUX26) && defined(TCONFIG_MICROSD)
165 if (nvram_get_int("usb_mmc") == 1) {
166 /* insert SD/MMC modules if present */
167 modprobe("mmc_core");
168 modprobe("mmc_block");
169 modprobe("sdhci");
171 #endif
174 /* if enabled, force USB2 before USB1.1 */
175 if (nvram_get_int("usb_usb2") == 1) {
176 i = nvram_get_int("usb_irq_thresh");
177 if ((i < 0) || (i > 6))
178 i = 0;
179 sprintf(param, "log2_irq_thresh=%d", i);
180 modprobe(USB20_MOD, param);
183 if (nvram_get_int("usb_uhci") == 1) {
184 modprobe(USBUHCI_MOD);
187 if (nvram_get_int("usb_ohci") == 1) {
188 modprobe(USBOHCI_MOD);
191 if (nvram_get_int("usb_printer")) {
192 symlink("/dev/usb", "/dev/printers");
193 modprobe(USBPRINTER_MOD);
195 /* start printer server only if not already running */
196 if (p9100d_sig(0) != 0) {
197 eval("p910nd",
198 nvram_get_int("usb_printer_bidirect") ? "-b" : "", //bidirectional
199 "-f", "/dev/usb/lp0", // device
200 "0" // listen port
204 #ifdef LINUX26
205 if (nvram_get_int("idle_enable") == 1) {
206 xstart( "sd-idle" );
208 #endif
210 #ifdef TCONFIG_UPS
211 start_ups();
212 #endif
214 #ifdef TCONFIG_USBAP
215 //enable eth2 after detect new iface by wl_high module
216 sleep(5);
217 xstart("service", "wireless", "restart");
218 #endif
220 // shibby
221 // If we want restore backup of webmon from USB device,
222 // we have to wait for mount USB devices by hotplug
223 // and then reboot firewall service (webmon iptables rules) one more time.
224 if( nvram_match( "log_wm", "1" ) && nvram_match( "webmon_bkp", "1" ) )
225 xstart( "service", "firewall", "restart" );
230 void stop_usb(void)
232 int disabled = !nvram_get_int("usb_enable");
234 // only find and kill the printer server we started (port 0)
235 p9100d_sig(SIGTERM);
236 modprobe_r(USBPRINTER_MOD);
238 // only stop storage services if disabled
239 if (disabled || !nvram_get_int("usb_storage")) {
240 // Unmount all partitions
241 remove_storage_main(0);
243 // Stop storage services
244 modprobe_r("ext2");
245 modprobe_r("ext3");
246 modprobe_r("jbd");
247 #ifdef LINUX26
248 modprobe_r("mbcache");
249 #endif
250 modprobe_r("vfat");
251 modprobe_r("fat");
252 modprobe_r("fuse");
253 #ifdef TCONFIG_HFS
254 modprobe_r("hfs");
255 modprobe_r("hfsplus");
256 #endif
257 sleep(1);
259 #ifdef TCONFIG_SAMBASRV
260 modprobe_r("nls_cp437");
261 modprobe_r("nls_cp850");
262 modprobe_r("nls_cp852");
263 modprobe_r("nls_cp866");
264 #ifdef LINUX26
265 modprobe_r("nls_cp932");
266 modprobe_r("nls_cp936");
267 modprobe_r("nls_cp949");
268 modprobe_r("nls_cp950");
269 #endif
270 #endif
271 modprobe_r(USBSTORAGE_MOD);
272 modprobe_r(SD_MOD);
273 #ifdef LINUX26
274 modprobe_r(SCSI_WAIT_MOD);
275 #endif
276 modprobe_r(SCSI_MOD);
279 #if defined(LINUX26) && defined(TCONFIG_MICROSD)
280 if (disabled || !nvram_get_int("usb_storage") || nvram_get_int("usb_mmc") != 1) {
281 modprobe_r("sdhci");
282 modprobe_r("mmc_block");
283 modprobe_r("mmc_core");
285 #endif
287 if (disabled || nvram_get_int("usb_ohci") != 1) modprobe_r(USBOHCI_MOD);
288 if (disabled || nvram_get_int("usb_uhci") != 1) modprobe_r(USBUHCI_MOD);
289 if (disabled || nvram_get_int("usb_usb2") != 1) modprobe_r(USB20_MOD);
291 #ifdef LINUX26
292 modprobe_r("leds-usb");
293 modprobe_r("ledtrig-usbdev");
294 led(LED_USB, LED_OFF);
295 #endif
297 // only unload core modules if usb is disabled
298 if (disabled) {
299 umount("/proc/bus/usb"); // unmount usb device filesystem
300 modprobe_r(USBOHCI_MOD);
301 modprobe_r(USBUHCI_MOD);
302 modprobe_r(USB20_MOD);
303 modprobe_r(USBCORE_MOD);
306 #ifdef LINUX26
307 if (nvram_get_int("idle_enable") == 0) {
308 killall("sd-idle", SIGTERM);
311 #ifdef TCONFIG_UPS
312 stop_ups();
313 #endif
315 if (nvram_match("3g_usb", "0") ) {
316 if (nvram_match("3g_module", "sierra") ) {
317 modprobe_r("sierra");
318 modprobe_r("usbserial");
321 if (nvram_match("3g_module", "option") ) {
322 modprobe_r("option");
323 modprobe_r("usbserial");
326 // shibby
327 // when modem use usbserial module and we will try remove module, module will crash
328 // the only solution at the moment is reboot router
329 // FIX THIS
330 if (nvram_match("3g_module", "usbserial") ) {
331 modprobe_r("usbserial");
335 if (nvram_match("boardtype", "0x052b")) { // Netgear WNR3500L v2 - disable USB port
336 xstart("gpio", "disable", "20");
340 #endif
345 #define MOUNT_VAL_FAIL 0
346 #define MOUNT_VAL_RONLY 1
347 #define MOUNT_VAL_RW 2
348 #define MOUNT_VAL_EXIST 3
350 int mount_r(char *mnt_dev, char *mnt_dir, char *type)
352 struct mntent *mnt;
353 int ret;
354 char options[140];
355 char flagfn[128];
356 int dir_made;
358 if ((mnt = findmntents(mnt_dev, 0, NULL, 0))) {
359 syslog(LOG_INFO, "USB partition at %s already mounted on %s",
360 mnt_dev, mnt->mnt_dir);
361 return MOUNT_VAL_EXIST;
364 options[0] = 0;
366 if (type) {
367 unsigned long flags = MS_NOATIME | MS_NODEV;
369 if (strcmp(type, "swap") == 0 || strcmp(type, "mbr") == 0) {
370 /* not a mountable partition */
371 flags = 0;
373 else if (strcmp(type, "ext2") == 0 || strcmp(type, "ext3") == 0) {
374 if (nvram_invmatch("usb_ext_opt", ""))
375 sprintf(options, nvram_safe_get("usb_ext_opt"));
377 else if (strcmp(type, "vfat") == 0) {
378 if (nvram_invmatch("smbd_cset", ""))
379 sprintf(options, "iocharset=%s%s",
380 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
381 nvram_get("smbd_cset"));
382 if (nvram_invmatch("smbd_cpage", "")) {
383 char *cp = nvram_safe_get("smbd_cpage");
384 sprintf(options + strlen(options), ",codepage=%s" + (options[0] ? 0 : 1), cp);
385 sprintf(flagfn, "nls_cp%s", cp);
387 cp = nvram_get("smbd_nlsmod");
388 if ((cp) && (*cp != 0) && (strcmp(cp, flagfn) != 0))
389 modprobe_r(cp);
391 modprobe(flagfn);
392 nvram_set("smbd_nlsmod", flagfn);
394 sprintf(options + strlen(options), ",shortname=winnt" + (options[0] ? 0 : 1));
395 #ifdef LINUX26
396 sprintf(options + strlen(options), ",flush" + (options[0] ? 0 : 1));
397 #endif
398 if (nvram_invmatch("usb_fat_opt", ""))
399 sprintf(options + strlen(options), "%s%s", options[0] ? "," : "", nvram_safe_get("usb_fat_opt"));
401 else if (strncmp(type, "ntfs", 4) == 0) {
402 if (nvram_invmatch("smbd_cset", ""))
403 sprintf(options, "iocharset=%s%s",
404 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
405 nvram_get("smbd_cset"));
406 if (nvram_invmatch("usb_ntfs_opt", ""))
407 sprintf(options + strlen(options), "%s%s", options[0] ? "," : "", nvram_safe_get("usb_ntfs_opt"));
410 if (flags) {
411 if ((dir_made = mkdir_if_none(mnt_dir))) {
412 /* Create the flag file for remove the directory on dismount. */
413 sprintf(flagfn, "%s/.autocreated-dir", mnt_dir);
414 f_write(flagfn, NULL, 0, 0, 0);
417 ret = mount(mnt_dev, mnt_dir, type, flags, options[0] ? options : "");
419 /* try ntfs-3g in case it's installed */
420 if (ret != 0 && strncmp(type, "ntfs", 4) == 0) {
421 sprintf(options + strlen(options), ",noatime,nodev" + (options[0] ? 0 : 1));
422 #ifdef TCONFIG_NTFS
423 if (nvram_get_int("usb_fs_ntfs"))
424 #endif
425 ret = eval("ntfs-3g", "-o", options, mnt_dev, mnt_dir);
428 #ifdef TCONFIG_HFS
429 if (ret != 0 && strncmp(type, "hfs", "") == 0) {
430 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
433 if (ret != 0 && strncmp(type, "hfsplus", "") == 0) {
434 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
436 #endif
438 if (ret != 0) /* give it another try - guess fs */
439 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
441 if (ret == 0) {
442 syslog(LOG_INFO, "USB %s%s fs at %s mounted on %s",
443 type, (flags & MS_RDONLY) ? " (ro)" : "", mnt_dev, mnt_dir);
444 return (flags & MS_RDONLY) ? MOUNT_VAL_RONLY : MOUNT_VAL_RW;
447 if (dir_made) {
448 unlink(flagfn);
449 rmdir(mnt_dir);
453 return MOUNT_VAL_FAIL;
457 struct mntent *mount_fstab(char *dev_name, char *type, char *label, char *uuid)
459 struct mntent *mnt = NULL;
460 #if 0
461 if (eval("mount", "-a") == 0)
462 mnt = findmntents(dev_name, 0, NULL, 0);
463 #else
464 char spec[PATH_MAX+1];
466 if (label && *label) {
467 sprintf(spec, "LABEL=%s", label);
468 if (eval("mount", spec) == 0)
469 mnt = findmntents(dev_name, 0, NULL, 0);
472 if (!mnt && uuid && *uuid) {
473 sprintf(spec, "UUID=%s", uuid);
474 if (eval("mount", spec) == 0)
475 mnt = findmntents(dev_name, 0, NULL, 0);
478 if (!mnt) {
479 if (eval("mount", dev_name) == 0)
480 mnt = findmntents(dev_name, 0, NULL, 0);
483 if (!mnt) {
484 /* Still did not find what we are looking for, try absolute path */
485 if (realpath(dev_name, spec)) {
486 if (eval("mount", spec) == 0)
487 mnt = findmntents(dev_name, 0, NULL, 0);
490 #endif
492 if (mnt)
493 syslog(LOG_INFO, "USB %s fs at %s mounted on %s", type, dev_name, mnt->mnt_dir);
494 return (mnt);
498 /* Check if the UFD is still connected because the links created in /dev/discs
499 * are not removed when the UFD is unplugged.
500 * The file to read is: /proc/scsi/usb-storage-#/#, where # is the host no.
501 * We are looking for "Attached: Yes".
503 static int usb_ufd_connected(int host_no)
505 char proc_file[128];
506 #ifndef LINUX26
507 char line[256];
508 #endif
509 FILE *fp;
511 sprintf(proc_file, "%s/%s-%d/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no, host_no);
512 fp = fopen(proc_file, "r");
514 if (!fp) {
515 /* try the way it's implemented in newer kernels: /proc/scsi/usb-storage/[host] */
516 sprintf(proc_file, "%s/%s/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no);
517 fp = fopen(proc_file, "r");
520 if (fp) {
521 #ifdef LINUX26
522 fclose(fp);
523 return 1;
524 #else
525 while (fgets(line, sizeof(line), fp) != NULL) {
526 if (strstr(line, "Attached: Yes")) {
527 fclose(fp);
528 return 1;
531 fclose(fp);
532 #endif
535 return 0;
539 #ifndef MNT_DETACH
540 #define MNT_DETACH 0x00000002 /* from linux/fs.h - just detach from the tree */
541 #endif
542 int umount_mountpoint(struct mntent *mnt, uint flags);
543 int uswap_mountpoint(struct mntent *mnt, uint flags);
545 /* Unmount this partition from all its mountpoints. Note that it may
546 * actually be mounted several times, either with different names or
547 * with "-o bind" flag.
548 * If the special flagfile is now revealed, delete it and [attempt to] delete
549 * the directory.
551 int umount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
553 sync(); /* This won't matter if the device is unplugged, though. */
555 if (flags & EFH_HUNKNOWN) {
556 /* EFH_HUNKNOWN flag is passed if the host was unknown.
557 * Only unmount disconnected drives in this case.
559 if (usb_ufd_connected(host_num))
560 return 0;
563 /* Find all the active swaps that are on this device and stop them. */
564 findmntents(dev_name, 1, uswap_mountpoint, flags);
566 /* Find all the mountpoints that are for this device and unmount them. */
567 findmntents(dev_name, 0, umount_mountpoint, flags);
568 return 0;
571 int uswap_mountpoint(struct mntent *mnt, uint flags)
573 swapoff(mnt->mnt_fsname);
574 return 0;
577 int umount_mountpoint(struct mntent *mnt, uint flags)
579 int ret = 1, count;
580 char flagfn[128];
582 sprintf(flagfn, "%s/.autocreated-dir", mnt->mnt_dir);
584 /* Run user pre-unmount scripts if any. It might be too late if
585 * the drive has been disconnected, but we'll try it anyway.
587 if (nvram_get_int("usb_automount"))
588 run_nvscript("script_usbumount", mnt->mnt_dir, 3);
589 /* Run *.autostop scripts located in the root of the partition being unmounted if any. */
590 run_userfile(mnt->mnt_dir, ".autostop", mnt->mnt_dir, 5);
591 run_nvscript("script_autostop", mnt->mnt_dir, 5);
593 count = 0;
594 while ((ret = umount(mnt->mnt_dir)) && (count < 2)) {
595 count++;
596 /* If we could not unmount the drive on the 1st try,
597 * kill all NAS applications so they are not keeping the device busy -
598 * unless it's an unmount request from the Web GUI.
600 if ((count == 1) && ((flags & EFH_USER) == 0))
601 restart_nas_services(1, 0);
602 sleep(1);
605 if (ret == 0)
606 syslog(LOG_INFO, "USB partition unmounted from %s", mnt->mnt_dir);
608 if (ret && ((flags & EFH_SHUTDN) != 0)) {
609 /* If system is stopping (not restarting), and we couldn't unmount the
610 * partition, try to remount it as read-only. Ignore the return code -
611 * we can still try to do a lazy unmount.
613 eval("mount", "-o", "remount,ro", mnt->mnt_dir);
616 if (ret && ((flags & EFH_USER) == 0)) {
617 /* Make one more try to do a lazy unmount unless it's an unmount
618 * request from the Web GUI.
619 * MNT_DETACH will expose the underlying mountpoint directory to all
620 * except whatever has cd'ed to the mountpoint (thereby making it busy).
621 * So the unmount can't actually fail. It disappears from the ken of
622 * everyone else immediately, and from the ken of whomever is keeping it
623 * busy when they move away from it. And then it disappears for real.
625 ret = umount2(mnt->mnt_dir, MNT_DETACH);
626 syslog(LOG_INFO, "USB partition busy - will unmount ASAP from %s", mnt->mnt_dir);
629 if (ret == 0) {
630 if ((unlink(flagfn) == 0)) {
631 // Only delete the directory if it was auto-created
632 rmdir(mnt->mnt_dir);
635 return (ret == 0);
639 /* Mount this partition on this disc.
640 * If the device is already mounted on any mountpoint, don't mount it again.
641 * If this is a swap partition, try swapon -a.
642 * If this is a regular partition, try mount -a.
644 * Before we mount any partitions:
645 * If the type is swap and /etc/fstab exists, do "swapon -a"
646 * If /etc/fstab exists, try mounting using fstab.
647 * We delay invoking mount because mount will probe all the partitions
648 * to read the labels, and we don't want it to do that early on.
649 * We don't invoke swapon until we actually find a swap partition.
651 * If the mount succeeds, execute the *.autorun scripts in the top
652 * directory of the newly mounted partition.
653 * Returns NZ for success, 0 if we did not mount anything.
655 int mount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
657 char the_label[128], mountpoint[128], uuid[40];
658 int ret;
659 char *type, *p;
660 static char *swp_argv[] = { "swapon", "-a", NULL };
661 struct mntent *mnt;
663 if ((type = find_label_or_uuid(dev_name, the_label, uuid)) == NULL)
664 return 0;
666 if (f_exists("/etc/fstab")) {
667 if (strcmp(type, "swap") == 0) {
668 _eval(swp_argv, NULL, 0, NULL);
669 return 0;
672 if (mount_r(dev_name, NULL, NULL) == MOUNT_VAL_EXIST)
673 return 0;
675 if ((mnt = mount_fstab(dev_name, type, the_label, uuid))) {
676 strcpy(mountpoint, mnt->mnt_dir);
677 ret = MOUNT_VAL_RW;
678 goto done;
682 if (*the_label != 0) {
683 for (p = the_label; *p; p++) {
684 if (!isalnum(*p) && !strchr("+-&.@", *p))
685 *p = '_';
687 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, the_label);
688 if ((ret = mount_r(dev_name, mountpoint, type)))
689 goto done;
692 /* Can't mount to /mnt/LABEL, so try mounting to /mnt/discDN_PN */
693 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, pt_name);
694 ret = mount_r(dev_name, mountpoint, type);
695 done:
696 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
698 /* Run user *.autorun and post-mount scripts if any. */
699 run_userfile(mountpoint, ".autorun", mountpoint, 3);
700 if (nvram_get_int("usb_automount"))
701 run_nvscript("script_usbmount", mountpoint, 3);
703 return (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
707 #if 0 /* LINUX26 */
710 * Finds SCSI Host number. Returns the host number >=0 if found, or (-1) otherwise.
711 * The name and host number of scsi block device in kernel 2.6 (for attached devices) can be found as
712 * /sys($DEVPATH)/host<host_no>/target<*>/<id>/block:[sda|sdb|...]
713 * where $DEVPATH is passed to hotplug events, and looks like
714 * /devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.2
716 * For printers this function finds a minor assigned to a printer
717 * /sys($DEVPATH)/usb:lp[0|1|2|...]
719 int find_dev_host(const char *devpath)
721 DIR *usb_devpath;
722 struct dirent *dp;
723 char buf[256];
724 int host = -1; /* Scsi Host */
726 sprintf(buf, "/sys%s", devpath);
727 if ((usb_devpath = opendir(buf))) {
728 while ((dp = readdir(usb_devpath))) {
729 errno = 0;
730 if (strncmp(dp->d_name, "host", 4) == 0) {
731 host = strtol(dp->d_name + 4, (char **)NULL, 10);
732 if (errno)
733 host = -1;
734 else
735 break;
737 else if (strncmp(dp->d_name, "usb:lp", 6) == 0) {
738 host = strtol(dp->d_name + 6, (char **)NULL, 10);
739 if (errno)
740 host = -1;
741 else
742 break;
744 else
745 continue;
747 closedir(usb_devpath);
749 return (host);
752 #endif /* LINUX26 */
754 int dir_is_mountpoint(const char *root, const char *dir)
756 char path[256];
757 struct stat sb;
758 int thisdev;
760 snprintf(path, sizeof(path), "%s%s%s", root ? : "", root ? "/" : "", dir);
762 /* Check if this is a directory */
763 sb.st_mode = S_IFDIR; /* failsafe */
764 stat(path, &sb);
766 if (S_ISDIR(sb.st_mode)) {
768 /* If this dir & its parent dir are on the same device, it is not a mountpoint */
769 strcat(path, "/.");
770 stat(path, &sb);
771 thisdev = sb.st_dev;
772 strcat(path, ".");
773 ++sb.st_dev; /* failsafe */
774 stat(path, &sb);
776 return (thisdev != sb.st_dev);
779 return 0;
782 /* Mount or unmount all partitions on this controller.
783 * Parameter: action_add:
784 * 0 = unmount
785 * >0 = mount only if automount config option is enabled.
786 * <0 = mount regardless of config option.
788 void hotplug_usb_storage_device(int host_no, int action_add, uint flags)
790 if (!nvram_get_int("usb_enable"))
791 return;
792 _dprintf("%s: host %d action: %d\n", __FUNCTION__, host_no, action_add);
794 if (action_add) {
795 if (nvram_get_int("usb_storage") && (nvram_get_int("usb_automount") || action_add < 0)) {
796 /* Do not probe the device here. It's either initiated by user,
797 * or hotplug_usb() already did.
799 if (exec_for_host(host_no, 0x00, flags, mount_partition)) {
800 restart_nas_services(0, 1); // restart all NAS applications
804 else {
805 if (nvram_get_int("usb_storage") || ((flags & EFH_USER) == 0)) {
806 /* When unplugged, unmount the device even if
807 * usb storage is disabled in the GUI.
809 exec_for_host(host_no, (flags & EFH_USER) ? 0x00 : 0x02, flags, umount_partition);
810 /* Restart NAS applications (they could be killed by umount_mountpoint),
811 * or just re-read the configuration.
813 restart_nas_services(0, 1);
819 /* This gets called at reboot or upgrade. The system is stopping. */
820 void remove_storage_main(int shutdn)
822 if (shutdn)
823 restart_nas_services(1, 0);
824 /* Unmount all partitions */
825 exec_for_host(-1, 0x02, shutdn ? EFH_SHUTDN : 0, umount_partition);
829 /*******
830 * All the complex locking & checking code was removed when the kernel USB-storage
831 * bugs were fixed.
832 * The crash bug was with overlapped I/O to different USB drives, not specifically
833 * with mount processing.
835 * And for USB devices that are slow to come up. The kernel now waits until the
836 * USB drive has settled, and it correctly reads the partition table before calling
837 * the hotplug agent.
839 * The kernel patch was cleaning up data structures on an unplug. It
840 * needs to wait until the disk is unmounted. We have 20 seconds to do
841 * the unmounts.
842 *******/
844 #ifdef LINUX26
845 static inline void usbled_proc(char *device, int add)
847 char *p;
848 char param[32];
850 if (do_led(LED_USB, LED_PROBE) != 255) {
851 strncpy(param, device, sizeof(param));
852 if ((p = strchr(param, ':')) != NULL)
853 *p = 0;
855 /* verify if we need to ignore this device (i.e. an internal SD/MMC slot ) */
856 p = nvram_safe_get("usb_noled");
857 if (strcmp(p, param) == 0)
858 return;
860 f_write_string(add ? "/proc/leds-usb/add" : "/proc/leds-usb/remove", param, 0, 0);
863 #endif
865 /* Plugging or removing usb device
867 * On an occurrance, multiple hotplug events may be fired off.
868 * For example, if a hub is plugged or unplugged, an event
869 * will be generated for everything downstream of it, plus one for
870 * the hub itself. These are fired off simultaneously, not serially.
871 * This means that many many hotplug processes will be running at
872 * the same time.
874 * The hotplug event generated by the kernel gives us several pieces
875 * of information:
876 * PRODUCT is vendorid/productid/rev#.
877 * DEVICE is /proc/bus/usb/bus#/dev#
878 * ACTION is add or remove
879 * SCSI_HOST is the host (controller) number (this relies on the custom kernel patch)
881 * Note that when we get a hotplug add event, the USB susbsystem may
882 * or may not have yet tried to read the partition table of the
883 * device. For a new controller that has never been seen before,
884 * generally yes. For a re-plug of a controller that has been seen
885 * before, generally no.
887 * On a remove, the partition info has not yet been expunged. The
888 * partitions show up as /dev/discs/disc#/part#, and /proc/partitions.
889 * It appears that doing a "stat" for a non-existant partition will
890 * causes the kernel to re-validate the device and update the
891 * partition table info. However, it won't re-validate if the disc is
892 * mounted--you'll get a "Device busy for revalidation (usage=%d)" in
893 * syslog.
895 * The $INTERFACE is "class/subclass/protocol"
896 * Some interesting classes:
897 * 8 = mass storage
898 * 7 = printer
899 * 3 = HID. 3/1/2 = mouse.
900 * 6 = still image (6/1/1 = Digital camera Camera)
901 * 9 = Hub
902 * 255 = scanner (255/255/255)
904 * Observed:
905 * Hub seems to have no INTERFACE (null), and TYPE of "9/0/0"
906 * Flash disk seems to have INTERFACE of "8/6/80", and TYPE of "0/0/0"
908 * When a hub is unplugged, a hotplug event is generated for it and everything
909 * downstream from it. You cannot depend on getting these events in any
910 * particular order, since there will be many hotplug programs all fired off
911 * at almost the same time.
912 * On a remove, don't try to access the downstream devices right away, give the
913 * kernel time to finish cleaning up all the data structures, which will be
914 * in the process of being torn down.
916 * On the initial plugin, the first time the kernel usb-storage subsystem sees
917 * the host (identified by GUID), it automatically reads the partition table.
918 * On subsequent plugins, it does not.
920 * Special values for Web Administration to unmount or remount
921 * all partitions of the host:
922 * INTERFACE=TOMATO/...
923 * ACTION=add/remove
924 * SCSI_HOST=<host_no>
925 * If host_no is negative, we unmount all partions of *all* hosts.
927 void hotplug_usb(void)
929 int add;
930 int host = -1;
931 char *interface = getenv("INTERFACE");
932 char *action = getenv("ACTION");
933 char *product = getenv("PRODUCT");
934 #ifdef LINUX26
935 char *device = getenv("DEVICENAME");
936 int is_block = strcmp(getenv("SUBSYSTEM") ? : "", "block") == 0;
937 #else
938 char *device = getenv("DEVICE");
939 #endif
940 char *scsi_host = getenv("SCSI_HOST");
942 _dprintf("%s hotplug INTERFACE=%s ACTION=%s PRODUCT=%s HOST=%s DEVICE=%s\n",
943 getenv("SUBSYSTEM") ? : "USB", interface, action, product, scsi_host, device);
945 if (!nvram_get_int("usb_enable")) return;
946 #ifdef LINUX26
947 if (!action || ((!interface || !product) && !is_block))
948 #else
949 if (!interface || !action || !product) /* Hubs bail out here. */
950 #endif
951 return;
953 if (scsi_host)
954 host = atoi(scsi_host);
956 if (!wait_action_idle(10)) return;
958 add = (strcmp(action, "add") == 0);
959 if (add && (strncmp(interface ? : "", "TOMATO/", 7) != 0)) {
960 #ifdef LINUX26
961 if (!is_block && device)
962 #endif
963 syslog(LOG_DEBUG, "Attached USB device %s [INTERFACE=%s PRODUCT=%s]",
964 device, interface, product);
965 #ifndef LINUX26
966 /* To allow automount to be blocked on startup.
967 * In kernel 2.6 we still need to serialize mount/umount calls -
968 * so the lock is down below in the "block" hotplug processing.
970 file_unlock(file_lock("usb"));
971 #endif
974 if (strncmp(interface ? : "", "TOMATO/", 7) == 0) { /* web admin */
975 if (scsi_host == NULL)
976 host = atoi(product); // for backward compatibility
977 /* If host is negative, unmount all partitions of *all* hosts.
978 * If host == -1, execute "soft" unmount (do not kill NAS apps, no "lazy" umount).
979 * If host == -2, run "hard" unmount, as if the drive is unplugged.
980 * This feature can be used in custom scripts as following:
982 * # INTERFACE=TOMATO/1 ACTION=remove PRODUCT=-1 SCSI_HOST=-1 hotplug usb
984 * PRODUCT is required to pass the env variables verification.
986 /* Unmount or remount all partitions of the host. */
987 hotplug_usb_storage_device(host < 0 ? -1 : host, add ? -1 : 0,
988 host == -2 ? 0 : EFH_USER);
990 #ifdef LINUX26
991 else if (is_block && strcmp(getenv("MAJOR") ? : "", "8") == 0 && strcmp(getenv("PHYSDEVBUS") ? : "", "scsi") == 0) {
992 /* scsi partition */
993 char devname[64];
994 int lock;
996 sprintf(devname, "/dev/%s", device);
997 lock = file_lock("usb");
998 if (add) {
999 if (nvram_get_int("usb_storage") && nvram_get_int("usb_automount")) {
1000 int minor = atoi(getenv("MINOR") ? : "0");
1001 if ((minor % 16) == 0 && !is_no_partition(device)) {
1002 /* This is a disc, and not a "no-partition" device,
1003 * like APPLE iPOD shuffle. We can't mount it.
1005 return;
1007 if (mount_partition(devname, host, NULL, device, EFH_HP_ADD)) {
1008 restart_nas_services(0, 1); // restart all NAS applications
1012 else {
1013 /* When unplugged, unmount the device even if usb storage is disabled in the GUI */
1014 umount_partition(devname, host, NULL, device, EFH_HP_REMOVE);
1015 /* Restart NAS applications (they could be killed by umount_mountpoint),
1016 * or just re-read the configuration.
1018 restart_nas_services(0, 1);
1020 file_unlock(lock);
1022 #endif
1023 else if (strncmp(interface ? : "", "8/", 2) == 0) { /* usb storage */
1024 #ifdef LINUX26
1025 usbled_proc(device, add);
1026 #endif
1027 run_nvscript("script_usbhotplug", NULL, 2);
1028 #ifndef LINUX26
1029 hotplug_usb_storage_device(host, add, (add ? EFH_HP_ADD : EFH_HP_REMOVE) | (host < 0 ? EFH_HUNKNOWN : 0));
1030 #endif
1032 else { /* It's some other type of USB device, not storage. */
1033 #ifdef LINUX26
1034 if (is_block) return;
1035 #endif
1036 #ifdef LINUX26
1037 if (strncmp(interface ? : "", "7/", 2) == 0) /* printer */
1038 usbled_proc(device, add);
1039 #endif
1040 /* Do nothing. The user's hotplug script must do it all. */
1041 run_nvscript("script_usbhotplug", NULL, 2);