diff options
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r-- | util-linux/mdev.c | 249 |
1 files changed, 180 insertions, 69 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 0a34122b4..79871d30e 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -92,7 +92,9 @@ | |||
92 | //usage: "\n" | 92 | //usage: "\n" |
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.\n" |
96 | //usage: "\n" | ||
97 | //usage: "If /dev/mdev.log file exists, debug log will be appended to it." | ||
96 | 98 | ||
97 | #include "libbb.h" | 99 | #include "libbb.h" |
98 | #include "xregex.h" | 100 | #include "xregex.h" |
@@ -139,10 +141,101 @@ | |||
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; |
145 | bool regex_has_slash; | ||
146 | mode_t mode; | 239 | mode_t mode; |
147 | int maj, min0, min1; | 240 | int maj, min0, min1; |
148 | struct bb_uidgid_t ugid; | 241 | struct bb_uidgid_t ugid; |
@@ -154,6 +247,7 @@ struct rule { | |||
154 | 247 | ||
155 | struct globals { | 248 | struct globals { |
156 | int root_major, root_minor; | 249 | int root_major, root_minor; |
250 | smallint verbose; | ||
157 | char *subsystem; | 251 | char *subsystem; |
158 | #if ENABLE_FEATURE_MDEV_CONF | 252 | #if ENABLE_FEATURE_MDEV_CONF |
159 | const char *filename; | 253 | const char *filename; |
@@ -245,7 +339,6 @@ static void parse_next_rule(void) | |||
245 | } | 339 | } |
246 | xregcomp(&G.cur_rule.match, val, REG_EXTENDED); | 340 | xregcomp(&G.cur_rule.match, val, REG_EXTENDED); |
247 | G.cur_rule.regex_compiled = 1; | 341 | G.cur_rule.regex_compiled = 1; |
248 | G.cur_rule.regex_has_slash = (strchr(val, '/') != NULL); | ||
249 | } | 342 | } |
250 | 343 | ||
251 | /* 2nd field: uid:gid - device ownership */ | 344 | /* 2nd field: uid:gid - device ownership */ |
@@ -366,13 +459,16 @@ static char *build_alias(char *alias, const char *device_name) | |||
366 | * after NUL, but we promise to not mangle (IOW: to restore if needed) | 459 | * after NUL, but we promise to not mangle (IOW: to restore if needed) |
367 | * path string. | 460 | * path string. |
368 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! | 461 | * NB2: "mdev -s" may call us many times, do not leak memory/fds! |
462 | * | ||
463 | * device_name = $DEVNAME (may be NULL) | ||
464 | * path = /sys/$DEVPATH | ||
369 | */ | 465 | */ |
370 | static void make_device(char *path, int delete) | 466 | static void make_device(char *device_name, char *path, int operation) |
371 | { | 467 | { |
372 | char *device_name, *subsystem_slash_devname; | ||
373 | int major, minor, type, len; | 468 | int major, minor, type, len; |
374 | 469 | ||
375 | dbg("%s('%s', delete:%d)", __func__, path, delete); | 470 | if (G.verbose) |
471 | bb_error_msg("device: %s, %s", device_name, path); | ||
376 | 472 | ||
377 | /* Try to read major/minor string. Note that the kernel puts \n after | 473 | /* 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 | 474 | * the data, so we don't need to worry about null terminating the string |
@@ -380,7 +476,7 @@ static void make_device(char *path, int delete) | |||
380 | * We also depend on path having writeable space after it. | 476 | * We also depend on path having writeable space after it. |
381 | */ | 477 | */ |
382 | major = -1; | 478 | major = -1; |
383 | if (!delete) { | 479 | if (operation == OP_add) { |
384 | char *dev_maj_min = path + strlen(path); | 480 | char *dev_maj_min = path + strlen(path); |
385 | 481 | ||
386 | strcpy(dev_maj_min, "/dev"); | 482 | strcpy(dev_maj_min, "/dev"); |
@@ -391,40 +487,27 @@ static void make_device(char *path, int delete) | |||
391 | return; | 487 | return; |
392 | /* no "dev" file, but we can still run scripts | 488 | /* no "dev" file, but we can still run scripts |
393 | * based on device name */ | 489 | * based on device name */ |
394 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) { | 490 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) == 2) { |
491 | if (G.verbose) | ||
492 | bb_error_msg("maj,min: %u,%u", major, minor); | ||
493 | } else { | ||
395 | major = -1; | 494 | major = -1; |
396 | } | 495 | } |
397 | } | 496 | } |
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. |
405 | * We use strstr("/block/") to forestall future surprises. */ | 505 | * We use strstr("/block/") to forestall future surprises. |
506 | */ | ||
406 | type = S_IFCHR; | 507 | type = S_IFCHR; |
407 | if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0)) | 508 | if (strstr(path, "/block/") || (G.subsystem && strncmp(G.subsystem, "block", 5) == 0)) |
408 | type = S_IFBLK; | 509 | type = S_IFBLK; |
409 | 510 | ||
410 | /* Make path point to "subsystem/device_name" */ | ||
411 | subsystem_slash_devname = NULL; | ||
412 | /* Check for coldplug invocations first */ | ||
413 | if (strncmp(path, "/sys/block/", 11) == 0) /* legacy case */ | ||
414 | path += sizeof("/sys/") - 1; | ||
415 | else if (strncmp(path, "/sys/class/", 11) == 0) | ||
416 | path += sizeof("/sys/class/") - 1; | ||
417 | else { | ||
418 | /* Example of a hotplug invocation: | ||
419 | * SUBSYSTEM="block" | ||
420 | * DEVPATH="/sys" + "/devices/virtual/mtd/mtd3/mtdblock3" | ||
421 | * ("/sys" is added by mdev_main) | ||
422 | * - path does not contain subsystem | ||
423 | */ | ||
424 | subsystem_slash_devname = concat_path_file(G.subsystem, device_name); | ||
425 | path = subsystem_slash_devname; | ||
426 | } | ||
427 | |||
428 | #if ENABLE_FEATURE_MDEV_CONF | 511 | #if ENABLE_FEATURE_MDEV_CONF |
429 | G.rule_idx = 0; /* restart from the beginning (think mdev -s) */ | 512 | G.rule_idx = 0; /* restart from the beginning (think mdev -s) */ |
430 | #endif | 513 | #endif |
@@ -434,10 +517,10 @@ static void make_device(char *path, int delete) | |||
434 | char *command; | 517 | char *command; |
435 | char *alias; | 518 | char *alias; |
436 | char aliaslink = aliaslink; /* for compiler */ | 519 | char aliaslink = aliaslink; /* for compiler */ |
437 | const char *node_name; | 520 | char *node_name; |
438 | const struct rule *rule; | 521 | const struct rule *rule; |
439 | 522 | ||
440 | str_to_match = ""; | 523 | str_to_match = device_name; |
441 | 524 | ||
442 | rule = next_rule(); | 525 | rule = next_rule(); |
443 | 526 | ||
@@ -455,10 +538,8 @@ static void make_device(char *path, int delete) | |||
455 | dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); | 538 | dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); |
456 | if (!str_to_match) | 539 | if (!str_to_match) |
457 | continue; | 540 | continue; |
458 | } else { | ||
459 | /* regex to match [subsystem/]device_name */ | ||
460 | str_to_match = (rule->regex_has_slash ? path : device_name); | ||
461 | } | 541 | } |
542 | /* else: str_to_match = device_name */ | ||
462 | 543 | ||
463 | if (rule->regex_compiled) { | 544 | if (rule->regex_compiled) { |
464 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); | 545 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); |
@@ -537,7 +618,7 @@ static void make_device(char *path, int delete) | |||
537 | /* Are we running this command now? | 618 | /* Are we running this command now? |
538 | * Run $cmd on delete, @cmd on create, *cmd on both | 619 | * Run $cmd on delete, @cmd on create, *cmd on both |
539 | */ | 620 | */ |
540 | if (s2 - s != delete) { | 621 | if (s2 - s != (operation == OP_remove) || *s2 == '*') { |
541 | /* We are here if: '*', | 622 | /* We are here if: '*', |
542 | * or: '@' and delete = 0, | 623 | * or: '@' and delete = 0, |
543 | * or: '$' and delete = 1 | 624 | * or: '$' and delete = 1 |
@@ -556,21 +637,30 @@ static void make_device(char *path, int delete) | |||
556 | dbg("alias2:'%s'", alias); | 637 | dbg("alias2:'%s'", alias); |
557 | } | 638 | } |
558 | 639 | ||
559 | if (!delete && major >= 0) { | 640 | if (operation == OP_add && major >= 0) { |
560 | dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor); | 641 | char *slash = strrchr(node_name, '/'); |
642 | if (slash) { | ||
643 | *slash = '\0'; | ||
644 | bb_make_directory(node_name, 0755, FILEUTILS_RECUR); | ||
645 | *slash = '/'; | ||
646 | } | ||
647 | if (G.verbose) | ||
648 | 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) | 649 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) |
562 | bb_perror_msg("can't create '%s'", node_name); | 650 | bb_perror_msg("can't create '%s'", node_name); |
563 | if (major == G.root_major && minor == G.root_minor) | ||
564 | symlink(node_name, "root"); | ||
565 | if (ENABLE_FEATURE_MDEV_CONF) { | 651 | if (ENABLE_FEATURE_MDEV_CONF) { |
566 | chmod(node_name, rule->mode); | 652 | chmod(node_name, rule->mode); |
567 | chown(node_name, rule->ugid.uid, rule->ugid.gid); | 653 | chown(node_name, rule->ugid.uid, rule->ugid.gid); |
568 | } | 654 | } |
655 | if (major == G.root_major && minor == G.root_minor) | ||
656 | symlink(node_name, "root"); | ||
569 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 657 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
570 | if (aliaslink == '>') { | 658 | if (aliaslink == '>') { |
571 | //TODO: on devtmpfs, device_name already exists and symlink() fails. | 659 | //TODO: on devtmpfs, device_name already exists and symlink() fails. |
572 | //End result is that instead of symlink, we have two nodes. | 660 | //End result is that instead of symlink, we have two nodes. |
573 | //What should be done? | 661 | //What should be done? |
662 | if (G.verbose) | ||
663 | bb_error_msg("symlink: %s", device_name); | ||
574 | symlink(node_name, device_name); | 664 | symlink(node_name, device_name); |
575 | } | 665 | } |
576 | } | 666 | } |
@@ -582,17 +672,24 @@ static void make_device(char *path, int delete) | |||
582 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | 672 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); |
583 | putenv(s); | 673 | putenv(s); |
584 | putenv(s1); | 674 | putenv(s1); |
675 | if (G.verbose) | ||
676 | bb_error_msg("running: %s", command); | ||
585 | if (system(command) == -1) | 677 | if (system(command) == -1) |
586 | bb_perror_msg("can't run '%s'", command); | 678 | bb_perror_msg("can't run '%s'", command); |
587 | bb_unsetenv_and_free(s1); | 679 | bb_unsetenv_and_free(s1); |
588 | bb_unsetenv_and_free(s); | 680 | bb_unsetenv_and_free(s); |
589 | } | 681 | } |
590 | 682 | ||
591 | if (delete && major >= -1) { | 683 | if (operation == OP_remove && major >= -1) { |
592 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 684 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
593 | if (aliaslink == '>') | 685 | if (aliaslink == '>') { |
686 | if (G.verbose) | ||
687 | bb_error_msg("unlink: %s", device_name); | ||
594 | unlink(device_name); | 688 | unlink(device_name); |
689 | } | ||
595 | } | 690 | } |
691 | if (G.verbose) | ||
692 | bb_error_msg("unlink: %s", node_name); | ||
596 | unlink(node_name); | 693 | unlink(node_name); |
597 | } | 694 | } |
598 | 695 | ||
@@ -605,8 +702,6 @@ static void make_device(char *path, int delete) | |||
605 | if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching) | 702 | if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching) |
606 | break; | 703 | break; |
607 | } /* for (;;) */ | 704 | } /* for (;;) */ |
608 | |||
609 | free(subsystem_slash_devname); | ||
610 | } | 705 | } |
611 | 706 | ||
612 | /* File callback for /sys/ traversal */ | 707 | /* File callback for /sys/ traversal */ |
@@ -624,7 +719,7 @@ static int FAST_FUNC fileAction(const char *fileName, | |||
624 | 719 | ||
625 | strcpy(scratch, fileName); | 720 | strcpy(scratch, fileName); |
626 | scratch[len] = '\0'; | 721 | scratch[len] = '\0'; |
627 | make_device(scratch, /*delete:*/ 0); | 722 | make_device(/*DEVNAME:*/ NULL, scratch, OP_add); |
628 | 723 | ||
629 | return TRUE; | 724 | return TRUE; |
630 | } | 725 | } |
@@ -661,37 +756,45 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | |||
661 | static void load_firmware(const char *firmware, const char *sysfs_path) | 756 | static void load_firmware(const char *firmware, const char *sysfs_path) |
662 | { | 757 | { |
663 | int cnt; | 758 | int cnt; |
664 | int firmware_fd, loading_fd, data_fd; | 759 | int firmware_fd, loading_fd; |
665 | 760 | ||
666 | /* check for /lib/firmware/$FIRMWARE */ | 761 | /* check for /lib/firmware/$FIRMWARE */ |
667 | xchdir("/lib/firmware"); | 762 | xchdir("/lib/firmware"); |
668 | firmware_fd = xopen(firmware, O_RDONLY); | 763 | firmware_fd = open(firmware, O_RDONLY); /* can fail */ |
669 | |||
670 | /* in case we goto out ... */ | ||
671 | data_fd = -1; | ||
672 | 764 | ||
673 | /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ | 765 | /* check for /sys/$DEVPATH/loading ... give 30 seconds to appear */ |
674 | xchdir(sysfs_path); | 766 | xchdir(sysfs_path); |
675 | for (cnt = 0; cnt < 30; ++cnt) { | 767 | for (cnt = 0; cnt < 30; ++cnt) { |
676 | loading_fd = open("loading", O_WRONLY); | 768 | loading_fd = open("loading", O_WRONLY); |
677 | if (loading_fd != -1) | 769 | if (loading_fd >= 0) |
678 | goto loading; | 770 | goto loading; |
679 | sleep(1); | 771 | sleep(1); |
680 | } | 772 | } |
681 | goto out; | 773 | goto out; |
682 | 774 | ||
683 | loading: | 775 | loading: |
684 | /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */ | 776 | cnt = 0; |
685 | if (full_write(loading_fd, "1", 1) != 1) | 777 | if (firmware_fd >= 0) { |
686 | goto out; | 778 | int data_fd; |
687 | 779 | ||
688 | /* load firmware into /sys/$DEVPATH/data */ | 780 | /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */ |
689 | data_fd = open("data", O_WRONLY); | 781 | if (full_write(loading_fd, "1", 1) != 1) |
690 | if (data_fd == -1) | 782 | goto out; |
691 | goto out; | 783 | |
692 | cnt = bb_copyfd_eof(firmware_fd, data_fd); | 784 | /* load firmware into /sys/$DEVPATH/data */ |
785 | data_fd = open("data", O_WRONLY); | ||
786 | if (data_fd < 0) | ||
787 | goto out; | ||
788 | cnt = bb_copyfd_eof(firmware_fd, data_fd); | ||
789 | if (ENABLE_FEATURE_CLEAN_UP) | ||
790 | close(data_fd); | ||
791 | } | ||
693 | 792 | ||
694 | /* tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" */ | 793 | /* Tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" |
794 | * Note: we emit -1 also if firmware file wasn't found. | ||
795 | * There are cases when otherwise kernel would wait for minutes | ||
796 | * before timing out. | ||
797 | */ | ||
695 | if (cnt > 0) | 798 | if (cnt > 0) |
696 | full_write(loading_fd, "0", 1); | 799 | full_write(loading_fd, "0", 1); |
697 | else | 800 | else |
@@ -701,7 +804,6 @@ static void load_firmware(const char *firmware, const char *sysfs_path) | |||
701 | if (ENABLE_FEATURE_CLEAN_UP) { | 804 | if (ENABLE_FEATURE_CLEAN_UP) { |
702 | close(firmware_fd); | 805 | close(firmware_fd); |
703 | close(loading_fd); | 806 | close(loading_fd); |
704 | close(data_fd); | ||
705 | } | 807 | } |
706 | } | 808 | } |
707 | 809 | ||
@@ -762,9 +864,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
762 | char *fw; | 864 | char *fw; |
763 | char *seq; | 865 | char *seq; |
764 | char *action; | 866 | char *action; |
765 | char *env_path; | 867 | char *env_devname; |
766 | static const char keywords[] ALIGN1 = "remove\0add\0"; | 868 | char *env_devpath; |
767 | enum { OP_remove = 0, OP_add }; | ||
768 | smalluint op; | 869 | smalluint op; |
769 | 870 | ||
770 | /* Hotplug: | 871 | /* Hotplug: |
@@ -773,12 +874,13 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
773 | * DEVPATH is like "/block/sda" or "/class/input/mice" | 874 | * DEVPATH is like "/block/sda" or "/class/input/mice" |
774 | */ | 875 | */ |
775 | action = getenv("ACTION"); | 876 | action = getenv("ACTION"); |
776 | env_path = getenv("DEVPATH"); | 877 | op = index_in_strings(keywords, action); |
878 | env_devname = getenv("DEVNAME"); /* can be NULL */ | ||
879 | env_devpath = getenv("DEVPATH"); | ||
777 | G.subsystem = getenv("SUBSYSTEM"); | 880 | G.subsystem = getenv("SUBSYSTEM"); |
778 | if (!action || !env_path /*|| !G.subsystem*/) | 881 | if (!action || !env_devpath /*|| !G.subsystem*/) |
779 | bb_show_usage(); | 882 | bb_show_usage(); |
780 | fw = getenv("FIRMWARE"); | 883 | fw = getenv("FIRMWARE"); |
781 | op = index_in_strings(keywords, action); | ||
782 | /* If it exists, does /dev/mdev.seq match $SEQNUM? | 884 | /* If it exists, does /dev/mdev.seq match $SEQNUM? |
783 | * If it does not match, earlier mdev is running | 885 | * If it does not match, earlier mdev is running |
784 | * in parallel, and we need to wait */ | 886 | * in parallel, and we need to wait */ |
@@ -804,16 +906,25 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
804 | } while (--timeout); | 906 | } while (--timeout); |
805 | } | 907 | } |
806 | 908 | ||
807 | snprintf(temp, PATH_MAX, "/sys%s", env_path); | 909 | { |
910 | int logfd = open("/dev/mdev.log", O_WRONLY | O_APPEND); | ||
911 | if (logfd >= 0) { | ||
912 | xmove_fd(logfd, STDERR_FILENO); | ||
913 | G.verbose = 1; | ||
914 | bb_error_msg("seq: %s action: %s", seq, action); | ||
915 | } | ||
916 | } | ||
917 | |||
918 | snprintf(temp, PATH_MAX, "/sys%s", env_devpath); | ||
808 | if (op == OP_remove) { | 919 | if (op == OP_remove) { |
809 | /* Ignoring "remove firmware". It was reported | 920 | /* Ignoring "remove firmware". It was reported |
810 | * to happen and to cause erroneous deletion | 921 | * to happen and to cause erroneous deletion |
811 | * of device nodes. */ | 922 | * of device nodes. */ |
812 | if (!fw) | 923 | if (!fw) |
813 | make_device(temp, /*delete:*/ 1); | 924 | make_device(env_devname, temp, op); |
814 | } | 925 | } |
815 | else if (op == OP_add) { | 926 | else if (op == OP_add) { |
816 | make_device(temp, /*delete:*/ 0); | 927 | make_device(env_devname, temp, op); |
817 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { | 928 | if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { |
818 | if (fw) | 929 | if (fw) |
819 | load_firmware(fw, temp); | 930 | load_firmware(fw, temp); |