diff options
-rw-r--r-- | docs/mdev.txt | 4 | ||||
-rw-r--r-- | util-linux/mdev.c | 77 |
2 files changed, 73 insertions, 8 deletions
diff --git a/docs/mdev.txt b/docs/mdev.txt index 61f93c9df..b24025f7b 100644 --- a/docs/mdev.txt +++ b/docs/mdev.txt | |||
@@ -51,9 +51,9 @@ device nodes if your system needs something more than the default root/root | |||
51 | 660 permissions. | 51 | 660 permissions. |
52 | 52 | ||
53 | The file has the format: | 53 | The file has the format: |
54 | [-]<device regex> <uid>:<gid> <permissions> | 54 | [-][envmatch]<device regex> <uid>:<gid> <permissions> |
55 | or | 55 | or |
56 | @<maj[,min1[-min2]]> <uid>:<gid> <permissions> | 56 | [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions> |
57 | or | 57 | or |
58 | $envvar=<regex> <uid>:<gid> <permissions> | 58 | $envvar=<regex> <uid>:<gid> <permissions> |
59 | 59 | ||
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c592ef687..775e5c241 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -80,7 +80,7 @@ | |||
80 | //usage: IF_FEATURE_MDEV_CONF( | 80 | //usage: IF_FEATURE_MDEV_CONF( |
81 | //usage: "\n" | 81 | //usage: "\n" |
82 | //usage: "It uses /etc/mdev.conf with lines\n" | 82 | //usage: "It uses /etc/mdev.conf with lines\n" |
83 | //usage: " [-]DEVNAME UID:GID PERM" | 83 | //usage: " [-][ENV=regex;]...DEVNAME UID:GID PERM" |
84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") | 84 | //usage: IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]") |
85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") | 85 | //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") |
86 | //usage: "\n" | 86 | //usage: "\n" |
@@ -233,6 +233,12 @@ | |||
233 | static const char keywords[] ALIGN1 = "add\0remove\0change\0"; | 233 | static const char keywords[] ALIGN1 = "add\0remove\0change\0"; |
234 | enum { OP_add, OP_remove }; | 234 | enum { OP_add, OP_remove }; |
235 | 235 | ||
236 | struct envmatch { | ||
237 | struct envmatch *next; | ||
238 | char *envname; | ||
239 | regex_t match; | ||
240 | }; | ||
241 | |||
236 | struct rule { | 242 | struct rule { |
237 | bool keep_matching; | 243 | bool keep_matching; |
238 | bool regex_compiled; | 244 | bool regex_compiled; |
@@ -243,6 +249,7 @@ struct rule { | |||
243 | char *ren_mov; | 249 | char *ren_mov; |
244 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) | 250 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) |
245 | regex_t match; | 251 | regex_t match; |
252 | struct envmatch *envmatch; | ||
246 | }; | 253 | }; |
247 | 254 | ||
248 | struct globals { | 255 | struct globals { |
@@ -288,14 +295,48 @@ static void make_default_cur_rule(void) | |||
288 | 295 | ||
289 | static void clean_up_cur_rule(void) | 296 | static void clean_up_cur_rule(void) |
290 | { | 297 | { |
298 | struct envmatch *e; | ||
299 | |||
291 | free(G.cur_rule.envvar); | 300 | free(G.cur_rule.envvar); |
301 | free(G.cur_rule.ren_mov); | ||
292 | if (G.cur_rule.regex_compiled) | 302 | if (G.cur_rule.regex_compiled) |
293 | regfree(&G.cur_rule.match); | 303 | regfree(&G.cur_rule.match); |
294 | free(G.cur_rule.ren_mov); | ||
295 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) | 304 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) |
305 | e = G.cur_rule.envmatch; | ||
306 | while (e) { | ||
307 | free(e->envname); | ||
308 | regfree(&e->match); | ||
309 | e = e->next; | ||
310 | } | ||
296 | make_default_cur_rule(); | 311 | make_default_cur_rule(); |
297 | } | 312 | } |
298 | 313 | ||
314 | static char *parse_envmatch_pfx(char *val) | ||
315 | { | ||
316 | struct envmatch **nextp = &G.cur_rule.envmatch; | ||
317 | |||
318 | for (;;) { | ||
319 | struct envmatch *e; | ||
320 | char *semicolon; | ||
321 | char *eq = strchr(val, '='); | ||
322 | if (!eq /* || eq == val? */) | ||
323 | return val; | ||
324 | if (endofname(val) != eq) | ||
325 | return val; | ||
326 | semicolon = strchr(eq, ';'); | ||
327 | if (!semicolon) | ||
328 | return val; | ||
329 | /* ENVVAR=regex;... */ | ||
330 | *nextp = e = xzalloc(sizeof(*e)); | ||
331 | nextp = &e->next; | ||
332 | e->envname = xstrndup(val, eq - val); | ||
333 | *semicolon = '\0'; | ||
334 | xregcomp(&e->match, eq + 1, REG_EXTENDED); | ||
335 | *semicolon = ';'; | ||
336 | val = semicolon + 1; | ||
337 | } | ||
338 | } | ||
339 | |||
299 | static void parse_next_rule(void) | 340 | static void parse_next_rule(void) |
300 | { | 341 | { |
301 | /* Note: on entry, G.cur_rule is set to default */ | 342 | /* Note: on entry, G.cur_rule is set to default */ |
@@ -314,6 +355,7 @@ static void parse_next_rule(void) | |||
314 | val = tokens[0]; | 355 | val = tokens[0]; |
315 | G.cur_rule.keep_matching = ('-' == val[0]); | 356 | G.cur_rule.keep_matching = ('-' == val[0]); |
316 | val += G.cur_rule.keep_matching; /* swallow leading dash */ | 357 | val += G.cur_rule.keep_matching; /* swallow leading dash */ |
358 | val = parse_envmatch_pfx(val); | ||
317 | if (val[0] == '@') { | 359 | if (val[0] == '@') { |
318 | /* @major,minor[-minor2] */ | 360 | /* @major,minor[-minor2] */ |
319 | /* (useful when name is ambiguous: | 361 | /* (useful when name is ambiguous: |
@@ -328,8 +370,10 @@ static void parse_next_rule(void) | |||
328 | if (sc == 2) | 370 | if (sc == 2) |
329 | G.cur_rule.min1 = G.cur_rule.min0; | 371 | G.cur_rule.min1 = G.cur_rule.min0; |
330 | } else { | 372 | } else { |
373 | char *eq = strchr(val, '='); | ||
331 | if (val[0] == '$') { | 374 | if (val[0] == '$') { |
332 | char *eq = strchr(++val, '='); | 375 | /* $ENVVAR=regex ... */ |
376 | val++; | ||
333 | if (!eq) { | 377 | if (!eq) { |
334 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); | 378 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); |
335 | goto next_rule; | 379 | goto next_rule; |
@@ -423,6 +467,21 @@ static const struct rule *next_rule(void) | |||
423 | return rule; | 467 | return rule; |
424 | } | 468 | } |
425 | 469 | ||
470 | static int env_matches(struct envmatch *e) | ||
471 | { | ||
472 | while (e) { | ||
473 | int r; | ||
474 | char *val = getenv(e->envname); | ||
475 | if (!val) | ||
476 | return 0; | ||
477 | r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0); | ||
478 | if (r != 0) /* no match */ | ||
479 | return 0; | ||
480 | e = e->next; | ||
481 | } | ||
482 | return 1; | ||
483 | } | ||
484 | |||
426 | #else | 485 | #else |
427 | 486 | ||
428 | # define next_rule() (&G.cur_rule) | 487 | # define next_rule() (&G.cur_rule) |
@@ -537,6 +596,8 @@ static void make_device(char *device_name, char *path, int operation) | |||
537 | rule = next_rule(); | 596 | rule = next_rule(); |
538 | 597 | ||
539 | #if ENABLE_FEATURE_MDEV_CONF | 598 | #if ENABLE_FEATURE_MDEV_CONF |
599 | if (!env_matches(rule->envmatch)) | ||
600 | continue; | ||
540 | if (rule->maj >= 0) { /* @maj,min rule */ | 601 | if (rule->maj >= 0) { /* @maj,min rule */ |
541 | if (major != rule->maj) | 602 | if (major != rule->maj) |
542 | continue; | 603 | continue; |
@@ -749,8 +810,10 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM, | |||
749 | if (1 == depth) { | 810 | if (1 == depth) { |
750 | free(G.subsystem); | 811 | free(G.subsystem); |
751 | G.subsystem = strrchr(fileName, '/'); | 812 | G.subsystem = strrchr(fileName, '/'); |
752 | if (G.subsystem) | 813 | if (G.subsystem) { |
753 | G.subsystem = xstrdup(G.subsystem + 1); | 814 | G.subsystem = xstrdup(G.subsystem + 1); |
815 | xsetenv("SUBSYSTEM", G.subsystem); | ||
816 | } | ||
754 | } | 817 | } |
755 | 818 | ||
756 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); | 819 | return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); |
@@ -843,8 +906,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
843 | xchdir("/dev"); | 906 | xchdir("/dev"); |
844 | 907 | ||
845 | if (argv[1] && strcmp(argv[1], "-s") == 0) { | 908 | if (argv[1] && strcmp(argv[1], "-s") == 0) { |
846 | /* Scan: | 909 | /* |
847 | * mdev -s | 910 | * Scan: mdev -s |
848 | */ | 911 | */ |
849 | struct stat st; | 912 | struct stat st; |
850 | 913 | ||
@@ -856,6 +919,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
856 | G.root_major = major(st.st_dev); | 919 | G.root_major = major(st.st_dev); |
857 | G.root_minor = minor(st.st_dev); | 920 | G.root_minor = minor(st.st_dev); |
858 | 921 | ||
922 | putenv((char*)"ACTION=add"); | ||
923 | |||
859 | /* ACTION_FOLLOWLINKS is needed since in newer kernels | 924 | /* ACTION_FOLLOWLINKS is needed since in newer kernels |
860 | * /sys/block/loop* (for example) are symlinks to dirs, | 925 | * /sys/block/loop* (for example) are symlinks to dirs, |
861 | * not real directories. | 926 | * not real directories. |