diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-22 03:46:30 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2011-09-22 03:46:30 +0200 |
commit | 3eccd7ecbe6f34e60cbc04ada9abb87313fbfc00 (patch) | |
tree | 89dd63ac4b65de1702b7dc934646c578ab08d7e9 | |
parent | 16714245f9a16ce3725aab079aea7b0d28c6b32f (diff) | |
download | busybox-w32-3eccd7ecbe6f34e60cbc04ada9abb87313fbfc00.tar.gz busybox-w32-3eccd7ecbe6f34e60cbc04ada9abb87313fbfc00.tar.bz2 busybox-w32-3eccd7ecbe6f34e60cbc04ada9abb87313fbfc00.zip |
mdev: don't reparse rules on -s
function old new delta
make_device 1648 1843 +195
clean_up_cur_rule - 61 +61
make_default_cur_rule - 41 +41
mdev_main 690 712 +22
------------------------------------------------------------------------------
(add/remove: 2/0 grow/shrink: 2/0 up/down: 319/0) Total: 319 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | util-linux/mdev.c | 558 |
1 files changed, 341 insertions, 217 deletions
diff --git a/util-linux/mdev.c b/util-linux/mdev.c index c56741b08..0b3e06cf1 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c | |||
@@ -168,9 +168,29 @@ | |||
168 | * This happens regardless of /sys/class/.../dev existence. | 168 | * This happens regardless of /sys/class/.../dev existence. |
169 | */ | 169 | */ |
170 | 170 | ||
171 | struct rule { | ||
172 | bool keep_matching; | ||
173 | bool regex_compiled; | ||
174 | bool regex_has_slash; | ||
175 | mode_t mode; | ||
176 | int maj, min0, min1; | ||
177 | struct bb_uidgid_t ugid; | ||
178 | char *envvar; | ||
179 | char *ren_mov; | ||
180 | IF_FEATURE_MDEV_EXEC(char *r_cmd;) | ||
181 | regex_t match; | ||
182 | }; | ||
183 | |||
171 | struct globals { | 184 | struct globals { |
172 | int root_major, root_minor; | 185 | int root_major, root_minor; |
173 | char *subsystem; | 186 | char *subsystem; |
187 | #if ENABLE_FEATURE_MDEV_CONF | ||
188 | const char *filename; | ||
189 | parser_t *parser; | ||
190 | struct rule **rule_vec; | ||
191 | unsigned rule_idx; | ||
192 | #endif | ||
193 | struct rule cur_rule; | ||
174 | } FIX_ALIASING; | 194 | } FIX_ALIASING; |
175 | #define G (*(struct globals*)&bb_common_bufsiz1) | 195 | #define G (*(struct globals*)&bb_common_bufsiz1) |
176 | #define INIT_G() do { } while (0) | 196 | #define INIT_G() do { } while (0) |
@@ -182,6 +202,164 @@ struct globals { | |||
182 | /* We use additional 64+ bytes in make_device() */ | 202 | /* We use additional 64+ bytes in make_device() */ |
183 | #define SCRATCH_SIZE 80 | 203 | #define SCRATCH_SIZE 80 |
184 | 204 | ||
205 | #if 0 | ||
206 | # define dbg(...) bb_error_msg(__VA_ARGS__) | ||
207 | #else | ||
208 | # define dbg(...) ((void)0) | ||
209 | #endif | ||
210 | |||
211 | |||
212 | #if ENABLE_FEATURE_MDEV_CONF | ||
213 | |||
214 | static void make_default_cur_rule(void) | ||
215 | { | ||
216 | memset(&G.cur_rule, 0, sizeof(G.cur_rule)); | ||
217 | G.cur_rule.maj = -1; /* "not a @major,minor rule" */ | ||
218 | G.cur_rule.mode = 0660; | ||
219 | } | ||
220 | |||
221 | static void clean_up_cur_rule(void) | ||
222 | { | ||
223 | free(G.cur_rule.envvar); | ||
224 | if (G.cur_rule.regex_compiled) | ||
225 | regfree(&G.cur_rule.match); | ||
226 | free(G.cur_rule.ren_mov); | ||
227 | IF_FEATURE_MDEV_EXEC(free(G.cur_rule.r_cmd);) | ||
228 | make_default_cur_rule(); | ||
229 | } | ||
230 | |||
231 | static void parse_next_rule(void) | ||
232 | { | ||
233 | /* Note: on entry, G.cur_rule is set to default */ | ||
234 | while (1) { | ||
235 | char *tokens[4]; | ||
236 | char *val; | ||
237 | |||
238 | if (!config_read(G.parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) | ||
239 | break; | ||
240 | |||
241 | /* Fields: [-]regex uid:gid mode [alias] [cmd] */ | ||
242 | dbg("token1:'%s'", tokens[1]); | ||
243 | |||
244 | /* 1st field */ | ||
245 | val = tokens[0]; | ||
246 | G.cur_rule.keep_matching = ('-' == val[0]); | ||
247 | val += G.cur_rule.keep_matching; /* swallow leading dash */ | ||
248 | if (val[0] == '@') { | ||
249 | /* @major,minor[-minor2] */ | ||
250 | /* (useful when name is ambiguous: | ||
251 | * "/sys/class/usb/lp0" and | ||
252 | * "/sys/class/printer/lp0") | ||
253 | */ | ||
254 | int sc = sscanf(val, "@%u,%u-%u", &G.cur_rule.maj, &G.cur_rule.min0, &G.cur_rule.min1); | ||
255 | if (sc < 2 || G.cur_rule.maj < 0) { | ||
256 | bb_error_msg("bad @maj,min on line %d", G.parser->lineno); | ||
257 | goto next_rule; | ||
258 | } | ||
259 | if (sc == 2) | ||
260 | G.cur_rule.min1 = G.cur_rule.min0; | ||
261 | } else { | ||
262 | if (val[0] == '$') { | ||
263 | char *eq = strchr(++val, '='); | ||
264 | if (!eq) { | ||
265 | bb_error_msg("bad $envvar=regex on line %d", G.parser->lineno); | ||
266 | goto next_rule; | ||
267 | } | ||
268 | G.cur_rule.envvar = xstrndup(val, eq - val); | ||
269 | val = eq + 1; | ||
270 | } | ||
271 | xregcomp(&G.cur_rule.match, val, REG_EXTENDED); | ||
272 | G.cur_rule.regex_compiled = 1; | ||
273 | G.cur_rule.regex_has_slash = (strchr(val, '/') != NULL); | ||
274 | } | ||
275 | |||
276 | /* 2nd field: uid:gid - device ownership */ | ||
277 | if (get_uidgid(&G.cur_rule.ugid, tokens[1], /*allow_numeric:*/ 1) == 0) { | ||
278 | bb_error_msg("unknown user/group '%s' on line %d", tokens[1], G.parser->lineno); | ||
279 | goto next_rule; | ||
280 | } | ||
281 | |||
282 | /* 3rd field: mode - device permissions */ | ||
283 | bb_parse_mode(tokens[2], &G.cur_rule.mode); | ||
284 | |||
285 | /* 4th field (opt): ">|=alias" or "!" to not create the node */ | ||
286 | val = tokens[3]; | ||
287 | if (ENABLE_FEATURE_MDEV_RENAME && val && strchr(">=!", val[0])) { | ||
288 | char *s = skip_non_whitespace(val); | ||
289 | G.cur_rule.ren_mov = xstrndup(val, s - val); | ||
290 | val = skip_whitespace(s); | ||
291 | } | ||
292 | |||
293 | if (ENABLE_FEATURE_MDEV_EXEC && val && val[0]) { | ||
294 | const char *s = "$@*"; | ||
295 | const char *s2 = strchr(s, val[0]); | ||
296 | if (!s2) { | ||
297 | bb_error_msg("bad line %u", G.parser->lineno); | ||
298 | goto next_rule; | ||
299 | } | ||
300 | IF_FEATURE_MDEV_EXEC(G.cur_rule.r_cmd = xstrdup(val);) | ||
301 | } | ||
302 | |||
303 | return; | ||
304 | next_rule: | ||
305 | clean_up_cur_rule(); | ||
306 | } /* while (config_read) */ | ||
307 | |||
308 | dbg("config_close(G.parser)"); | ||
309 | config_close(G.parser); | ||
310 | G.parser = NULL; | ||
311 | |||
312 | return; | ||
313 | } | ||
314 | |||
315 | /* If mdev -s, we remember rules in G.rule_vec[]. | ||
316 | * Otherwise, there is no point in doing it, and we just | ||
317 | * save only one parsed rule in G.cur_rule. | ||
318 | */ | ||
319 | static const struct rule *next_rule(void) | ||
320 | { | ||
321 | struct rule *rule; | ||
322 | |||
323 | /* Open conf file if we didn't do it yet */ | ||
324 | if (!G.parser && G.filename) { | ||
325 | dbg("config_open('%s')", G.filename); | ||
326 | G.parser = config_open2(G.filename, fopen_for_read); | ||
327 | G.filename = NULL; | ||
328 | } | ||
329 | |||
330 | if (G.rule_vec) { | ||
331 | /* mdev -s */ | ||
332 | /* Do we have rule parsed already? */ | ||
333 | if (G.rule_vec[G.rule_idx]) { | ||
334 | dbg("< G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | ||
335 | return G.rule_vec[G.rule_idx++]; | ||
336 | } | ||
337 | make_default_cur_rule(); | ||
338 | } else { | ||
339 | /* not mdev -s */ | ||
340 | clean_up_cur_rule(); | ||
341 | } | ||
342 | |||
343 | /* Parse one more rule if file isn't fully read */ | ||
344 | rule = &G.cur_rule; | ||
345 | if (G.parser) { | ||
346 | parse_next_rule(); | ||
347 | if (G.rule_vec) { /* mdev -s */ | ||
348 | rule = memcpy(xmalloc(sizeof(G.cur_rule)), &G.cur_rule, sizeof(G.cur_rule)); | ||
349 | G.rule_vec = xrealloc_vector(G.rule_vec, 4, G.rule_idx); | ||
350 | G.rule_vec[G.rule_idx++] = rule; | ||
351 | dbg("> G.rule_vec[G.rule_idx:%d]=%p", G.rule_idx, G.rule_vec[G.rule_idx]); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | return rule; | ||
356 | } | ||
357 | |||
358 | #else | ||
359 | |||
360 | # define next_rule() (&G.cur_rule) | ||
361 | |||
362 | #endif | ||
185 | 363 | ||
186 | /* Builds an alias path. | 364 | /* Builds an alias path. |
187 | * This function potentionally reallocates the alias parameter. | 365 | * This function potentionally reallocates the alias parameter. |
@@ -218,8 +396,8 @@ static void make_device(char *path, int delete) | |||
218 | { | 396 | { |
219 | char *device_name, *subsystem_slash_devname; | 397 | char *device_name, *subsystem_slash_devname; |
220 | int major, minor, type, len; | 398 | int major, minor, type, len; |
221 | mode_t mode; | 399 | |
222 | parser_t *parser; | 400 | dbg("%s('%s', delete:%d)", __func__, path, delete); |
223 | 401 | ||
224 | /* Try to read major/minor string. Note that the kernel puts \n after | 402 | /* Try to read major/minor string. Note that the kernel puts \n after |
225 | * the data, so we don't need to worry about null terminating the string | 403 | * the data, so we don't need to worry about null terminating the string |
@@ -272,246 +450,184 @@ static void make_device(char *path, int delete) | |||
272 | path = subsystem_slash_devname; | 450 | path = subsystem_slash_devname; |
273 | } | 451 | } |
274 | 452 | ||
275 | /* If we have config file, look up user settings */ | 453 | #if ENABLE_FEATURE_MDEV_CONF |
276 | if (ENABLE_FEATURE_MDEV_CONF) | 454 | G.rule_idx = 0; /* restart from the beginning (think mdev -s) */ |
277 | parser = config_open2("/etc/mdev.conf", fopen_for_read); | 455 | #endif |
278 | 456 | for (;;) { | |
279 | do { | 457 | const char *str_to_match; |
280 | int keep_matching; | 458 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; |
281 | struct bb_uidgid_t ugid; | 459 | char *command; |
282 | char *tokens[4]; | 460 | char *alias; |
283 | char *command = NULL; | ||
284 | char *alias = NULL; | ||
285 | char aliaslink = aliaslink; /* for compiler */ | 461 | char aliaslink = aliaslink; /* for compiler */ |
462 | const char *node_name; | ||
463 | const struct rule *rule; | ||
286 | 464 | ||
287 | /* Defaults in case we won't match any line */ | 465 | str_to_match = ""; |
288 | ugid.uid = ugid.gid = 0; | 466 | |
289 | keep_matching = 0; | 467 | rule = next_rule(); |
290 | mode = 0660; | 468 | |
291 | 469 | #if ENABLE_FEATURE_MDEV_CONF | |
292 | if (ENABLE_FEATURE_MDEV_CONF | 470 | if (rule->maj >= 0) { /* @maj,min rule */ |
293 | && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL) | 471 | if (major != rule->maj) |
294 | ) { | 472 | continue; |
295 | char *val; | 473 | if (minor < rule->min0 || minor > rule->min1) |
296 | char *str_to_match; | 474 | continue; |
297 | regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP]; | 475 | memset(off, 0, sizeof(off)); |
298 | 476 | goto rule_matches; | |
299 | val = tokens[0]; | 477 | } |
300 | keep_matching = ('-' == val[0]); | 478 | if (rule->envvar) { /* $envvar=regex rule */ |
301 | val += keep_matching; /* swallow leading dash */ | 479 | str_to_match = getenv(rule->envvar); |
302 | 480 | dbg("getenv('%s'):'%s'", rule->envvar, str_to_match); | |
303 | /* Match against either "subsystem/device_name" | 481 | if (!str_to_match) |
304 | * or "device_name" alone */ | 482 | continue; |
305 | str_to_match = strchr(val, '/') ? path : device_name; | 483 | } else { |
306 | 484 | /* regex to match [subsystem/]device_name */ | |
307 | /* Fields: regex uid:gid mode [alias] [cmd] */ | 485 | str_to_match = (rule->regex_has_slash ? path : device_name); |
308 | 486 | } | |
309 | if (val[0] == '@') { | 487 | |
310 | /* @major,minor[-minor2] */ | 488 | if (rule->regex_compiled) { |
311 | /* (useful when name is ambiguous: | 489 | int regex_match = regexec(&rule->match, str_to_match, ARRAY_SIZE(off), off, 0); |
312 | * "/sys/class/usb/lp0" and | 490 | dbg("regex_match for '%s':%d", str_to_match, regex_match); |
313 | * "/sys/class/printer/lp0") */ | 491 | //bb_error_msg("matches:"); |
314 | int cmaj, cmin0, cmin1, sc; | 492 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { |
315 | if (major < 0) | 493 | // if (off[i].rm_so < 0) continue; |
316 | continue; /* no dev, no match */ | 494 | // bb_error_msg("match %d: '%.*s'\n", i, |
317 | sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1); | 495 | // (int)(off[i].rm_eo - off[i].rm_so), |
318 | if (sc < 1 | 496 | // device_name + off[i].rm_so); |
319 | || major != cmaj | 497 | //} |
320 | || (sc == 2 && minor != cmin0) | 498 | |
321 | || (sc == 3 && (minor < cmin0 || minor > cmin1)) | 499 | if (regex_match != 0 |
322 | ) { | 500 | /* regexec returns whole pattern as "range" 0 */ |
323 | continue; /* this line doesn't match */ | 501 | || off[0].rm_so != 0 |
324 | } | 502 | || (int)off[0].rm_eo != (int)strlen(str_to_match) |
325 | goto line_matches; | 503 | ) { |
326 | } | 504 | continue; /* this rule doesn't match */ |
327 | if (val[0] == '$') { | ||
328 | /* regex to match an environment variable */ | ||
329 | char *eq = strchr(++val, '='); | ||
330 | if (!eq) | ||
331 | continue; | ||
332 | *eq = '\0'; | ||
333 | str_to_match = getenv(val); | ||
334 | if (!str_to_match) | ||
335 | continue; | ||
336 | str_to_match -= strlen(val) + 1; | ||
337 | *eq = '='; | ||
338 | } | 505 | } |
339 | /* else: regex to match [subsystem/]device_name */ | 506 | } |
340 | 507 | /* else: it's final implicit "match-all" rule */ | |
341 | { | 508 | #endif |
342 | regex_t match; | 509 | |
343 | int result; | 510 | rule_matches: |
344 | 511 | dbg("rule matched"); | |
345 | xregcomp(&match, val, REG_EXTENDED); | 512 | |
346 | result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0); | 513 | /* Build alias name */ |
347 | regfree(&match); | 514 | alias = NULL; |
348 | //bb_error_msg("matches:"); | 515 | if (ENABLE_FEATURE_MDEV_RENAME && rule->ren_mov) { |
349 | //for (int i = 0; i < ARRAY_SIZE(off); i++) { | 516 | aliaslink = rule->ren_mov[0]; |
350 | // if (off[i].rm_so < 0) continue; | 517 | if (aliaslink == '!') { |
351 | // bb_error_msg("match %d: '%.*s'\n", i, | 518 | /* "!": suppress node creation/deletion */ |
352 | // (int)(off[i].rm_eo - off[i].rm_so), | 519 | major = -2; |
353 | // device_name + off[i].rm_so); | ||
354 | //} | ||
355 | |||
356 | /* If no match, skip rest of line */ | ||
357 | /* (regexec returns whole pattern as "range" 0) */ | ||
358 | if (result | ||
359 | || off[0].rm_so | ||
360 | || ((int)off[0].rm_eo != (int)strlen(str_to_match)) | ||
361 | ) { | ||
362 | continue; /* this line doesn't match */ | ||
363 | } | ||
364 | } | 520 | } |
365 | line_matches: | 521 | else if (aliaslink == '>' || aliaslink == '=') { |
366 | /* This line matches. Stop parsing after parsing | 522 | if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) { |
367 | * the rest the line unless keep_matching == 1 */ | 523 | char *s; |
368 | 524 | char *p; | |
369 | /* 2nd field: uid:gid - device ownership */ | 525 | unsigned n; |
370 | if (get_uidgid(&ugid, tokens[1], /*allow_numeric:*/ 1) == 0) | 526 | |
371 | bb_error_msg("unknown user/group %s on line %d", tokens[1], parser->lineno); | 527 | /* substitute %1..9 with off[1..9], if any */ |
372 | 528 | n = 0; | |
373 | /* 3rd field: mode - device permissions */ | 529 | s = rule->ren_mov; |
374 | bb_parse_mode(tokens[2], &mode); | 530 | while (*s) |
375 | 531 | if (*s++ == '%') | |
376 | val = tokens[3]; | 532 | n++; |
377 | /* 4th field (opt): ">|=alias" or "!" to not create the node */ | 533 | |
378 | 534 | p = alias = xzalloc(strlen(rule->ren_mov) + n * strlen(str_to_match)); | |
379 | if (ENABLE_FEATURE_MDEV_RENAME && val) { | 535 | s = rule->ren_mov + 1; |
380 | char *a, *s, *st; | 536 | while (*s) { |
381 | 537 | *p = *s; | |
382 | a = val; | 538 | if ('%' == *s) { |
383 | s = strchrnul(val, ' '); | 539 | unsigned i = (s[1] - '0'); |
384 | st = strchrnul(val, '\t'); | 540 | if (i <= 9 && off[i].rm_so >= 0) { |
385 | if (st < s) | 541 | n = off[i].rm_eo - off[i].rm_so; |
386 | s = st; | 542 | strncpy(p, str_to_match + off[i].rm_so, n); |
387 | st = (s[0] && s[1]) ? s+1 : NULL; | 543 | p += n - 1; |
388 | 544 | s++; | |
389 | aliaslink = a[0]; | ||
390 | if (aliaslink == '!' && s == a+1) { | ||
391 | val = st; | ||
392 | /* "!": suppress node creation/deletion */ | ||
393 | major = -2; | ||
394 | } | ||
395 | else if (aliaslink == '>' || aliaslink == '=') { | ||
396 | val = st; | ||
397 | s[0] = '\0'; | ||
398 | if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) { | ||
399 | char *p; | ||
400 | unsigned i, n; | ||
401 | |||
402 | /* substitute %1..9 with off[1..9], if any */ | ||
403 | n = 0; | ||
404 | s = a; | ||
405 | while (*s) | ||
406 | if (*s++ == '%') | ||
407 | n++; | ||
408 | |||
409 | p = alias = xzalloc(strlen(a) + n * strlen(str_to_match)); | ||
410 | s = a + 1; | ||
411 | while (*s) { | ||
412 | *p = *s; | ||
413 | if ('%' == *s) { | ||
414 | i = (s[1] - '0'); | ||
415 | if (i <= 9 && off[i].rm_so >= 0) { | ||
416 | n = off[i].rm_eo - off[i].rm_so; | ||
417 | strncpy(p, str_to_match + off[i].rm_so, n); | ||
418 | p += n - 1; | ||
419 | s++; | ||
420 | } | ||
421 | } | 545 | } |
422 | p++; | ||
423 | s++; | ||
424 | } | 546 | } |
425 | } else { | 547 | p++; |
426 | alias = xstrdup(a + 1); | 548 | s++; |
427 | } | 549 | } |
550 | } else { | ||
551 | alias = xstrdup(rule->ren_mov + 1); | ||
428 | } | 552 | } |
429 | } | 553 | } |
554 | } | ||
555 | dbg("alias:'%s'", alias); | ||
430 | 556 | ||
431 | if (ENABLE_FEATURE_MDEV_EXEC && val) { | 557 | command = NULL; |
432 | const char *s = "$@*"; | 558 | IF_FEATURE_MDEV_EXEC(command = rule->r_cmd;) |
433 | const char *s2 = strchr(s, val[0]); | 559 | if (command) { |
434 | 560 | const char *s = "$@*"; | |
435 | if (!s2) { | 561 | const char *s2 = strchr(s, command[0]); |
436 | bb_error_msg("bad line %u", parser->lineno); | ||
437 | if (ENABLE_FEATURE_MDEV_RENAME) | ||
438 | free(alias); | ||
439 | continue; | ||
440 | } | ||
441 | 562 | ||
442 | /* Are we running this command now? | 563 | /* Are we running this command now? |
443 | * Run $cmd on delete, @cmd on create, *cmd on both | 564 | * Run $cmd on delete, @cmd on create, *cmd on both |
565 | */ | ||
566 | if (s2 - s != delete) { | ||
567 | /* We are here if: '*', | ||
568 | * or: '@' and delete = 0, | ||
569 | * or: '$' and delete = 1 | ||
444 | */ | 570 | */ |
445 | if (s2 - s != delete) { | 571 | command++; |
446 | /* We are here if: '*', | 572 | } else { |
447 | * or: '@' and delete = 0, | 573 | command = NULL; |
448 | * or: '$' and delete = 1 | ||
449 | */ | ||
450 | command = xstrdup(val + 1); | ||
451 | } | ||
452 | } | 574 | } |
453 | } | 575 | } |
454 | 576 | dbg("command:'%s'", command); | |
455 | /* End of field parsing */ | ||
456 | 577 | ||
457 | /* "Execute" the line we found */ | 578 | /* "Execute" the line we found */ |
458 | { | 579 | node_name = device_name; |
459 | const char *node_name; | 580 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { |
460 | 581 | node_name = alias = build_alias(alias, device_name); | |
461 | node_name = device_name; | 582 | dbg("alias2:'%s'", alias); |
462 | if (ENABLE_FEATURE_MDEV_RENAME && alias) | 583 | } |
463 | node_name = alias = build_alias(alias, device_name); | ||
464 | |||
465 | if (!delete && major >= 0) { | ||
466 | if (mknod(node_name, mode | type, makedev(major, minor)) && errno != EEXIST) | ||
467 | bb_perror_msg("can't create '%s'", node_name); | ||
468 | if (major == G.root_major && minor == G.root_minor) | ||
469 | symlink(node_name, "root"); | ||
470 | if (ENABLE_FEATURE_MDEV_CONF) { | ||
471 | chmod(node_name, mode); | ||
472 | chown(node_name, ugid.uid, ugid.gid); | ||
473 | } | ||
474 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | ||
475 | if (aliaslink == '>') | ||
476 | symlink(node_name, device_name); | ||
477 | } | ||
478 | } | ||
479 | 584 | ||
480 | if (ENABLE_FEATURE_MDEV_EXEC && command) { | 585 | if (!delete && major >= 0) { |
481 | /* setenv will leak memory, use putenv/unsetenv/free */ | 586 | dbg("mknod('%s',%o,(%d,%d))", node_name, rule->mode | type, major, minor); |
482 | char *s = xasprintf("%s=%s", "MDEV", node_name); | 587 | if (mknod(node_name, rule->mode | type, makedev(major, minor)) && errno != EEXIST) |
483 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | 588 | bb_perror_msg("can't create '%s'", node_name); |
484 | putenv(s); | 589 | if (major == G.root_major && minor == G.root_minor) |
485 | putenv(s1); | 590 | symlink(node_name, "root"); |
486 | if (system(command) == -1) | 591 | if (ENABLE_FEATURE_MDEV_CONF) { |
487 | bb_perror_msg("can't run '%s'", command); | 592 | chmod(node_name, rule->mode); |
488 | bb_unsetenv_and_free(s1); | 593 | chown(node_name, rule->ugid.uid, rule->ugid.gid); |
489 | bb_unsetenv_and_free(s); | ||
490 | free(command); | ||
491 | } | 594 | } |
492 | 595 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | |
493 | if (delete && major >= -1) { | 596 | if (aliaslink == '>') |
494 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | 597 | symlink(node_name, device_name); |
495 | if (aliaslink == '>') | ||
496 | unlink(device_name); | ||
497 | } | ||
498 | unlink(node_name); | ||
499 | } | 598 | } |
599 | } | ||
500 | 600 | ||
501 | if (ENABLE_FEATURE_MDEV_RENAME) | 601 | if (ENABLE_FEATURE_MDEV_EXEC && command) { |
502 | free(alias); | 602 | /* setenv will leak memory, use putenv/unsetenv/free */ |
603 | char *s = xasprintf("%s=%s", "MDEV", node_name); | ||
604 | char *s1 = xasprintf("%s=%s", "SUBSYSTEM", G.subsystem); | ||
605 | putenv(s); | ||
606 | putenv(s1); | ||
607 | if (system(command) == -1) | ||
608 | bb_perror_msg("can't run '%s'", command); | ||
609 | bb_unsetenv_and_free(s1); | ||
610 | bb_unsetenv_and_free(s); | ||
503 | } | 611 | } |
504 | 612 | ||
613 | if (delete && major >= -1) { | ||
614 | if (ENABLE_FEATURE_MDEV_RENAME && alias) { | ||
615 | if (aliaslink == '>') | ||
616 | unlink(device_name); | ||
617 | } | ||
618 | unlink(node_name); | ||
619 | } | ||
620 | |||
621 | if (ENABLE_FEATURE_MDEV_RENAME) | ||
622 | free(alias); | ||
623 | |||
505 | /* We found matching line. | 624 | /* We found matching line. |
506 | * Stop unless it was prefixed with '-' */ | 625 | * Stop unless it was prefixed with '-' |
507 | if (ENABLE_FEATURE_MDEV_CONF && !keep_matching) | 626 | */ |
627 | if (!ENABLE_FEATURE_MDEV_CONF || !rule->keep_matching) | ||
508 | break; | 628 | break; |
629 | } /* for (;;) */ | ||
509 | 630 | ||
510 | /* end of "while line is read from /etc/mdev.conf" */ | ||
511 | } while (ENABLE_FEATURE_MDEV_CONF); | ||
512 | |||
513 | if (ENABLE_FEATURE_MDEV_CONF) | ||
514 | config_close(parser); | ||
515 | free(subsystem_slash_devname); | 631 | free(subsystem_slash_devname); |
516 | } | 632 | } |
517 | 633 | ||
@@ -618,6 +734,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
618 | 734 | ||
619 | INIT_G(); | 735 | INIT_G(); |
620 | 736 | ||
737 | #if ENABLE_FEATURE_MDEV_CONF | ||
738 | G.filename = "/etc/mdev.conf"; | ||
739 | #endif | ||
740 | |||
621 | /* We can be called as hotplug helper */ | 741 | /* We can be called as hotplug helper */ |
622 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ | 742 | /* Kernel cannot provide suitable stdio fds for us, do it ourself */ |
623 | bb_sanitize_stdio(); | 743 | bb_sanitize_stdio(); |
@@ -633,6 +753,10 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) | |||
633 | */ | 753 | */ |
634 | struct stat st; | 754 | struct stat st; |
635 | 755 | ||
756 | #if ENABLE_FEATURE_MDEV_CONF | ||
757 | /* Same as xrealloc_vector(NULL, 4, 0): */ | ||
758 | G.rule_vec = xzalloc((1 << 4) * sizeof(*G.rule_vec)); | ||
759 | #endif | ||
636 | xstat("/", &st); | 760 | xstat("/", &st); |
637 | G.root_major = major(st.st_dev); | 761 | G.root_major = major(st.st_dev); |
638 | G.root_minor = minor(st.st_dev); | 762 | G.root_minor = minor(st.st_dev); |