aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/mdev.txt4
-rw-r--r--util-linux/mdev.c77
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
51660 permissions. 51660 permissions.
52 52
53The file has the format: 53The file has the format:
54 [-]<device regex> <uid>:<gid> <permissions> 54 [-][envmatch]<device regex> <uid>:<gid> <permissions>
55or 55or
56 @<maj[,min1[-min2]]> <uid>:<gid> <permissions> 56 [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions>
57or 57or
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 @@
233static const char keywords[] ALIGN1 = "add\0remove\0change\0"; 233static const char keywords[] ALIGN1 = "add\0remove\0change\0";
234enum { OP_add, OP_remove }; 234enum { OP_add, OP_remove };
235 235
236struct envmatch {
237 struct envmatch *next;
238 char *envname;
239 regex_t match;
240};
241
236struct rule { 242struct 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
248struct globals { 255struct globals {
@@ -288,14 +295,48 @@ static void make_default_cur_rule(void)
288 295
289static void clean_up_cur_rule(void) 296static 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
314static 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
299static void parse_next_rule(void) 340static 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
470static 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.