summaryrefslogtreecommitdiffhomepage
path: root/util-linux/mdev.c
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2013-02-26 00:40:46 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2013-02-26 00:40:46 +0100
commit40b97fb31ec7c24db706b47182f400f2a13dbbfc (patch)
treec963df67c75ca61f86bbdc3f3f000ce0b1991731 /util-linux/mdev.c
parent1961aea305e258ba7ab3910d084451220f55ed44 (diff)
mdev: add environment variable match
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@googlemail.com>
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r--util-linux/mdev.c77
1 files changed, 71 insertions, 6 deletions
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 @@
//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.