aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2012-05-18 04:45:35 +0200
committerDenys Vlasenko <vda.linux@googlemail.com>2012-05-18 04:45:35 +0200
commit516530c932bd17d87c9eb4347a490be051e495f4 (patch)
tree28c18a2785280ff61f819174c5a72d4348298f9e
parent7c8aa2b47cf76f710959a1f4a914010aca425016 (diff)
downloadbusybox-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.conf3
-rw-r--r--util-linux/mdev.c167
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
109zap(.*) root:dialout 660 =zap/%1 109zap(.*) root:dialout 660 =zap/%1
110dahdi!(.*) root:dialout 660 =dahdi/%1 110dahdi!(.*) 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
233static const char keywords[] ALIGN1 = "add\0remove\0change\0";
234enum { OP_add, OP_remove };
235
142struct rule { 236struct 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
155struct globals { 249struct 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 */
370static void make_device(char *path, int delete) 468static 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);