[git commit] mdev: add environment variable match

Denys Vlasenko vda.linux at googlemail.com
Mon Feb 25 23:40:46 UTC 2013


commit: http://git.busybox.net/busybox/commit/?id=40b97fb31ec7c24db706b47182f400f2a13dbbfc
branch: http://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
make_device                                         1998    2189    +191
clean_up_cur_rule                                     61      96     +35
dirAction                                             75      87     +12
mdev_main                                            838     849     +11
packed_usage                                       29272   29273      +1
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 5/0 up/down: 250/0)             Total: 250 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 docs/mdev.txt     |    4 +-
 util-linux/mdev.c |   77 ++++++++++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 73 insertions(+), 8 deletions(-)

diff --git a/docs/mdev.txt b/docs/mdev.txt
index 61f93c9..b24025f 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
 660 permissions.
 
 The file has the format:
-	[-]<device regex>	<uid>:<gid> <permissions>
+	[-][envmatch]<device regex>	<uid>:<gid> <permissions>
 or
-	@<maj[,min1[-min2]]>	<uid>:<gid> <permissions>
+	[envmatch]@<maj[,min1[-min2]]>	<uid>:<gid> <permissions>
 or
 	$envvar=<regex>		<uid>:<gid> <permissions>
 
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index c592ef6..775e5c2 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -80,7 +80,7 @@
 //usage:	IF_FEATURE_MDEV_CONF(
 //usage:       "\n"
 //usage:       "It uses /etc/mdev.conf with lines\n"
-//usage:       "	[-]DEVNAME UID:GID PERM"
+//usage:       "	[-][ENV=regex;]...DEVNAME UID:GID PERM"
 //usage:			IF_FEATURE_MDEV_RENAME(" [>|=PATH]|[!]")
 //usage:			IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]")
 //usage:       "\n"
@@ -233,6 +233,12 @@
 static const char keywords[] ALIGN1 = "add\0remove\0change\0";
 enum { OP_add, OP_remove };
 
+struct envmatch {
+	struct envmatch *next;
+	char *envname;
+	regex_t match;
+};
+
 struct rule {
 	bool keep_matching;
 	bool regex_compiled;
@@ -243,6 +249,7 @@ struct rule {
 	char *ren_mov;
 	IF_FEATURE_MDEV_EXEC(char *r_cmd;)
 	regex_t match;
+	struct envmatch *envmatch;
 };
 
 struct globals {
@@ -288,14 +295,48 @@ static void make_default_cur_rule(void)
 
 static void clean_up_cur_rule(void)
 {
+	struct envmatch *e;
+
 	free(G.cur_rule.envvar);
+	free(G.cur_rule.ren_mov);
 	if (G.cur_rule.regex_compiled)
 		regfree(&G.cur_rule.match);
-	free(G.cur_rule.ren_mov);
 	IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);)
+	e = G.cur_rule.envmatch;
+	while (e) {
+		free(e->envname);
+		regfree(&e->match);
+		e = e->next;
+	}
 	make_default_cur_rule();
 }
 
+static char *parse_envmatch_pfx(char *val)
+{
+	struct envmatch **nextp = &G.cur_rule.envmatch;
+
+	for (;;) {
+		struct envmatch *e;
+		char *semicolon;
+		char *eq = strchr(val, '=');
+		if (!eq /* || eq == val? */)
+			return val;
+		if (endofname(val) != eq)
+			return val;
+		semicolon = strchr(eq, ';');
+		if (!semicolon)
+			return val;
+		/* ENVVAR=regex;... */
+		*nextp = e = xzalloc(sizeof(*e));
+		nextp = &e->next;
+		e->envname = xstrndup(val, eq - val);
+		*semicolon = '\0';
+		xregcomp(&e->match, eq + 1, REG_EXTENDED);
+		*semicolon = ';';
+		val = semicolon + 1;
+	}
+}
+
 static void parse_next_rule(void)
 {
 	/* Note: on entry, G.cur_rule is set to default */
@@ -314,6 +355,7 @@ static void parse_next_rule(void)
 		val = tokens[0];
 		G.cur_rule.keep_matching = ('-' == val[0]);
 		val += G.cur_rule.keep_matching; /* swallow leading dash */
+		val = parse_envmatch_pfx(val);
 		if (val[0] == '@') {
 			/* @major,minor[-minor2] */
 			/* (useful when name is ambiguous:
@@ -328,8 +370,10 @@ static void parse_next_rule(void)
 			if (sc == 2)
 				G.cur_rule.min1 = G.cur_rule.min0;
 		} else {
+			char *eq = strchr(val, '=');
 			if (val[0] == '$') {
-				char *eq = strchr(++val, '=');
+				/* $ENVVAR=regex ... */
+				val++;
 				if (!eq) {
 					bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno);
 					goto next_rule;
@@ -423,6 +467,21 @@ static const struct rule *next_rule(void)
 	return rule;
 }
 
+static int env_matches(struct envmatch *e)
+{
+	while (e) {
+		int r;
+		char *val = getenv(e->envname);
+		if (!val)
+			return 0;
+		r = regexec(&e->match, val, /*size*/ 0, /*range[]*/ NULL, /*eflags*/ 0);
+		if (r != 0) /* no match */
+			return 0;
+		e = e->next;
+	}
+	return 1;
+}
+
 #else
 
 # define next_rule() (&G.cur_rule)
@@ -537,6 +596,8 @@ static void make_device(char *device_name, char *path, int operation)
 		rule = next_rule();
 
 #if ENABLE_FEATURE_MDEV_CONF
+		if (!env_matches(rule->envmatch))
+			continue;
 		if (rule->maj >= 0) {  /* @maj,min rule */
 			if (major != rule->maj)
 				continue;
@@ -749,8 +810,10 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
 	if (1 == depth) {
 		free(G.subsystem);
 		G.subsystem = strrchr(fileName, '/');
-		if (G.subsystem)
+		if (G.subsystem) {
 			G.subsystem = xstrdup(G.subsystem + 1);
+			xsetenv("SUBSYSTEM", G.subsystem);
+		}
 	}
 
 	return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
@@ -843,8 +906,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
 	xchdir("/dev");
 
 	if (argv[1] && strcmp(argv[1], "-s") == 0) {
-		/* Scan:
-		 * mdev -s
+		/*
+		 * Scan: mdev -s
 		 */
 		struct stat st;
 
@@ -856,6 +919,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
 		G.root_major = major(st.st_dev);
 		G.root_minor = minor(st.st_dev);
 
+		putenv((char*)"ACTION=add");
+
 		/* ACTION_FOLLOWLINKS is needed since in newer kernels
 		 * /sys/block/loop* (for example) are symlinks to dirs,
 		 * not real directories.


More information about the busybox-cvs mailing list