diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 21:37:07 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-19 21:37:07 +0000 |
commit | 3798db58cfa0e939d0fc1822c9864355c1422cd0 (patch) | |
tree | 99f44bad59ccf82f4c1defa3bd81f09078eea8a0 /util-linux/mdev.c | |
parent | f66fe9af89e3d0f8a92894c59b6808f9202c0e86 (diff) | |
download | busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.tar.gz busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.tar.bz2 busybox-w32-3798db58cfa0e939d0fc1822c9864355c1422cd0.zip |
mdev: support $ENVVAR=regex
Diffstat (limited to 'util-linux/mdev.c')
-rw-r--r-- | util-linux/mdev.c | 69 |
1 files changed, 42 insertions, 27 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index a3275f881..ea1edcc40 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -89,15 +89,11 @@ static char *build_alias(char *alias, const char *device_name) | |||
89 | /* NB: "mdev -s" may call us many times, do not leak memory/fds! */ | 89 | /* NB: "mdev -s" may call us many times, do not leak memory/fds! */ |
90 | static void make_device(char *path, int delete) | 90 | static void make_device(char *path, int delete) |
91 | { | 91 | { |
92 | const char *device_name; | 92 | char *device_name; |
93 | int major, minor, type, len; | 93 | int major, minor, type, len; |
94 | int mode; | 94 | int mode; |
95 | char *dev_maj_min = path + strlen(path); | ||
96 | parser_t *parser; | 95 | parser_t *parser; |
97 | 96 | ||
98 | /* Force the configuration file settings exactly. */ | ||
99 | umask(0); | ||
100 | |||
101 | /* Try to read major/minor string. Note that the kernel puts \n after | 97 | /* Try to read major/minor string. Note that the kernel puts \n after |
102 | * the data, so we don't need to worry about null terminating the string | 98 | * the data, so we don't need to worry about null terminating the string |
103 | * because sscanf() will stop at the first nondigit, which \n is. | 99 | * because sscanf() will stop at the first nondigit, which \n is. |
@@ -105,21 +101,23 @@ static void make_device(char *path, int delete) | |||
105 | */ | 101 | */ |
106 | major = -1; | 102 | major = -1; |
107 | if (!delete) { | 103 | if (!delete) { |
104 | char *dev_maj_min = path + strlen(path); | ||
105 | |||
108 | strcpy(dev_maj_min, "/dev"); | 106 | strcpy(dev_maj_min, "/dev"); |
109 | len = open_read_close(path, dev_maj_min + 1, 64); | 107 | len = open_read_close(path, dev_maj_min + 1, 64); |
110 | *dev_maj_min++ = '\0'; | 108 | *dev_maj_min = '\0'; |
111 | if (len < 1) { | 109 | if (len < 1) { |
112 | if (!ENABLE_FEATURE_MDEV_EXEC) | 110 | if (!ENABLE_FEATURE_MDEV_EXEC) |
113 | return; | 111 | return; |
114 | /* no "dev" file, so just try to run script */ | 112 | /* no "dev" file, but we can still run scripts |
115 | *dev_maj_min = '\0'; | 113 | * based on device name */ |
116 | } else if (sscanf(dev_maj_min, "%u:%u", &major, &minor) != 2) { | 114 | } else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) { |
117 | major = -1; | 115 | major = -1; |
118 | } | 116 | } |
119 | } | 117 | } |
120 | 118 | ||
121 | /* Determine device name, type, major and minor */ | 119 | /* Determine device name, type, major and minor */ |
122 | device_name = bb_basename(path); | 120 | device_name = (char*) bb_basename(path); |
123 | /* http://kernel.org/doc/pending/hotplug.txt says that only | 121 | /* http://kernel.org/doc/pending/hotplug.txt says that only |
124 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. | 122 | * "/sys/block/..." is for block devices. "/sys/bus" etc is not. |
125 | * But since 2.6.25 block devices are also in /sys/class/block, | 123 | * 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) | |||
139 | parser = config_open2("/etc/mdev.conf", fopen_for_read); | 137 | parser = config_open2("/etc/mdev.conf", fopen_for_read); |
140 | 138 | ||
141 | do { | 139 | do { |
142 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; | ||
143 | int keep_matching; | 140 | int keep_matching; |
144 | char *val, *name; | ||
145 | struct bb_uidgid_t ugid; | 141 | struct bb_uidgid_t ugid; |
146 | char *tokens[4]; | 142 | char *tokens[4]; |
147 | char *command = NULL; | 143 | char *command = NULL; |
@@ -156,19 +152,22 @@ static void make_device(char *path, int delete) | |||
156 | if (ENABLE_FEATURE_MDEV_CONF | 152 | if (ENABLE_FEATURE_MDEV_CONF |
157 | && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) | 153 | && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) |
158 | ) { | 154 | ) { |
155 | char *val; | ||
156 | char *str_to_match; | ||
157 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; | ||
158 | |||
159 | val = tokens[0]; | 159 | val = tokens[0]; |
160 | keep_matching = ('-' == val[0]); | 160 | keep_matching = ('-' == val[0]); |
161 | val += keep_matching; /* swallow leading dash */ | 161 | val += keep_matching; /* swallow leading dash */ |
162 | 162 | ||
163 | /* Match against either "subsystem/device_name" | 163 | /* Match against either "subsystem/device_name" |
164 | * or "device_name" alone */ | 164 | * or "device_name" alone */ |
165 | name = strchr(val, '/') ? path : (char *) device_name; | 165 | str_to_match = strchr(val, '/') ? path : device_name; |
166 | 166 | ||
167 | /* Fields: regex uid:gid mode [alias] [cmd] */ | 167 | /* Fields: regex uid:gid mode [alias] [cmd] */ |
168 | 168 | ||
169 | /* 1st field: @<numeric maj,min>... */ | ||
170 | if (val[0] == '@') { | 169 | if (val[0] == '@') { |
171 | /* @major,minor[-last] */ | 170 | /* @major,minor[-minor2] */ |
172 | /* (useful when name is ambiguous: | 171 | /* (useful when name is ambiguous: |
173 | * "/sys/class/usb/lp0" and | 172 | * "/sys/class/usb/lp0" and |
174 | * "/sys/class/printer/lp0") */ | 173 | * "/sys/class/printer/lp0") */ |
@@ -182,15 +181,29 @@ static void make_device(char *path, int delete) | |||
182 | ) { | 181 | ) { |
183 | continue; /* this line doesn't match */ | 182 | continue; /* this line doesn't match */ |
184 | } | 183 | } |
185 | } else { /* ... or regex to match device name */ | 184 | goto line_matches; |
185 | } | ||
186 | if (val[0] == '$') { | ||
187 | /* regex to match an environment variable */ | ||
188 | char *eq = strchr(++val, '='); | ||
189 | if (!eq) | ||
190 | continue; | ||
191 | *eq = '\0'; | ||
192 | str_to_match = getenv(val); | ||
193 | if (!str_to_match) | ||
194 | continue; | ||
195 | str_to_match -= strlen(val) + 1; | ||
196 | *eq = '='; | ||
197 | } | ||
198 | /* else: regex to match [subsystem/]device_name */ | ||
199 | |||
200 | { | ||
186 | regex_t match; | 201 | regex_t match; |
187 | int result; | 202 | int result; |
188 | 203 | ||
189 | /* Is this it? */ | ||
190 | xregcomp(&match, val, REG_EXTENDED); | 204 | xregcomp(&match, val, REG_EXTENDED); |
191 | result = regexec(&match, name, ARRAY_SIZE(off), off, 0); | 205 | result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0); |
192 | regfree(&match); | 206 | regfree(&match); |
193 | |||
194 | //bb_error_msg("matches:"); | 207 | //bb_error_msg("matches:"); |
195 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { | 208 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { |
196 | // if (off[i].rm_so < 0) continue; | 209 | // if (off[i].rm_so < 0) continue; |
@@ -199,17 +212,17 @@ static void make_device(char *path, int delete) | |||
199 | // device_name + off[i].rm_so); | 212 | // device_name + off[i].rm_so); |
200 | //} | 213 | //} |
201 | 214 | ||
202 | /* If not this device, skip rest of line */ | 215 | /* If no match, skip rest of line */ |
203 | /* (regexec returns whole pattern as "range" 0) */ | 216 | /* (regexec returns whole pattern as "range" 0) */ |
204 | if (result || off[0].rm_so | 217 | if (result || off[0].rm_so |
205 | || ((int)off[0].rm_eo != (int)strlen(name)) | 218 | || ((int)off[0].rm_eo != (int)strlen(str_to_match)) |
206 | ) { | 219 | ) { |
207 | continue; /* this line doesn't match */ | 220 | continue; /* this line doesn't match */ |
208 | } | 221 | } |
209 | } | 222 | } |
210 | 223 | line_matches: | |
211 | /* This line matches: stop parsing the file after parsing | 224 | /* This line matches. Stop parsing after parsing |
212 | * the rest of fields unless keep_matching == 1 */ | 225 | * the rest the line unless keep_matching == 1 */ |
213 | 226 | ||
214 | /* 2nd field: uid:gid - device ownership */ | 227 | /* 2nd field: uid:gid - device ownership */ |
215 | parse_chown_usergroup_or_die(&ugid, tokens[1]); | 228 | parse_chown_usergroup_or_die(&ugid, tokens[1]); |
@@ -243,7 +256,7 @@ static void make_device(char *path, int delete) | |||
243 | if (*s++ == '%') | 256 | if (*s++ == '%') |
244 | n++; | 257 | n++; |
245 | 258 | ||
246 | p = alias = xzalloc(strlen(a) + n * strlen(name)); | 259 | p = alias = xzalloc(strlen(a) + n * strlen(str_to_match)); |
247 | s = a + 1; | 260 | s = a + 1; |
248 | while (*s) { | 261 | while (*s) { |
249 | *p = *s; | 262 | *p = *s; |
@@ -251,7 +264,7 @@ static void make_device(char *path, int delete) | |||
251 | i = (s[1] - '0'); | 264 | i = (s[1] - '0'); |
252 | if (i <= 9 && off[i].rm_so >= 0) { | 265 | if (i <= 9 && off[i].rm_so >= 0) { |
253 | n = off[i].rm_eo - off[i].rm_so; | 266 | n = off[i].rm_eo - off[i].rm_so; |
254 | strncpy(p, name + off[i].rm_so, n); | 267 | strncpy(p, str_to_match + off[i].rm_so, n); |
255 | p += n - 1; | 268 | p += n - 1; |
256 | s++; | 269 | s++; |
257 | } | 270 | } |
@@ -447,9 +460,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
447 | 460 | ||
448 | /* We can be called as hotplug helper */ | 461 | /* We can be called as hotplug helper */ |
449 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ | 462 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ |
450 | |||
451 | bb_sanitize_stdio(); | 463 | bb_sanitize_stdio(); |
452 | 464 | ||
465 | /* Force the configuration file settings exactly */ | ||
466 | umask(0); | ||
467 | |||
453 | xchdir("/dev"); | 468 | xchdir("/dev"); |
454 | 469 | ||
455 | if (argv[1] && strcmp(argv[1], "-s") == 0) { | 470 | if (argv[1] && strcmp(argv[1], "-s") == 0) { |