diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2012-05-18 04:45:35 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2012-05-18 04:45:35 +0200 |
commit | 516530c932bd17d87c9eb4347a490be051e495f4 (patch) | |
tree | 28c18a2785280ff61f819174c5a72d4348298f9e | |
parent | 7c8aa2b47cf76f710959a1f4a914010aca425016 (diff) | |
download | busybox-w32-516530c932bd17d87c9eb4347a490be051e495f4.tar.gz busybox-w32-516530c932bd17d87c9eb4347a490be051e495f4.tar.bz2 busybox-w32-516530c932bd17d87c9eb4347a490be051e495f4.zip |
mdev: add support for $DEVNAME and /dev/mdev.log debug aid
function old new delta
make_device 1843 2083 +240
mdev_main 712 804 +92
packed_usage 29236 29251 +15
keywords 288 19 -269
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 3/1 up/down: 347/-269) Total: 78 bytes
text data bss dec hex filename
887506 497 7584 895587 daa63 busybox_old
887982 497 7584 896063 dac3f busybox_unstripped
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | examples/mdev_fat.conf | 3 | ||||
-rw-r--r-- | util-linux/mdev.c | 167 |
2 files changed, 147 insertions, 23 deletions
diff --git a/examples/mdev_fat.conf b/examples/mdev_fat.conf index da28bc36b..df329b4b5 100644 --- a/examples/mdev_fat.conf +++ b/examples/mdev_fat.conf | |||
@@ -108,6 +108,3 @@ usbdev[0-9].[0-9]_.* root:root 660 | |||
108 | # zaptel devices | 108 | # zaptel devices |
109 | zap(.*) root:dialout 660 =zap/%1 | 109 | zap(.*) root:dialout 660 =zap/%1 |
110 | dahdi!(.*) root:dialout 660 =dahdi/%1 | 110 | dahdi!(.*) root:dialout 660 =dahdi/%1 |
111 | |||
112 | # If $DEVNAME exists, create device with this name | ||
113 | $DEVNAME=bus/usb/.* 0:0 660 ! @mkdir -p "`dirname "$DEVNAME"`"; mknod -m 0660 "$DEVNAME" c "$MAJOR" "$MINOR" | ||
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 0a34122b4..70d19033d 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -93,6 +93,8 @@ | |||
93 | //usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n" | 93 | //usage: "If /dev/mdev.seq file exists, mdev will wait for its value\n" |
94 | //usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n" | 94 | //usage: "to match $SEQNUM variable. This prevents plug/unplug races.\n" |
95 | //usage: "To activate this feature, create empty /dev/mdev.seq at boot." | 95 | //usage: "To activate this feature, create empty /dev/mdev.seq at boot." |
96 | //usage: "\n" | ||
97 | //usage: "If /dev/mdev.log file exists, debug log will be appended to it.\n" | ||
96 | 98 | ||
97 | #include "libbb.h" | 99 | #include "libbb.h" |
98 | #include "xregex.h" | 100 | #include "xregex.h" |
@@ -139,6 +141,98 @@ | |||
139 | * This happens regardless of /sys/class/.../dev existence. | 141 | * This happens regardless of /sys/class/.../dev existence. |
140 | */ | 142 | */ |
141 | 143 | ||
144 | /* Kernel's hotplug environment constantly changes. | ||
145 | * Here are new cases I observed on 3.1.0: | ||
146 | * | ||
147 | * Case with $DEVNAME and $DEVICE, not just $DEVPATH: | ||
148 | * ACTION=add | ||
149 | * BUSNUM=001 | ||
150 | * DEVICE=/proc/bus/usb/001/003 | ||
151 | * DEVNAME=bus/usb/001/003 | ||
152 | * DEVNUM=003 | ||
153 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5 | ||
154 | * DEVTYPE=usb_device | ||
155 | * MAJOR=189 | ||
156 | * MINOR=2 | ||
157 | * PRODUCT=18d1/4e12/227 | ||
158 | * SUBSYSTEM=usb | ||
159 | * TYPE=0/0/0 | ||
160 | * | ||
161 | * Case with $DEVICE, but no $DEVNAME - apparenty, usb iface notification? | ||
162 | * "Please load me a module" thing? | ||
163 | * ACTION=add | ||
164 | * DEVICE=/proc/bus/usb/001/003 | ||
165 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0 | ||
166 | * DEVTYPE=usb_interface | ||
167 | * INTERFACE=8/6/80 | ||
168 | * MODALIAS=usb:v18D1p4E12d0227dc00dsc00dp00ic08isc06ip50 | ||
169 | * PRODUCT=18d1/4e12/227 | ||
170 | * SUBSYSTEM=usb | ||
171 | * TYPE=0/0/0 | ||
172 | * | ||
173 | * ACTION=add | ||
174 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5 | ||
175 | * DEVTYPE=scsi_host | ||
176 | * SUBSYSTEM=scsi | ||
177 | * | ||
178 | * ACTION=add | ||
179 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/scsi_host/host5 | ||
180 | * SUBSYSTEM=scsi_host | ||
181 | * | ||
182 | * ACTION=add | ||
183 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0 | ||
184 | * DEVTYPE=scsi_target | ||
185 | * SUBSYSTEM=scsi | ||
186 | * | ||
187 | * Case with strange $MODALIAS: | ||
188 | * ACTION=add | ||
189 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0 | ||
190 | * DEVTYPE=scsi_device | ||
191 | * MODALIAS=scsi:t-0x00 | ||
192 | * SUBSYSTEM=scsi | ||
193 | * | ||
194 | * ACTION=add | ||
195 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_disk/5:0:0:0 | ||
196 | * SUBSYSTEM=scsi_disk | ||
197 | * | ||
198 | * ACTION=add | ||
199 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/scsi_device/5:0:0:0 | ||
200 | * SUBSYSTEM=scsi_device | ||
201 | * | ||
202 | * Case with explicit $MAJOR/$MINOR (no need to read /sys/$DEVPATH/dev?): | ||
203 | * ACTION=add | ||
204 | * DEVNAME=bsg/5:0:0:0 | ||
205 | * DEVPATH=/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host5/target5:0:0/5:0:0:0/bsg/5:0:0:0 | ||
206 | * MAJOR=253 | ||
207 | * MINOR=1 | ||
208 | * SUBSYSTEM=bsg | ||
209 | * | ||
210 | * ACTION=add | ||
211 | * DEVPATH=/devices/virtual/bdi/8:16 | ||
212 | * SUBSYSTEM=bdi | ||
213 | * | ||
214 | * ACTION=add | ||
215 | * DEVNAME=sdb | ||
216 | * DEVPATH=/block/sdb | ||
217 | * DEVTYPE=disk | ||
218 | * MAJOR=8 | ||
219 | * MINOR=16 | ||
220 | * SUBSYSTEM=block | ||
221 | * | ||
222 | * Case with ACTION=change: | ||
223 | * ACTION=change | ||
224 | * DEVNAME=sdb | ||
225 | * DEVPATH=/block/sdb | ||
226 | * DEVTYPE=disk | ||
227 | * DISK_MEDIA_CHANGE=1 | ||
228 | * MAJOR=8 | ||
229 | * MINOR=16 | ||
230 | * SUBSYSTEM=block | ||
231 | */ | ||
232 | |||
233 | static const char keywords[] ALIGN1 = "add\0remove\0change\0"; | ||
234 | enum { OP_add, OP_remove }; | ||
235 | |||
142 | struct rule { | 236 | struct rule { |
143 | bool keep_matching; | 237 | bool keep_matching; |
144 | bool regex_compiled; | 238 | bool regex_compiled; |
@@ -154,6 +248,7 @@ struct rule { | |||
154 | 248 | ||
155 | struct globals { | 249 | struct globals { |
156 | int root_major, root_minor; | 250 | int root_major, root_minor; |
251 | smallint verbose; | ||
157 | char *subsystem; | 252 | char *subsystem; |
158 | #if ENABLE_FEATURE_MDEV_CONF | 253 | #if ENABLE_FEATURE_MDEV_CONF |
159 | const char *filename; | 254 | const char *filename; |
@@ -366,13 +461,17 @@ static char *build_alias(char *alias, const char *device_name) | |||
366 | * after NUL, but we promise to not mangle (IOW: to restore if needed) | 461 | * after NUL, but we promise to not mangle (IOW: to restore if needed) |
367 | * path string. | 462 | * path string. |
368 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! | 463 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! |
464 | * | ||
465 | * device_name = $DEVNAME (may be NULL) | ||
466 | * path = /sys/$DEVPATH | ||
369 | */ | 467 | */ |
370 | static void make_device(char *path, int delete) | 468 | static void make_device(char *device_name, char *path, int operation) |
371 | { | 469 | { |
372 | char *device_name, *subsystem_slash_devname; | 470 | char *subsystem_slash_devname; |
373 | int major, minor, type, len; | 471 | int major, minor, type, len; |
374 | 472 | ||
375 | dbg("%s('%s', delete:%d)", __func__, path, delete); | 473 | if (G.verbose) |
474 | bb_error_msg("make_device: %s, %s, op:%d", device_name, path, operation); | ||
376 | 475 | ||
377 | /* Try to read major/minor string. Note that the kernel puts \n after | 476 | /* Try to read major/minor string. Note that the kernel puts \n after |
378 | * the data, so we don't need to worry about null terminating the string | 477 | * the data, so we don't need to worry about null terminating the string |
@@ -380,7 +479,7 @@ static void make_device(char *path, int delete) | |||
380 | * We also depend on path having writeable space after it. | 479 | * We also depend on path having writeable space after it. |
381 | */ | 480 | */ |
382 | major = -1; | 481 | major = -1; |
383 | if (!delete) { | 482 | if (operation != OP_remove) { |
384 | char *dev_maj_min = path + strlen(path); | 483 | char *dev_maj_min = path + strlen(path); |
385 | 484 | ||
386 | strcpy(dev_maj_min, "/dev"); | 485 | strcpy(dev_maj_min, "/dev"); |
@@ -398,7 +497,8 @@ static void make_device(char *path, int delete) | |||
398 | /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ | 497 | /* else: for delete, -1 still deletes the node, but < -1 suppresses that */ |
399 | 498 | ||
400 | /* Determine device name, type, major and minor */ | 499 | /* Determine device name, type, major and minor */ |
401 | device_name = (char*) bb_basename(path); | 500 | if (!device_name) |
501 | device_name = (char*) bb_basename(path); | ||
402 | /* http://kernel.org/doc/pending/hotplug.txt says that only | 502 | /* http://kernel.org/doc/pending/hotplug.txt says that only |
403 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. | 503 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. |
404 | * But since 2.6.25 block devices are also in /sys/class/block. | 504 | * But since 2.6.25 block devices are also in /sys/class/block. |
@@ -434,7 +534,7 @@ static void make_device(char *path, int delete) | |||
434 | char *command; | 534 | char *command; |
435 | char *alias; | 535 | char *alias; |
436 | char aliaslink = aliaslink; /* for compiler */ | 536 | char aliaslink = aliaslink; /* for compiler */ |
437 | const char *node_name; | 537 | char *node_name; |
438 | const struct rule *rule; | 538 | const struct rule *rule; |
439 | 539 | ||
440 | str_to_match = ""; | 540 | str_to_match = ""; |
@@ -456,6 +556,8 @@ static void make_device(char *path, int delete) | |||
456 | if (!str_to_match) | 556 | if (!str_to_match) |
457 | continue; | 557 | continue; |
458 | } else { | 558 | } else { |
559 | //TODO: $DEVNAME can have slashes too, | ||
560 | // we should stop abusing '/' as a special syntax in our regex'es | ||
459 | /* regex to match [subsystem/]device_name */ | 561 | /* regex to match [subsystem/]device_name */ |
460 | str_to_match = (rule->regex_has_slash ? path : device_name); | 562 | str_to_match = (rule->regex_has_slash ? path : device_name); |
461 | } | 563 | } |
@@ -537,7 +639,7 @@ static void make_device(char *path, int delete) | |||
537 | /* Are we running this command now? | 639 | /* Are we running this command now? |
538 | * Run $cmd on delete, @cmd on create, *cmd on both | 640 | * Run $cmd on delete, @cmd on create, *cmd on both |
539 | */ | 641 | */ |
540 | if (s2 - s != delete) { | 642 | if (s2 - s != (operation == OP_remove) || *s2 == '*') { |
541 | /* We are here if: '*', | 643 | /* We are here if: '*', |
542 | * or: '@' and delete = 0, | 644 | * or: '@' and delete = 0, |
543 | * or: '$' and delete = 1 | 645 | * or: '$' and delete = 1 |
@@ -556,8 +658,15 @@ static void make_device(char *path, int delete) | |||
556 | dbg("alias2:'%s'", alias); | 658 | dbg("alias2:'%s'", alias); |
557 | } | 659 | } |
558 | 660 | ||
559 | if (!delete && major >= 0) { | 661 | if (operation == OP_add && major >= 0) { |
560 | dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor); | 662 | char *slash = strrchr(node_name, '/'); |
663 | if (slash) { | ||
664 | *slash = '\0'; | ||
665 | bb_make_directory(node_name, 0755, FILEUTILS_RECUR); | ||
666 | *slash = '/'; | ||
667 | } | ||
668 | if (G.verbose) | ||
669 | bb_error_msg("mknod: %s (%d,%d) %o", node_name, major, minor, rule->mode | type); | ||
561 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) | 670 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) |
562 | bb_perror_msg("can't create '%s'", node_name); | 671 | bb_perror_msg("can't create '%s'", node_name); |
563 | if (major == G.root_major && minor == G.root_minor) | 672 | if (major == G.root_major && minor == G.root_minor) |
@@ -571,6 +680,8 @@ static void make_device(char *path, int delete) | |||
571 | //TODO: on devtmpfs, device_name already exists and symlink() fails. | 680 | //TODO: on devtmpfs, device_name already exists and symlink() fails. |
572 | //End result is that instead of symlink, we have two nodes. | 681 | //End result is that instead of symlink, we have two nodes. |
573 | //What should be done? | 682 | //What should be done? |
683 | if (G.verbose) | ||
684 | bb_error_msg("symlink: %s", device_name); | ||
574 | symlink(node_name, device_name); | 685 | symlink(node_name, device_name); |
575 | } | 686 | } |
576 | } | 687 | } |
@@ -582,17 +693,24 @@ static void make_device(char *path, int delete) | |||
582 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | 693 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); |
583 | putenv(s); | 694 | putenv(s); |
584 | putenv(s1); | 695 | putenv(s1); |
696 | if (G.verbose) | ||
697 | bb_error_msg("running: %s", command); | ||
585 | if (system(command) == -1) | 698 | if (system(command) == -1) |
586 | bb_perror_msg("can't run '%s'", command); | 699 | bb_perror_msg("can't run '%s'", command); |
587 | bb_unsetenv_and_free(s1); | 700 | bb_unsetenv_and_free(s1); |
588 | bb_unsetenv_and_free(s); | 701 | bb_unsetenv_and_free(s); |
589 | } | 702 | } |
590 | 703 | ||
591 | if (delete && major >= -1) { | 704 | if (operation == OP_remove && major >= -1) { |
592 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 705 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
593 | if (aliaslink == '>') | 706 | if (aliaslink == '>') { |
707 | if (G.verbose) | ||
708 | bb_error_msg("unlink: %s", device_name); | ||
594 | unlink(device_name); | 709 | unlink(device_name); |
710 | } | ||
595 | } | 711 | } |
712 | if (G.verbose) | ||
713 | bb_error_msg("unlink: %s", node_name); | ||
596 | unlink(node_name); | 714 | unlink(node_name); |
597 | } | 715 | } |
598 | 716 | ||
@@ -624,7 +742,7 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
624 | 742 | ||
625 | strcpy(scratch, fileName); | 743 | strcpy(scratch, fileName); |
626 | scratch[len] = '\0'; | 744 | scratch[len] = '\0'; |
627 | make_device(scratch, /*delete:*/ 0); | 745 | make_device(/*DEVNAME:*/ NULL, scratch, OP_add); |
628 | 746 | ||
629 | return TRUE; | 747 | return TRUE; |
630 | } | 748 | } |
@@ -762,9 +880,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
762 | char *fw; | 880 | char *fw; |
763 | char *seq; | 881 | char *seq; |
764 | char *action; | 882 | char *action; |
765 | char *env_path; | 883 | char *env_devname; |
766 | static const char keywords[] ALIGN1 = "remove\0add\0"; | 884 | char *env_devpath; |
767 | enum { OP_remove = 0, OP_add }; | ||
768 | smalluint op; | 885 | smalluint op; |
769 | 886 | ||
770 | /* Hotplug: | 887 | /* Hotplug: |
@@ -773,9 +890,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
773 | * DEVPATH is like "/block/sda" or "/class/input/mice" | 890 | * DEVPATH is like "/block/sda" or "/class/input/mice" |
774 | */ | 891 | */ |
775 | action = getenv("ACTION"); | 892 | action = getenv("ACTION"); |
776 | env_path = getenv("DEVPATH"); | 893 | env_devname = getenv("DEVNAME"); /* can be NULL */ |
894 | env_devpath = getenv("DEVPATH"); | ||
777 | G.subsystem = getenv("SUBSYSTEM"); | 895 | G.subsystem = getenv("SUBSYSTEM"); |
778 | if (!action || !env_path /*|| !G.subsystem*/) | 896 | if (!action || !env_devpath /*|| !G.subsystem*/) |
779 | bb_show_usage(); | 897 | bb_show_usage(); |
780 | fw = getenv("FIRMWARE"); | 898 | fw = getenv("FIRMWARE"); |
781 | op = index_in_strings(keywords, action); | 899 | op = index_in_strings(keywords, action); |
@@ -804,16 +922,25 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
804 | } while (--timeout); | 922 | } while (--timeout); |
805 | } | 923 | } |
806 | 924 | ||
807 | snprintf(temp, PATH_MAX, "/sys%s", env_path); | 925 | { |
926 | int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND); | ||
927 | if (logfd >= 0) { | ||
928 | xmove_fd(logfd, STDERR_FILENO); | ||
929 | G.verbose = 1; | ||
930 | bb_error_msg("pid: %u seq: %s action: %s", getpid(), seq, action); | ||
931 | } | ||
932 | } | ||
933 | |||
934 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); | ||
808 | if (op == OP_remove) { | 935 | if (op == OP_remove) { |
809 | /* Ignoring "remove firmware". It was reported | 936 | /* Ignoring "remove firmware". It was reported |
810 | * to happen and to cause erroneous deletion | 937 | * to happen and to cause erroneous deletion |
811 | * of device nodes. */ | 938 | * of device nodes. */ |
812 | if (!fw) | 939 | if (!fw) |
813 | make_device(temp, /*delete:*/ 1); | 940 | make_device(env_devname, temp, op); |
814 | } | 941 | } |
815 | else if (op == OP_add) { | 942 | else if (op == OP_add) { |
816 | make_device(temp, /*delete:*/ 0); | 943 | make_device(env_devname, temp, op); |
817 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { | 944 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { |
818 | if (fw) | 945 | if (fw) |
819 | load_firmware(fw, temp); | 946 | load_firmware(fw, temp); |