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); |
