diff options
| author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 21:37:07 +0000 |
|---|---|---|
| committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 21:37:07 +0000 |
| commit | 3798db58cfa0e939d0fc1822c9864355c1422cd0 (patch) | |
| tree | 99f44bad59ccf82f4c1defa3bd81f09078eea8a0 /util-linux/mdev.c | |
| parent | f66fe9af89e3d0f8a92894c59b6808f9202c0e86 (diff) | |
| download | busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.tar.gz busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.tar.bz2 busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.zip | |
mdev: support $ENVVAR=regex
Diffstat (limited to 'util-linux/mdev.c')
| -rw-r--r-- | util-linux/mdev.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index a3275f881..ea1edcc40 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
| @@ -89,15 +89,11 @@ static char *build_alias(char *alias, const char *device_name) | |||
| 89 | /* NB: "mdev -s" may call us many times, do not leak memory/fds! */ | 89 | /* NB: "mdev -s" may call us many times, do not leak memory/fds! */ |
| 90 | static void make_device(char *path, int delete) | 90 | static void make_device(char *path, int delete) |
| 91 | { | 91 | { |
| 92 | const char *device_name; | 92 | char *device_name; |
| 93 | int major, minor, type, len; | 93 | int major, minor, type, len; |
| 94 | int mode; | 94 | int mode; |
| 95 | char *dev_maj_min = path + strlen(path); | ||
| 96 | parser_t *parser; | 95 | parser_t *parser; |
| 97 | 96 | ||
| 98 | /* Force the configuration file settings exactly. */ | ||
| 99 | umask(0); | ||
| 100 | |||
| 101 | /* Try to read major/minor string. Note that the kernel puts \n after | 97 | /* Try to read major/minor string. Note that the kernel puts \n after |
| 102 | * the data, so we don't need to worry about null terminating the string | 98 | * the data, so we don't need to worry about null terminating the string |
| 103 | * because sscanf() will stop at the first nondigit, which \n is. | 99 | * because sscanf() will stop at the first nondigit, which \n is. |
| @@ -105,21 +101,23 @@ static void make_device(char *path, int delete) | |||
| 105 | */ | 101 | */ |
| 106 | major = -1; | 102 | major = -1; |
| 107 | if (!delete) { | 103 | if (!delete) { |
| 104 | char *dev_maj_min = path + strlen(path); | ||
| 105 | |||
| 108 | strcpy(dev_maj_min, "/dev"); | 106 | strcpy(dev_maj_min, "/dev"); |
| 109 | len = open_read_close(path, dev_maj_min + 1, 64); | 107 | len = open_read_close(path, dev_maj_min + 1, 64); |
| 110 | *dev_maj_min++ = '\0'; | 108 | *dev_maj_min = '\0'; |
| 111 | if (len < 1) { | 109 | if (len < 1) { |
| 112 | if (!ENABLE_FEATURE_MDEV_EXEC) | 110 | if (!ENABLE_FEATURE_MDEV_EXEC) |
| 113 | return; | 111 | return; |
| 114 | /* no "dev" file, so just try to run script */ | 112 | /* no "dev" file, but we can still run scripts |
| 115 | *dev_maj_min = '\0'; | 113 | * based on device name */ |
| 116 | } else if (sscanf(dev_maj_min, "%u:%u", &major, &minor) != 2) { | 114 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) { |
| 117 | major = -1; | 115 | major = -1; |
| 118 | } | 116 | } |
| 119 | } | 117 | } |
| 120 | 118 | ||
| 121 | /* Determine device name, type, major and minor */ | 119 | /* Determine device name, type, major and minor */ |
| 122 | device_name = bb_basename(path); | 120 | device_name = (char*) bb_basename(path); |
| 123 | /* http://kernel.org/doc/pending/hotplug.txt says that only | 121 | /* http://kernel.org/doc/pending/hotplug.txt says that only |
| 124 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. | 122 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. |
| 125 | * But since 2.6.25 block devices are also in /sys/class/block, | 123 | * But since 2.6.25 block devices are also in /sys/class/block, |
| @@ -139,9 +137,7 @@ static void make_device(char *path, int delete) | |||
| 139 | parser = config_open2("/etc/mdev.conf", fopen_for_read); | 137 | parser = config_open2("/etc/mdev.conf", fopen_for_read); |
| 140 | 138 | ||
| 141 | do { | 139 | do { |
| 142 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; | ||
| 143 | int keep_matching; | 140 | int keep_matching; |
| 144 | char *val, *name; | ||
| 145 | struct bb_uidgid_t ugid; | 141 | struct bb_uidgid_t ugid; |
| 146 | char *tokens[4]; | 142 | char *tokens[4]; |
| 147 | char *command = NULL; | 143 | char *command = NULL; |
| @@ -156,19 +152,22 @@ static void make_device(char *path, int delete) | |||
| 156 | if (ENABLE_FEATURE_MDEV_CONF | 152 | if (ENABLE_FEATURE_MDEV_CONF |
| 157 | && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) | 153 | && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) |
| 158 | ) { | 154 | ) { |
| 155 | char *val; | ||
| 156 | char *str_to_match; | ||
| 157 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; | ||
| 158 | |||
| 159 | val = tokens[0]; | 159 | val = tokens[0]; |
| 160 | keep_matching = ('-' == val[0]); | 160 | keep_matching = ('-' == val[0]); |
| 161 | val += keep_matching; /* swallow leading dash */ | 161 | val += keep_matching; /* swallow leading dash */ |
| 162 | 162 | ||
| 163 | /* Match against either "subsystem/device_name" | 163 | /* Match against either "subsystem/device_name" |
| 164 | * or "device_name" alone */ | 164 | * or "device_name" alone */ |
| 165 | name = strchr(val, '/') ? path : (char *) device_name; | 165 | str_to_match = strchr(val, '/') ? path : device_name; |
| 166 | 166 | ||
| 167 | /* Fields: regex uid:gid mode [alias] [cmd] */ | 167 | /* Fields: regex uid:gid mode [alias] [cmd] */ |
| 168 | 168 | ||
| 169 | /* 1st field: @<numeric maj,min>... */ | ||
| 170 | if (val[0] == '@') { | 169 | if (val[0] == '@') { |
| 171 | /* @major,minor[-last] */ | 170 | /* @major,minor[-minor2] */ |
| 172 | /* (useful when name is ambiguous: | 171 | /* (useful when name is ambiguous: |
| 173 | * "/sys/class/usb/lp0" and | 172 | * "/sys/class/usb/lp0" and |
| 174 | * "/sys/class/printer/lp0") */ | 173 | * "/sys/class/printer/lp0") */ |
| @@ -182,15 +181,29 @@ static void make_device(char *path, int delete) | |||
| 182 | ) { | 181 | ) { |
| 183 | continue; /* this line doesn't match */ | 182 | continue; /* this line doesn't match */ |
| 184 | } | 183 | } |
| 185 | } else { /* ... or regex to match device name */ | 184 | goto line_matches; |
| 185 | } | ||
| 186 | if (val[0] == '$') { | ||
| 187 | /* regex to match an environment variable */ | ||
| 188 | char *eq = strchr(++val, '='); | ||
| 189 | if (!eq) | ||
| 190 | continue; | ||
| 191 | *eq = '\0'; | ||
| 192 | str_to_match = getenv(val); | ||
| 193 | if (!str_to_match) | ||
| 194 | continue; | ||
| 195 | str_to_match -= strlen(val) + 1; | ||
| 196 | *eq = '='; | ||
| 197 | } | ||
| 198 | /* else: regex to match [subsystem/]device_name */ | ||
| 199 | |||
| 200 | { | ||
| 186 | regex_t match; | 201 | regex_t match; |
| 187 | int result; | 202 | int result; |
| 188 | 203 | ||
| 189 | /* Is this it? */ | ||
| 190 | xregcomp(&match, val, REG_EXTENDED); | 204 | xregcomp(&match, val, REG_EXTENDED); |
| 191 | result = regexec(&match, name, ARRAY_SIZE(off), off, 0); | 205 | result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0); |
| 192 | regfree(&match); | 206 | regfree(&match); |
| 193 | |||
| 194 | //bb_error_msg("matches:"); | 207 | //bb_error_msg("matches:"); |
| 195 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { | 208 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { |
| 196 | // if (off[i].rm_so < 0) continue; | 209 | // if (off[i].rm_so < 0) continue; |
| @@ -199,17 +212,17 @@ static void make_device(char *path, int delete) | |||
| 199 | // device_name + off[i].rm_so); | 212 | // device_name + off[i].rm_so); |
| 200 | //} | 213 | //} |
| 201 | 214 | ||
| 202 | /* If not this device, skip rest of line */ | 215 | /* If no match, skip rest of line */ |
| 203 | /* (regexec returns whole pattern as "range" 0) */ | 216 | /* (regexec returns whole pattern as "range" 0) */ |
| 204 | if (result || off[0].rm_so | 217 | if (result || off[0].rm_so |
| 205 | || ((int)off[0].rm_eo != (int)strlen(name)) | 218 | || ((int)off[0].rm_eo != (int)strlen(str_to_match)) |
| 206 | ) { | 219 | ) { |
| 207 | continue; /* this line doesn't match */ | 220 | continue; /* this line doesn't match */ |
| 208 | } | 221 | } |
| 209 | } | 222 | } |
| 210 | 223 | line_matches: | |
| 211 | /* This line matches: stop parsing the file after parsing | 224 | /* This line matches. Stop parsing after parsing |
| 212 | * the rest of fields unless keep_matching == 1 */ | 225 | * the rest the line unless keep_matching == 1 */ |
| 213 | 226 | ||
| 214 | /* 2nd field: uid:gid - device ownership */ | 227 | /* 2nd field: uid:gid - device ownership */ |
| 215 | parse_chown_usergroup_or_die(&ugid, tokens[1]); | 228 | parse_chown_usergroup_or_die(&ugid, tokens[1]); |
| @@ -243,7 +256,7 @@ static void make_device(char *path, int delete) | |||
| 243 | if (*s++ == '%') | 256 | if (*s++ == '%') |
| 244 | n++; | 257 | n++; |
| 245 | 258 | ||
| 246 | p = alias = xzalloc(strlen(a) + n * strlen(name)); | 259 | p = alias = xzalloc(strlen(a) + n * strlen(str_to_match)); |
| 247 | s = a + 1; | 260 | s = a + 1; |
| 248 | while (*s) { | 261 | while (*s) { |
| 249 | *p = *s; | 262 | *p = *s; |
| @@ -251,7 +264,7 @@ static void make_device(char *path, int delete) | |||
| 251 | i = (s[1] - '0'); | 264 | i = (s[1] - '0'); |
| 252 | if (i <= 9 && off[i].rm_so >= 0) { | 265 | if (i <= 9 && off[i].rm_so >= 0) { |
| 253 | n = off[i].rm_eo - off[i].rm_so; | 266 | n = off[i].rm_eo - off[i].rm_so; |
| 254 | strncpy(p, name + off[i].rm_so, n); | 267 | strncpy(p, str_to_match + off[i].rm_so, n); |
| 255 | p += n - 1; | 268 | p += n - 1; |
| 256 | s++; | 269 | s++; |
| 257 | } | 270 | } |
| @@ -447,9 +460,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
| 447 | 460 | ||
| 448 | /* We can be called as hotplug helper */ | 461 | /* We can be called as hotplug helper */ |
| 449 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ | 462 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ |
| 450 | |||
| 451 | bb_sanitize_stdio(); | 463 | bb_sanitize_stdio(); |
| 452 | 464 | ||
| 465 | /* Force the configuration file settings exactly */ | ||
| 466 | umask(0); | ||
| 467 | |||
| 453 | xchdir("/dev"); | 468 | xchdir("/dev"); |
| 454 | 469 | ||
| 455 | if (argv[1] && strcmp(argv[1], "-s") == 0) { | 470 | if (argv[1] && strcmp(argv[1], "-s") == 0) { |
