mdev: support $ENVVAR=regex

This commit is contained in:
Denis Vlasenko 2009-04-19 21:37:07 +00:00
parent f66fe9af89
commit 3798db58cf
2 changed files with 55 additions and 27 deletions

View File

@ -59,6 +59,19 @@ br--r--r-- 1 2 2 8,0 sda
" \ " \
"" "" "" ""
# continuing to use directory structure from prev test
rm -rf mdev.testdir/dev/*
echo "\$MODALIAS=qw 1:1 666" >mdev.testdir/etc/mdev.conf
echo "\$MODALIAS=qw. 2:2 444" >>mdev.testdir/etc/mdev.conf
echo "\$MODALIAS=qw. 3:3 400" >>mdev.testdir/etc/mdev.conf
testing "mdev \$ENVVAR=regex match" \
"env - PATH=$PATH ACTION=add DEVPATH=/block/sda MODALIAS=qwe chroot mdev.testdir /mdev 2>&1;
ls -ln mdev.testdir/dev | $FILTER_LS" \
"\
br--r--r-- 1 2 2 8,0 sda
" \
"" ""
# continuing to use directory structure from prev test # continuing to use directory structure from prev test
rm -rf mdev.testdir/dev/* rm -rf mdev.testdir/dev/*
echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf

View File

@ -89,15 +89,11 @@ static char *build_alias(char *alias, const char *device_name)
/* NB: "mdev -s" may call us many times, do not leak memory/fds! */ /* NB: "mdev -s" may call us many times, do not leak memory/fds! */
static void make_device(char *path, int delete) static void make_device(char *path, int delete)
{ {
const char *device_name; char *device_name;
int major, minor, type, len; int major, minor, type, len;
int mode; int mode;
char *dev_maj_min = path + strlen(path);
parser_t *parser; parser_t *parser;
/* Force the configuration file settings exactly. */
umask(0);
/* Try to read major/minor string. Note that the kernel puts \n after /* Try to read major/minor string. Note that the kernel puts \n after
* the data, so we don't need to worry about null terminating the string * the data, so we don't need to worry about null terminating the string
* because sscanf() will stop at the first nondigit, which \n is. * because sscanf() will stop at the first nondigit, which \n is.
@ -105,21 +101,23 @@ static void make_device(char *path, int delete)
*/ */
major = -1; major = -1;
if (!delete) { if (!delete) {
char *dev_maj_min = path + strlen(path);
strcpy(dev_maj_min, "/dev"); strcpy(dev_maj_min, "/dev");
len = open_read_close(path, dev_maj_min + 1, 64); len = open_read_close(path, dev_maj_min + 1, 64);
*dev_maj_min++ = '\0'; *dev_maj_min = '\0';
if (len < 1) { if (len < 1) {
if (!ENABLE_FEATURE_MDEV_EXEC) if (!ENABLE_FEATURE_MDEV_EXEC)
return; return;
/* no "dev" file, so just try to run script */ /* no "dev" file, but we can still run scripts
*dev_maj_min = '\0'; * based on device name */
} else if (sscanf(dev_maj_min, "%u:%u", &major, &minor) != 2) { } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) {
major = -1; major = -1;
} }
} }
/* Determine device name, type, major and minor */ /* Determine device name, type, major and minor */
device_name = bb_basename(path); device_name = (char*) bb_basename(path);
/* http://kernel.org/doc/pending/hotplug.txt says that only /* http://kernel.org/doc/pending/hotplug.txt says that only
* "/sys/block/..." is for block devices. "/sys/bus" etc is not. * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
* But since 2.6.25 block devices are also in /sys/class/block, * But since 2.6.25 block devices are also in /sys/class/block,
@ -139,9 +137,7 @@ static void make_device(char *path, int delete)
parser = config_open2("/etc/mdev.conf", fopen_for_read); parser = config_open2("/etc/mdev.conf", fopen_for_read);
do { do {
regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
int keep_matching; int keep_matching;
char *val, *name;
struct bb_uidgid_t ugid; struct bb_uidgid_t ugid;
char *tokens[4]; char *tokens[4];
char *command = NULL; char *command = NULL;
@ -156,19 +152,22 @@ static void make_device(char *path, int delete)
if (ENABLE_FEATURE_MDEV_CONF if (ENABLE_FEATURE_MDEV_CONF
&& config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)
) { ) {
char *val;
char *str_to_match;
regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
val = tokens[0]; val = tokens[0];
keep_matching = ('-' == val[0]); keep_matching = ('-' == val[0]);
val += keep_matching; /* swallow leading dash */ val += keep_matching; /* swallow leading dash */
/* Match against either "subsystem/device_name" /* Match against either "subsystem/device_name"
* or "device_name" alone */ * or "device_name" alone */
name = strchr(val, '/') ? path : (char *) device_name; str_to_match = strchr(val, '/') ? path : device_name;
/* Fields: regex uid:gid mode [alias] [cmd] */ /* Fields: regex uid:gid mode [alias] [cmd] */
/* 1st field: @<numeric maj,min>... */
if (val[0] == '@') { if (val[0] == '@') {
/* @major,minor[-last] */ /* @major,minor[-minor2] */
/* (useful when name is ambiguous: /* (useful when name is ambiguous:
* "/sys/class/usb/lp0" and * "/sys/class/usb/lp0" and
* "/sys/class/printer/lp0") */ * "/sys/class/printer/lp0") */
@ -182,15 +181,29 @@ static void make_device(char *path, int delete)
) { ) {
continue; /* this line doesn't match */ continue; /* this line doesn't match */
} }
} else { /* ... or regex to match device name */ goto line_matches;
}
if (val[0] == '$') {
/* regex to match an environment variable */
char *eq = strchr(++val, '=');
if (!eq)
continue;
*eq = '\0';
str_to_match = getenv(val);
if (!str_to_match)
continue;
str_to_match -= strlen(val) + 1;
*eq = '=';
}
/* else: regex to match [subsystem/]device_name */
{
regex_t match; regex_t match;
int result; int result;
/* Is this it? */
xregcomp(&match, val, REG_EXTENDED); xregcomp(&match, val, REG_EXTENDED);
result = regexec(&match, name, ARRAY_SIZE(off), off, 0); result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0);
regfree(&match); regfree(&match);
//bb_error_msg("matches:"); //bb_error_msg("matches:");
//for (int i = 0; i < ARRAY_SIZE(off); i++) { //for (int i = 0; i < ARRAY_SIZE(off); i++) {
// if (off[i].rm_so < 0) continue; // if (off[i].rm_so < 0) continue;
@ -199,17 +212,17 @@ static void make_device(char *path, int delete)
// device_name + off[i].rm_so); // device_name + off[i].rm_so);
//} //}
/* If not this device, skip rest of line */ /* If no match, skip rest of line */
/* (regexec returns whole pattern as "range" 0) */ /* (regexec returns whole pattern as "range" 0) */
if (result || off[0].rm_so if (result || off[0].rm_so
|| ((int)off[0].rm_eo != (int)strlen(name)) || ((int)off[0].rm_eo != (int)strlen(str_to_match))
) { ) {
continue; /* this line doesn't match */ continue; /* this line doesn't match */
} }
} }
line_matches:
/* This line matches: stop parsing the file after parsing /* This line matches. Stop parsing after parsing
* the rest of fields unless keep_matching == 1 */ * the rest the line unless keep_matching == 1 */
/* 2nd field: uid:gid - device ownership */ /* 2nd field: uid:gid - device ownership */
parse_chown_usergroup_or_die(&ugid, tokens[1]); parse_chown_usergroup_or_die(&ugid, tokens[1]);
@ -243,7 +256,7 @@ static void make_device(char *path, int delete)
if (*s++ == '%') if (*s++ == '%')
n++; n++;
p = alias = xzalloc(strlen(a) + n * strlen(name)); p = alias = xzalloc(strlen(a) + n * strlen(str_to_match));
s = a + 1; s = a + 1;
while (*s) { while (*s) {
*p = *s; *p = *s;
@ -251,7 +264,7 @@ static void make_device(char *path, int delete)
i = (s[1] - '0'); i = (s[1] - '0');
if (i <= 9 && off[i].rm_so >= 0) { if (i <= 9 && off[i].rm_so >= 0) {
n = off[i].rm_eo - off[i].rm_so; n = off[i].rm_eo - off[i].rm_so;
strncpy(p, name + off[i].rm_so, n); strncpy(p, str_to_match + off[i].rm_so, n);
p += n - 1; p += n - 1;
s++; s++;
} }
@ -447,9 +460,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv)
/* We can be called as hotplug helper */ /* We can be called as hotplug helper */
/* Kernel cannot provide suitable stdio fds for us, do it ourself */ /* Kernel cannot provide suitable stdio fds for us, do it ourself */
bb_sanitize_stdio(); bb_sanitize_stdio();
/* Force the configuration file settings exactly */
umask(0);
xchdir("/dev"); xchdir("/dev");
if (argv[1] && strcmp(argv[1], "-s") == 0) { if (argv[1] && strcmp(argv[1], "-s") == 0) {