Samba: extra codepages
[tomato.git] / release / src / router / rc / usb.c
blob17f66ca6267769eda556d418120764c2bb3ff985
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 #if 1
28 #include <sys/kdaemon.h>
29 #define SET_PARM(n) (n * 2 | 1)
31 void tune_bdflush(void)
33 bdflush(SET_PARM(5), 100);
34 bdflush(SET_PARM(6), 100);
35 bdflush(SET_PARM(8), 0);
37 #else
38 /* Store values in nvram for customization */
39 void tune_bdflush(void)
41 unsigned int v[9];
42 const char *p;
44 p = nvram_safe_get("usb_bdflush");
45 // nvram default: 30 500 0 0 100 100 60 0 0
46 if (sscanf(p, "%u%u%u%u%u%u%u%u%u",
47 &v[0], &v[1], &v[2], &v[3], &v[4], &v[5], &v[6], &v[7], &v[8]) == 9) { // lightly verify
48 f_write_string("/proc/sys/vm/bdflush", p, 0, 0);
51 #endif
54 void start_usb(void)
56 _dprintf("%s\n", __FUNCTION__);
57 tune_bdflush();
59 if (nvram_get_int("usb_enable")) {
60 // led(LED_AOSS, LED_ON);
61 modprobe("usbcore");
63 /* mount usb device filesystem */
64 mount("usbdevfs", "/proc/bus/usb", "usbdevfs", MS_MGC_VAL, NULL);
66 if (nvram_get_int("usb_storage")) {
67 /* insert scsi and storage modules before usb drivers */
68 modprobe("scsi_mod");
69 modprobe("sd_mod");
70 modprobe("usb-storage");
72 if (nvram_get_int("usb_fs_ext3")) {
73 /* insert ext3 first so that lazy mount tries ext3 before ext2 */
74 modprobe("jbd");
75 modprobe("ext3");
76 modprobe("ext2");
79 if (nvram_get_int("usb_fs_fat")) {
80 modprobe("fat");
81 modprobe("vfat");
85 /* if enabled, force USB2 before USB1.1 */
86 if (nvram_get_int("usb_usb2")) {
87 modprobe("ehci-hcd");
90 if (nvram_get_int("usb_uhci")) {
91 modprobe("usb-uhci");
94 if (nvram_get_int("usb_ohci")) {
95 modprobe("usb-ohci");
98 if (nvram_get_int("usb_printer")) {
99 modprobe("printer");
100 symlink("/dev/usb", "/dev/printers");
102 /* start printer server */
103 xstart("p910nd",
104 nvram_get_int("usb_printer_bidirect") ? "-b" : "", //bidirectional
105 "-f", "/dev/usb/lp0", // device
106 "0" // listen port
110 else {
111 // led(LED_AOSS, LED_OFF);
115 void stop_usb(void)
117 // stop printing service
118 int i;
119 char s[32];
120 char pid[] = "/var/run/p9100d.pid";
122 // only find and kill the printer server we started (port 0)
123 if (f_read_string(pid, s, sizeof(s)) > 0) {
124 if ((i = atoi(s)) > 1) {
125 kill(i, SIGTERM);
126 sleep(1);
127 unlink(pid);
130 modprobe_r("printer");
132 // only stop storage services if disabled
133 if (!nvram_get_int("usb_enable") || !nvram_get_int("usb_storage")) {
134 // Unmount all partitions
135 remove_storage_main(0);
137 // Stop storage services
138 modprobe_r("ext2");
139 modprobe_r("ext3");
140 modprobe_r("jbd");
141 modprobe_r("vfat");
142 modprobe_r("fat");
143 modprobe_r("fuse");
144 #ifdef TCONFIG_SAMBASRV
145 modprobe_r("nls_cp437");
146 modprobe_r("nls_cp850");
147 modprobe_r("nls_cp852");
148 modprobe_r("nls_cp866");
149 #ifdef LINUX26
150 modprobe_r("nls_cp932");
151 modprobe_r("nls_cp936");
152 modprobe_r("nls_cp949");
153 modprobe_r("nls_cp950");
154 #endif
155 #endif
156 modprobe_r("usb-storage");
157 modprobe_r("sd_mod");
158 modprobe_r("scsi_mod");
161 // only unload core modules if usb is disabled
162 if (!nvram_get_int("usb_enable")) {
163 umount("/proc/bus/usb"); // unmount usb device filesystem
164 modprobe_r("usb-ohci");
165 modprobe_r("usb-uhci");
166 modprobe_r("ehci-hcd");
167 modprobe_r("usbcore");
172 #define MOUNT_VAL_FAIL 0
173 #define MOUNT_VAL_RONLY 1
174 #define MOUNT_VAL_RW 2
175 #define MOUNT_VAL_EXIST 3
177 int mount_r(char *mnt_dev, char *mnt_dir, char *type)
179 struct mntent *mnt;
180 int ret;
181 char options[40];
182 char flagfn[128];
183 int dir_made;
185 if ((mnt = findmntents(mnt_dev, 0, NULL, 0))) {
186 syslog(LOG_INFO, "USB partition at %s already mounted on %s",
187 mnt_dev, mnt->mnt_dir);
188 return MOUNT_VAL_EXIST;
191 options[0] = 0;
193 if (type) {
194 unsigned long flags = MS_NOATIME | MS_NODEV;
196 if (strcmp(type, "swap") == 0 || strcmp(type, "mbr") == 0) {
197 /* not a mountable partition */
198 flags = 0;
200 else if (strcmp(type, "ext2") == 0 || strcmp(type, "ext3") == 0) {
202 #ifdef TCONFIG_SAMBASRV
203 else if (strcmp(type, "vfat") == 0) {
204 if (nvram_invmatch("smbd_cset", "") && isdigit(nvram_safe_get("smbd_cset")[0]))
205 sprintf(options, "iocharset=cp%s", nvram_safe_get("smbd_cset"));
206 if (nvram_invmatch("smbd_cpage", "")) {
207 char *cp = nvram_safe_get("smbd_cpage");
208 sprintf(options + strlen(options), ",codepage=%s" + (options[0] ? 0 : 1), cp);
209 sprintf(flagfn, "nls_cp%s", cp);
211 cp = nvram_get("smbd_nlsmod");
212 if ((cp) && (*cp != 0) && (strcmp(cp, flagfn) != 0))
213 modprobe_r(cp);
215 modprobe(flagfn);
216 nvram_set("smbd_nlsmod", flagfn);
219 else if (strncmp(type, "ntfs", 4) == 0) {
220 if (nvram_invmatch("smbd_cset", ""))
221 sprintf(options, "iocharset=%s%s",
222 isdigit(nvram_get("smbd_cset")[0]) ? "cp" : "",
223 nvram_get("smbd_cset"));
225 #endif
227 if (flags) {
228 if ((dir_made = mkdir_if_none(mnt_dir))) {
229 /* Create the flag file for remove the directory on dismount. */
230 sprintf(flagfn, "%s/.autocreated-dir", mnt_dir);
231 f_write(flagfn, NULL, 0, 0, 0);
234 ret = mount(mnt_dev, mnt_dir, type, flags, options[0] ? options : "");
236 /* try ntfs-3g in case it's installed */
237 if (ret != 0 && strncmp(type, "ntfs", 4) == 0) {
238 sprintf(options + strlen(options), ",noatime,nodev" + (options[0] ? 0 : 1));
239 #ifdef TCONFIG_NTFS
240 if (nvram_get_int("usb_fs_ntfs"))
241 #endif
242 ret = eval("ntfs-3g", "-o", options, mnt_dev, mnt_dir);
244 if (ret != 0) /* give it another try - guess fs */
245 ret = eval("mount", "-o", "noatime,nodev", mnt_dev, mnt_dir);
247 if (ret == 0) {
248 syslog(LOG_INFO, "USB %s%s fs at %s mounted on %s",
249 type, (flags & MS_RDONLY) ? " (ro)" : "", mnt_dev, mnt_dir);
250 return (flags & MS_RDONLY) ? MOUNT_VAL_RONLY : MOUNT_VAL_RW;
253 if (dir_made) {
254 unlink(flagfn);
255 rmdir(mnt_dir);
259 return MOUNT_VAL_FAIL;
263 struct mntent *mount_fstab(char *dev_name, char *type, char *label, char *uuid)
265 struct mntent *mnt = NULL;
266 #if 0
267 if (eval("mount", "-a") == 0)
268 mnt = findmntents(dev_name, 0, NULL, 0);
269 #else
270 char spec[PATH_MAX+1];
272 if (label && *label) {
273 sprintf(spec, "LABEL=%s", label);
274 if (eval("mount", spec) == 0)
275 mnt = findmntents(dev_name, 0, NULL, 0);
278 if (!mnt && uuid && *uuid) {
279 sprintf(spec, "UUID=%s", uuid);
280 if (eval("mount", spec) == 0)
281 mnt = findmntents(dev_name, 0, NULL, 0);
284 if (!mnt) {
285 if (eval("mount", dev_name) == 0)
286 mnt = findmntents(dev_name, 0, NULL, 0);
289 if (!mnt) {
290 /* Still did not find what we are looking for, try absolute path */
291 if (realpath(dev_name, spec)) {
292 if (eval("mount", spec) == 0)
293 mnt = findmntents(dev_name, 0, NULL, 0);
296 #endif
298 if (mnt)
299 syslog(LOG_INFO, "USB %s fs at %s mounted on %s", type, dev_name, mnt->mnt_dir);
300 return (mnt);
304 /* Check if the UFD is still connected because the links created in /dev/discs
305 * are not removed when the UFD is unplugged.
306 * The file to read is: /proc/scsi/usb-storage-#/#, where # is the host no.
307 * We are looking for "Attached: Yes".
309 static int usb_ufd_connected(int host_no)
311 char proc_file[128], line[256];
312 FILE *fp;
314 sprintf(proc_file, "%s/%s-%d/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no, host_no);
315 fp = fopen(proc_file, "r");
317 if (!fp) {
318 /* try the way it's implemented in newer kernels: /proc/scsi/usb-storage/[host] */
319 sprintf(proc_file, "%s/%s/%d", PROC_SCSI_ROOT, USB_STORAGE, host_no);
320 fp = fopen(proc_file, "r");
323 if (fp) {
324 while (fgets(line, sizeof(line), fp) != NULL) {
325 if (strstr(line, "Attached: Yes")) {
326 fclose(fp);
327 return 1;
330 fclose(fp);
333 return 0;
337 #ifndef MNT_DETACH
338 #define MNT_DETACH 0x00000002 /* from linux/fs.h - just detach from the tree */
339 #endif
340 int umount_mountpoint(struct mntent *mnt, uint flags);
341 int uswap_mountpoint(struct mntent *mnt, uint flags);
343 /* Unmount this partition from all its mountpoints. Note that it may
344 * actually be mounted several times, either with different names or
345 * with "-o bind" flag.
346 * If the special flagfile is now revealed, delete it and [attempt to] delete
347 * the directory.
349 int umount_partition(char *dev_name, int host_num, int disc_num, int part_num, uint flags)
351 sync(); /* This won't matter if the device is unplugged, though. */
353 if (flags & EFH_HUNKNOWN) {
354 /* EFH_HUNKNOWN flag is passed if the host was unknown.
355 * Only unmount disconnected drives in this case.
357 if (usb_ufd_connected(host_num))
358 return(0);
361 /* Find all the active swaps that are on this device and stop them. */
362 findmntents(dev_name, 1, uswap_mountpoint, flags);
364 /* Find all the mountpoints that are for this device and unmount them. */
365 findmntents(dev_name, 0, umount_mountpoint, flags);
366 return 0;
369 int uswap_mountpoint(struct mntent *mnt, uint flags)
371 swapoff(mnt->mnt_fsname);
372 return 0;
375 int umount_mountpoint(struct mntent *mnt, uint flags)
377 int ret = 1, count;
378 char flagfn[128];
380 /* Kill all NAS applications here so they are not keeping the device busy,
381 * unless it's an unmount request from the Web GUI.
383 if ((flags & EFH_USER) == 0) {
384 restart_nas_services(1, 0);
387 sprintf(flagfn, "%s/.autocreated-dir", mnt->mnt_dir);
388 run_nvscript("script_autostop", mnt->mnt_dir, 5);
389 count = 0;
390 while ((ret = umount(mnt->mnt_dir)) && (count < 2)) {
391 count++;
392 sleep(1);
395 if (!ret)
396 syslog(LOG_INFO, "USB partition unmounted from %s", mnt->mnt_dir);
398 if (ret && ((flags & EFH_SHUTDN) != 0)) {
399 /* If system is stopping (not restarting), and we couldn't unmount the
400 * partition, try to remount it as read-only. Ignore the return code -
401 * we can still try to do a lazy unmount.
403 eval("mount", "-o", "remount,ro", mnt->mnt_dir);
406 if (ret && ((flags & EFH_USER) == 0)) {
407 /* Make one more try to do a lazy unmount unless it's an unmount
408 * request from the Web GUI.
409 * MNT_DETACH will expose the underlying mountpoint directory to all
410 * except whatever has cd'ed to the mountpoint (thereby making it busy).
411 * So the unmount can't actually fail. It disappears from the ken of
412 * everyone else immediately, and from the ken of whomever is keeping it
413 * busy until they move away from it. And then it disappears for real.
415 ret = umount2(mnt->mnt_dir, MNT_DETACH);
416 syslog(LOG_INFO, "USB partition busy - will unmount ASAP from %s", mnt->mnt_dir);
419 if (!ret) {
420 if ((unlink(flagfn) == 0)) {
421 // Only delete the directory if it was auto-created
422 rmdir(mnt->mnt_dir);
425 return(!ret);
429 /* Mount this partition on this disc.
430 * If the device is already mounted on any mountpoint, don't mount it again.
431 * If this is a swap partition, try swapon -a.
432 * If this is a regular partition, try mount -a.
434 * Before we mount any partitions:
435 * If the type is swap and /etc/fstab exists, do "swapon -a"
436 * If /etc/fstab exists, try mounting using fstab.
437 * We delay invoking mount because mount will probe all the partitions
438 * to read the labels, and we don't want it to do that early on.
439 * We don't invoke swapon until we actually find a swap partition.
441 * If the mount succeeds, execute the *.autorun scripts in the top
442 * directory of the newly mounted partition.
443 * Returns NZ for success, 0 if we did not mount anything.
445 int mount_partition(char *dev_name, int host_num, int disc_num, int part_num, uint flags)
447 char the_label[128], mountpoint[128], uuid[40];
448 int ret;
449 char *type;
450 static char *swp_argv[] = { "swapon", "-a", NULL };
451 struct mntent *mnt;
453 if ((type = detect_fs_type(dev_name)) == NULL)
454 return(0);
455 find_label_or_uuid(dev_name, the_label, uuid);
457 if (f_exists("/etc/fstab")) {
458 if (strcmp(type, "swap") == 0) {
459 _eval(swp_argv, NULL, 0, NULL);
460 return(0);
463 if (mount_r(dev_name, NULL, NULL) == MOUNT_VAL_EXIST)
464 return(0);
466 if ((mnt = mount_fstab(dev_name, type, the_label, uuid))) {
467 run_userfile(mnt->mnt_dir, ".autorun", mnt->mnt_dir, 3);
468 return(1);
472 if (*the_label != 0) {
473 sprintf(mountpoint, "%s/%s", MOUNT_ROOT, the_label);
474 if ((ret = mount_r(dev_name, mountpoint, type))) {
475 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
476 run_userfile(mountpoint, ".autorun", mountpoint, 3);
477 return(ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
481 /* Can't mount to /mnt/LABEL, so try mounting to /mnt/discDN_PN */
482 sprintf(mountpoint, "%s/disc%d_%d", MOUNT_ROOT, disc_num, part_num);
483 ret = mount_r(dev_name, mountpoint, type);
484 if (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW)
485 run_userfile(mountpoint, ".autorun", mountpoint, 3);
486 return (ret == MOUNT_VAL_RONLY || ret == MOUNT_VAL_RW);
490 /* Mount or unmount all partitions on this controller.
491 * Parameter: action_add:
492 * 0 = unmount
493 * >0 = mount only if automount config option is enabled.
494 * <0 = mount regardless of config option.
496 void hotplug_usb_storage_device(int host_no, int action_add, uint flags)
498 if (!nvram_get_int("usb_enable"))
499 return;
500 _dprintf("%s: host %d action: %d\n", __FUNCTION__, host_no, action_add);
502 if (action_add) {
503 if (nvram_get_int("usb_storage") && (nvram_get_int("usb_automount") || action_add < 0)) {
504 /* Do not probe the device here. It's either initiated by user,
505 * or hotplug_usb() already did.
507 if (exec_for_host(host_no, 0x00, flags, mount_partition)) {
508 restart_nas_services(0, 1); // restart all NAS applications
509 run_nvscript("script_usbmount", NULL, 3);
513 else {
514 if (nvram_get_int("usb_storage") || ((flags & EFH_USER) == 0)) {
515 /* When unplugged, unmount the device even if
516 * usb storage is disabled in the GUI.
518 if (flags & EFH_USER) {
519 /* Unmount from Web. Run user pre-unmount script if any.
521 run_nvscript("script_usbumount", NULL, 3);
523 exec_for_host(host_no, (flags & EFH_USER) ? 0x00 : 0x02, flags, umount_partition);
524 /* Restart NAS applications (they could be killed by umount_mountpoint),
525 * or just re-read the configuration.
527 restart_nas_services(0, 1);
533 /* This gets called at reboot or upgrade. The system is stopping. */
534 void remove_storage_main(int shutdn)
536 if (nvram_get_int("usb_enable") && nvram_get_int("usb_storage")) {
537 if (nvram_get_int("usb_automount")) {
538 // run pre-unmount script if any
539 run_nvscript("script_usbumount", NULL, 3);
542 if (shutdn)
543 restart_nas_services(1, 0);
544 /* Unmount all partitions */
545 exec_for_host(-1, 0x02, shutdn ? EFH_SHUTDN : 0, umount_partition);
549 /*******
550 * All the complex locking & checking code was removed when the kernel USB-storage
551 * bugs were fixed.
552 * The crash bug was with overlapped I/O to different USB drives, not specifically
553 * with mount processing.
555 * And for USB devices that are slow to come up. The kernel now waits until the
556 * USB drive has settled, and it correctly reads the partition table before calling
557 * the hotplug agent.
559 * The kernel patch was cleaning up data structures on an unplug. It
560 * needs to wait until the disk is unmounted. We have 20 seconds to do
561 * the unmounts.
562 *******/
565 /* Plugging or removing usb device
567 * On an occurrance, multiple hotplug events may be fired off.
568 * For example, if a hub is plugged or unplugged, an event
569 * will be generated for everything downstream of it, plus one for
570 * the hub itself. These are fired off simultaneously, not serially.
571 * This means that many many hotplug processes will be running at
572 * the same time.
574 * The hotplug event generated by the kernel gives us several pieces
575 * of information:
576 * PRODUCT is vendorid/productid/rev#.
577 * DEVICE is /proc/bus/usb/bus#/dev#
578 * ACTION is add or remove
579 * SCSI_HOST is the host (controller) number (this relies on the custom kernel patch)
581 * Note that when we get a hotplug add event, the USB susbsystem may
582 * or may not have yet tried to read the partition table of the
583 * device. For a new controller that has never been seen before,
584 * generally yes. For a re-plug of a controller that has been seen
585 * before, generally no.
587 * On a remove, the partition info has not yet been expunged. The
588 * partitions show up as /dev/discs/disc#/part#, and /proc/partitions.
589 * It appears that doing a "stat" for a non-existant partition will
590 * causes the kernel to re-validate the device and update the
591 * partition table info. However, it won't re-validate if the disc is
592 * mounted--you'll get a "Device busy for revalidation (usage=%d)" in
593 * syslog.
595 * The $INTERFACE is "class/subclass/protocol"
596 * Some interesting classes:
597 * 8 = mass storage
598 * 7 = printer
599 * 3 = HID. 3/1/2 = mouse.
600 * 6 = still image (6/1/1 = Digital camera Camera)
601 * 9 = Hub
602 * 255 = scanner (255/255/255)
604 * Observed:
605 * Hub seems to have no INTERFACE (null), and TYPE of "9/0/0"
606 * Flash disk seems to have INTERFACE of "8/6/80", and TYPE of "0/0/0"
608 * When a hub is unplugged, a hotplug event is generated for it and everything
609 * downstream from it. You cannot depend on getting these events in any
610 * particular order, since there will be many hotplug programs all fired off
611 * at almost the same time.
612 * On a remove, don't try to access the downstream devices right away, give the
613 * kernel time to finish cleaning up all the data structures, which will be
614 * in the process of being torn down.
616 * On the initial plugin, the first time the kernel usb-storage subsystem sees
617 * the host (identified by GUID), it automatically reads the partition table.
618 * On subsequent plugins, it does not.
620 * Special values for Web Administration to unmount or remount
621 * all partitions of the host:
622 * INTERFACE=TOMATO/...
623 * ACTION=add/remove
624 * SCSI_HOST=<host_no>
625 * If host_no is negative, we unmount all partions of *all* hosts.
627 void hotplug_usb(void)
629 int add;
630 int host = -1;
631 char *interface = getenv("INTERFACE");
632 char *action = getenv("ACTION");
633 char *product = getenv("PRODUCT");
634 char *device = getenv("DEVICE");
635 char *scsi_host = getenv("SCSI_HOST");
637 _dprintf("USB hotplug INTERFACE=%s ACTION=%s PRODUCT=%s HOST=%s DEVICE=%s\n",
638 interface, action, product, scsi_host, device);
640 if (!nvram_get_int("usb_enable")) return;
641 if (!interface || !action || !product) /* Hubs bail out here. */
642 return;
644 if (scsi_host)
645 host = atoi(scsi_host);
647 add = (strcmp(action, "add") == 0);
648 if (add && (strncmp(interface, "TOMATO/", 7) != 0)) {
649 syslog(LOG_DEBUG, "Attached USB device %s [INTERFACE=%s PRODUCT=%s]",
650 device, interface, product);
651 file_unlock(file_lock("usb")); /* To allow automount to be blocked on startup. */
654 if (strncmp(interface, "TOMATO/", 7) == 0) { /* web admin */
655 if (scsi_host == NULL)
656 host = atoi(product); // for backward compatibility
657 /* If host is negative, unmount all partitions of *all* hosts.
658 * This feature can be used in custom scripts as following:
660 * # INTERFACE=TOMATO/1 ACTION=remove PRODUCT=-1 SCSI_HOST=-1 hotplug usb
662 * PRODUCT is required to pass the env variables verification.
664 /* Unmount or remount all partitions of the host. */
665 hotplug_usb_storage_device(host, add ? -1 : 0, EFH_USER);
667 else if (strncmp(interface, "8/", 2) == 0) { /* usb storage */
668 run_nvscript("script_usbhotplug", NULL, 2);
669 hotplug_usb_storage_device(host, add, host < 0 ? EFH_HUNKNOWN : 0);
671 else { /* It's some other type of USB device, not storage. */
672 /* Do nothing. The user's hotplug script must do it all. */
673 run_nvscript("script_usbhotplug", NULL, 2);