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.
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>

View File

@ -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.