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>
This commit is contained in:
Denys Vlasenko 2013-02-26 00:40:46 +01:00
parent 1961aea305
commit 40b97fb31e
2 changed files with 73 additions and 8 deletions

View File

@ -51,9 +51,9 @@ device nodes if your system needs something more than the default root/root
660 permissions. 660 permissions.
The file has the format: The file has the format:
[-]<device regex> <uid>:<gid> <permissions> [-][envmatch]<device regex> <uid>:<gid> <permissions>
or or
@<maj[,min1[-min2]]> <uid>:<gid> <permissions> [envmatch]@<maj[,min1[-min2]]> <uid>:<gid> <permissions>
or or
$envvar=<regex> <uid>:<gid> <permissions> $envvar=<regex> <uid>:<gid> <permissions>

View File

@ -80,7 +80,7 @@
//usage: IF_FEATURE_MDEV_CONF( //usage: IF_FEATURE_MDEV_CONF(
//usage: "\n" //usage: "\n"
//usage: "It uses /etc/mdev.conf with lines\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_RENAME(" [>|=PATH]|[!]")
//usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") //usage: IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]")
//usage: "\n" //usage: "\n"
@ -233,6 +233,12 @@
static const char keywords[] ALIGN1 = "add\0remove\0change\0"; static const char keywords[] ALIGN1 = "add\0remove\0change\0";
enum { OP_add, OP_remove }; enum { OP_add, OP_remove };
struct envmatch {
struct envmatch *next;
char *envname;
regex_t match;
};
struct rule { struct rule {
bool keep_matching; bool keep_matching;
bool regex_compiled; bool regex_compiled;
@ -243,6 +249,7 @@ struct rule {
char *ren_mov; char *ren_mov;
IF_FEATURE_MDEV_EXEC(char *r_cmd;) IF_FEATURE_MDEV_EXEC(char *r_cmd;)
regex_t match; regex_t match;
struct envmatch *envmatch;
}; };
struct globals { struct globals {
@ -288,14 +295,48 @@ static void make_default_cur_rule(void)
static void clean_up_cur_rule(void) static void clean_up_cur_rule(void)
{ {
struct envmatch *e;
free(G.cur_rule.envvar); free(G.cur_rule.envvar);
free(G.cur_rule.ren_mov);
if (G.cur_rule.regex_compiled) if (G.cur_rule.regex_compiled)
regfree(&G.cur_rule.match); regfree(&G.cur_rule.match);
free(G.cur_rule.ren_mov);
IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) 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(); 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) static void parse_next_rule(void)
{ {
/* Note: on entry, G.cur_rule is set to default */ /* Note: on entry, G.cur_rule is set to default */
@ -314,6 +355,7 @@ static void parse_next_rule(void)
val = tokens[0]; val = tokens[0];
G.cur_rule.keep_matching = ('-' == val[0]); G.cur_rule.keep_matching = ('-' == val[0]);
val += G.cur_rule.keep_matching; /* swallow leading dash */ val += G.cur_rule.keep_matching; /* swallow leading dash */
val = parse_envmatch_pfx(val);
if (val[0] == '@') { if (val[0] == '@') {
/* @major,minor[-minor2] */ /* @major,minor[-minor2] */
/* (useful when name is ambiguous: /* (useful when name is ambiguous:
@ -328,8 +370,10 @@ static void parse_next_rule(void)
if (sc == 2) if (sc == 2)
G.cur_rule.min1 = G.cur_rule.min0; G.cur_rule.min1 = G.cur_rule.min0;
} else { } else {
char *eq = strchr(val, '=');
if (val[0] == '$') { if (val[0] == '$') {
char *eq = strchr(++val, '='); /* $ENVVAR=regex ... */
val++;
if (!eq) { if (!eq) {
bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno);
goto next_rule; goto next_rule;
@ -423,6 +467,21 @@ static const struct rule *next_rule(void)
return rule; 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 #else
# define next_rule() (&G.cur_rule) # define next_rule() (&G.cur_rule)
@ -537,6 +596,8 @@ static void make_device(char *device_name, char *path, int operation)
rule = next_rule(); rule = next_rule();
#if ENABLE_FEATURE_MDEV_CONF #if ENABLE_FEATURE_MDEV_CONF
if (!env_matches(rule->envmatch))
continue;
if (rule->maj >= 0) { /* @maj,min rule */ if (rule->maj >= 0) { /* @maj,min rule */
if (major != rule->maj) if (major != rule->maj)
continue; continue;
@ -749,8 +810,10 @@ static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
if (1 == depth) { if (1 == depth) {
free(G.subsystem); free(G.subsystem);
G.subsystem = strrchr(fileName, '/'); G.subsystem = strrchr(fileName, '/');
if (G.subsystem) if (G.subsystem) {
G.subsystem = xstrdup(G.subsystem + 1); G.subsystem = xstrdup(G.subsystem + 1);
xsetenv("SUBSYSTEM", G.subsystem);
}
} }
return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
@ -843,8 +906,8 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
xchdir("/dev"); xchdir("/dev");
if (argv[1] && strcmp(argv[1], "-s") == 0) { if (argv[1] && strcmp(argv[1], "-s") == 0) {
/* Scan: /*
* mdev -s * Scan: mdev -s
*/ */
struct stat st; 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_major = major(st.st_dev);
G.root_minor = minor(st.st_dev); G.root_minor = minor(st.st_dev);
putenv((char*)"ACTION=add");
/* ACTION_FOLLOWLINKS is needed since in newer kernels /* ACTION_FOLLOWLINKS is needed since in newer kernels
* /sys/block/loop* (for example) are symlinks to dirs, * /sys/block/loop* (for example) are symlinks to dirs,
* not real directories. * not real directories.