Upgrade mdev to allow commands to be run on create/delete.
This commit was genuinely broken at the time (not related to our build system): scripts/config/mkconfigs.c (2005-08-01 - 2006-10-05 arasi) uretilen bbconfigopts.h icine .config satirlarini kacissiz, ham newline'larla gömüyordu - gecerli C degildi, busybox'un kendi bb_mkdep araci bile parse edemiyordu (7d219aab7 ile duzeltildi, mkconfigs shell scripte cevrildi)
No binary (build failed)
—
(log yok)
| @@ -1799,19 +1799,25 @@ USE_FEATURE_DATE_ISOFMT( \ | |
| "\t-s\tScan /sys and populate /dev during system boot\n\n" \ | |
| "Called with no options (via hotplug) it uses environment variables\n" \ | |
| "to determine which device to add/remove." | |
| - | #ifdef CONFIG_FEATURE_MDEV_CONFIG |
| - | #define mdev_notes_usage \ |
| + | #define mdev_notes_usage "" \ |
| + | USE_FEATURE_MDEV_CONFIG( \ |
| "The mdev config file contains lines that look like:\n" \ | |
| " hd[a-z][0-9]* 0:3 660\n\n" \ | |
| "That's device name (with regex match), uid:gid, and permissions.\n\n" \ | |
| - | "Optionally, that can be followed (on the same line) by an asterisk\n" \ |
| - | "and a command line to run after creating the corresponding device(s),\n"\ |
| - | "ala:\n\n" \ |
| - | " hdc root:cdrom 660 *ln -s hdc cdrom\n\n" \ |
| + | USE_FEATURE_MDEV_EXEC( \ |
| + | "Optionally, that can be followed (on the same line) by a special character\n" \ |
| + | "and a command line to run after creating/before deleting the corresponding\n" \ |
| + | "device(s). The environment variable $MDEV indicates the active device node\n" \ |
| + | "(which is useful if it's a regex match). For example:\n\n" \ |
| + | " hdc root:cdrom 660 *ln -s $MDEV cdrom\n\n" \ |
| + | "The special characters are @ (run after creating), $ (run before deleting),\n" \ |
| + | "and * (run both after creating and before deleting). The commands run in\n" \ |
| + | "the /dev directory, and use system() which calls /bin/sh.\n\n" \ |
| + | ) \ |
| "Config file parsing stops on the first matching line. If no config\n"\ | |
| "entry is matched, devices are created with default 0:0 660. (Make\n"\ | |
| - | "the last line match .* to override this.)\n\n" |
| - | #endif |
| + | "the last line match .* to override this.)\n\n" \ |
| + | ) |
| #define mesg_trivial_usage \ | |
| "[y|n]" | |
| @@ -265,16 +265,31 @@ config CONFIG_FEATURE_MDEV_CONF | |
| That's device name (with regex match), uid:gid, and permissions. | |
| - | Optionally, that can be followed (on the same line) by an asterisk |
| - | and a command line to run after creating the corresponding device(s), |
| - | ala: |
| - | |
| - | hdc root:cdrom 660 *ln -s hdc cdrom |
| - | |
| Config file parsing stops on the first matching line. If no config | |
| entry is matched, devices are created with default 0:0 660. (Make | |
| the last line match .* to override this.) | |
| + | config CONFIG_FEATURE_MDEV_EXEC |
| + | bool "Support command execution at device addition/removal" |
| + | default n |
| + | depends on CONFIG_FEATURE_MDEV_CONF |
| + | help |
| + | This adds support for an optional field to /etc/mdev.conf, consisting |
| + | of a special character and a command line to run after creating the |
| + | corresponding device(s) and before removing, ala: |
| + | |
| + | hdc root:cdrom 660 *ln -s $MDEV cdrom |
| + | |
| + | The $MDEV environment variable is set to the name of the device. |
| + | |
| + | The special characters and their meanings are: |
| + | @ Run after creating the device. |
| + | $ Run before removing the device. |
| + | * Run both after creating and before removing the device. |
| + | |
| + | Commands are executed via system() so you need /bin/sh, meaning you |
| + | probably want to select a default shell in the Shells menu. |
| + | |
| config CONFIG_MKSWAP | |
| bool "mkswap" | |
| default n | |
| @@ -8,25 +8,14 @@ | |
| * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | |
| */ | |
| + | #include "busybox.h" |
| #include <ctype.h> | |
| - | #include <dirent.h> |
| #include <errno.h> | |
| - | #include <fcntl.h> |
| - | #include <stdio.h> |
| - | #include <string.h> |
| #include <sys/mman.h> | |
| - | #include <sys/stat.h> |
| #include <sys/sysmacros.h> | |
| - | #include <sys/types.h> |
| - | #include <unistd.h> |
| - | #include <stdlib.h> |
| - | #include "busybox.h" |
| #include "xregex.h" | |
| #define DEV_PATH "/dev" | |
| - | #define MDEV_CONF "/etc/mdev.conf" |
| - | |
| - | #include <busybox.h> |
| struct mdev_globals | |
| { | |
| @@ -36,14 +25,15 @@ struct mdev_globals | |
| #define bbg mdev_globals | |
| /* mknod in /dev based on a path like "/sys/block/hda/hda1" */ | |
| - | static void make_device(char *path) |
| + | static void make_device(char *path, int delete) |
| { | |
| - | char *device_name, *s; |
| + | char *device_name; |
| int major, minor, type, len, fd; | |
| int mode = 0660; | |
| uid_t uid = 0; | |
| gid_t gid = 0; | |
| char *temp = path + strlen(path); | |
| + | char *command = NULL; |
| /* Try to read major/minor string. Note that the kernel puts \n after | |
| * the data, so we don't need to worry about null terminating the string | |
| @@ -69,7 +59,7 @@ static void make_device(char *path) | |
| char *conf, *pos, *end; | |
| /* mmap the config file */ | |
| - | if (-1 != (fd=open(MDEV_CONF,O_RDONLY))) { |
| + | if (-1 != (fd=open("/etc/mdev.conf",O_RDONLY))) { |
| len = lseek(fd, 0, SEEK_END); | |
| conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0); | |
| if (conf) { | |
| @@ -86,88 +76,89 @@ static void make_device(char *path) | |
| ; | |
| /* Three fields: regex, uid:gid, mode */ | |
| - | for (field=3; field; field--) { |
| + | for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC); |
| + | field++) |
| + | { |
| /* Skip whitespace */ | |
| - | while (pos<end && isspace(*pos)) |
| - | pos++; |
| - | if (pos==end || *pos=='#') |
| - | break; |
| - | for (end2=pos; end2<end && !isspace(*end2) && *end2!='#'; end2++) |
| + | while (pos<end && isspace(*pos)) pos++; |
| + | if (pos==end || *pos=='#') break; |
| + | for (end2=pos; |
| + | end2<end && !isspace(*end2) && *end2!='#'; end2++) |
| ; | |
| - | switch (field) { |
| + | if (!field) { |
| /* Regex to match this device */ | |
| - | case 3: |
| - | { |
| - | char *regex = strndupa(pos,end2-pos); |
| - | regex_t match; |
| - | regmatch_t off; |
| - | int result; |
| - | |
| - | /* Is this it? */ |
| - | xregcomp(&match,regex,REG_EXTENDED); |
| - | result = regexec(&match,device_name,1,&off,0); |
| - | regfree(&match); |
| - | |
| - | /* If not this device, skip rest of line */ |
| - | if (result || off.rm_so || off.rm_eo!=strlen(device_name)) |
| - | goto end_line; |
| + | char *regex = strndupa(pos, end2-pos); |
| + | regex_t match; |
| + | regmatch_t off; |
| + | int result; |
| + | |
| + | /* Is this it? */ |
| + | xregcomp(&match,regex, REG_EXTENDED); |
| + | result = regexec(&match, device_name, 1, &off, 0); |
| + | regfree(&match); |
| + | |
| + | /* If not this device, skip rest of line */ |
| + | if (result || off.rm_so |
| + | || off.rm_eo != strlen(device_name)) |
| break; | |
| - | } |
| + | |
| + | } else if (field == 1) { |
| /* uid:gid */ | |
| - | case 2: |
| - | { |
| - | char *s2; |
| - | |
| - | /* Find : */ |
| - | for(s=pos; s<end2 && *s!=':'; s++) |
| - | ; |
| - | if (s == end2) |
| - | goto end_line; |
| - | |
| - | /* Parse UID */ |
| - | uid = strtoul(pos,&s2,10); |
| - | if (s != s2) { |
| - | struct passwd *pass; |
| - | pass = getpwnam(strndupa(pos,s-pos)); |
| - | if (!pass) |
| - | goto end_line; |
| - | uid = pass->pw_uid; |
| - | } |
| - | s++; |
| - | /* parse GID */ |
| - | gid = strtoul(s,&s2,10); |
| - | if (end2 != s2) { |
| - | struct group *grp; |
| - | grp = getgrnam(strndupa(s,end2-s)); |
| - | if (!grp) |
| - | goto end_line; |
| - | gid = grp->gr_gid; |
| - | } |
| - | break; |
| + | |
| + | char *s, *s2; |
| + | |
| + | /* Find : */ |
| + | for(s=pos; s<end2 && *s!=':'; s++) |
| + | ; |
| + | if (s == end2) break; |
| + | |
| + | /* Parse UID */ |
| + | uid = strtoul(pos,&s2,10); |
| + | if (s != s2) { |
| + | struct passwd *pass; |
| + | pass = getpwnam(strndupa(pos, s-pos)); |
| + | if (!pass) break; |
| + | uid = pass->pw_uid; |
| + | } |
| + | s++; |
| + | /* parse GID */ |
| + | gid = strtoul(s, &s2, 10); |
| + | if (end2 != s2) { |
| + | struct group *grp; |
| + | grp = getgrnam(strndupa(s, end2-s)); |
| + | if (!grp) break; |
| + | gid = grp->gr_gid; |
| } | |
| + | } else if (field == 2) { |
| /* mode */ | |
| - | case 1: |
| - | { |
| - | mode = strtoul(pos,&pos,8); |
| - | if (pos != end2) |
| - | goto end_line; |
| - | else |
| - | goto found_device; |
| + | |
| + | mode = strtoul(pos, &pos, 8); |
| + | if (pos != end2) break; |
| + | } else if (ENABLE_FEATURE_MDEV_EXEC && field == 3) { |
| + | // Command to run |
| + | char *s = "@$*", *s2; |
| + | if (!(s2 = strchr(s, *pos++))) { |
| + | // Force error |
| + | field = 1; |
| + | break; |
| } | |
| + | if ((s2-s+1) & (1<<delete)) |
| + | command = bb_xstrndup(pos, end-pos); |
| } | |
| + | |
| pos = end2; | |
| } | |
| - | end_line: |
| + | |
| /* Did everything parse happily? */ | |
| - | if (field && field!=3) |
| - | bb_error_msg_and_die("Bad line %d",line); |
| + | |
| + | if (field > 2) break; |
| + | if (field) bb_error_msg_and_die("Bad line %d",line); |
| /* Next line */ | |
| pos = ++end; | |
| } | |
| - | found_device: |
| munmap(conf, len); | |
| } | |
| close(fd); | |
| @@ -175,13 +166,29 @@ found_device: | |
| } | |
| umask(0); | |
| - | if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) |
| - | bb_perror_msg_and_die("mknod %s failed", device_name); |
| + | if (!delete) { |
| + | if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) |
| + | bb_perror_msg_and_die("mknod %s failed", device_name); |
| - | if (major==bbg.root_major && minor==bbg.root_minor) |
| - | symlink(device_name, "root"); |
| + | if (major == bbg.root_major && minor == bbg.root_minor) |
| + | symlink(device_name, "root"); |
| - | if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); |
| + | if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid); |
| + | } |
| + | if (command) { |
| + | int rc; |
| + | char *s; |
| + | |
| + | s=bb_xasprintf("MDEV=%s",device_name); |
| + | putenv(s); |
| + | rc = system(command); |
| + | s[4]=0; |
| + | putenv(s); |
| + | free(s); |
| + | free(command); |
| + | if (rc == -1) bb_perror_msg_and_die("Couldn't run %s", command); |
| + | } |
| + | if (delete) unlink(device_name); |
| } | |
| /* Recursive search of /sys/block or /sys/class. path must be a writeable | |
| @@ -212,7 +219,7 @@ static void find_dev(char *path) | |
| /* If there's a dev entry, mknod it */ | |
| - | if (!strcmp(entry->d_name, "dev")) make_device(path); |
| + | if (!strcmp(entry->d_name, "dev")) make_device(path, 0); |
| } | |
| closedir(dir); | |
| @@ -247,12 +254,9 @@ int mdev_main(int argc, char *argv[]) | |
| if (!action || !env_path) | |
| bb_show_usage(); | |
| - | if (!strcmp(action, "add")) { |
| - | sprintf(temp, "/sys%s", env_path); |
| - | make_device(temp); |
| - | } else if (!strcmp(action, "remove")) { |
| - | unlink(strrchr(env_path, '/') + 1); |
| - | } |
| + | sprintf(temp, "/sys%s", env_path); |
| + | if (!strcmp(action, "add")) make_device(temp,0); |
| + | else if (!strcmp(action, "remove")) make_device(temp,1); |
| } | |
| if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp); | |