libevent: updated to 2.0.22
[tomato.git] / release / src-rt-6.x.4708 / router / rc / usb.c
blobba77c3ffd9051e5a76185d06934b0873e7cdb303
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 USBXHCI_MOD "xhci-hcd"
53 #define USBPRINTER_MOD "usblp"
54 #define SCSI_WAIT_MOD "scsi_wait_scan"
55 #define USBFS "usbfs"
56 #else
57 #define USBOHCI_MOD "usb-ohci"
58 #define USBUHCI_MOD "usb-uhci"
59 #define USBPRINTER_MOD "printer"
60 #define USBFS "usbdevfs"
61 #endif
63 static int p9100d_sig(int sig)
65 const char p910pid[] = "/var/run/p9100d.pid";
66 char s[32];
67 int pid;
69 if (f_read_string(p910pid, s, sizeof(s)) > 0) {
70 if ((pid = atoi(s)) > 1) {
71 if (kill(pid, sig) == 0) {
72 if (sig == SIGTERM) {
73 sleep(1);
74 unlink(p910pid);
76 return 0;
80 return -1;
83 void start_usb(void)
85 char param[32];
86 int i;
88 if (nvram_match("boardtype", "0x052b")) { // Netgear WNR3500L v2 - initialize USB port
89 xstart("gpio", "enable", "20");
91 else if (get_model() == MODEL_DIR868L) {
92 xstart("gpio", "enable", "10");
94 else if (get_model() == MODEL_WS880) {
95 xstart("gpio", "enable", "7");
97 else if (get_model() == MODEL_R1D || get_model() == MODEL_R6400) {
98 xstart("gpio", "enable", "0");
100 else if (get_model() == MODEL_EA6700 || get_model() == MODEL_EA6900 || get_model() == MODEL_WZR1750) {
101 xstart("gpio", "enable", "9");
102 if (get_model() == MODEL_WZR1750)
103 xstart("gpio", "disable", "10"); //usb3.0
106 _dprintf("%s\n", __FUNCTION__);
107 tune_bdflush();
109 if (nvram_get_int("usb_enable")) {
110 modprobe(USBCORE_MOD);
112 /* mount usb device filesystem */
113 mount(USBFS, "/proc/bus/usb", USBFS, MS_MGC_VAL, NULL);
115 #ifdef LINUX26
116 i = do_led(LED_USB, LED_PROBE);
117 if (i != 255) {
118 /*modprobe("ledtrig-usbdev");
119 modprobe("leds-usb");
120 sprintf(param, "%d", i);
121 f_write_string("/proc/leds-usb/gpio_pin", param, 0, 0);*/
122 do_led(LED_USB, LED_OFF);
124 #endif
125 #ifdef TCONFIG_USBAP
126 char instance[20];
127 /* From Asus QTD cache params */
128 char arg1[20] = {0};
129 char arg2[20] = {0};
130 char arg3[20] = {0};
131 char arg4[20] = {0};
132 char arg5[20] = {0};
133 char arg6[20] = {0};
134 char arg7[20] = {0};
135 /* Save QTD cache params in nvram */
136 sprintf(arg1, "log2_irq_thresh=%d", nvram_get_int("ehciirqt"));
137 sprintf(arg2, "qtdc_pid=%d", nvram_get_int("qtdc_pid"));
138 sprintf(arg3, "qtdc_vid=%d", nvram_get_int("qtdc_vid"));
139 sprintf(arg4, "qtdc0_ep=%d", nvram_get_int("qtdc0_ep"));
140 sprintf(arg5, "qtdc0_sz=%d", nvram_get_int("qtdc0_sz"));
141 sprintf(arg6, "qtdc1_ep=%d", nvram_get_int("qtdc1_ep"));
142 sprintf(arg7, "qtdc1_sz=%d", nvram_get_int("qtdc1_sz"));
144 modprobe("ehci-hcd", arg1, arg2, arg3, arg4, arg5, arg6, arg7);
146 sprintf(instance, "instance_base=1");
147 modprobe("wl_high", instance );
148 #endif
150 if (nvram_get_int("usb_storage")) {
151 /* insert scsi and storage modules before usb drivers */
152 modprobe(SCSI_MOD);
153 #ifdef LINUX26
154 modprobe(SCSI_WAIT_MOD);
155 #endif
156 modprobe(SD_MOD);
157 modprobe(USBSTORAGE_MOD);
159 if (nvram_get_int("usb_fs_ext3") || nvram_get_int("usb_fs_ext4")) {
160 #ifdef LINUX26
161 modprobe("mbcache"); // used by ext4
162 #endif
163 modprobe("jbd2");
164 modprobe("crc16");
165 modprobe("ext4");
168 /* if (nvram_get_int("usb_fs_ext3")) {
169 #ifdef LINUX26
170 modprobe("mbcache"); // used by ext2/ext3
171 #endif
172 // insert ext3 first so that lazy mount tries ext3 before ext2
173 modprobe("jbd");
174 modprobe("ext3");
175 modprobe("ext2");
176 } */
178 if (nvram_get_int("usb_fs_fat")) {
179 modprobe("fat");
180 modprobe("vfat");
183 //!oneleft
184 if (nvram_get_int("usb_fs_exfat")) {
185 modprobe("exfat");
188 #if defined(TCONFIG_UFSDA) || defined(TCONFIG_UFSDN)
189 if (nvram_get_int("usb_fs_ntfs")) {
190 modprobe("ufsd");
192 #endif
194 #if defined(TCONFIG_TUXERA)
195 if (nvram_get_int("usb_fs_ntfs")) {
196 modprobe("tntfs");
198 #endif
200 #ifdef TCONFIG_HFS
201 if (nvram_get_int("usb_fs_hfs")) {
202 modprobe("hfs");
203 modprobe("hfsplus");
205 #endif
207 #if defined(LINUX26) && defined(TCONFIG_MICROSD)
208 if (nvram_get_int("usb_mmc") == 1) {
209 /* insert SD/MMC modules if present */
210 modprobe("mmc_core");
211 modprobe("mmc_block");
212 modprobe("sdhci");
214 #endif
217 if (nvram_get_int("usb_usb3") == 1) {
218 modprobe(USBXHCI_MOD);
221 /* if enabled, force USB2 before USB1.1 */
222 if (nvram_get_int("usb_usb2") == 1) {
223 i = nvram_get_int("usb_irq_thresh");
224 if ((i < 0) || (i > 6))
225 i = 0;
226 sprintf(param, "log2_irq_thresh=%d", i);
227 modprobe(USB20_MOD, param);
231 if (nvram_get_int("usb_uhci") == 1) {
232 modprobe(USBUHCI_MOD);
235 if (nvram_get_int("usb_ohci") == 1) {
236 modprobe(USBOHCI_MOD);
239 if (nvram_get_int("usb_printer")) {
240 symlink("/dev/usb", "/dev/printers");
241 modprobe(USBPRINTER_MOD);
243 /* start printer server only if not already running */
244 if (p9100d_sig(0) != 0) {
245 eval("p910nd",
246 nvram_get_int("usb_printer_bidirect") ? "-b" : "", //bidirectional
247 "-f", "/dev/usb/lp0", // device
248 "0" // listen port
252 #ifdef LINUX26
253 if (nvram_get_int("idle_enable") == 1) {
254 xstart( "sd-idle" );
256 #endif
258 #ifdef TCONFIG_UPS
259 modprobe("usbhid");
260 start_ups();
261 #endif
263 #ifdef TCONFIG_USBAP
264 //enable eth2 after detect new iface by wl_high module
265 sleep(5);
266 xstart("service", "wireless", "restart");
267 #endif
269 // shibby
270 // If we want restore backup of webmon from USB device,
271 // we have to wait for mount USB devices by hotplug
272 // and then reboot firewall service (webmon iptables rules) one more time.
273 if( nvram_match( "log_wm", "1" ) && nvram_match( "webmon_bkp", "1" ) )
274 xstart( "service", "firewall", "restart" );
279 void stop_usb(void)
281 int disabled = !nvram_get_int("usb_enable");
283 #ifdef TCONFIG_UPS
284 stop_ups();
285 modprobe_r("usbhid");
286 #endif
288 // only find and kill the printer server we started (port 0)
289 p9100d_sig(SIGTERM);
290 modprobe_r(USBPRINTER_MOD);
292 // only stop storage services if disabled
293 if (disabled || !nvram_get_int("usb_storage")) {
294 // Unmount all partitions
295 remove_storage_main(0);
297 // Stop storage services
298 modprobe_r("ext2");
299 modprobe_r("ext3");
300 modprobe_r("jbd");
301 modprobe_r("ext4");
302 modprobe_r("jbd2");
303 modprobe_r("crc16");
304 #ifdef LINUX26
305 modprobe_r("mbcache");
306 #endif
307 modprobe_r("vfat");
308 modprobe_r("fat");
309 modprobe_r("exfat"); //!oneleft
310 modprobe_r("fuse");
311 #if defined(TCONFIG_UFSDA) || defined(TCONFIG_UFSDN)
312 modprobe_r("ufsd");
313 #endif
314 #if defined(TCONFIG_TUXERA)
315 modprobe_r("tntfs");
316 #endif
317 #ifdef TCONFIG_HFS
318 modprobe_r("hfs");
319 modprobe_r("hfsplus");
320 #endif
321 sleep(1);
323 #ifdef TCONFIG_SAMBASRV
324 modprobe_r("nls_cp437");
325 modprobe_r("nls_cp850");
326 modprobe_r("nls_cp852");
327 modprobe_r("nls_cp866");
328 #ifdef LINUX26
329 modprobe_r("nls_cp932");
330 modprobe_r("nls_cp936");
331 modprobe_r("nls_cp949");
332 modprobe_r("nls_cp950");
333 #endif
334 #endif
335 modprobe_r(USBSTORAGE_MOD);
336 modprobe_r(SD_MOD);
337 #ifdef LINUX26
338 modprobe_r(SCSI_WAIT_MOD);
339 #endif
340 modprobe_r(SCSI_MOD);
343 #if defined(LINUX26) && defined(TCONFIG_MICROSD)
344 if (disabled || !nvram_get_int("usb_storage") || nvram_get_int("usb_mmc") != 1) {
345 modprobe_r("sdhci");
346 modprobe_r("mmc_block");
347 modprobe_r("mmc_core");
349 #endif
351 if (disabled || nvram_get_int("usb_ohci") != 1) modprobe_r(USBOHCI_MOD);
352 if (disabled || nvram_get_int("usb_uhci") != 1) modprobe_r(USBUHCI_MOD);
353 if (disabled || nvram_get_int("usb_xhci") != 1) modprobe_r(USBXHCI_MOD);
354 if (disabled || nvram_get_int("usb_usb2") != 1) modprobe_r(USB20_MOD);
356 #ifdef LINUX26
357 //modprobe_r("leds-usb");
358 //modprobe_r("ledtrig-usbdev");
359 led(LED_USB, LED_OFF);
360 #endif
362 // only unload core modules if usb is disabled
363 if (disabled) {
364 umount("/proc/bus/usb"); // unmount usb device filesystem
365 modprobe_r(USBOHCI_MOD);
366 modprobe_r(USBUHCI_MOD);
367 modprobe_r(USBXHCI_MOD);
368 modprobe_r(USB20_MOD);
369 modprobe_r(USBCORE_MOD);
372 #ifdef LINUX26
373 if (nvram_get_int("idle_enable") == 0) {
374 killall("sd-idle", SIGTERM);
377 #ifdef TCONFIG_UPS
378 stop_ups();
379 #endif
381 if (nvram_match("3g_usb", "0") ) {
382 if (nvram_match("3g_module", "sierra") ) {
383 modprobe_r("sierra");
384 modprobe_r("usbserial");
387 if (nvram_match("3g_module", "option") ) {
388 modprobe_r("option");
389 modprobe_r("usbserial");
392 // shibby
393 // when modem use usbserial module and we will try remove module, module will crash
394 // the only solution at the moment is reboot router
395 // FIX THIS
396 if (nvram_match("3g_module", "usbserial") ) {
397 modprobe_r("usbserial");
402 if (nvram_match("boardtype", "0x052b")) { // Netgear WNR3500L v2 - disable USB port
403 xstart("gpio", "disable", "20");
405 else if (get_model() == MODEL_DIR868L) {
406 xstart("gpio", "disable", "10");
408 else if (get_model() == MODEL_WS880) {
409 xstart("gpio", "disable", "7");
411 else if (get_model() == MODEL_R1D || get_model() == MODEL_R6400) {
412 xstart("gpio", "disable", "0");
414 else if (get_model() == MODEL_EA6700 || get_model() == MODEL_EA6900 || get_model() == MODEL_WZR1750) {
415 xstart("gpio", "disable", "9");
416 if (get_model() == MODEL_WZR1750)
417 xstart("gpio", "enable", "10"); //usb3.0
419 #endif
424 #define MOUNT_VAL_FAIL 0
425 #define MOUNT_VAL_RONLY 1
426 #define MOUNT_VAL_RW 2
427 #define MOUNT_VAL_EXIST 3
429 int mount_r(char *mnt_dev, char *mnt_dir, char *type)
431 struct mntent *mnt;
432 int ret;
433 char options[140];
434 char flagfn[128];
435 int dir_made;
437 if ((mnt = findmntents(mnt_dev, 0, NULL, 0))) {
438 syslog(LOG_INFO, "USB partition at %s already mounted on %s",
439 mnt_dev, mnt->mnt_dir);
440 return MOUNT_VAL_EXIST;
443 options[0] = 0;
445 if (type) {
446 unsigned long flags = MS_NOATIME | MS_NODEV;
448 if (strcmp(type, "swap") == 0 || strcmp(type, "mbr") == 0) {
449 /* not a mountable partition */
450 flags = 0;
452 else if (strcmp(type, "ext2") == 0 || strcmp(type, "ext3") == 0) {
453 if (nvram_invmatch("usb_ext_opt", ""))
454 sprintf(options, nvram_safe_get("usb_ext_opt"));
456 else if (strcmp(type, "vfat") == 0) {
457 if (nvram_invmatch("smbd_cset", ""))
458 sprintf(options, "iocharset=%s%s",
459 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
460 nvram_get("smbd_cset"));
461 if (nvram_invmatch("smbd_cpage", "")) {
462 char *cp = nvram_safe_get("smbd_cpage");
463 sprintf(options + strlen(options), ",codepage=%s" + (options[0] ? 0 : 1), cp);
464 sprintf(flagfn, "nls_cp%s", cp);
466 cp = nvram_get("smbd_nlsmod");
467 if ((cp) && (*cp != 0) && (strcmp(cp, flagfn) != 0))
468 modprobe_r(cp);
470 modprobe(flagfn);
471 nvram_set("smbd_nlsmod", flagfn);
473 sprintf(options + strlen(options), ",shortname=winnt" + (options[0] ? 0 : 1));
474 #ifdef LINUX26
475 sprintf(options + strlen(options), ",flush" + (options[0] ? 0 : 1));
476 #endif
477 if (nvram_invmatch("usb_fat_opt", ""))
478 sprintf(options + strlen(options), "%s%s", options[0] ? "," : "", nvram_safe_get("usb_fat_opt"));
480 else if (strncmp(type, "ntfs", 4) == 0) {
481 if (nvram_invmatch("smbd_cset", ""))
482 sprintf(options, "iocharset=%s%s",
483 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
484 nvram_get("smbd_cset"));
485 if (nvram_invmatch("usb_ntfs_opt", ""))
486 sprintf(options + strlen(options), "%s%s", options[0] ? "," : "", nvram_safe_get("usb_ntfs_opt"));
489 if (flags) {
490 if ((dir_made = mkdir_if_none(mnt_dir))) {
491 /* Create the flag file for remove the directory on dismount. */
492 sprintf(flagfn, "%s/.autocreated-dir", mnt_dir);
493 f_write(flagfn, NULL, 0, 0, 0);
496 ret = mount(mnt_dev, mnt_dir, type, flags, options[0] ? options : "");
498 #ifdef TCONFIG_NTFS
499 /* try ntfs-3g in case it's installed */
500 if (ret != 0 && strncmp(type, "ntfs", 4) == 0) {
501 sprintf(options + strlen(options), ",noatime,nodev" + (options[0] ? 0 : 1));
502 if (nvram_get_int("usb_fs_ntfs")) {
503 if( nvram_match( "usb_ntfs_driver", "ntfs3g" )) {
504 ret = eval("ntfs-3g", "-o", options, mnt_dev, mnt_dir);
506 #if defined(TCONFIG_UFSDA) || defined(TCONFIG_UFSDN)
507 else if( nvram_match( "usb_ntfs_driver", "paragon" )) {
508 ret = eval("mount", "-t", "ufsd", "-o", options, "-o", "force", mnt_dev, mnt_dir);
510 #endif
511 #ifdef TCONFIG_TUXERA
512 else if( nvram_match( "usb_ntfs_driver", "tuxera" )) {
513 ret = eval("mount", "-t", "tntfs", "-o", options, mnt_dev, mnt_dir);
515 #endif
518 #endif
520 #ifdef TCONFIG_HFS
521 if (ret != 0 && strncmp(type, "hfs", "") == 0) {
522 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
525 if (ret != 0 && strncmp(type, "hfsplus", "") == 0) {
526 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
528 #endif
530 if (ret != 0) /* give it another try - guess fs */
531 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
533 if (ret == 0) {
534 syslog(LOG_INFO, "USB %s%s fs at %s mounted on %s",
535 type, (flags & MS_RDONLY) ? " (ro)" : "", mnt_dev, mnt_dir);
536 return (flags & MS_RDONLY) ? MOUNT_VAL_RONLY : MOUNT_VAL_RW;
539 if (dir_made) {
540 unlink(flagfn);
541 rmdir(mnt_dir);
545 return MOUNT_VAL_FAIL;
549 struct mntent *mount_fstab(char *dev_name, char *type, char *label, char *uuid)
551 struct mntent *mnt = NULL;
552 #if 0
553 if (eval("mount", "-a") == 0)
554 mnt = findmntents(dev_name, 0, NULL, 0);
555 #else
556 char spec[PATH_MAX+1];
558 if (label && *label) {
559 sprintf(spec, "LABEL=%s", label);
560 if (eval("mount", spec) == 0)
561 mnt = findmntents(dev_name, 0, NULL, 0);
564 if (!mnt && uuid && *uuid) {
565 sprintf(spec, "UUID=%s", uuid);
566 if (eval("mount", spec) == 0)
567 mnt = findmntents(dev_name, 0, NULL, 0);
570 if (!mnt) {
571 if (eval("mount", dev_name) == 0)
572 mnt = findmntents(dev_name, 0, NULL, 0);
575 if (!mnt) {
576 /* Still did not find what we are looking for, try absolute path */
577 if (realpath(dev_name, spec)) {
578 if (eval("mount", spec) == 0)
579 mnt = findmntents(dev_name, 0, NULL, 0);
582 #endif
584 if (mnt)
585 syslog(LOG_INFO, "USB %s fs at %s mounted on %s", type, dev_name, mnt->mnt_dir);
586 return (mnt);
590 /* Check if the UFD is still connected because the links created in /dev/discs
591 * are not removed when the UFD is unplugged.
592 * The file to read is: /proc/scsi/usb-storage-#/#, where # is the host no.
593 * We are looking for "Attached: Yes".
595 static int usb_ufd_connected(int host_no)
597 char proc_file[128];
598 #ifndef LINUX26
599 char line[256];
600 #endif
601 FILE *fp;
603 sprintf(proc_file, "%s/%s-%d/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no, host_no);
604 fp = fopen(proc_file, "r");
606 if (!fp) {
607 /* try the way it's implemented in newer kernels: /proc/scsi/usb-storage/[host] */
608 sprintf(proc_file, "%s/%s/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no);
609 fp = fopen(proc_file, "r");
612 if (fp) {
613 #ifdef LINUX26
614 fclose(fp);
615 return 1;
616 #else
617 while (fgets(line, sizeof(line), fp) != NULL) {
618 if (strstr(line, "Attached: Yes")) {
619 fclose(fp);
620 return 1;
623 fclose(fp);
624 #endif
627 return 0;
631 #ifndef MNT_DETACH
632 #define MNT_DETACH 0x00000002 /* from linux/fs.h - just detach from the tree */
633 #endif
634 int umount_mountpoint(struct mntent *mnt, uint flags);
635 int uswap_mountpoint(struct mntent *mnt, uint flags);
637 /* Unmount this partition from all its mountpoints. Note that it may
638 * actually be mounted several times, either with different names or
639 * with "-o bind" flag.
640 * If the special flagfile is now revealed, delete it and [attempt to] delete
641 * the directory.
643 int umount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
645 sync(); /* This won't matter if the device is unplugged, though. */
647 if (flags & EFH_HUNKNOWN) {
648 /* EFH_HUNKNOWN flag is passed if the host was unknown.
649 * Only unmount disconnected drives in this case.
651 if (usb_ufd_connected(host_num))
652 return 0;
655 /* Find all the active swaps that are on this device and stop them. */
656 findmntents(dev_name, 1, uswap_mountpoint, flags);
658 /* Find all the mountpoints that are for this device and unmount them. */
659 findmntents(dev_name, 0, umount_mountpoint, flags);
660 return 0;
663 int uswap_mountpoint(struct mntent *mnt, uint flags)
665 swapoff(mnt->mnt_fsname);
666 return 0;
669 int umount_mountpoint(struct mntent *mnt, uint flags)
671 int ret = 1, count;
672 char flagfn[128];
674 sprintf(flagfn, "%s/.autocreated-dir", mnt->mnt_dir);
676 /* Run user pre-unmount scripts if any. It might be too late if
677 * the drive has been disconnected, but we'll try it anyway.
679 if (nvram_get_int("usb_automount"))
680 run_nvscript("script_usbumount", mnt->mnt_dir, 3);
681 /* Run *.autostop scripts located in the root of the partition being unmounted if any. */
682 run_userfile(mnt->mnt_dir, ".autostop", mnt->mnt_dir, 5);
683 run_nvscript("script_autostop", mnt->mnt_dir, 5);
685 count = 0;
686 while ((ret = umount(mnt->mnt_dir)) && (count < 2)) {
687 count++;
688 /* If we could not unmount the drive on the 1st try,
689 * kill all NAS applications so they are not keeping the device busy -
690 * unless it's an unmount request from the Web GUI.
692 if ((count == 1) && ((flags & EFH_USER) == 0))
693 restart_nas_services(1, 0);
694 sleep(1);
697 if (ret == 0)
698 syslog(LOG_INFO, "USB partition unmounted from %s", mnt->mnt_dir);
700 if (ret && ((flags & EFH_SHUTDN) != 0)) {
701 /* If system is stopping (not restarting), and we couldn't unmount the
702 * partition, try to remount it as read-only. Ignore the return code -
703 * we can still try to do a lazy unmount.
705 eval("mount", "-o", "remount,ro", mnt->mnt_dir);
708 if (ret && ((flags & EFH_USER) == 0)) {
709 /* Make one more try to do a lazy unmount unless it's an unmount
710 * request from the Web GUI.
711 * MNT_DETACH will expose the underlying mountpoint directory to all
712 * except whatever has cd'ed to the mountpoint (thereby making it busy).
713 * So the unmount can't actually fail. It disappears from the ken of
714 * everyone else immediately, and from the ken of whomever is keeping it
715 * busy when they move away from it. And then it disappears for real.
717 ret = umount2(mnt->mnt_dir, MNT_DETACH);
718 syslog(LOG_INFO, "USB partition busy - will unmount ASAP from %s", mnt->mnt_dir);
721 if (ret == 0) {
722 if ((unlink(flagfn) == 0)) {
723 // Only delete the directory if it was auto-created
724 rmdir(mnt->mnt_dir);
727 return (ret == 0);
731 /* Mount this partition on this disc.
732 * If the device is already mounted on any mountpoint, don't mount it again.
733 * If this is a swap partition, try swapon -a.
734 * If this is a regular partition, try mount -a.
736 * Before we mount any partitions:
737 * If the type is swap and /etc/fstab exists, do "swapon -a"
738 * If /etc/fstab exists, try mounting using fstab.
739 * We delay invoking mount because mount will probe all the partitions
740 * to read the labels, and we don't want it to do that early on.
741 * We don't invoke swapon until we actually find a swap partition.
743 * If the mount succeeds, execute the *.autorun scripts in the top
744 * directory of the newly mounted partition.
745 * Returns NZ for success, 0 if we did not mount anything.
747 int mount_partition(char *dev_name, int host_num, char *dsc_name, char *pt_name, uint flags)
749 char the_label[128], mountpoint[128], uuid[40];
750 int ret;
751 char *type, *p;
752 static char *swp_argv[] = { "swapon", "-a", NULL };
753 struct mntent *mnt;
755 if ((type = find_label_or_uuid(dev_name, the_label, uuid)) == NULL)
756 return 0;
758 if (f_exists("/etc/fstab")) {
759 if (strcmp(type, "swap") == 0) {
760 _eval(swp_argv, NULL, 0, NULL);
761 return 0;
764 if (mount_r(dev_name, NULL, NULL) == MOUNT_VAL_EXIST)
765 return 0;
767 if ((mnt = mount_fstab(dev_name, type, the_label, uuid))) {
768 strcpy(mountpoint, mnt->mnt_dir);
769 ret = MOUNT_VAL_RW;
770 goto done;
774 if (*the_label != 0) {
775 for (p = the_label; *p; p++) {
776 if (!isalnum(*p) && !strchr("+-&.@", *p))
777 *p = '_';
779 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, the_label);
780 if ((ret = mount_r(dev_name, mountpoint, type)))
781 goto done;
784 /* Can't mount to /mnt/LABEL, so try mounting to /mnt/discDN_PN */
785 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, pt_name);
786 ret = mount_r(dev_name, mountpoint, type);
787 done:
788 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
790 /* Run user *.autorun and post-mount scripts if any. */
791 run_userfile(mountpoint, ".autorun", mountpoint, 3);
792 if (nvram_get_int("usb_automount"))
793 run_nvscript("script_usbmount", mountpoint, 3);
795 return (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
799 #if 0 /* LINUX26 */
802 * Finds SCSI Host number. Returns the host number >=0 if found, or (-1) otherwise.
803 * The name and host number of scsi block device in kernel 2.6 (for attached devices) can be found as
804 * /sys($DEVPATH)/host<host_no>/target<*>/<id>/block:[sda|sdb|...]
805 * where $DEVPATH is passed to hotplug events, and looks like
806 * /devices/pci0000:00/0000:00:04.1/usb1/1-1/1-1:1.2
808 * For printers this function finds a minor assigned to a printer
809 * /sys($DEVPATH)/usb:lp[0|1|2|...]
811 int find_dev_host(const char *devpath)
813 DIR *usb_devpath;
814 struct dirent *dp;
815 char buf[256];
816 int host = -1; /* Scsi Host */
818 sprintf(buf, "/sys%s", devpath);
819 if ((usb_devpath = opendir(buf))) {
820 while ((dp = readdir(usb_devpath))) {
821 errno = 0;
822 if (strncmp(dp->d_name, "host", 4) == 0) {
823 host = strtol(dp->d_name + 4, (char **)NULL, 10);
824 if (errno)
825 host = -1;
826 else
827 break;
829 else if (strncmp(dp->d_name, "usb:lp", 6) == 0) {
830 host = strtol(dp->d_name + 6, (char **)NULL, 10);
831 if (errno)
832 host = -1;
833 else
834 break;
836 else
837 continue;
839 closedir(usb_devpath);
841 return (host);
844 #endif /* LINUX26 */
846 int dir_is_mountpoint(const char *root, const char *dir)
848 char path[256];
849 struct stat sb;
850 int thisdev;
852 snprintf(path, sizeof(path), "%s%s%s", root ? : "", root ? "/" : "", dir);
854 /* Check if this is a directory */
855 sb.st_mode = S_IFDIR; /* failsafe */
856 stat(path, &sb);
858 if (S_ISDIR(sb.st_mode)) {
860 /* If this dir & its parent dir are on the same device, it is not a mountpoint */
861 strcat(path, "/.");
862 stat(path, &sb);
863 thisdev = sb.st_dev;
864 strcat(path, ".");
865 ++sb.st_dev; /* failsafe */
866 stat(path, &sb);
868 return (thisdev != sb.st_dev);
871 return 0;
874 /* Mount or unmount all partitions on this controller.
875 * Parameter: action_add:
876 * 0 = unmount
877 * >0 = mount only if automount config option is enabled.
878 * <0 = mount regardless of config option.
880 void hotplug_usb_storage_device(int host_no, int action_add, uint flags)
882 if (!nvram_get_int("usb_enable"))
883 return;
884 _dprintf("%s: host %d action: %d\n", __FUNCTION__, host_no, action_add);
886 if (action_add) {
887 if (nvram_get_int("usb_storage") && (nvram_get_int("usb_automount") || action_add < 0)) {
888 /* Do not probe the device here. It's either initiated by user,
889 * or hotplug_usb() already did.
891 if (exec_for_host(host_no, 0x00, flags, mount_partition)) {
892 restart_nas_services(0, 1); // restart all NAS applications
896 else {
897 if (nvram_get_int("usb_storage") || ((flags & EFH_USER) == 0)) {
898 /* When unplugged, unmount the device even if
899 * usb storage is disabled in the GUI.
901 exec_for_host(host_no, (flags & EFH_USER) ? 0x00 : 0x02, flags, umount_partition);
902 /* Restart NAS applications (they could be killed by umount_mountpoint),
903 * or just re-read the configuration.
905 restart_nas_services(0, 1);
911 /* This gets called at reboot or upgrade. The system is stopping. */
912 void remove_storage_main(int shutdn)
914 if (shutdn)
915 restart_nas_services(1, 0);
916 /* Unmount all partitions */
917 exec_for_host(-1, 0x02, shutdn ? EFH_SHUTDN : 0, umount_partition);
921 /*******
922 * All the complex locking & checking code was removed when the kernel USB-storage
923 * bugs were fixed.
924 * The crash bug was with overlapped I/O to different USB drives, not specifically
925 * with mount processing.
927 * And for USB devices that are slow to come up. The kernel now waits until the
928 * USB drive has settled, and it correctly reads the partition table before calling
929 * the hotplug agent.
931 * The kernel patch was cleaning up data structures on an unplug. It
932 * needs to wait until the disk is unmounted. We have 20 seconds to do
933 * the unmounts.
934 *******/
936 #ifdef LINUX26
937 static inline void usbled_proc(char *device, int add)
939 char *p;
940 char param[32];
942 DIR *usb1=NULL;
943 DIR *usb2=NULL;
944 DIR *usb3=NULL;
945 DIR *usb4=NULL;
947 /*Start USB LED Patch provided by AndreDVJ at: http://www.linksysinfo.org/index.php?threads/tomato-for-arm-routers.69719/page-21#post-269691 - Some fortification added by NULLing out vars after use*/
948 if (get_model() == MODEL_R7000) {
949 usb1 = opendir ("/sys/bus/usb/devices/2-1:1.0"); // port 1 gpio 17
950 usb2 = opendir ("/sys/bus/usb/devices/2-2:1.0"); // port 2 gpio 18
951 usb3 = opendir ("/sys/bus/usb/devices/1-1:1.0"); // port 1 gpio 17
952 usb4 = opendir ("/sys/bus/usb/devices/1-2:1.0"); // port 2 gpio 18
954 if(add) {
955 if (usb1 != NULL) {
956 xstart("gpio", "disable", "17");
957 (void) closedir (usb1);
958 usb1 = NULL;
960 if (usb2 != NULL) {
961 xstart("gpio", "disable", "18");
962 (void) closedir (usb2);
963 usb2 = NULL;
965 if (usb3 != NULL) {
966 xstart("gpio", "disable", "17");
967 (void) closedir (usb3);
968 usb3 = NULL;
970 if (usb4 != NULL) {
971 xstart("gpio", "disable", "18");
972 (void) closedir (usb4);
973 usb4 = NULL;
975 } else {
976 if (usb1 == NULL && usb3 == NULL) {
977 xstart("gpio", "enable", "17");
979 if (usb2 == NULL && usb4 == NULL) {
980 xstart("gpio", "enable", "18");
984 /*End USB LED Patch provided by AndreDVJ at: http://www.linksysinfo.org/index.php?threads/tomato-for-arm-routers.69719/page-21#post-269691 - Some fortification added by NULLing out vars after use*/
986 if (get_model() == MODEL_WS880) {
987 do_led(LED_USB3, (add) ? LED_ON : LED_OFF);
988 return;
991 if (do_led(LED_USB, LED_PROBE) != 255) {
992 strncpy(param, device, sizeof(param));
993 if ((p = strchr(param, ':')) != NULL)
994 *p = 0;
996 /* verify if we need to ignore this device (i.e. an internal SD/MMC slot ) */
997 p = nvram_safe_get("usb_noled");
998 if (strcmp(p, param) == 0)
999 return;
1001 // Remove legacy approach in the code here - rather, use do_led() function, which is designed to do this
1002 // The reason for changing this ... some HW (like Netgear WNDR4000) don't work with direct GPIO write -> use do_led()!
1003 //f_write_string(add ? "/proc/leds-usb/add" : "/proc/leds-usb/remove", param, 0, 0);
1004 if (add)
1005 do_led(LED_USB, LED_ON);
1006 else
1007 do_led(LED_USB, LED_OFF);
1010 #endif
1012 /* Plugging or removing usb device
1014 * On an occurrance, multiple hotplug events may be fired off.
1015 * For example, if a hub is plugged or unplugged, an event
1016 * will be generated for everything downstream of it, plus one for
1017 * the hub itself. These are fired off simultaneously, not serially.
1018 * This means that many many hotplug processes will be running at
1019 * the same time.
1021 * The hotplug event generated by the kernel gives us several pieces
1022 * of information:
1023 * PRODUCT is vendorid/productid/rev#.
1024 * DEVICE is /proc/bus/usb/bus#/dev#
1025 * ACTION is add or remove
1026 * SCSI_HOST is the host (controller) number (this relies on the custom kernel patch)
1028 * Note that when we get a hotplug add event, the USB susbsystem may
1029 * or may not have yet tried to read the partition table of the
1030 * device. For a new controller that has never been seen before,
1031 * generally yes. For a re-plug of a controller that has been seen
1032 * before, generally no.
1034 * On a remove, the partition info has not yet been expunged. The
1035 * partitions show up as /dev/discs/disc#/part#, and /proc/partitions.
1036 * It appears that doing a "stat" for a non-existant partition will
1037 * causes the kernel to re-validate the device and update the
1038 * partition table info. However, it won't re-validate if the disc is
1039 * mounted--you'll get a "Device busy for revalidation (usage=%d)" in
1040 * syslog.
1042 * The $INTERFACE is "class/subclass/protocol"
1043 * Some interesting classes:
1044 * 8 = mass storage
1045 * 7 = printer
1046 * 3 = HID. 3/1/2 = mouse.
1047 * 6 = still image (6/1/1 = Digital camera Camera)
1048 * 9 = Hub
1049 * 255 = scanner (255/255/255)
1051 * Observed:
1052 * Hub seems to have no INTERFACE (null), and TYPE of "9/0/0"
1053 * Flash disk seems to have INTERFACE of "8/6/80", and TYPE of "0/0/0"
1055 * When a hub is unplugged, a hotplug event is generated for it and everything
1056 * downstream from it. You cannot depend on getting these events in any
1057 * particular order, since there will be many hotplug programs all fired off
1058 * at almost the same time.
1059 * On a remove, don't try to access the downstream devices right away, give the
1060 * kernel time to finish cleaning up all the data structures, which will be
1061 * in the process of being torn down.
1063 * On the initial plugin, the first time the kernel usb-storage subsystem sees
1064 * the host (identified by GUID), it automatically reads the partition table.
1065 * On subsequent plugins, it does not.
1067 * Special values for Web Administration to unmount or remount
1068 * all partitions of the host:
1069 * INTERFACE=TOMATO/...
1070 * ACTION=add/remove
1071 * SCSI_HOST=<host_no>
1072 * If host_no is negative, we unmount all partions of *all* hosts.
1074 void hotplug_usb(void)
1076 int add;
1077 int host = -1;
1078 char *interface = getenv("INTERFACE");
1079 char *action = getenv("ACTION");
1080 char *product = getenv("PRODUCT");
1081 #ifdef LINUX26
1082 char *device = getenv("DEVICENAME");
1083 int is_block = strcmp(getenv("SUBSYSTEM") ? : "", "block") == 0;
1084 #else
1085 char *device = getenv("DEVICE");
1086 #endif
1087 char *scsi_host = getenv("SCSI_HOST");
1089 _dprintf("%s hotplug INTERFACE=%s ACTION=%s PRODUCT=%s HOST=%s DEVICE=%s\n",
1090 getenv("SUBSYSTEM") ? : "USB", interface, action, product, scsi_host, device);
1092 if (!nvram_get_int("usb_enable")) return;
1093 #ifdef LINUX26
1094 if (!action || ((!interface || !product) && !is_block))
1095 #else
1096 if (!interface || !action || !product) /* Hubs bail out here. */
1097 #endif
1098 return;
1100 if (scsi_host)
1101 host = atoi(scsi_host);
1103 if (!wait_action_idle(10)) return;
1105 add = (strcmp(action, "add") == 0);
1106 if (add && (strncmp(interface ? : "", "TOMATO/", 7) != 0)) {
1107 #ifdef LINUX26
1108 if (!is_block && device)
1109 #endif
1110 syslog(LOG_DEBUG, "Attached USB device %s [INTERFACE=%s PRODUCT=%s]",
1111 device, interface, product);
1112 #ifndef LINUX26
1113 /* To allow automount to be blocked on startup.
1114 * In kernel 2.6 we still need to serialize mount/umount calls -
1115 * so the lock is down below in the "block" hotplug processing.
1117 file_unlock(file_lock("usb"));
1118 #endif
1121 if (strncmp(interface ? : "", "TOMATO/", 7) == 0) { /* web admin */
1122 if (scsi_host == NULL)
1123 host = atoi(product); // for backward compatibility
1124 /* If host is negative, unmount all partitions of *all* hosts.
1125 * If host == -1, execute "soft" unmount (do not kill NAS apps, no "lazy" umount).
1126 * If host == -2, run "hard" unmount, as if the drive is unplugged.
1127 * This feature can be used in custom scripts as following:
1129 * # INTERFACE=TOMATO/1 ACTION=remove PRODUCT=-1 SCSI_HOST=-1 hotplug usb
1131 * PRODUCT is required to pass the env variables verification.
1133 /* Unmount or remount all partitions of the host. */
1134 hotplug_usb_storage_device(host < 0 ? -1 : host, add ? -1 : 0,
1135 host == -2 ? 0 : EFH_USER);
1137 #ifdef LINUX26
1138 else if (is_block && strcmp(getenv("MAJOR") ? : "", "8") == 0 && strcmp(getenv("PHYSDEVBUS") ? : "", "scsi") == 0) {
1139 /* scsi partition */
1140 char devname[64];
1141 int lock;
1143 sprintf(devname, "/dev/%s", device);
1144 lock = file_lock("usb");
1145 if (add) {
1146 if (nvram_get_int("usb_storage") && nvram_get_int("usb_automount")) {
1147 int minor = atoi(getenv("MINOR") ? : "0");
1148 if ((minor % 16) == 0 && !is_no_partition(device)) {
1149 /* This is a disc, and not a "no-partition" device,
1150 * like APPLE iPOD shuffle. We can't mount it.
1152 return;
1154 if (mount_partition(devname, host, NULL, device, EFH_HP_ADD)) {
1155 restart_nas_services(0, 1); // restart all NAS applications
1159 else {
1160 /* When unplugged, unmount the device even if usb storage is disabled in the GUI */
1161 umount_partition(devname, host, NULL, device, EFH_HP_REMOVE);
1162 /* Restart NAS applications (they could be killed by umount_mountpoint),
1163 * or just re-read the configuration.
1165 restart_nas_services(0, 1);
1167 file_unlock(lock);
1169 #endif
1170 else if (strncmp(interface ? : "", "8/", 2) == 0) { /* usb storage */
1171 #ifdef LINUX26
1172 usbled_proc(device, add);
1173 #endif
1174 run_nvscript("script_usbhotplug", NULL, 2);
1175 #ifndef LINUX26
1176 hotplug_usb_storage_device(host, add, (add ? EFH_HP_ADD : EFH_HP_REMOVE) | (host < 0 ? EFH_HUNKNOWN : 0));
1177 #endif
1179 else { /* It's some other type of USB device, not storage. */
1180 #ifdef LINUX26
1181 if (is_block) return;
1182 #endif
1183 #ifdef LINUX26
1184 if (strncmp(interface ? : "", "7/", 2) == 0) /* printer */
1185 usbled_proc(device, add);
1186 #endif
1187 /* Do nothing. The user's hotplug script must do it all. */
1188 run_nvscript("script_usbhotplug", NULL, 2);