diff options
author | Ron Yorston <rmy@pobox.com> | 2019-02-12 08:43:06 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2019-02-12 08:43:06 +0000 |
commit | 7a8bd5ae33d8c390763f0787afe6b8c495e2d978 (patch) | |
tree | 29b0abb320d73b37f4fa4d9b355b3b32db42e836 | |
parent | 0eda390d68c456975289471e68b615ae096ab33b (diff) | |
parent | f81e0120f4478c58e126bcadb19b9954ed184e8f (diff) | |
download | busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.gz busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.tar.bz2 busybox-w32-7a8bd5ae33d8c390763f0787afe6b8c495e2d978.zip |
Merge branch 'busybox' into merge
29 files changed, 1117 insertions, 331 deletions
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 43b6fca26..3a4c1044a 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c | |||
@@ -409,7 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
409 | { | 409 | { |
410 | unsigned opt; | 410 | unsigned opt; |
411 | char *signame; | 411 | char *signame; |
412 | char *startas; | 412 | char *startas = NULL; |
413 | char *chuid; | 413 | char *chuid; |
414 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY | 414 | #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY |
415 | // char *retry_arg = NULL; | 415 | // char *retry_arg = NULL; |
@@ -425,10 +425,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
425 | /* -K or -S is required; they are mutually exclusive */ | 425 | /* -K or -S is required; they are mutually exclusive */ |
426 | /* -p is required if -m is given */ | 426 | /* -p is required if -m is given */ |
427 | /* -xpun (at least one) is required if -K is given */ | 427 | /* -xpun (at least one) is required if -K is given */ |
428 | /* -xa (at least one) is required if -S is given */ | 428 | // /* -xa (at least one) is required if -S is given */ |
429 | //WRONG: "start-stop-daemon -S -- sleep 5" is a valid invocation | ||
429 | /* -q turns off -v */ | 430 | /* -q turns off -v */ |
430 | "\0" | 431 | "\0" |
431 | "K:S:K--S:S--K:m?p:K?xpun:S?xa" | 432 | "K:S:K--S:S--K:m?p:K?xpun" |
432 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), | 433 | IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"), |
433 | LONGOPTS | 434 | LONGOPTS |
434 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile | 435 | &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile |
@@ -442,21 +443,34 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
442 | if (signal_nr < 0) bb_show_usage(); | 443 | if (signal_nr < 0) bb_show_usage(); |
443 | } | 444 | } |
444 | 445 | ||
445 | if (!(opt & OPT_a)) | 446 | //argc -= optind; |
446 | startas = execname; | 447 | argv += optind; |
447 | if (!execname) /* in case -a is given and -x is not */ | 448 | // ARGS contains zeroth arg if -x/-a is not given, else it starts with 1st arg. |
449 | // These will try to execute "[/bin/]sleep 5": | ||
450 | // "start-stop-daemon -S -- sleep 5" | ||
451 | // "start-stop-daemon -S -x /bin/sleep -- 5" | ||
452 | // "start-stop-daemon -S -a sleep -- 5" | ||
453 | // NB: -n option does _not_ behave in this way: this will try to execute "5": | ||
454 | // "start-stop-daemon -S -n sleep -- 5" | ||
455 | if (!execname) { /* -x is not given */ | ||
448 | execname = startas; | 456 | execname = startas; |
449 | if (execname) { | 457 | if (!execname) { /* neither -x nor -a is given */ |
450 | G.execname_sizeof = strlen(execname) + 1; | 458 | execname = argv[0]; |
451 | G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); | 459 | if (!execname) |
460 | bb_show_usage(); | ||
461 | argv++; | ||
462 | } | ||
452 | } | 463 | } |
464 | if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */ | ||
465 | startas = execname; | ||
466 | *--argv = startas; | ||
467 | G.execname_sizeof = strlen(execname) + 1; | ||
468 | G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); | ||
453 | 469 | ||
454 | // IF_FEATURE_START_STOP_DAEMON_FANCY( | 470 | // IF_FEATURE_START_STOP_DAEMON_FANCY( |
455 | // if (retry_arg) | 471 | // if (retry_arg) |
456 | // retries = xatoi_positive(retry_arg); | 472 | // retries = xatoi_positive(retry_arg); |
457 | // ) | 473 | // ) |
458 | //argc -= optind; | ||
459 | argv += optind; | ||
460 | 474 | ||
461 | if (userspec) { | 475 | if (userspec) { |
462 | user_id = bb_strtou(userspec, NULL, 10); | 476 | user_id = bb_strtou(userspec, NULL, 10); |
@@ -473,7 +487,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
473 | 487 | ||
474 | if (G.found_procs) { | 488 | if (G.found_procs) { |
475 | if (!QUIET) | 489 | if (!QUIET) |
476 | printf("%s is already running\n%u\n", execname, (unsigned)G.found_procs->pid); | 490 | printf("%s is already running\n", execname); |
477 | return !(opt & OPT_OKNODO); | 491 | return !(opt & OPT_OKNODO); |
478 | } | 492 | } |
479 | 493 | ||
@@ -482,30 +496,37 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
482 | xstat(execname, &G.execstat); | 496 | xstat(execname, &G.execstat); |
483 | #endif | 497 | #endif |
484 | 498 | ||
485 | *--argv = startas; | ||
486 | if (opt & OPT_BACKGROUND) { | 499 | if (opt & OPT_BACKGROUND) { |
487 | #if BB_MMU | ||
488 | bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); | ||
489 | /* DAEMON_DEVNULL_STDIO is superfluous - | ||
490 | * it's always done by bb_daemonize() */ | ||
491 | #else | ||
492 | /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do | 500 | /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do |
493 | * without: SSD is not itself a daemon, it _execs_ a daemon. | 501 | * without: SSD is not itself a daemon, it _execs_ a daemon. |
494 | * The usual NOMMU problem of "child can't run indefinitely, | 502 | * The usual NOMMU problem of "child can't run indefinitely, |
495 | * it must exec" does not bite us: we exec anyway. | 503 | * it must exec" does not bite us: we exec anyway. |
504 | * | ||
505 | * bb_daemonize(DAEMON_DEVNULL_STDIO | DAEMON_CLOSE_EXTRA_FDS | DAEMON_DOUBLE_FORK) | ||
506 | * can be used on MMU systems, but use of vfork() | ||
507 | * is preferable since we want to create pidfile | ||
508 | * _before_ parent returns, and vfork() on Linux | ||
509 | * ensures that (by blocking parent until exec in the child). | ||
496 | */ | 510 | */ |
497 | pid_t pid = xvfork(); | 511 | pid_t pid = xvfork(); |
498 | if (pid != 0) { | 512 | if (pid != 0) { |
499 | /* parent */ | 513 | /* Parent */ |
500 | /* why _exit? the child may have changed the stack, | 514 | /* why _exit? the child may have changed the stack, |
501 | * so "return 0" may do bad things */ | 515 | * so "return 0" may do bad things |
516 | */ | ||
502 | _exit(EXIT_SUCCESS); | 517 | _exit(EXIT_SUCCESS); |
503 | } | 518 | } |
504 | /* Child */ | 519 | /* Child */ |
505 | setsid(); /* detach from controlling tty */ | 520 | setsid(); /* detach from controlling tty */ |
506 | /* Redirect stdio to /dev/null, close extra FDs */ | 521 | /* Redirect stdio to /dev/null, close extra FDs */ |
507 | bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); | 522 | bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); |
508 | #endif | 523 | /* On Linux, session leader can acquire ctty |
524 | * unknowingly, by opening a tty. | ||
525 | * Prevent this: stop being a session leader. | ||
526 | */ | ||
527 | pid = xvfork(); | ||
528 | if (pid != 0) | ||
529 | _exit(EXIT_SUCCESS); /* Parent */ | ||
509 | } | 530 | } |
510 | if (opt & OPT_MAKEPID) { | 531 | if (opt & OPT_MAKEPID) { |
511 | /* User wants _us_ to make the pidfile */ | 532 | /* User wants _us_ to make the pidfile */ |
@@ -534,6 +555,10 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) | |||
534 | } | 555 | } |
535 | } | 556 | } |
536 | #endif | 557 | #endif |
537 | execvp(startas, argv); | 558 | /* Try: |
559 | * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000 | ||
560 | * should exec "/bin/usleep", but argv[0] should be "qwerty": | ||
561 | */ | ||
562 | execvp(execname, argv); | ||
538 | bb_perror_msg_and_die("can't execute '%s'", startas); | 563 | bb_perror_msg_and_die("can't execute '%s'", startas); |
539 | } | 564 | } |
diff --git a/editors/awk.c b/editors/awk.c index 86cd9a289..dbb26068d 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -275,18 +275,21 @@ typedef struct tsplitter_s { | |||
275 | | TC_STRING | TC_NUMBER | TC_UOPPOST) | 275 | | TC_STRING | TC_NUMBER | TC_UOPPOST) |
276 | #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) | 276 | #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) |
277 | 277 | ||
278 | #define OF_RES1 0x010000 | 278 | #define OF_RES1 0x010000 |
279 | #define OF_RES2 0x020000 | 279 | #define OF_RES2 0x020000 |
280 | #define OF_STR1 0x040000 | 280 | #define OF_STR1 0x040000 |
281 | #define OF_STR2 0x080000 | 281 | #define OF_STR2 0x080000 |
282 | #define OF_NUM1 0x100000 | 282 | #define OF_NUM1 0x100000 |
283 | #define OF_CHECKED 0x200000 | 283 | #define OF_CHECKED 0x200000 |
284 | #define OF_REQUIRED 0x400000 | ||
285 | |||
284 | 286 | ||
285 | /* combined operator flags */ | 287 | /* combined operator flags */ |
286 | #define xx 0 | 288 | #define xx 0 |
287 | #define xV OF_RES2 | 289 | #define xV OF_RES2 |
288 | #define xS (OF_RES2 | OF_STR2) | 290 | #define xS (OF_RES2 | OF_STR2) |
289 | #define Vx OF_RES1 | 291 | #define Vx OF_RES1 |
292 | #define Rx (OF_RES1 | OF_NUM1 | OF_REQUIRED) | ||
290 | #define VV (OF_RES1 | OF_RES2) | 293 | #define VV (OF_RES1 | OF_RES2) |
291 | #define Nx (OF_RES1 | OF_NUM1) | 294 | #define Nx (OF_RES1 | OF_NUM1) |
292 | #define NV (OF_RES1 | OF_NUM1 | OF_RES2) | 295 | #define NV (OF_RES1 | OF_NUM1 | OF_RES2) |
@@ -425,7 +428,7 @@ static const uint32_t tokeninfo[] = { | |||
425 | 0, | 428 | 0, |
426 | 0, /* \n */ | 429 | 0, /* \n */ |
427 | ST_IF, ST_DO, ST_FOR, OC_BREAK, | 430 | ST_IF, ST_DO, ST_FOR, OC_BREAK, |
428 | OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, | 431 | OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, |
429 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, | 432 | OC_PRINTF, OC_NEXT, OC_NEXTFILE, |
430 | OC_RETURN|Vx, OC_EXIT|Nx, | 433 | OC_RETURN|Vx, OC_EXIT|Nx, |
431 | ST_WHILE, | 434 | ST_WHILE, |
@@ -593,7 +596,7 @@ static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; | |||
593 | static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; | 596 | static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; |
594 | static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; | 597 | static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; |
595 | static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; | 598 | static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; |
596 | static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; | 599 | static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments"; |
597 | static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; | 600 | static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; |
598 | static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; | 601 | static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; |
599 | static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; | 602 | static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; |
@@ -1269,7 +1272,7 @@ static node *parse_expr(uint32_t iexp) | |||
1269 | debug_printf_parse("%s(%x)\n", __func__, iexp); | 1272 | debug_printf_parse("%s(%x)\n", __func__, iexp); |
1270 | 1273 | ||
1271 | sn.info = PRIMASK; | 1274 | sn.info = PRIMASK; |
1272 | sn.r.n = glptr = NULL; | 1275 | sn.r.n = sn.a.n = glptr = NULL; |
1273 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; | 1276 | xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; |
1274 | 1277 | ||
1275 | while (!((tc = next_token(xtc)) & iexp)) { | 1278 | while (!((tc = next_token(xtc)) & iexp)) { |
@@ -1291,6 +1294,7 @@ static node *parse_expr(uint32_t iexp) | |||
1291 | || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) | 1294 | || ((t_info == vn->info) && ((t_info & OPCLSMASK) == OC_COLON)) |
1292 | ) { | 1295 | ) { |
1293 | vn = vn->a.n; | 1296 | vn = vn->a.n; |
1297 | if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); | ||
1294 | } | 1298 | } |
1295 | if ((t_info & OPCLSMASK) == OC_TERNARY) | 1299 | if ((t_info & OPCLSMASK) == OC_TERNARY) |
1296 | t_info += P(6); | 1300 | t_info += P(6); |
@@ -1429,7 +1433,11 @@ static void chain_expr(uint32_t info) | |||
1429 | node *n; | 1433 | node *n; |
1430 | 1434 | ||
1431 | n = chain_node(info); | 1435 | n = chain_node(info); |
1436 | |||
1432 | n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); | 1437 | n->l.n = parse_expr(TC_OPTERM | TC_GRPTERM); |
1438 | if ((info & OF_REQUIRED) && !n->l.n) | ||
1439 | syntax_error(EMSG_TOO_FEW_ARGS); | ||
1440 | |||
1433 | if (t_tclass & TC_GRPTERM) | 1441 | if (t_tclass & TC_GRPTERM) |
1434 | rollback_token(); | 1442 | rollback_token(); |
1435 | } | 1443 | } |
@@ -1609,12 +1617,25 @@ static void parse_program(char *p) | |||
1609 | f = newfunc(t_string); | 1617 | f = newfunc(t_string); |
1610 | f->body.first = NULL; | 1618 | f->body.first = NULL; |
1611 | f->nargs = 0; | 1619 | f->nargs = 0; |
1612 | while (next_token(TC_VARIABLE | TC_SEQTERM) & TC_VARIABLE) { | 1620 | /* Match func arg list: a comma sep list of >= 0 args, and a close paren */ |
1621 | while (next_token(TC_VARIABLE | TC_SEQTERM | TC_COMMA)) { | ||
1622 | /* Either an empty arg list, or trailing comma from prev iter | ||
1623 | * must be followed by an arg */ | ||
1624 | if (f->nargs == 0 && t_tclass == TC_SEQTERM) | ||
1625 | break; | ||
1626 | |||
1627 | /* TC_SEQSTART/TC_COMMA must be followed by TC_VARIABLE */ | ||
1628 | if (t_tclass != TC_VARIABLE) | ||
1629 | syntax_error(EMSG_UNEXP_TOKEN); | ||
1630 | |||
1613 | v = findvar(ahash, t_string); | 1631 | v = findvar(ahash, t_string); |
1614 | v->x.aidx = f->nargs++; | 1632 | v->x.aidx = f->nargs++; |
1615 | 1633 | ||
1634 | /* Arg followed either by end of arg list or 1 comma */ | ||
1616 | if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) | 1635 | if (next_token(TC_COMMA | TC_SEQTERM) & TC_SEQTERM) |
1617 | break; | 1636 | break; |
1637 | if (t_tclass != TC_COMMA) | ||
1638 | syntax_error(EMSG_UNEXP_TOKEN); | ||
1618 | } | 1639 | } |
1619 | seq = &f->body; | 1640 | seq = &f->body; |
1620 | chain_group(); | 1641 | chain_group(); |
diff --git a/editors/sed.c b/editors/sed.c index fd56e0e7f..a5cedbd8d 100644 --- a/editors/sed.c +++ b/editors/sed.c | |||
@@ -377,25 +377,25 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) | |||
377 | /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ | 377 | /* Grab a filename. Whitespace at start is skipped, then goes to EOL. */ |
378 | static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval) | 378 | static int parse_file_cmd(/*sed_cmd_t *sed_cmd,*/ const char *filecmdstr, char **retval) |
379 | { | 379 | { |
380 | int start = 0, idx, hack = 0; | 380 | const char *start; |
381 | const char *eol; | ||
381 | 382 | ||
382 | /* Skip whitespace, then grab filename to end of line */ | 383 | /* Skip whitespace, then grab filename to end of line */ |
383 | while (isspace(filecmdstr[start])) | 384 | start = skip_whitespace(filecmdstr); |
384 | start++; | 385 | eol = strchrnul(start, '\n'); |
385 | idx = start; | 386 | if (eol == start) |
386 | while (filecmdstr[idx] && filecmdstr[idx] != '\n') | ||
387 | idx++; | ||
388 | |||
389 | /* If lines glued together, put backslash back. */ | ||
390 | if (filecmdstr[idx] == '\n') | ||
391 | hack = 1; | ||
392 | if (idx == start) | ||
393 | bb_error_msg_and_die("empty filename"); | 387 | bb_error_msg_and_die("empty filename"); |
394 | *retval = xstrndup(filecmdstr+start, idx-start+hack+1); | ||
395 | if (hack) | ||
396 | (*retval)[idx] = '\\'; | ||
397 | 388 | ||
398 | return idx; | 389 | if (*eol) { |
390 | /* If lines glued together, put backslash back. */ | ||
391 | *retval = xstrndup(start, eol-start + 1); | ||
392 | (*retval)[eol-start] = '\\'; | ||
393 | } else { | ||
394 | /* eol is NUL */ | ||
395 | *retval = xstrdup(start); | ||
396 | } | ||
397 | |||
398 | return eol - filecmdstr; | ||
399 | } | 399 | } |
400 | 400 | ||
401 | static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) | 401 | static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) |
diff --git a/editors/vi.c b/editors/vi.c index 3c758cca0..a46339813 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -600,6 +600,7 @@ static void check_context(char); // remember context for '' command | |||
600 | #if ENABLE_FEATURE_VI_UNDO | 600 | #if ENABLE_FEATURE_VI_UNDO |
601 | static void flush_undo_data(void); | 601 | static void flush_undo_data(void); |
602 | static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack | 602 | static void undo_push(char *, unsigned int, unsigned char); // Push an operation on the undo stack |
603 | static void undo_push_insert(char *, int, int); // convenience function | ||
603 | static void undo_pop(void); // Undo the last operation | 604 | static void undo_pop(void); // Undo the last operation |
604 | # if ENABLE_FEATURE_VI_UNDO_QUEUE | 605 | # if ENABLE_FEATURE_VI_UNDO_QUEUE |
605 | static void undo_queue_commit(void); // Flush any queued objects to the undo stack | 606 | static void undo_queue_commit(void); // Flush any queued objects to the undo stack |
@@ -2013,19 +2014,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2013 | c = get_one_char(); | 2014 | c = get_one_char(); |
2014 | *p = c; | 2015 | *p = c; |
2015 | #if ENABLE_FEATURE_VI_UNDO | 2016 | #if ENABLE_FEATURE_VI_UNDO |
2016 | switch (undo) { | 2017 | undo_push_insert(p, 1, undo); |
2017 | case ALLOW_UNDO: | ||
2018 | undo_push(p, 1, UNDO_INS); | ||
2019 | break; | ||
2020 | case ALLOW_UNDO_CHAIN: | ||
2021 | undo_push(p, 1, UNDO_INS_CHAIN); | ||
2022 | break; | ||
2023 | # if ENABLE_FEATURE_VI_UNDO_QUEUE | ||
2024 | case ALLOW_UNDO_QUEUED: | ||
2025 | undo_push(p, 1, UNDO_INS_QUEUED); | ||
2026 | break; | ||
2027 | # endif | ||
2028 | } | ||
2029 | #else | 2018 | #else |
2030 | modified_count++; | 2019 | modified_count++; |
2031 | #endif /* ENABLE_FEATURE_VI_UNDO */ | 2020 | #endif /* ENABLE_FEATURE_VI_UNDO */ |
@@ -2053,19 +2042,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2053 | if (c == '\n') | 2042 | if (c == '\n') |
2054 | undo_queue_commit(); | 2043 | undo_queue_commit(); |
2055 | # endif | 2044 | # endif |
2056 | switch (undo) { | 2045 | undo_push_insert(p, 1, undo); |
2057 | case ALLOW_UNDO: | ||
2058 | undo_push(p, 1, UNDO_INS); | ||
2059 | break; | ||
2060 | case ALLOW_UNDO_CHAIN: | ||
2061 | undo_push(p, 1, UNDO_INS_CHAIN); | ||
2062 | break; | ||
2063 | # if ENABLE_FEATURE_VI_UNDO_QUEUE | ||
2064 | case ALLOW_UNDO_QUEUED: | ||
2065 | undo_push(p, 1, UNDO_INS_QUEUED); | ||
2066 | break; | ||
2067 | # endif | ||
2068 | } | ||
2069 | #else | 2046 | #else |
2070 | modified_count++; | 2047 | modified_count++; |
2071 | #endif /* ENABLE_FEATURE_VI_UNDO */ | 2048 | #endif /* ENABLE_FEATURE_VI_UNDO */ |
@@ -2085,7 +2062,7 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2085 | p += bias; | 2062 | p += bias; |
2086 | q += bias; | 2063 | q += bias; |
2087 | #if ENABLE_FEATURE_VI_UNDO | 2064 | #if ENABLE_FEATURE_VI_UNDO |
2088 | undo_push(p, len, UNDO_INS); | 2065 | undo_push_insert(p, len, undo); |
2089 | #endif | 2066 | #endif |
2090 | memcpy(p, q, len); | 2067 | memcpy(p, q, len); |
2091 | p += len; | 2068 | p += len; |
@@ -2339,16 +2316,18 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to | |||
2339 | } | 2316 | } |
2340 | break; | 2317 | break; |
2341 | case UNDO_INS_QUEUED: | 2318 | case UNDO_INS_QUEUED: |
2342 | if (length != 1) | 2319 | if (length < 1) |
2343 | return; | 2320 | return; |
2344 | switch (undo_queue_state) { | 2321 | switch (undo_queue_state) { |
2345 | case UNDO_EMPTY: | 2322 | case UNDO_EMPTY: |
2346 | undo_queue_state = UNDO_INS; | 2323 | undo_queue_state = UNDO_INS; |
2347 | undo_queue_spos = src; | 2324 | undo_queue_spos = src; |
2348 | case UNDO_INS: | 2325 | case UNDO_INS: |
2349 | undo_q++; // Don't need to save any data for insertions | 2326 | while (length--) { |
2350 | if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) | 2327 | undo_q++; // Don't need to save any data for insertions |
2351 | undo_queue_commit(); | 2328 | if (undo_q == CONFIG_FEATURE_VI_UNDO_QUEUE_MAX) |
2329 | undo_queue_commit(); | ||
2330 | } | ||
2352 | return; | 2331 | return; |
2353 | case UNDO_DEL: | 2332 | case UNDO_DEL: |
2354 | // Switch from storing deleted text to inserted text | 2333 | // Switch from storing deleted text to inserted text |
@@ -2394,6 +2373,23 @@ static void undo_push(char *src, unsigned int length, uint8_t u_type) // Add to | |||
2394 | modified_count++; | 2373 | modified_count++; |
2395 | } | 2374 | } |
2396 | 2375 | ||
2376 | static void undo_push_insert(char *p, int len, int undo) | ||
2377 | { | ||
2378 | switch (undo) { | ||
2379 | case ALLOW_UNDO: | ||
2380 | undo_push(p, len, UNDO_INS); | ||
2381 | break; | ||
2382 | case ALLOW_UNDO_CHAIN: | ||
2383 | undo_push(p, len, UNDO_INS_CHAIN); | ||
2384 | break; | ||
2385 | # if ENABLE_FEATURE_VI_UNDO_QUEUE | ||
2386 | case ALLOW_UNDO_QUEUED: | ||
2387 | undo_push(p, len, UNDO_INS_QUEUED); | ||
2388 | break; | ||
2389 | # endif | ||
2390 | } | ||
2391 | } | ||
2392 | |||
2397 | static void undo_pop(void) // Undo the last operation | 2393 | static void undo_pop(void) // Undo the last operation |
2398 | { | 2394 | { |
2399 | int repeat; | 2395 | int repeat; |
@@ -2667,14 +2663,7 @@ static uintptr_t string_insert(char *p, const char *s, int undo) // insert the s | |||
2667 | 2663 | ||
2668 | i = strlen(s); | 2664 | i = strlen(s); |
2669 | #if ENABLE_FEATURE_VI_UNDO | 2665 | #if ENABLE_FEATURE_VI_UNDO |
2670 | switch (undo) { | 2666 | undo_push_insert(p, i, undo); |
2671 | case ALLOW_UNDO: | ||
2672 | undo_push(p, i, UNDO_INS); | ||
2673 | break; | ||
2674 | case ALLOW_UNDO_CHAIN: | ||
2675 | undo_push(p, i, UNDO_INS_CHAIN); | ||
2676 | break; | ||
2677 | } | ||
2678 | #endif | 2667 | #endif |
2679 | bias = text_hole_make(p, i); | 2668 | bias = text_hole_make(p, i); |
2680 | p += bias; | 2669 | p += bias; |
@@ -4263,14 +4252,9 @@ static void do_cmd(int c) | |||
4263 | case 'r': // r- replace the current char with user input | 4252 | case 'r': // r- replace the current char with user input |
4264 | c1 = get_one_char(); // get the replacement char | 4253 | c1 = get_one_char(); // get the replacement char |
4265 | if (*dot != '\n') { | 4254 | if (*dot != '\n') { |
4266 | #if ENABLE_FEATURE_VI_UNDO | 4255 | dot = text_hole_delete(dot, dot, ALLOW_UNDO); |
4267 | undo_push(dot, 1, UNDO_DEL); | 4256 | dot = char_insert(dot, c1, ALLOW_UNDO_CHAIN); |
4268 | *dot = c1; | 4257 | dot_left(); |
4269 | undo_push(dot, 1, UNDO_INS_CHAIN); | ||
4270 | #else | ||
4271 | *dot = c1; | ||
4272 | modified_count++; | ||
4273 | #endif | ||
4274 | } | 4258 | } |
4275 | end_cmd_q(); // stop adding to q | 4259 | end_cmd_q(); // stop adding to q |
4276 | break; | 4260 | break; |
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index 90714bcdf..bb8774e08 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf | |||
@@ -74,43 +74,49 @@ option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 | |||
74 | option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" | 74 | option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" |
75 | option 14 "dumpfile" | 75 | option 14 "dumpfile" |
76 | 76 | ||
77 | # Currently supported options (for more info, see options.c): | 77 | # Currently supported options [hex option value] (for more info, see options.c): |
78 | #opt lease NUM | 78 | #opt lease NUM # [0x33] |
79 | #opt subnet IP | 79 | #opt subnet IP # [0x01] |
80 | #opt broadcast IP | 80 | #opt broadcast IP # [0x1c] |
81 | #opt router IP_LIST | 81 | #opt router IP_LIST # [0x03] |
82 | #opt ipttl NUM | 82 | #opt ipttl NUM # [0x17] |
83 | #opt mtu NUM | 83 | #opt mtu NUM # [0x1a] |
84 | #opt hostname STRING # client's hostname | 84 | #opt hostname STRING # [0x0c] client's hostname |
85 | #opt domain STRING # client's domain suffix | 85 | #opt domain STRING # [0x0f] client's domain suffix |
86 | #opt search STRING_LIST # search domains | 86 | #opt search STRING_LIST # [0x77] search domains |
87 | #opt nisdomain STRING | 87 | #opt nisdomain STRING # [0x28] |
88 | #opt timezone NUM # (localtime - UTC_time) in seconds. signed | 88 | #opt timezone NUM # [0x02] (localtime - UTC_time) in seconds. signed |
89 | #opt tftp STRING # tftp server name | 89 | #opt tftp STRING # [0x42] tftp server name |
90 | #opt bootfile STRING # tftp file to download (e.g. kernel image) | 90 | #opt bootfile STRING # [0x43] tftp file to download (e.g. kernel image) |
91 | #opt bootsize NUM # size of that file | 91 | #opt bootsize NUM # [0x0d] size of that file |
92 | #opt rootpath STRING # (NFS) path to mount as root fs | 92 | #opt rootpath STRING # [0x11] (NFS) path to mount as root fs |
93 | #opt wpad STRING | 93 | #opt wpad STRING # [0xfc] Web Proxy Auto Discovery Protocol |
94 | #opt serverid IP # default: server's IP | 94 | #opt serverid IP # [0x36] default: server's IP |
95 | #opt message STRING # error message (udhcpd sends it on success too) | 95 | #opt message STRING # [0x38] error message (udhcpd sends it on success too) |
96 | #opt vlanid NUM # 802.1P VLAN ID | 96 | #opt vlanid NUM # [0x84] 802.1P VLAN ID |
97 | #opt vlanpriority NUM # 802.1Q VLAN priority | 97 | #opt vlanpriority NUM # [0x85] 802.1Q VLAN priority |
98 | # RFC 5071: PXELINUX Options | ||
99 | #opt 0xd0 F100747E # [0xd0] magic | ||
100 | #opt pxeconffile STRING # [0xd1] | ||
101 | #opt pxepathprefix STRING # [0xd2] | ||
102 | #opt reboottime NUM # [0xd3] bootstrap timeout | ||
98 | # Options specifying server(s) | 103 | # Options specifying server(s) |
99 | #opt dns IP_LIST | 104 | #opt dns IP_LIST # [0x06] |
100 | #opt wins IP_LIST | 105 | #opt wins IP_LIST # [0x2c] |
101 | #opt nissrv IP_LIST | 106 | #opt nissrv IP_LIST # [0x29] |
102 | #opt ntpsrv IP_LIST | 107 | #opt ntpsrv IP_LIST # [0x2a] |
103 | #opt lprsrv IP_LIST | 108 | #opt lprsrv IP_LIST # [0x09] |
104 | #opt swapsrv IP | 109 | #opt swapsrv IP # [0x10] |
105 | # Options specifying routes | 110 | # Options specifying routes |
106 | #opt routes IP_PAIR_LIST | 111 | #opt routes IP_PAIR_LIST # [0x21] |
107 | #opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option | 112 | #opt staticroutes STATIC_ROUTES # [0x79] RFC 3442 classless static route option |
108 | #opt msstaticroutes STATIC_ROUTES # same, using MS option number | 113 | #opt msstaticroutes STATIC_ROUTES # [0xf9] same, using MS option number |
109 | # Obsolete options, no longer supported | 114 | # Obsolete options, no longer supported |
110 | #opt logsrv IP_LIST # 704/UDP log server (not syslog!) | 115 | #opt logsrv IP_LIST # [0x07] 704/UDP log server (not syslog!) |
111 | #opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) | 116 | #opt namesrv IP_LIST # [0x05] IEN 116 name server, obsolete (August 1979!!!) |
112 | #opt cookiesrv IP_LIST # RFC 865 "quote of the day" server, rarely (never?) used | 117 | #opt cookiesrv IP_LIST # [0x08] RFC 865 "quote of the day" server, rarely (never?) used |
113 | #opt timesrv IP_LIST # RFC 868 time server, rarely (never?) used | 118 | #opt timesrv IP_LIST # [0x04] RFC 868 time server, rarely (never?) used |
114 | # TODO: in development | 119 | # TODO: in development |
115 | #opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc | 120 | #opt userclass STRING # [0x4d] RFC 3004. set of LASCII strings. "I am a printer" etc |
116 | #opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs | 121 | #opt sipsrv STRING LIST # [0x78] RFC 3361. flag byte, then: 0: domain names, 1: IP addrs |
122 | #opt ip6rd .... # [0xd4] IPv6 rapid deployment | ||
diff --git a/examples/var_service/dhcp_if/convert2ipconf b/examples/var_service/dhcp_if/convert2ipconf index 62a288ebf..31e3c7fde 100755 --- a/examples/var_service/dhcp_if/convert2ipconf +++ b/examples/var_service/dhcp_if/convert2ipconf | |||
@@ -26,6 +26,30 @@ exec 2>&1 | |||
26 | test "$interface" || exit 1 | 26 | test "$interface" || exit 1 |
27 | test "$ip" || exit 1 | 27 | test "$ip" || exit 1 |
28 | 28 | ||
29 | # some servers do not return subnet option. | ||
30 | # guess it for standard private networks. | ||
31 | if ! test "$mask"; then | ||
32 | case "$ip" in | ||
33 | 10.*) | ||
34 | mask=8;; | ||
35 | 192.168.*) | ||
36 | mask=16;; | ||
37 | #172.16-31.x.x | ||
38 | 172.1[6789].*) | ||
39 | mask=12;; | ||
40 | 172.2[0123456789].*) | ||
41 | mask=12;; | ||
42 | 172.3[01].*) | ||
43 | mask=12;; | ||
44 | esac | ||
45 | fi | ||
46 | |||
47 | # some servers do not return router option. | ||
48 | # assume DHCP server is the router. | ||
49 | if ! test "$router"; then | ||
50 | test "$serverid" && router="$serverid" | ||
51 | fi | ||
52 | |||
29 | { | 53 | { |
30 | echo "let cfg=cfg+1" | 54 | echo "let cfg=cfg+1" |
31 | test "$interface" && echo "if[\$cfg]='$interface'" | 55 | test "$interface" && echo "if[\$cfg]='$interface'" |
diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run index 5d1d4e355..5c662f298 100755 --- a/examples/var_service/ifplugd_if/run +++ b/examples/var_service/ifplugd_if/run | |||
@@ -16,7 +16,7 @@ exec \ | |||
16 | env - PATH="$PATH" \ | 16 | env - PATH="$PATH" \ |
17 | softlimit \ | 17 | softlimit \ |
18 | setuidgid root \ | 18 | setuidgid root \ |
19 | ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" | 19 | ifplugd -aqlMns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" |
20 | 20 | ||
21 | # We use -t3 to wake ifplugd up less often. | 21 | # We use -t3 to wake ifplugd up less often. |
22 | # If after three tests (3*3=9 > 8) link state seen to be different, | 22 | # If after three tests (3*3=9 > 8) link state seen to be different, |
@@ -29,6 +29,7 @@ ifplugd -aqlns -t3 -u8 -d8 -i "$if" -r "$pwd/ifplugd_handler" | |||
29 | # from pointlessly trying to get a lease. | 29 | # from pointlessly trying to get a lease. |
30 | # -q means that stopping monitoring does not stop dhcp/zcip/etc: | 30 | # -q means that stopping monitoring does not stop dhcp/zcip/etc: |
31 | # presumably, admin decided to control them manually. | 31 | # presumably, admin decided to control them manually. |
32 | # -M prevents frequent respawning if device does not exist (yet?) | ||
32 | 33 | ||
33 | #-a Don't up interface automatically | 34 | #-a Don't up interface automatically |
34 | #-p Don't run "up" script on startup | 35 | #-p Don't run "up" script on startup |
diff --git a/examples/var_service/supplicant_if/run b/examples/var_service/supplicant_if/run index 45211e001..279d18af5 100755 --- a/examples/var_service/supplicant_if/run +++ b/examples/var_service/supplicant_if/run | |||
@@ -8,7 +8,8 @@ pwd="$PWD" | |||
8 | if="${PWD##*/dhcp_}" | 8 | if="${PWD##*/dhcp_}" |
9 | 9 | ||
10 | echo "* Upping iface $if" | 10 | echo "* Upping iface $if" |
11 | ip link set dev "$if" up | 11 | # "or sleep" idiom prevents rapid respawning if iface does not exist |
12 | ip link set dev "$if" up || { sleep 5; exit; } | ||
12 | 13 | ||
13 | ##echo "* Powersave disable on $if" | 14 | ##echo "* Powersave disable on $if" |
14 | ##iw dev "$if" set power_save off | 15 | ##iw dev "$if" set power_save off |
diff --git a/findutils/grep.c b/findutils/grep.c index a4033a40b..2cbe7ea91 100644 --- a/findutils/grep.c +++ b/findutils/grep.c | |||
@@ -404,7 +404,7 @@ static int grep_file(FILE *file) | |||
404 | #endif | 404 | #endif |
405 | ) { | 405 | ) { |
406 | if (option_mask32 & OPT_x) { | 406 | if (option_mask32 & OPT_x) { |
407 | found = (gl->matched_range.rm_so == 0 | 407 | found |= (gl->matched_range.rm_so == 0 |
408 | && match_at[gl->matched_range.rm_eo] == '\0'); | 408 | && match_at[gl->matched_range.rm_eo] == '\0'); |
409 | } else | 409 | } else |
410 | if (!(option_mask32 & OPT_w)) { | 410 | if (!(option_mask32 & OPT_w)) { |
@@ -443,15 +443,23 @@ static int grep_file(FILE *file) | |||
443 | } | 443 | } |
444 | } | 444 | } |
445 | } | 445 | } |
446 | /* If it's non-inverted search, we can stop | 446 | /* If it's a non-inverted search, we can stop |
447 | * at first match */ | 447 | * at first match and report it. |
448 | if (found && !invert_search) | 448 | * If it's an inverted search, we can move on |
449 | goto do_found; | 449 | * to the next line of input, ignoring the |
450 | * rest of the patterns. | ||
451 | */ | ||
452 | if (found) { | ||
453 | //if (invert_search) | ||
454 | // goto do_not_found; | ||
455 | //goto do_found; | ||
456 | break; // this accomplishes both | ||
457 | } | ||
450 | pattern_ptr = pattern_ptr->link; | 458 | pattern_ptr = pattern_ptr->link; |
451 | } /* while (pattern_ptr) */ | 459 | } /* while (pattern_ptr) */ |
452 | 460 | ||
453 | if (found ^ invert_search) { | 461 | if (found ^ invert_search) { |
454 | do_found: | 462 | //do_found: |
455 | /* keep track of matches */ | 463 | /* keep track of matches */ |
456 | nmatches++; | 464 | nmatches++; |
457 | 465 | ||
@@ -552,6 +560,7 @@ static int grep_file(FILE *file) | |||
552 | } | 560 | } |
553 | #if ENABLE_FEATURE_GREP_CONTEXT | 561 | #if ENABLE_FEATURE_GREP_CONTEXT |
554 | else { /* no match */ | 562 | else { /* no match */ |
563 | //do_not_found: | ||
555 | /* if we need to print some context lines after the last match, do so */ | 564 | /* if we need to print some context lines after the last match, do so */ |
556 | if (print_n_lines_after) { | 565 | if (print_n_lines_after) { |
557 | print_line(line, strlen(line), linenum, '-'); | 566 | print_line(line, strlen(line), linenum, '-'); |
diff --git a/include/libbb.h b/include/libbb.h index 1b5994357..0c7e03ee8 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -1244,11 +1244,11 @@ void set_task_comm(const char *comm) FAST_FUNC; | |||
1244 | * to /dev/null if they are not. | 1244 | * to /dev/null if they are not. |
1245 | */ | 1245 | */ |
1246 | enum { | 1246 | enum { |
1247 | DAEMON_CHDIR_ROOT = 1, | 1247 | DAEMON_CHDIR_ROOT = 1 << 0, |
1248 | DAEMON_DEVNULL_STDIO = 2, | 1248 | DAEMON_DEVNULL_STDIO = 1 << 1, |
1249 | DAEMON_CLOSE_EXTRA_FDS = 4, | 1249 | DAEMON_CLOSE_EXTRA_FDS = 1 << 2, |
1250 | DAEMON_ONLY_SANITIZE = 8, /* internal use */ | 1250 | DAEMON_ONLY_SANITIZE = 1 << 3, /* internal use */ |
1251 | DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ | 1251 | //DAEMON_DOUBLE_FORK = 1 << 4, /* double fork to avoid controlling tty */ |
1252 | }; | 1252 | }; |
1253 | #if BB_MMU | 1253 | #if BB_MMU |
1254 | enum { re_execed = 0 }; | 1254 | enum { re_execed = 0 }; |
diff --git a/libbb/capability.c b/libbb/capability.c index 6587dcbf7..d0ae78b91 100644 --- a/libbb/capability.c +++ b/libbb/capability.c | |||
@@ -67,7 +67,7 @@ unsigned FAST_FUNC cap_name_to_number(const char *cap) | |||
67 | goto found; | 67 | goto found; |
68 | } | 68 | } |
69 | for (i = 0; i < ARRAY_SIZE(capabilities); i++) { | 69 | for (i = 0; i < ARRAY_SIZE(capabilities); i++) { |
70 | if (strcasecmp(capabilities[i], cap) != 0) | 70 | if (strcasecmp(capabilities[i], cap) == 0) |
71 | goto found; | 71 | goto found; |
72 | } | 72 | } |
73 | bb_error_msg_and_die("unknown capability '%s'", cap); | 73 | bb_error_msg_and_die("unknown capability '%s'", cap); |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 0b4e326d8..0ec9baa5f 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -2462,13 +2462,14 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2462 | timeout = st->timeout; | 2462 | timeout = st->timeout; |
2463 | } | 2463 | } |
2464 | #if MAX_HISTORY > 0 | 2464 | #if MAX_HISTORY > 0 |
2465 | if (state->flags & DO_HISTORY) { | ||
2465 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | 2466 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
2466 | if (state->hist_file) | 2467 | if (state->hist_file) |
2467 | if (state->cnt_history == 0) | 2468 | if (state->cnt_history == 0) |
2468 | load_history(state); | 2469 | load_history(state); |
2469 | # endif | 2470 | # endif |
2470 | if (state->flags & DO_HISTORY) | ||
2471 | state->cur_history = state->cnt_history; | 2471 | state->cur_history = state->cnt_history; |
2472 | } | ||
2472 | #endif | 2473 | #endif |
2473 | 2474 | ||
2474 | /* prepare before init handlers */ | 2475 | /* prepare before init handlers */ |
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 569a6fc34..2d497d754 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c | |||
@@ -297,14 +297,14 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) | |||
297 | dup2(fd, 0); | 297 | dup2(fd, 0); |
298 | dup2(fd, 1); | 298 | dup2(fd, 1); |
299 | dup2(fd, 2); | 299 | dup2(fd, 2); |
300 | if (flags & DAEMON_DOUBLE_FORK) { | 300 | // if (flags & DAEMON_DOUBLE_FORK) { |
301 | /* On Linux, session leader can acquire ctty | 301 | // /* On Linux, session leader can acquire ctty |
302 | * unknowingly, by opening a tty. | 302 | // * unknowingly, by opening a tty. |
303 | * Prevent this: stop being a session leader. | 303 | // * Prevent this: stop being a session leader. |
304 | */ | 304 | // */ |
305 | if (fork_or_rexec(argv)) | 305 | // if (fork_or_rexec(argv)) |
306 | _exit(EXIT_SUCCESS); /* parent */ | 306 | // _exit(EXIT_SUCCESS); /* parent */ |
307 | } | 307 | // } |
308 | } | 308 | } |
309 | while (fd > 2) { | 309 | while (fd > 2) { |
310 | close(fd--); | 310 | close(fd--); |
diff --git a/loginutils/adduser.c b/loginutils/adduser.c index b2b5be5b3..850c810c4 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c | |||
@@ -198,7 +198,7 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) | |||
198 | 198 | ||
199 | pw.pw_gecos = (char *)"Linux User,,,"; | 199 | pw.pw_gecos = (char *)"Linux User,,,"; |
200 | /* We assume that newly created users "inherit" root's shell setting */ | 200 | /* We assume that newly created users "inherit" root's shell setting */ |
201 | pw.pw_shell = (char *)get_shell_name(); | 201 | pw.pw_shell = xstrdup(get_shell_name()); /* might come from getpwnam(), need to make a copy */ |
202 | pw.pw_dir = NULL; | 202 | pw.pw_dir = NULL; |
203 | 203 | ||
204 | opts = getopt32long(argv, "^" | 204 | opts = getopt32long(argv, "^" |
diff --git a/loginutils/login.c b/loginutils/login.c index 25bb5203b..4df651cc6 100644 --- a/loginutils/login.c +++ b/loginutils/login.c | |||
@@ -245,7 +245,9 @@ static void login_pam_end(pam_handle_t *pamh) | |||
245 | pam_strerror(pamh, pamret), pamret); | 245 | pam_strerror(pamh, pamret), pamret); |
246 | } | 246 | } |
247 | } | 247 | } |
248 | #endif /* ENABLE_PAM */ | 248 | #else |
249 | # define login_pam_end(pamh) ((void)0) | ||
250 | #endif | ||
249 | 251 | ||
250 | static void get_username_or_die(char *buf, int size_buf) | 252 | static void get_username_or_die(char *buf, int size_buf) |
251 | { | 253 | { |
@@ -471,6 +473,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
471 | * to know _why_ login failed */ | 473 | * to know _why_ login failed */ |
472 | syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg, | 474 | syslog(LOG_WARNING, "pam_%s call failed: %s (%d)", failed_msg, |
473 | pam_strerror(pamh, pamret), pamret); | 475 | pam_strerror(pamh, pamret), pamret); |
476 | login_pam_end(pamh); | ||
474 | safe_strncpy(username, "UNKNOWN", sizeof(username)); | 477 | safe_strncpy(username, "UNKNOWN", sizeof(username)); |
475 | #else /* not PAM */ | 478 | #else /* not PAM */ |
476 | pw = getpwnam(username); | 479 | pw = getpwnam(username); |
@@ -528,8 +531,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) | |||
528 | if (child_pid < 0) | 531 | if (child_pid < 0) |
529 | bb_perror_msg("vfork"); | 532 | bb_perror_msg("vfork"); |
530 | else { | 533 | else { |
531 | if (safe_waitpid(child_pid, NULL, 0) == -1) | 534 | wait_for_exitstatus(child_pid); |
532 | bb_perror_msg("waitpid"); | ||
533 | update_utmp_DEAD_PROCESS(child_pid); | 535 | update_utmp_DEAD_PROCESS(child_pid); |
534 | } | 536 | } |
535 | IF_PAM(login_pam_end(pamh);) | 537 | IF_PAM(login_pam_end(pamh);) |
diff --git a/miscutils/bc.c b/miscutils/bc.c index 7fecb264d..36e978ed8 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -4,8 +4,8 @@ | |||
4 | * Adapted from https://github.com/gavinhoward/bc | 4 | * Adapted from https://github.com/gavinhoward/bc |
5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. | 5 | * Original code copyright (c) 2018 Gavin D. Howard and contributors. |
6 | */ | 6 | */ |
7 | //TODO: GNU extensions: | 7 | //TODO: |
8 | // support "define f(*param[])" - "pass array by reference" syntax | 8 | // maybe implement a^b for non-integer b? |
9 | 9 | ||
10 | #define DEBUG_LEXER 0 | 10 | #define DEBUG_LEXER 0 |
11 | #define DEBUG_COMPILE 0 | 11 | #define DEBUG_COMPILE 0 |
@@ -380,6 +380,12 @@ typedef struct BcInstPtr { | |||
380 | size_t inst_idx; | 380 | size_t inst_idx; |
381 | } BcInstPtr; | 381 | } BcInstPtr; |
382 | 382 | ||
383 | typedef enum BcType { | ||
384 | BC_TYPE_VAR, | ||
385 | BC_TYPE_ARRAY, | ||
386 | BC_TYPE_REF, | ||
387 | } BcType; | ||
388 | |||
383 | typedef enum BcLexType { | 389 | typedef enum BcLexType { |
384 | XC_LEX_EOF, | 390 | XC_LEX_EOF, |
385 | XC_LEX_INVALID, | 391 | XC_LEX_INVALID, |
@@ -1092,15 +1098,25 @@ static void bc_vec_pop_all(BcVec *v) | |||
1092 | bc_vec_npop(v, v->len); | 1098 | bc_vec_npop(v, v->len); |
1093 | } | 1099 | } |
1094 | 1100 | ||
1095 | static size_t bc_vec_push(BcVec *v, const void *data) | 1101 | static size_t bc_vec_npush(BcVec *v, size_t n, const void *data) |
1096 | { | 1102 | { |
1097 | size_t len = v->len; | 1103 | size_t len = v->len; |
1098 | if (len >= v->cap) bc_vec_grow(v, 1); | 1104 | if (len + n > v->cap) bc_vec_grow(v, n); |
1099 | memmove(v->v + (v->size * len), data, v->size); | 1105 | memmove(v->v + (v->size * len), data, v->size * n); |
1100 | v->len++; | 1106 | v->len = len + n; |
1101 | return len; | 1107 | return len; |
1102 | } | 1108 | } |
1103 | 1109 | ||
1110 | static size_t bc_vec_push(BcVec *v, const void *data) | ||
1111 | { | ||
1112 | return bc_vec_npush(v, 1, data); | ||
1113 | //size_t len = v->len; | ||
1114 | //if (len >= v->cap) bc_vec_grow(v, 1); | ||
1115 | //memmove(v->v + (v->size * len), data, v->size); | ||
1116 | //v->len = len + 1; | ||
1117 | //return len; | ||
1118 | } | ||
1119 | |||
1104 | // G.prog.results often needs "pop old operand, push result" idiom. | 1120 | // G.prog.results often needs "pop old operand, push result" idiom. |
1105 | // Can do this without a few extra ops | 1121 | // Can do this without a few extra ops |
1106 | static size_t bc_result_pop_and_push(const void *data) | 1122 | static size_t bc_result_pop_and_push(const void *data) |
@@ -3528,14 +3544,14 @@ static void xc_parse_pushName(char *name) | |||
3528 | // (The above describes 32-bit case). | 3544 | // (The above describes 32-bit case). |
3529 | #define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) | 3545 | #define SMALL_INDEX_LIMIT (0x100 - sizeof(size_t)) |
3530 | 3546 | ||
3531 | static void xc_parse_pushIndex(size_t idx) | 3547 | static void bc_vec_pushIndex(BcVec *v, size_t idx) |
3532 | { | 3548 | { |
3533 | size_t mask; | 3549 | size_t mask; |
3534 | unsigned amt; | 3550 | unsigned amt; |
3535 | 3551 | ||
3536 | dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); | 3552 | dbg_lex("%s:%d pushing index %zd", __func__, __LINE__, idx); |
3537 | if (idx < SMALL_INDEX_LIMIT) { | 3553 | if (idx < SMALL_INDEX_LIMIT) { |
3538 | xc_parse_push(idx); | 3554 | bc_vec_pushByte(v, idx); |
3539 | return; | 3555 | return; |
3540 | } | 3556 | } |
3541 | 3557 | ||
@@ -3548,14 +3564,19 @@ static void xc_parse_pushIndex(size_t idx) | |||
3548 | } | 3564 | } |
3549 | // amt is at least 1 here - "one byte of length data follows" | 3565 | // amt is at least 1 here - "one byte of length data follows" |
3550 | 3566 | ||
3551 | xc_parse_push((SMALL_INDEX_LIMIT - 1) + amt); | 3567 | bc_vec_pushByte(v, (SMALL_INDEX_LIMIT - 1) + amt); |
3552 | 3568 | ||
3553 | do { | 3569 | do { |
3554 | xc_parse_push((unsigned char)idx); | 3570 | bc_vec_pushByte(v, (unsigned char)idx); |
3555 | idx >>= 8; | 3571 | idx >>= 8; |
3556 | } while (idx != 0); | 3572 | } while (idx != 0); |
3557 | } | 3573 | } |
3558 | 3574 | ||
3575 | static void xc_parse_pushIndex(size_t idx) | ||
3576 | { | ||
3577 | bc_vec_pushIndex(&G.prs.func->code, idx); | ||
3578 | } | ||
3579 | |||
3559 | static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) | 3580 | static void xc_parse_pushInst_and_Index(unsigned inst, size_t idx) |
3560 | { | 3581 | { |
3561 | xc_parse_push(inst); | 3582 | xc_parse_push(inst); |
@@ -4340,7 +4361,7 @@ static BC_STATUS zbc_parse_break_or_continue(BcLexType type) | |||
4340 | } | 4361 | } |
4341 | #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) | 4362 | #define zbc_parse_break_or_continue(...) (zbc_parse_break_or_continue(__VA_ARGS__) COMMA_SUCCESS) |
4342 | 4363 | ||
4343 | static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) | 4364 | static BC_STATUS zbc_func_insert(BcFunc *f, char *name, BcType type) |
4344 | { | 4365 | { |
4345 | BcId *autoid; | 4366 | BcId *autoid; |
4346 | BcId a; | 4367 | BcId a; |
@@ -4349,13 +4370,13 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var) | |||
4349 | autoid = (void*)f->autos.v; | 4370 | autoid = (void*)f->autos.v; |
4350 | for (i = 0; i < f->autos.len; i++, autoid++) { | 4371 | for (i = 0; i < f->autos.len; i++, autoid++) { |
4351 | if (strcmp(name, autoid->name) == 0 | 4372 | if (strcmp(name, autoid->name) == 0 |
4352 | && var == autoid->idx | 4373 | && type == (BcType) autoid->idx |
4353 | ) { | 4374 | ) { |
4354 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); | 4375 | RETURN_STATUS(bc_error("duplicate function parameter or auto name")); |
4355 | } | 4376 | } |
4356 | } | 4377 | } |
4357 | 4378 | ||
4358 | a.idx = var; | 4379 | a.idx = type; |
4359 | a.name = name; | 4380 | a.name = name; |
4360 | 4381 | ||
4361 | bc_vec_push(&f->autos, &a); | 4382 | bc_vec_push(&f->autos, &a); |
@@ -4368,7 +4389,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4368 | { | 4389 | { |
4369 | BcParse *p = &G.prs; | 4390 | BcParse *p = &G.prs; |
4370 | BcStatus s; | 4391 | BcStatus s; |
4371 | bool var, comma, voidfunc; | 4392 | bool comma, voidfunc; |
4372 | char *name; | 4393 | char *name; |
4373 | 4394 | ||
4374 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); | 4395 | dbg_lex_enter("%s:%d entered", __func__, __LINE__); |
@@ -4406,6 +4427,16 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4406 | 4427 | ||
4407 | comma = false; | 4428 | comma = false; |
4408 | while (p->lex != BC_LEX_RPAREN) { | 4429 | while (p->lex != BC_LEX_RPAREN) { |
4430 | BcType t = BC_TYPE_VAR; | ||
4431 | |||
4432 | if (p->lex == XC_LEX_OP_MULTIPLY) { | ||
4433 | t = BC_TYPE_REF; | ||
4434 | s = zxc_lex_next(); | ||
4435 | if (s) RETURN_STATUS(s); | ||
4436 | s = zbc_POSIX_does_not_allow("references"); | ||
4437 | if (s) RETURN_STATUS(s); | ||
4438 | } | ||
4439 | |||
4409 | if (p->lex != XC_LEX_NAME) | 4440 | if (p->lex != XC_LEX_NAME) |
4410 | RETURN_STATUS(bc_error_bad_function_definition()); | 4441 | RETURN_STATUS(bc_error_bad_function_definition()); |
4411 | 4442 | ||
@@ -4415,9 +4446,8 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4415 | s = zxc_lex_next(); | 4446 | s = zxc_lex_next(); |
4416 | if (s) goto err; | 4447 | if (s) goto err; |
4417 | 4448 | ||
4418 | var = p->lex != BC_LEX_LBRACKET; | 4449 | if (p->lex == BC_LEX_LBRACKET) { |
4419 | 4450 | if (t == BC_TYPE_VAR) t = BC_TYPE_ARRAY; | |
4420 | if (!var) { | ||
4421 | s = zxc_lex_next(); | 4451 | s = zxc_lex_next(); |
4422 | if (s) goto err; | 4452 | if (s) goto err; |
4423 | 4453 | ||
@@ -4429,6 +4459,10 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4429 | s = zxc_lex_next(); | 4459 | s = zxc_lex_next(); |
4430 | if (s) goto err; | 4460 | if (s) goto err; |
4431 | } | 4461 | } |
4462 | else if (t == BC_TYPE_REF) { | ||
4463 | s = bc_error_at("vars can't be references"); | ||
4464 | goto err; | ||
4465 | } | ||
4432 | 4466 | ||
4433 | comma = p->lex == BC_LEX_COMMA; | 4467 | comma = p->lex == BC_LEX_COMMA; |
4434 | if (comma) { | 4468 | if (comma) { |
@@ -4436,7 +4470,7 @@ static BC_STATUS zbc_parse_funcdef(void) | |||
4436 | if (s) goto err; | 4470 | if (s) goto err; |
4437 | } | 4471 | } |
4438 | 4472 | ||
4439 | s = zbc_func_insert(p->func, name, var); | 4473 | s = zbc_func_insert(p->func, name, t); |
4440 | if (s) goto err; | 4474 | if (s) goto err; |
4441 | } | 4475 | } |
4442 | 4476 | ||
@@ -4488,7 +4522,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4488 | if (s) RETURN_STATUS(s); | 4522 | if (s) RETURN_STATUS(s); |
4489 | 4523 | ||
4490 | for (;;) { | 4524 | for (;;) { |
4491 | bool var; | 4525 | BcType t; |
4492 | 4526 | ||
4493 | if (p->lex != XC_LEX_NAME) | 4527 | if (p->lex != XC_LEX_NAME) |
4494 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); | 4528 | RETURN_STATUS(bc_error_at("bad 'auto' syntax")); |
@@ -4497,8 +4531,9 @@ static BC_STATUS zbc_parse_auto(void) | |||
4497 | s = zxc_lex_next(); | 4531 | s = zxc_lex_next(); |
4498 | if (s) goto err; | 4532 | if (s) goto err; |
4499 | 4533 | ||
4500 | var = (p->lex != BC_LEX_LBRACKET); | 4534 | t = BC_TYPE_VAR; |
4501 | if (!var) { | 4535 | if (p->lex == BC_LEX_LBRACKET) { |
4536 | t = BC_TYPE_ARRAY; | ||
4502 | s = zxc_lex_next(); | 4537 | s = zxc_lex_next(); |
4503 | if (s) goto err; | 4538 | if (s) goto err; |
4504 | 4539 | ||
@@ -4510,7 +4545,7 @@ static BC_STATUS zbc_parse_auto(void) | |||
4510 | if (s) goto err; | 4545 | if (s) goto err; |
4511 | } | 4546 | } |
4512 | 4547 | ||
4513 | s = zbc_func_insert(p->func, name, var); | 4548 | s = zbc_func_insert(p->func, name, t); |
4514 | if (s) goto err; | 4549 | if (s) goto err; |
4515 | 4550 | ||
4516 | if (p->lex == XC_LEX_NLINE | 4551 | if (p->lex == XC_LEX_NLINE |
@@ -5119,12 +5154,64 @@ static BC_STATUS zdc_parse_exprs_until_eof(void) | |||
5119 | #define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) | 5154 | #define STACK_HAS_MORE_THAN(s, n) ((s)->len > ((size_t)(n))) |
5120 | #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) | 5155 | #define STACK_HAS_EQUAL_OR_MORE_THAN(s, n) ((s)->len >= ((size_t)(n))) |
5121 | 5156 | ||
5122 | static BcVec* xc_program_search(char *id, bool var) | 5157 | static size_t xc_program_index(char *code, size_t *bgn) |
5158 | { | ||
5159 | unsigned char *bytes = (void*)(code + *bgn); | ||
5160 | unsigned amt; | ||
5161 | unsigned i; | ||
5162 | size_t res; | ||
5163 | |||
5164 | amt = *bytes++; | ||
5165 | if (amt < SMALL_INDEX_LIMIT) { | ||
5166 | *bgn += 1; | ||
5167 | return amt; | ||
5168 | } | ||
5169 | amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here | ||
5170 | *bgn += amt + 1; | ||
5171 | |||
5172 | res = 0; | ||
5173 | i = 0; | ||
5174 | do { | ||
5175 | res |= (size_t)(*bytes++) << i; | ||
5176 | i += 8; | ||
5177 | } while (--amt != 0); | ||
5178 | |||
5179 | return res; | ||
5180 | } | ||
5181 | |||
5182 | static char *xc_program_name(char *code, size_t *bgn) | ||
5183 | { | ||
5184 | code += *bgn; | ||
5185 | *bgn += strlen(code) + 1; | ||
5186 | |||
5187 | return xstrdup(code); | ||
5188 | } | ||
5189 | |||
5190 | static BcVec* xc_program_dereference(BcVec *vec) | ||
5191 | { | ||
5192 | BcVec *v; | ||
5193 | size_t vidx, nidx, i = 0; | ||
5194 | |||
5195 | //assert(vec->size == sizeof(uint8_t)); | ||
5196 | |||
5197 | vidx = xc_program_index(vec->v, &i); | ||
5198 | nidx = xc_program_index(vec->v, &i); | ||
5199 | |||
5200 | v = bc_vec_item(&G.prog.arrs, vidx); | ||
5201 | v = bc_vec_item(v, nidx); | ||
5202 | |||
5203 | //assert(v->size != sizeof(uint8_t)); | ||
5204 | |||
5205 | return v; | ||
5206 | } | ||
5207 | |||
5208 | static BcVec* xc_program_search(char *id, BcType type) | ||
5123 | { | 5209 | { |
5124 | BcId e, *ptr; | 5210 | BcId e, *ptr; |
5125 | BcVec *v, *map; | 5211 | BcVec *v, *map; |
5126 | size_t i; | 5212 | size_t i; |
5127 | int new; | 5213 | int new; |
5214 | bool var = (type == BC_TYPE_VAR); | ||
5128 | 5215 | ||
5129 | v = var ? &G.prog.vars : &G.prog.arrs; | 5216 | v = var ? &G.prog.vars : &G.prog.arrs; |
5130 | map = var ? &G.prog.var_map : &G.prog.arr_map; | 5217 | map = var ? &G.prog.var_map : &G.prog.arr_map; |
@@ -5178,17 +5265,20 @@ static BC_STATUS zxc_program_num(BcResult *r, BcNum **num) | |||
5178 | case XC_RESULT_VAR: | 5265 | case XC_RESULT_VAR: |
5179 | case XC_RESULT_ARRAY: | 5266 | case XC_RESULT_ARRAY: |
5180 | case XC_RESULT_ARRAY_ELEM: { | 5267 | case XC_RESULT_ARRAY_ELEM: { |
5181 | BcVec *v; | 5268 | BcType type = (r->t == XC_RESULT_VAR) ? BC_TYPE_VAR : BC_TYPE_ARRAY; |
5182 | void *p; | 5269 | BcVec *v = xc_program_search(r->d.id.name, type); |
5183 | v = xc_program_search(r->d.id.name, r->t == XC_RESULT_VAR); | 5270 | void *p = bc_vec_top(v); |
5184 | // dc variables are all stacks, so here we have this: | 5271 | |
5185 | p = bc_vec_top(v); | ||
5186 | // TODO: eliminate these stacks for bc-only config? | ||
5187 | if (r->t == XC_RESULT_ARRAY_ELEM) { | 5272 | if (r->t == XC_RESULT_ARRAY_ELEM) { |
5273 | size_t idx = r->d.id.idx; | ||
5274 | |||
5188 | v = p; | 5275 | v = p; |
5189 | if (v->len <= r->d.id.idx) | 5276 | if (v->size == sizeof(uint8_t)) |
5190 | bc_array_expand(v, r->d.id.idx + 1); | 5277 | v = xc_program_dereference(v); |
5191 | *num = bc_vec_item(v, r->d.id.idx); | 5278 | //assert(v->size == sizeof(BcNum)); |
5279 | if (v->len <= idx) | ||
5280 | bc_array_expand(v, idx + 1); | ||
5281 | *num = bc_vec_item(v, idx); | ||
5192 | } else { | 5282 | } else { |
5193 | *num = p; | 5283 | *num = p; |
5194 | } | 5284 | } |
@@ -5347,39 +5437,6 @@ static BC_STATUS zxc_program_read(void) | |||
5347 | } | 5437 | } |
5348 | #define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) | 5438 | #define zxc_program_read(...) (zxc_program_read(__VA_ARGS__) COMMA_SUCCESS) |
5349 | 5439 | ||
5350 | static size_t xc_program_index(char *code, size_t *bgn) | ||
5351 | { | ||
5352 | unsigned char *bytes = (void*)(code + *bgn); | ||
5353 | unsigned amt; | ||
5354 | unsigned i; | ||
5355 | size_t res; | ||
5356 | |||
5357 | amt = *bytes++; | ||
5358 | if (amt < SMALL_INDEX_LIMIT) { | ||
5359 | *bgn += 1; | ||
5360 | return amt; | ||
5361 | } | ||
5362 | amt -= (SMALL_INDEX_LIMIT - 1); // amt is 1 or more here | ||
5363 | *bgn += amt + 1; | ||
5364 | |||
5365 | res = 0; | ||
5366 | i = 0; | ||
5367 | do { | ||
5368 | res |= (size_t)(*bytes++) << i; | ||
5369 | i += 8; | ||
5370 | } while (--amt != 0); | ||
5371 | |||
5372 | return res; | ||
5373 | } | ||
5374 | |||
5375 | static char *xc_program_name(char *code, size_t *bgn) | ||
5376 | { | ||
5377 | code += *bgn; | ||
5378 | *bgn += strlen(code) + 1; | ||
5379 | |||
5380 | return xstrdup(code); | ||
5381 | } | ||
5382 | |||
5383 | static void xc_program_printString(const char *str) | 5440 | static void xc_program_printString(const char *str) |
5384 | { | 5441 | { |
5385 | #if ENABLE_DC | 5442 | #if ENABLE_DC |
@@ -5755,43 +5812,81 @@ static BC_STATUS zdc_program_assignStr(BcResult *r, BcVec *v, bool push) | |||
5755 | #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) | 5812 | #define zdc_program_assignStr(...) (zdc_program_assignStr(__VA_ARGS__) COMMA_SUCCESS) |
5756 | #endif // ENABLE_DC | 5813 | #endif // ENABLE_DC |
5757 | 5814 | ||
5758 | static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, bool var) | 5815 | static BC_STATUS zxc_program_popResultAndCopyToVar(char *name, BcType t) |
5759 | { | 5816 | { |
5760 | BcStatus s; | 5817 | BcStatus s; |
5761 | BcResult *ptr, r; | 5818 | BcResult *ptr, r; |
5762 | BcVec *v; | 5819 | BcVec *vec; |
5763 | BcNum *n; | 5820 | BcNum *n; |
5821 | bool var = (t == BC_TYPE_VAR); | ||
5764 | 5822 | ||
5765 | if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) | 5823 | if (!STACK_HAS_MORE_THAN(&G.prog.results, 0)) |
5766 | RETURN_STATUS(bc_error_stack_has_too_few_elements()); | 5824 | RETURN_STATUS(bc_error_stack_has_too_few_elements()); |
5767 | 5825 | ||
5768 | ptr = bc_vec_top(&G.prog.results); | 5826 | ptr = bc_vec_top(&G.prog.results); |
5769 | if ((ptr->t == XC_RESULT_ARRAY) != !var) | 5827 | if ((ptr->t == XC_RESULT_ARRAY) == var) |
5770 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5828 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5771 | v = xc_program_search(name, var); | 5829 | vec = xc_program_search(name, t); |
5772 | 5830 | ||
5773 | #if ENABLE_DC | 5831 | #if ENABLE_DC |
5774 | if (ptr->t == XC_RESULT_STR && !var) | 5832 | if (ptr->t == XC_RESULT_STR) { |
5775 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5833 | if (!var) |
5776 | if (ptr->t == XC_RESULT_STR) | 5834 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5777 | RETURN_STATUS(zdc_program_assignStr(ptr, v, true)); | 5835 | RETURN_STATUS(zdc_program_assignStr(ptr, vec, true)); |
5836 | } | ||
5778 | #endif | 5837 | #endif |
5779 | 5838 | ||
5780 | s = zxc_program_num(ptr, &n); | 5839 | s = zxc_program_num(ptr, &n); |
5781 | if (s) RETURN_STATUS(s); | 5840 | if (s) RETURN_STATUS(s); |
5782 | 5841 | ||
5783 | // Do this once more to make sure that pointers were not invalidated. | 5842 | // Do this once more to make sure that pointers were not invalidated. |
5784 | v = xc_program_search(name, var); | 5843 | vec = xc_program_search(name, t); |
5785 | 5844 | ||
5786 | if (var) { | 5845 | if (var) { |
5787 | bc_num_init_DEF_SIZE(&r.d.n); | 5846 | bc_num_init_DEF_SIZE(&r.d.n); |
5788 | bc_num_copy(&r.d.n, n); | 5847 | bc_num_copy(&r.d.n, n); |
5789 | } else { | 5848 | } else { |
5849 | BcVec *v = (BcVec*) n; | ||
5850 | bool ref, ref_size; | ||
5851 | |||
5852 | ref = (v->size == sizeof(BcVec) && t != BC_TYPE_ARRAY); | ||
5853 | ref_size = (v->size == sizeof(uint8_t)); | ||
5854 | |||
5855 | if (ref || (ref_size && t == BC_TYPE_REF)) { | ||
5856 | bc_vec_init(&r.d.v, sizeof(uint8_t), NULL); | ||
5857 | if (ref) { | ||
5858 | size_t vidx, idx; | ||
5859 | BcId id; | ||
5860 | |||
5861 | id.name = ptr->d.id.name; | ||
5862 | v = xc_program_search(ptr->d.id.name, BC_TYPE_REF); | ||
5863 | |||
5864 | // Make sure the pointer was not invalidated. | ||
5865 | vec = xc_program_search(name, t); | ||
5866 | |||
5867 | vidx = bc_map_find_exact(&G.prog.arr_map, &id); | ||
5868 | //assert(vidx != BC_VEC_INVALID_IDX); | ||
5869 | vidx = ((BcId*) bc_vec_item(&G.prog.arr_map, vidx))->idx; | ||
5870 | idx = v->len - 1; | ||
5871 | |||
5872 | bc_vec_pushIndex(&r.d.v, vidx); | ||
5873 | bc_vec_pushIndex(&r.d.v, idx); | ||
5874 | } | ||
5875 | // If we get here, we are copying a ref to a ref. | ||
5876 | else bc_vec_npush(&r.d.v, v->len, v->v); | ||
5877 | |||
5878 | // We need to return early. | ||
5879 | goto ret; | ||
5880 | } | ||
5881 | |||
5882 | if (ref_size && t != BC_TYPE_REF) | ||
5883 | v = xc_program_dereference(v); | ||
5884 | |||
5790 | bc_array_init(&r.d.v, true); | 5885 | bc_array_init(&r.d.v, true); |
5791 | bc_array_copy(&r.d.v, (BcVec *) n); | 5886 | bc_array_copy(&r.d.v, v); |
5792 | } | 5887 | } |
5793 | 5888 | ret: | |
5794 | bc_vec_push(v, &r.d); | 5889 | bc_vec_push(vec, &r.d); |
5795 | bc_vec_pop(&G.prog.results); | 5890 | bc_vec_pop(&G.prog.results); |
5796 | 5891 | ||
5797 | RETURN_STATUS(s); | 5892 | RETURN_STATUS(s); |
@@ -5818,7 +5913,7 @@ static BC_STATUS zxc_program_assign(char inst) | |||
5818 | 5913 | ||
5819 | if (left->t != XC_RESULT_VAR) | 5914 | if (left->t != XC_RESULT_VAR) |
5820 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 5915 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
5821 | v = xc_program_search(left->d.id.name, true); | 5916 | v = xc_program_search(left->d.id.name, BC_TYPE_VAR); |
5822 | 5917 | ||
5823 | RETURN_STATUS(zdc_program_assignStr(right, v, false)); | 5918 | RETURN_STATUS(zdc_program_assignStr(right, v, false)); |
5824 | } | 5919 | } |
@@ -5897,7 +5992,7 @@ static BC_STATUS xc_program_pushVar(char *code, size_t *bgn, | |||
5897 | 5992 | ||
5898 | #if ENABLE_DC | 5993 | #if ENABLE_DC |
5899 | if (pop || copy) { | 5994 | if (pop || copy) { |
5900 | BcVec *v = xc_program_search(name, true); | 5995 | BcVec *v = xc_program_search(name, BC_TYPE_VAR); |
5901 | BcNum *num = bc_vec_top(v); | 5996 | BcNum *num = bc_vec_top(v); |
5902 | 5997 | ||
5903 | free(name); | 5998 | free(name); |
@@ -6014,16 +6109,19 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) | |||
6014 | for (i = 0; i < nparams; ++i) { | 6109 | for (i = 0; i < nparams; ++i) { |
6015 | BcResult *arg; | 6110 | BcResult *arg; |
6016 | BcStatus s; | 6111 | BcStatus s; |
6112 | bool arr; | ||
6017 | 6113 | ||
6018 | a = bc_vec_item(&func->autos, nparams - 1 - i); | 6114 | a = bc_vec_item(&func->autos, nparams - 1 - i); |
6019 | arg = bc_vec_top(&G.prog.results); | 6115 | arg = bc_vec_top(&G.prog.results); |
6020 | 6116 | ||
6021 | if ((!a->idx) != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch | 6117 | arr = (a->idx == BC_TYPE_ARRAY || a->idx == BC_TYPE_REF); |
6118 | |||
6119 | if (arr != (arg->t == XC_RESULT_ARRAY) // array/variable mismatch | ||
6022 | // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) | 6120 | // || arg->t == XC_RESULT_STR - impossible, f("str") is not a legal syntax (strings are not bc expressions) |
6023 | ) { | 6121 | ) { |
6024 | RETURN_STATUS(bc_error_variable_is_wrong_type()); | 6122 | RETURN_STATUS(bc_error_variable_is_wrong_type()); |
6025 | } | 6123 | } |
6026 | s = zxc_program_popResultAndCopyToVar(a->name, a->idx); | 6124 | s = zxc_program_popResultAndCopyToVar(a->name, (BcType) a->idx); |
6027 | if (s) RETURN_STATUS(s); | 6125 | if (s) RETURN_STATUS(s); |
6028 | } | 6126 | } |
6029 | 6127 | ||
@@ -6031,12 +6129,13 @@ static BC_STATUS zbc_program_call(char *code, size_t *idx) | |||
6031 | for (; i < func->autos.len; i++, a++) { | 6129 | for (; i < func->autos.len; i++, a++) { |
6032 | BcVec *v; | 6130 | BcVec *v; |
6033 | 6131 | ||
6034 | v = xc_program_search(a->name, a->idx); | 6132 | v = xc_program_search(a->name, (BcType) a->idx); |
6035 | if (a->idx) { | 6133 | if (a->idx == BC_TYPE_VAR) { |
6036 | BcNum n2; | 6134 | BcNum n2; |
6037 | bc_num_init_DEF_SIZE(&n2); | 6135 | bc_num_init_DEF_SIZE(&n2); |
6038 | bc_vec_push(v, &n2); | 6136 | bc_vec_push(v, &n2); |
6039 | } else { | 6137 | } else { |
6138 | //assert(a->idx == BC_TYPE_ARRAY); | ||
6040 | BcVec v2; | 6139 | BcVec v2; |
6041 | bc_array_init(&v2, true); | 6140 | bc_array_init(&v2, true); |
6042 | bc_vec_push(v, &v2); | 6141 | bc_vec_push(v, &v2); |
@@ -6087,7 +6186,7 @@ static BC_STATUS zbc_program_return(char inst) | |||
6087 | a = (void*)f->autos.v; | 6186 | a = (void*)f->autos.v; |
6088 | for (i = 0; i < f->autos.len; i++, a++) { | 6187 | for (i = 0; i < f->autos.len; i++, a++) { |
6089 | BcVec *v; | 6188 | BcVec *v; |
6090 | v = xc_program_search(a->name, a->idx); | 6189 | v = xc_program_search(a->name, (BcType) a->idx); |
6091 | bc_vec_pop(v); | 6190 | bc_vec_pop(v); |
6092 | } | 6191 | } |
6093 | 6192 | ||
@@ -6399,7 +6498,7 @@ static BC_STATUS zdc_program_execStr(char *code, size_t *bgn, bool cond) | |||
6399 | 6498 | ||
6400 | if (exec) { | 6499 | if (exec) { |
6401 | BcVec *v; | 6500 | BcVec *v; |
6402 | v = xc_program_search(name, true); | 6501 | v = xc_program_search(name, BC_TYPE_VAR); |
6403 | n = bc_vec_top(v); | 6502 | n = bc_vec_top(v); |
6404 | } | 6503 | } |
6405 | 6504 | ||
@@ -6724,7 +6823,7 @@ static BC_STATUS zxc_program_exec(void) | |||
6724 | } | 6823 | } |
6725 | case DC_INST_PUSH_TO_VAR: { | 6824 | case DC_INST_PUSH_TO_VAR: { |
6726 | char *name = xc_program_name(code, &ip->inst_idx); | 6825 | char *name = xc_program_name(code, &ip->inst_idx); |
6727 | s = zxc_program_popResultAndCopyToVar(name, true); | 6826 | s = zxc_program_popResultAndCopyToVar(name, BC_TYPE_VAR); |
6728 | free(name); | 6827 | free(name); |
6729 | break; | 6828 | break; |
6730 | } | 6829 | } |
diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 610fed5d6..7a2e8534a 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c | |||
@@ -36,17 +36,26 @@ | |||
36 | //config: help | 36 | //config: help |
37 | //config: Detect I2C chips. | 37 | //config: Detect I2C chips. |
38 | //config: | 38 | //config: |
39 | //config:config I2CTRANSFER | ||
40 | //config: bool "i2ctransfer (4.0 kb)" | ||
41 | //config: default y | ||
42 | //config: select PLATFORM_LINUX | ||
43 | //config: help | ||
44 | //config: Send user-defined I2C messages in one transfer. | ||
45 | //config: | ||
39 | 46 | ||
40 | //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 47 | //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
41 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 48 | //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
42 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 49 | //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
43 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) | 50 | //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
51 | //applet:IF_I2CTRANSFER(APPLET(i2ctransfer, BB_DIR_USR_SBIN, BB_SUID_DROP)) | ||
44 | /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ | 52 | /* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ |
45 | 53 | ||
46 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o | 54 | //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o |
47 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o | 55 | //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o |
48 | //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o | 56 | //kbuild:lib-$(CONFIG_I2CDUMP) += i2c_tools.o |
49 | //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o | 57 | //kbuild:lib-$(CONFIG_I2CDETECT) += i2c_tools.o |
58 | //kbuild:lib-$(CONFIG_I2CTRANSFER) += i2c_tools.o | ||
50 | 59 | ||
51 | /* | 60 | /* |
52 | * Unsupported stuff: | 61 | * Unsupported stuff: |
@@ -80,12 +89,19 @@ | |||
80 | #define I2C_FUNCS 0x0705 | 89 | #define I2C_FUNCS 0x0705 |
81 | #define I2C_PEC 0x0708 | 90 | #define I2C_PEC 0x0708 |
82 | #define I2C_SMBUS 0x0720 | 91 | #define I2C_SMBUS 0x0720 |
92 | #define I2C_RDWR 0x0707 | ||
93 | #define I2C_RDWR_IOCTL_MAX_MSGS 42 | ||
94 | #define I2C_RDWR_IOCTL_MAX_MSGS_STR "42" | ||
83 | struct i2c_smbus_ioctl_data { | 95 | struct i2c_smbus_ioctl_data { |
84 | __u8 read_write; | 96 | __u8 read_write; |
85 | __u8 command; | 97 | __u8 command; |
86 | __u32 size; | 98 | __u32 size; |
87 | union i2c_smbus_data *data; | 99 | union i2c_smbus_data *data; |
88 | }; | 100 | }; |
101 | struct i2c_rdwr_ioctl_data { | ||
102 | struct i2c_msg *msgs; /* pointers to i2c_msgs */ | ||
103 | __u32 nmsgs; /* number of i2c_msgs */ | ||
104 | }; | ||
89 | /* end linux/i2c-dev.h */ | 105 | /* end linux/i2c-dev.h */ |
90 | 106 | ||
91 | /* | 107 | /* |
@@ -262,7 +278,7 @@ static int i2c_bus_lookup(const char *bus_str) | |||
262 | return xstrtou_range(bus_str, 10, 0, 0xfffff); | 278 | return xstrtou_range(bus_str, 10, 0, 0xfffff); |
263 | } | 279 | } |
264 | 280 | ||
265 | #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP | 281 | #if ENABLE_I2CGET || ENABLE_I2CSET || ENABLE_I2CDUMP || ENABLE_I2CTRANSFER |
266 | static int i2c_parse_bus_addr(const char *addr_str) | 282 | static int i2c_parse_bus_addr(const char *addr_str) |
267 | { | 283 | { |
268 | /* Slave address must be in range 0x03 - 0x77. */ | 284 | /* Slave address must be in range 0x03 - 0x77. */ |
@@ -1373,3 +1389,161 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) | |||
1373 | return 0; | 1389 | return 0; |
1374 | } | 1390 | } |
1375 | #endif /* ENABLE_I2CDETECT */ | 1391 | #endif /* ENABLE_I2CDETECT */ |
1392 | |||
1393 | #if ENABLE_I2CTRANSFER | ||
1394 | static void check_i2c_func(int fd) | ||
1395 | { | ||
1396 | unsigned long funcs; | ||
1397 | |||
1398 | get_funcs_matrix(fd, &funcs); | ||
1399 | |||
1400 | if (!(funcs & I2C_FUNC_I2C)) | ||
1401 | bb_error_msg_and_die("adapter does not support I2C transfers"); | ||
1402 | } | ||
1403 | |||
1404 | //usage:#define i2ctransfer_trivial_usage | ||
1405 | //usage: "[-fay] I2CBUS {rLENGTH[@ADDR] | wLENGTH[@ADDR] DATA...}..." | ||
1406 | //usage:#define i2ctransfer_full_usage "\n\n" | ||
1407 | //usage: "Read/write I2C data in one transfer" | ||
1408 | //usage: "\n" | ||
1409 | //usage: "\n -f Force access to busy addresses" | ||
1410 | //usage: "\n -a Force access to non-regular addresses" | ||
1411 | //usage: "\n -y Disable interactive mode" | ||
1412 | int i2ctransfer_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
1413 | int i2ctransfer_main(int argc UNUSED_PARAM, char **argv) | ||
1414 | { | ||
1415 | enum { | ||
1416 | opt_f = (1 << 0), | ||
1417 | opt_y = (1 << 1), | ||
1418 | opt_a = (1 << 2), | ||
1419 | }; | ||
1420 | int bus_num, bus_addr; | ||
1421 | int fd; | ||
1422 | unsigned opts, first, last; | ||
1423 | int nmsgs, nmsgs_sent, i; | ||
1424 | struct i2c_msg msgs[I2C_RDWR_IOCTL_MAX_MSGS]; | ||
1425 | struct i2c_rdwr_ioctl_data rdwr; | ||
1426 | |||
1427 | memset(msgs, 0, sizeof(msgs)); | ||
1428 | |||
1429 | opts = getopt32(argv, "^" | ||
1430 | "fya" | ||
1431 | "\0" "-2" /* minimum 2 args */ | ||
1432 | ); | ||
1433 | first = 0x03; | ||
1434 | last = 0x77; | ||
1435 | if (opts & opt_a) { | ||
1436 | first = 0x00; | ||
1437 | last = 0x7f; | ||
1438 | } | ||
1439 | |||
1440 | argv += optind; | ||
1441 | bus_num = i2c_bus_lookup(argv[0]); | ||
1442 | fd = i2c_dev_open(bus_num); | ||
1443 | check_i2c_func(fd); | ||
1444 | |||
1445 | bus_addr = -1; | ||
1446 | nmsgs = 0; | ||
1447 | while (*++argv) { | ||
1448 | char *arg_ptr; | ||
1449 | unsigned len; | ||
1450 | uint16_t flags; | ||
1451 | char *end; | ||
1452 | |||
1453 | if (nmsgs >= I2C_RDWR_IOCTL_MAX_MSGS) | ||
1454 | bb_error_msg_and_die("too many messages, max: "I2C_RDWR_IOCTL_MAX_MSGS_STR); | ||
1455 | |||
1456 | flags = 0; | ||
1457 | arg_ptr = *argv; | ||
1458 | switch (*arg_ptr++) { | ||
1459 | case 'r': flags |= I2C_M_RD; break; | ||
1460 | case 'w': break; | ||
1461 | default: | ||
1462 | bb_show_usage(); | ||
1463 | } | ||
1464 | |||
1465 | end = strchr(arg_ptr, '@'); | ||
1466 | if (end) *end = '\0'; | ||
1467 | len = xstrtou_range(arg_ptr, 0, 0, 0xffff); | ||
1468 | if (end) { | ||
1469 | bus_addr = xstrtou_range(end + 1, 0, first, last); | ||
1470 | i2c_set_slave_addr(fd, bus_addr, (opts & opt_f)); | ||
1471 | } else { | ||
1472 | /* Reuse last address if possible */ | ||
1473 | if (bus_addr < 0) | ||
1474 | bb_error_msg_and_die("no address given in '%s'", *argv); | ||
1475 | } | ||
1476 | |||
1477 | msgs[nmsgs].addr = bus_addr; | ||
1478 | msgs[nmsgs].flags = flags; | ||
1479 | msgs[nmsgs].len = len; | ||
1480 | if (len) | ||
1481 | msgs[nmsgs].buf = xzalloc(len); | ||
1482 | |||
1483 | if (!(flags & I2C_M_RD)) { | ||
1484 | /* Consume DATA arg(s) */ | ||
1485 | unsigned buf_idx = 0; | ||
1486 | |||
1487 | while (buf_idx < len) { | ||
1488 | uint8_t data8; | ||
1489 | unsigned long data; | ||
1490 | |||
1491 | arg_ptr = *++argv; | ||
1492 | if (!arg_ptr) | ||
1493 | bb_show_usage(); | ||
1494 | data = strtoul(arg_ptr, &end, 0); | ||
1495 | if (data > 0xff || arg_ptr == end) | ||
1496 | bb_error_msg_and_die("invalid data byte '%s'", *argv); | ||
1497 | |||
1498 | data8 = data; | ||
1499 | while (buf_idx < len) { | ||
1500 | msgs[nmsgs].buf[buf_idx++] = data8; | ||
1501 | if (!*end) | ||
1502 | break; | ||
1503 | switch (*end) { | ||
1504 | /* Pseudo randomness (8 bit AXR with a=13 and b=27) */ | ||
1505 | case 'p': | ||
1506 | data8 = (data8 ^ 27) + 13; | ||
1507 | data8 = (data8 << 1) | (data8 >> 7); | ||
1508 | break; | ||
1509 | case '+': data8++; break; | ||
1510 | case '-': data8--; break; | ||
1511 | case '=': break; | ||
1512 | default: | ||
1513 | bb_error_msg_and_die("invalid data byte suffix: '%s'", | ||
1514 | *argv); | ||
1515 | } | ||
1516 | } | ||
1517 | } | ||
1518 | } | ||
1519 | nmsgs++; | ||
1520 | } | ||
1521 | |||
1522 | if (!(opts & opt_y)) | ||
1523 | confirm_action(bus_addr, 0, 0, 0); | ||
1524 | |||
1525 | rdwr.msgs = msgs; | ||
1526 | rdwr.nmsgs = nmsgs; | ||
1527 | nmsgs_sent = ioctl_or_perror_and_die(fd, I2C_RDWR, &rdwr, "I2C_RDWR"); | ||
1528 | if (nmsgs_sent < nmsgs) | ||
1529 | bb_error_msg("warning: only %u/%u messages sent", nmsgs_sent, nmsgs); | ||
1530 | |||
1531 | for (i = 0; i < nmsgs_sent; i++) { | ||
1532 | if (msgs[i].len != 0 && (msgs[i].flags & I2C_M_RD)) { | ||
1533 | int j; | ||
1534 | for (j = 0; j < msgs[i].len - 1; j++) | ||
1535 | printf("0x%02x ", msgs[i].buf[j]); | ||
1536 | /* Print final byte with newline */ | ||
1537 | printf("0x%02x\n", msgs[i].buf[j]); | ||
1538 | } | ||
1539 | } | ||
1540 | |||
1541 | # if ENABLE_FEATURE_CLEAN_UP | ||
1542 | close(fd); | ||
1543 | for (i = 0; i < nmsgs; i++) | ||
1544 | free(msgs[i].buf); | ||
1545 | # endif | ||
1546 | |||
1547 | return 0; | ||
1548 | } | ||
1549 | #endif /* ENABLE_I2CTRANSFER */ | ||
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 9c164a71d..1a1064bdc 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
@@ -490,11 +490,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | |||
490 | ; | 490 | ; |
491 | enum { | 491 | enum { |
492 | ARG_id = 0, | 492 | ARG_id = 0, |
493 | ARG_protocol, | ||
493 | ARG_reorder_hdr, | 494 | ARG_reorder_hdr, |
494 | ARG_gvrp, | 495 | ARG_gvrp, |
495 | ARG_mvrp, | 496 | ARG_mvrp, |
496 | ARG_loose_binding, | 497 | ARG_loose_binding, |
497 | ARG_protocol, | ||
498 | }; | 498 | }; |
499 | enum { | 499 | enum { |
500 | PROTO_8021Q = 0, | 500 | PROTO_8021Q = 0, |
@@ -518,11 +518,11 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | |||
518 | id = get_u16(*argv, "id"); | 518 | id = get_u16(*argv, "id"); |
519 | addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); | 519 | addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); |
520 | } else if (arg == ARG_protocol) { | 520 | } else if (arg == ARG_protocol) { |
521 | arg = index_in_substrings(protocols, *argv); | 521 | arg = index_in_substrings(protocols, str_tolower(*argv)); |
522 | if (arg == PROTO_8021Q) | 522 | if (arg == PROTO_8021Q) |
523 | proto = ETH_P_8021Q; | 523 | proto = htons(ETH_P_8021Q); |
524 | else if (arg == PROTO_8021AD) | 524 | else if (arg == PROTO_8021AD) |
525 | proto = ETH_P_8021AD; | 525 | proto = htons(ETH_P_8021AD); |
526 | else | 526 | else |
527 | bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", | 527 | bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", |
528 | *argv); | 528 | *argv); |
@@ -673,13 +673,19 @@ static int do_add_or_delete(char **argv, const unsigned rtm) | |||
673 | 673 | ||
674 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; | 674 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; |
675 | } | 675 | } |
676 | /* Allow "ip link add dev" and "ip link add name" */ | ||
677 | if (!name_str) | ||
678 | name_str = dev_str; | ||
679 | else if (!dev_str) | ||
680 | dev_str = name_str; | ||
681 | /* else if (!strcmp(name_str, dev_str)) | ||
682 | name_str = dev_str; */ | ||
683 | |||
676 | if (rtm != RTM_NEWLINK) { | 684 | if (rtm != RTM_NEWLINK) { |
677 | if (!dev_str) | 685 | if (!dev_str) |
678 | return 1; /* Need a device to delete */ | 686 | return 1; /* Need a device to delete */ |
679 | req.i.ifi_index = xll_name_to_index(dev_str); | 687 | req.i.ifi_index = xll_name_to_index(dev_str); |
680 | } else { | 688 | } else { |
681 | if (!name_str) | ||
682 | name_str = dev_str; | ||
683 | if (link_str) { | 689 | if (link_str) { |
684 | int idx = xll_name_to_index(link_str); | 690 | int idx = xll_name_to_index(link_str); |
685 | addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); | 691 | addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); |
diff --git a/networking/tls_fe.c b/networking/tls_fe.c index f235082f5..10971bbff 100644 --- a/networking/tls_fe.c +++ b/networking/tls_fe.c | |||
@@ -43,17 +43,13 @@ typedef uint32_t word32; | |||
43 | #if 0 //UNUSED | 43 | #if 0 //UNUSED |
44 | static void fprime_copy(byte *x, const byte *a) | 44 | static void fprime_copy(byte *x, const byte *a) |
45 | { | 45 | { |
46 | int i; | 46 | memcpy(x, a, F25519_SIZE); |
47 | for (i = 0; i < F25519_SIZE; i++) | ||
48 | x[i] = a[i]; | ||
49 | } | 47 | } |
50 | #endif | 48 | #endif |
51 | 49 | ||
52 | static void lm_copy(byte* x, const byte* a) | 50 | static void lm_copy(byte* x, const byte* a) |
53 | { | 51 | { |
54 | int i; | 52 | memcpy(x, a, F25519_SIZE); |
55 | for (i = 0; i < F25519_SIZE; i++) | ||
56 | x[i] = a[i]; | ||
57 | } | 53 | } |
58 | 54 | ||
59 | #if 0 //UNUSED | 55 | #if 0 //UNUSED |
@@ -200,7 +196,7 @@ static void fe_load(byte *x, word32 c) | |||
200 | static void fe_normalize(byte *x) | 196 | static void fe_normalize(byte *x) |
201 | { | 197 | { |
202 | byte minusp[F25519_SIZE]; | 198 | byte minusp[F25519_SIZE]; |
203 | word16 c; | 199 | unsigned c; |
204 | int i; | 200 | int i; |
205 | 201 | ||
206 | /* Reduce using 2^255 = 19 mod p */ | 202 | /* Reduce using 2^255 = 19 mod p */ |
@@ -219,13 +215,13 @@ static void fe_normalize(byte *x) | |||
219 | */ | 215 | */ |
220 | c = 19; | 216 | c = 19; |
221 | 217 | ||
222 | for (i = 0; i + 1 < F25519_SIZE; i++) { | 218 | for (i = 0; i < F25519_SIZE - 1; i++) { |
223 | c += x[i]; | 219 | c += x[i]; |
224 | minusp[i] = (byte)c; | 220 | minusp[i] = (byte)c; |
225 | c >>= 8; | 221 | c >>= 8; |
226 | } | 222 | } |
227 | 223 | ||
228 | c += ((word16)x[i]) - 128; | 224 | c += ((unsigned)x[i]) - 128; |
229 | minusp[31] = (byte)c; | 225 | minusp[31] = (byte)c; |
230 | 226 | ||
231 | /* Load x-p if no underflow */ | 227 | /* Load x-p if no underflow */ |
@@ -234,13 +230,13 @@ static void fe_normalize(byte *x) | |||
234 | 230 | ||
235 | static void lm_add(byte* r, const byte* a, const byte* b) | 231 | static void lm_add(byte* r, const byte* a, const byte* b) |
236 | { | 232 | { |
237 | word16 c = 0; | 233 | unsigned c = 0; |
238 | int i; | 234 | int i; |
239 | 235 | ||
240 | /* Add */ | 236 | /* Add */ |
241 | for (i = 0; i < F25519_SIZE; i++) { | 237 | for (i = 0; i < F25519_SIZE; i++) { |
242 | c >>= 8; | 238 | c >>= 8; |
243 | c += ((word16)a[i]) + ((word16)b[i]); | 239 | c += ((unsigned)a[i]) + ((unsigned)b[i]); |
244 | r[i] = (byte)c; | 240 | r[i] = (byte)c; |
245 | } | 241 | } |
246 | 242 | ||
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index 62f9a2a4a..b68f9394e 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -154,8 +154,8 @@ enum { | |||
154 | //#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */ | 154 | //#define DHCP_STATIC_ROUTES 0x79 /* 121: RFC 3442. (mask,ip,router) tuples */ |
155 | //#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */ | 155 | //#define DHCP_VLAN_ID 0x84 /* 132: 802.1P VLAN ID */ |
156 | //#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */ | 156 | //#define DHCP_VLAN_PRIORITY 0x85 /* 133: 802.1Q VLAN priority */ |
157 | //#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration File */ | 157 | //#define DHCP_PXE_CONF_FILE 0xd1 /* 209: RFC 5071 Configuration file */ |
158 | //#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Configuration File */ | 158 | //#define DHCP_PXE_PATH_PREFIX 0xd2 /* 210: RFC 5071 Path prefix */ |
159 | //#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */ | 159 | //#define DHCP_REBOOT_TIME 0xd3 /* 211: RFC 5071 Reboot time */ |
160 | //#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */ | 160 | //#define DHCP_MS_STATIC_ROUTES 0xf9 /* 249: Microsoft's pre-RFC 3442 code for 0x79? */ |
161 | //#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */ | 161 | //#define DHCP_WPAD 0xfc /* 252: MSIE's Web Proxy Autodiscovery Protocol */ |
diff --git a/networking/wget.c b/networking/wget.c index 3cae1192c..bb70039f9 100644 --- a/networking/wget.c +++ b/networking/wget.c | |||
@@ -248,7 +248,7 @@ struct globals { | |||
248 | * With 512 byte buffer, it was measured to be | 248 | * With 512 byte buffer, it was measured to be |
249 | * an order of magnitude slower than with big one. | 249 | * an order of magnitude slower than with big one. |
250 | */ | 250 | */ |
251 | char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(sizeof(long)); | 251 | char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024] ALIGNED(16); |
252 | } FIX_ALIASING; | 252 | } FIX_ALIASING; |
253 | #define G (*ptr_to_globals) | 253 | #define G (*ptr_to_globals) |
254 | #define INIT_G() do { \ | 254 | #define INIT_G() do { \ |
@@ -388,9 +388,6 @@ static void set_alarm(void) | |||
388 | * is_ip_address() attempts to verify whether or not a string | 388 | * is_ip_address() attempts to verify whether or not a string |
389 | * contains an IPv4 or IPv6 address (vs. an FQDN). The result | 389 | * contains an IPv4 or IPv6 address (vs. an FQDN). The result |
390 | * of inet_pton() can be used to determine this. | 390 | * of inet_pton() can be used to determine this. |
391 | * | ||
392 | * TODO add proper error checking when inet_pton() returns -1 | ||
393 | * (some form of system error has occurred, and errno is set) | ||
394 | */ | 391 | */ |
395 | static int is_ip_address(const char *string) | 392 | static int is_ip_address(const char *string) |
396 | { | 393 | { |
@@ -908,10 +905,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
908 | polldata.fd = fileno(dfp); | 905 | polldata.fd = fileno(dfp); |
909 | polldata.events = POLLIN | POLLPRI; | 906 | polldata.events = POLLIN | POLLPRI; |
910 | #endif | 907 | #endif |
911 | if (G.output_fd == 1) | 908 | if (!(option_mask32 & WGET_OPT_QUIET)) { |
912 | fprintf(stderr, "writing to stdout\n"); | 909 | if (G.output_fd == 1) |
913 | else | 910 | fprintf(stderr, "writing to stdout\n"); |
914 | fprintf(stderr, "saving to '%s'\n", G.fname_out); | 911 | else |
912 | fprintf(stderr, "saving to '%s'\n", G.fname_out); | ||
913 | } | ||
915 | progress_meter(PROGRESS_START); | 914 | progress_meter(PROGRESS_START); |
916 | 915 | ||
917 | if (G.chunked) | 916 | if (G.chunked) |
@@ -1042,6 +1041,15 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
1042 | */ | 1041 | */ |
1043 | } | 1042 | } |
1044 | 1043 | ||
1044 | /* Draw full bar and free its resources */ | ||
1045 | G.chunked = 0; /* makes it show 100% even for chunked download */ | ||
1046 | G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ | ||
1047 | progress_meter(PROGRESS_END); | ||
1048 | if (G.content_len != 0) { | ||
1049 | bb_perror_msg_and_die("connection closed prematurely"); | ||
1050 | /* GNU wget says "DATE TIME (NN MB/s) - Connection closed at byte NNN. Retrying." */ | ||
1051 | } | ||
1052 | |||
1045 | /* If -c failed, we restart from the beginning, | 1053 | /* If -c failed, we restart from the beginning, |
1046 | * but we do not truncate file then, we do it only now, at the end. | 1054 | * but we do not truncate file then, we do it only now, at the end. |
1047 | * This lets user to ^C if his 99% complete 10 GB file download | 1055 | * This lets user to ^C if his 99% complete 10 GB file download |
@@ -1053,14 +1061,12 @@ static void NOINLINE retrieve_file_data(FILE *dfp) | |||
1053 | ftruncate(G.output_fd, pos); | 1061 | ftruncate(G.output_fd, pos); |
1054 | } | 1062 | } |
1055 | 1063 | ||
1056 | /* Draw full bar and free its resources */ | 1064 | if (!(option_mask32 & WGET_OPT_QUIET)) { |
1057 | G.chunked = 0; /* makes it show 100% even for chunked download */ | 1065 | if (G.output_fd == 1) |
1058 | G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ | 1066 | fprintf(stderr, "written to stdout\n"); |
1059 | progress_meter(PROGRESS_END); | 1067 | else |
1060 | if (G.output_fd == 1) | 1068 | fprintf(stderr, "'%s' saved\n", G.fname_out); |
1061 | fprintf(stderr, "written to stdout\n"); | 1069 | } |
1062 | else | ||
1063 | fprintf(stderr, "'%s' saved\n", G.fname_out); | ||
1064 | } | 1070 | } |
1065 | 1071 | ||
1066 | static void download_one_url(const char *url) | 1072 | static void download_one_url(const char *url) |
@@ -1421,7 +1427,8 @@ However, in real world it was observed that some web servers | |||
1421 | G.output_fd = -1; | 1427 | G.output_fd = -1; |
1422 | } | 1428 | } |
1423 | } else { | 1429 | } else { |
1424 | fprintf(stderr, "remote file exists\n"); | 1430 | if (!(option_mask32 & WGET_OPT_QUIET)) |
1431 | fprintf(stderr, "remote file exists\n"); | ||
1425 | } | 1432 | } |
1426 | 1433 | ||
1427 | if (dfp != sfp) { | 1434 | if (dfp != sfp) { |
@@ -1492,8 +1499,6 @@ IF_DESKTOP( "no-parent\0" No_argument "\xf0") | |||
1492 | G.proxy_flag = "on"; /* use proxies if env vars are set */ | 1499 | G.proxy_flag = "on"; /* use proxies if env vars are set */ |
1493 | G.user_agent = "Wget"; /* "User-Agent" header field */ | 1500 | G.user_agent = "Wget"; /* "User-Agent" header field */ |
1494 | 1501 | ||
1495 | #if ENABLE_FEATURE_WGET_LONG_OPTIONS | ||
1496 | #endif | ||
1497 | GETOPT32(argv, "^" | 1502 | GETOPT32(argv, "^" |
1498 | "cqSO:o:P:Y:U:T:+" | 1503 | "cqSO:o:P:Y:U:T:+" |
1499 | /*ignored:*/ "t:" | 1504 | /*ignored:*/ "t:" |
diff --git a/procps/sysctl.c b/procps/sysctl.c index 5fa7646d1..6d77185ca 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c | |||
@@ -56,7 +56,31 @@ enum { | |||
56 | 56 | ||
57 | static void sysctl_dots_to_slashes(char *name) | 57 | static void sysctl_dots_to_slashes(char *name) |
58 | { | 58 | { |
59 | char *cptr, *last_good, *end; | 59 | char *cptr, *last_good, *end, *slash; |
60 | char end_ch; | ||
61 | |||
62 | end = strchrnul(name, '='); | ||
63 | |||
64 | slash = strchrnul(name, '/'); | ||
65 | if (slash < end | ||
66 | && strchrnul(name, '.') < slash | ||
67 | ) { | ||
68 | /* There are both dots and slashes, and 1st dot is | ||
69 | * before 1st slash. | ||
70 | * (IOW: not raw, unmangled a/b/c.d format) | ||
71 | * | ||
72 | * procps supports this syntax for names with dots: | ||
73 | * net.ipv4.conf.eth0/100.mc_forwarding | ||
74 | * (dots and slashes are simply swapped) | ||
75 | */ | ||
76 | while (end != name) { | ||
77 | end--; | ||
78 | if (*end == '.') *end = '/'; | ||
79 | else if (*end == '/') *end = '.'; | ||
80 | } | ||
81 | return; | ||
82 | } | ||
83 | /* else: use our old behavior: */ | ||
60 | 84 | ||
61 | /* Convert minimum number of '.' to '/' so that | 85 | /* Convert minimum number of '.' to '/' so that |
62 | * we end up with existing file's name. | 86 | * we end up with existing file's name. |
@@ -76,10 +100,10 @@ static void sysctl_dots_to_slashes(char *name) | |||
76 | * | 100 | * |
77 | * To set up testing: modprobe 8021q; vconfig add eth0 100 | 101 | * To set up testing: modprobe 8021q; vconfig add eth0 100 |
78 | */ | 102 | */ |
79 | end = name + strlen(name); | 103 | end_ch = *end; |
80 | last_good = name - 1; | ||
81 | *end = '.'; /* trick the loop into trying full name too */ | 104 | *end = '.'; /* trick the loop into trying full name too */ |
82 | 105 | ||
106 | last_good = name - 1; | ||
83 | again: | 107 | again: |
84 | cptr = end; | 108 | cptr = end; |
85 | while (cptr > last_good) { | 109 | while (cptr > last_good) { |
@@ -96,7 +120,7 @@ static void sysctl_dots_to_slashes(char *name) | |||
96 | } | 120 | } |
97 | cptr--; | 121 | cptr--; |
98 | } | 122 | } |
99 | *end = '\0'; | 123 | *end = end_ch; |
100 | } | 124 | } |
101 | 125 | ||
102 | static int sysctl_act_on_setting(char *setting) | 126 | static int sysctl_act_on_setting(char *setting) |
@@ -112,6 +136,8 @@ static int sysctl_act_on_setting(char *setting) | |||
112 | while (*cptr) { | 136 | while (*cptr) { |
113 | if (*cptr == '/') | 137 | if (*cptr == '/') |
114 | *cptr = '.'; | 138 | *cptr = '.'; |
139 | else if (*cptr == '.') | ||
140 | *cptr = '/'; | ||
115 | cptr++; | 141 | cptr++; |
116 | } | 142 | } |
117 | 143 | ||
@@ -119,14 +145,16 @@ static int sysctl_act_on_setting(char *setting) | |||
119 | if (cptr) | 145 | if (cptr) |
120 | writing = 1; | 146 | writing = 1; |
121 | if (writing) { | 147 | if (writing) { |
122 | if (cptr == NULL) { | 148 | if (!cptr) { |
123 | bb_error_msg("error: '%s' must be of the form name=value", | 149 | bb_error_msg("error: '%s' must be of the form name=value", |
124 | outname); | 150 | outname); |
125 | retval = EXIT_FAILURE; | 151 | retval = EXIT_FAILURE; |
126 | goto end; | 152 | goto end; |
127 | } | 153 | } |
128 | value = cptr + 1; /* point to the value in name=value */ | 154 | value = cptr + 1; /* point to the value in name=value */ |
129 | if (setting == cptr || !*value) { | 155 | if (setting == cptr /* "name" can't be empty */ |
156 | /* || !*value - WRONG: "sysctl net.ipv4.ip_local_reserved_ports=" is a valid syntax (clears the value) */ | ||
157 | ) { | ||
130 | bb_error_msg("error: malformed setting '%s'", outname); | 158 | bb_error_msg("error: malformed setting '%s'", outname); |
131 | retval = EXIT_FAILURE; | 159 | retval = EXIT_FAILURE; |
132 | goto end; | 160 | goto end; |
@@ -175,6 +203,7 @@ static int sysctl_act_on_setting(char *setting) | |||
175 | close(fd); | 203 | close(fd); |
176 | if (value == NULL) { | 204 | if (value == NULL) { |
177 | bb_perror_msg("error reading key '%s'", outname); | 205 | bb_perror_msg("error reading key '%s'", outname); |
206 | retval = EXIT_FAILURE; | ||
178 | goto end; | 207 | goto end; |
179 | } | 208 | } |
180 | 209 | ||
@@ -203,19 +232,21 @@ static int sysctl_act_on_setting(char *setting) | |||
203 | 232 | ||
204 | static int sysctl_act_recursive(const char *path) | 233 | static int sysctl_act_recursive(const char *path) |
205 | { | 234 | { |
206 | DIR *dirp; | ||
207 | struct stat buf; | 235 | struct stat buf; |
208 | struct dirent *entry; | ||
209 | char *next; | ||
210 | int retval = 0; | 236 | int retval = 0; |
211 | 237 | ||
212 | stat(path, &buf); | 238 | if (!(option_mask32 & FLAG_WRITE) |
213 | if (S_ISDIR(buf.st_mode) && !(option_mask32 & FLAG_WRITE)) { | 239 | && stat(path, &buf) == 0 |
240 | && S_ISDIR(buf.st_mode) | ||
241 | ) { | ||
242 | struct dirent *entry; | ||
243 | DIR *dirp; | ||
244 | |||
214 | dirp = opendir(path); | 245 | dirp = opendir(path); |
215 | if (dirp == NULL) | 246 | if (dirp == NULL) |
216 | return -1; | 247 | return -1; |
217 | while ((entry = readdir(dirp)) != NULL) { | 248 | while ((entry = readdir(dirp)) != NULL) { |
218 | next = concat_subpath_file(path, entry->d_name); | 249 | char *next = concat_subpath_file(path, entry->d_name); |
219 | if (next == NULL) | 250 | if (next == NULL) |
220 | continue; /* d_name is "." or ".." */ | 251 | continue; /* d_name is "." or ".." */ |
221 | /* if path was ".", drop "./" prefix: */ | 252 | /* if path was ".", drop "./" prefix: */ |
@@ -303,6 +334,8 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) | |||
303 | return sysctl_act_recursive("."); | 334 | return sysctl_act_recursive("."); |
304 | } | 335 | } |
305 | 336 | ||
337 | //TODO: if(!argv[0]) bb_show_usage() ? | ||
338 | |||
306 | retval = 0; | 339 | retval = 0; |
307 | while (*argv) { | 340 | while (*argv) { |
308 | sysctl_dots_to_slashes(*argv); | 341 | sysctl_dots_to_slashes(*argv); |
diff --git a/scripts/checkstack.pl b/scripts/checkstack.pl index 55cdd78c1..cf912e0fb 100755 --- a/scripts/checkstack.pl +++ b/scripts/checkstack.pl | |||
@@ -1,10 +1,11 @@ | |||
1 | #!/usr/bin/perl | 1 | #!/usr/bin/env perl |
2 | # SPDX-License-Identifier: GPL-2.0 | ||
2 | 3 | ||
3 | # Stolen from Linux kernel :) | 4 | # Stolen from Linux kernel :) |
4 | 5 | ||
5 | # Check the stack usage of functions | 6 | # Check the stack usage of functions |
6 | # | 7 | # |
7 | # Copyright Joern Engel <joern@wh.fh-wedel.de> | 8 | # Copyright Joern Engel <joern@lazybastard.org> |
8 | # Inspired by Linus Torvalds | 9 | # Inspired by Linus Torvalds |
9 | # Original idea maybe from Keith Owens | 10 | # Original idea maybe from Keith Owens |
10 | # s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de> | 11 | # s390 port and big speedup by Arnd Bergmann <arnd@bergmann-dalldorf.de> |
@@ -14,40 +15,57 @@ | |||
14 | # sh64 port by Paul Mundt | 15 | # sh64 port by Paul Mundt |
15 | # Random bits by Matt Mackall <mpm@selenic.com> | 16 | # Random bits by Matt Mackall <mpm@selenic.com> |
16 | # M68k port by Geert Uytterhoeven and Andreas Schwab | 17 | # M68k port by Geert Uytterhoeven and Andreas Schwab |
18 | # blackfin port by Alex Landau | ||
19 | # AArch64, PARISC ports by Kyle McMartin | ||
20 | # sparc port by Martin Habets <errandir_news@mph.eclipse.co.uk> | ||
21 | # ppc64le port by Breno Leitao <leitao@debian.org> | ||
17 | # | 22 | # |
18 | # Usage: | 23 | # Usage: |
19 | # objdump -d vmlinux | checkstack.pl [arch] | 24 | # objdump -d vmlinux | scripts/checkstack.pl [arch] |
20 | # | 25 | # |
21 | # TODO : Port to all architectures (one regex per arch) | 26 | # TODO : Port to all architectures (one regex per arch) |
22 | 27 | ||
28 | use strict; | ||
29 | |||
23 | # check for arch | 30 | # check for arch |
24 | # | 31 | # |
25 | # $re is used for two matches: | 32 | # $re is used for two matches: |
26 | # $& (whole re) matches the complete objdump line with the stack growth | 33 | # $& (whole re) matches the complete objdump line with the stack growth |
27 | # $1 (first bracket) matches the size of the stack growth | 34 | # $1 (first bracket) matches the size of the stack growth |
28 | # | 35 | # |
36 | # $dre is similar, but for dynamic stack reductions: | ||
37 | # $& (whole re) matches the complete objdump line with the stack growth | ||
38 | # $1 (first bracket) matches the dynamic amount of the stack growth | ||
39 | # | ||
29 | # use anything else and feel the pain ;) | 40 | # use anything else and feel the pain ;) |
30 | my (@stack, $re, $x, $xs); | 41 | my (@stack, $re, $dre, $x, $xs, $funcre); |
31 | { | 42 | { |
32 | my $arch = shift; | 43 | my $arch = shift; |
33 | if ($arch eq "") { | 44 | if ($arch eq "") { |
34 | $arch = `uname -m`; | 45 | $arch = `uname -m`; |
46 | chomp($arch); | ||
35 | } | 47 | } |
36 | 48 | ||
37 | $x = "[0-9a-f]"; # hex character | 49 | $x = "[0-9a-f]"; # hex character |
38 | $xs = "[0-9a-f ]"; # hex character or space | 50 | $xs = "[0-9a-f ]"; # hex character or space |
39 | if ($arch eq 'arm') { | 51 | $funcre = qr/^$x* <(.*)>:$/; |
52 | if ($arch eq 'aarch64') { | ||
53 | #ffffffc0006325cc: a9bb7bfd stp x29, x30, [sp, #-80]! | ||
54 | #a110: d11643ff sub sp, sp, #0x590 | ||
55 | $re = qr/^.*stp.*sp, \#-([0-9]{1,8})\]\!/o; | ||
56 | $dre = qr/^.*sub.*sp, sp, #(0x$x{1,8})/o; | ||
57 | } elsif ($arch eq 'arm') { | ||
40 | #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 | 58 | #c0008ffc: e24dd064 sub sp, sp, #100 ; 0x64 |
41 | $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; | 59 | $re = qr/.*sub.*sp, sp, #(([0-9]{2}|[3-9])[0-9]{2})/o; |
60 | } elsif ($arch =~ /^x86(_64)?$/ || $arch =~ /^i[3456]86$/) { | ||
61 | #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp | ||
62 | # or | ||
63 | # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp | ||
64 | $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%(e|r)sp$/o; | ||
65 | $dre = qr/^.*[as][du][db] (%.*),\%(e|r)sp$/o; | ||
42 | } elsif ($arch eq 'blackfin') { | 66 | } elsif ($arch eq 'blackfin') { |
43 | # 52: 00 e8 03 00 LINK 0xc; | 67 | # 52: 00 e8 03 00 LINK 0xc; |
44 | $re = qr/.*LINK (0x$x{1,5});$/o; | 68 | $re = qr/.*[[:space:]]LINK[[:space:]]*(0x$x{1,8})/o; |
45 | } elsif ($arch =~ /^i[3456]86$/) { | ||
46 | #c0105234: 81 ec ac 05 00 00 sub $0x5ac,%esp | ||
47 | $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%esp$/o; | ||
48 | } elsif ($arch eq 'x86_64') { | ||
49 | # 2f60: 48 81 ec e8 05 00 00 sub $0x5e8,%rsp | ||
50 | $re = qr/^.*[as][du][db] \$(0x$x{1,8}),\%rsp$/o; | ||
51 | } elsif ($arch eq 'ia64') { | 69 | } elsif ($arch eq 'ia64') { |
52 | #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 | 70 | #e0000000044011fc: 01 0f fc 8c adds r12=-384,r12 |
53 | $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; | 71 | $re = qr/.*adds.*r12=-(([0-9]{2}|[3-9])[0-9]{2}),r12/o; |
@@ -61,42 +79,43 @@ my (@stack, $re, $x, $xs); | |||
61 | } elsif ($arch eq 'mips') { | 79 | } elsif ($arch eq 'mips') { |
62 | #88003254: 27bdffe0 addiu sp,sp,-32 | 80 | #88003254: 27bdffe0 addiu sp,sp,-32 |
63 | $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; | 81 | $re = qr/.*addiu.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; |
64 | } elsif ($arch eq 'ppc') { | 82 | } elsif ($arch eq 'nios2') { |
65 | #c00029f4: 94 21 ff 30 stwu r1,-208(r1) | 83 | #25a8: defffb04 addi sp,sp,-20 |
66 | $re = qr/.*stwu.*r1,-($x{1,8})\(r1\)/o; | 84 | $re = qr/.*addi.*sp,sp,-(([0-9]{2}|[3-9])[0-9]{2})/o; |
67 | } elsif ($arch eq 'ppc64') { | 85 | } elsif ($arch eq 'openrisc') { |
68 | #XXX | 86 | # c000043c: 9c 21 fe f0 l.addi r1,r1,-272 |
69 | $re = qr/.*stdu.*r1,-($x{1,8})\(r1\)/o; | 87 | $re = qr/.*l\.addi.*r1,r1,-(([0-9]{2}|[3-9])[0-9]{2})/o; |
70 | } elsif ($arch eq 'powerpc') { | 88 | } elsif ($arch eq 'parisc' || $arch eq 'parisc64') { |
89 | $re = qr/.*ldo ($x{1,8})\(sp\),sp/o; | ||
90 | } elsif ($arch eq 'powerpc' || $arch =~ /^ppc(64)?(le)?$/ ) { | ||
91 | # powerpc : 94 21 ff 30 stwu r1,-208(r1) | ||
92 | # ppc64(le) : 81 ff 21 f8 stdu r1,-128(r1) | ||
71 | $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; | 93 | $re = qr/.*st[dw]u.*r1,-($x{1,8})\(r1\)/o; |
72 | } elsif ($arch =~ /^s390x?$/) { | 94 | } elsif ($arch =~ /^s390x?$/) { |
73 | # 11160: a7 fb ff 60 aghi %r15,-160 | 95 | # 11160: a7 fb ff 60 aghi %r15,-160 |
74 | $re = qr/.*ag?hi.*\%r15,-(([0-9]{2}|[3-9])[0-9]{2})/o; | 96 | # or |
97 | # 100092: e3 f0 ff c8 ff 71 lay %r15,-56(%r15) | ||
98 | $re = qr/.*(?:lay|ag?hi).*\%r15,-(([0-9]{2}|[3-9])[0-9]{2}) | ||
99 | (?:\(\%r15\))?$/ox; | ||
75 | } elsif ($arch =~ /^sh64$/) { | 100 | } elsif ($arch =~ /^sh64$/) { |
76 | #XXX: we only check for the immediate case presently, | 101 | #XXX: we only check for the immediate case presently, |
77 | # though we will want to check for the movi/sub | 102 | # though we will want to check for the movi/sub |
78 | # pair for larger users. -- PFM. | 103 | # pair for larger users. -- PFM. |
79 | #a00048e0: d4fc40f0 addi.l r15,-240,r15 | 104 | #a00048e0: d4fc40f0 addi.l r15,-240,r15 |
80 | $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; | 105 | $re = qr/.*addi\.l.*r15,-(([0-9]{2}|[3-9])[0-9]{2}),r15/o; |
106 | } elsif ($arch eq 'sparc' || $arch eq 'sparc64') { | ||
107 | # f0019d10: 9d e3 bf 90 save %sp, -112, %sp | ||
108 | $re = qr/.*save.*%sp, -(([0-9]{2}|[3-9])[0-9]{2}), %sp/o; | ||
81 | } else { | 109 | } else { |
82 | print("wrong or unknown architecture\n"); | 110 | print("wrong or unknown architecture \"$arch\"\n"); |
83 | exit | 111 | exit |
84 | } | 112 | } |
85 | } | 113 | } |
86 | 114 | ||
87 | sub bysize($) { | ||
88 | my ($asize, $bsize); | ||
89 | ($asize = $a) =~ s/.*: *(.*)$/$1/; | ||
90 | ($bsize = $b) =~ s/.*: *(.*)$/$1/; | ||
91 | $bsize <=> $asize | ||
92 | } | ||
93 | |||
94 | # | 115 | # |
95 | # main() | 116 | # main() |
96 | # | 117 | # |
97 | my $funcre = qr/^$x* <(.*)>:$/; | 118 | my ($func, $file, $lastslash); |
98 | my $func; | ||
99 | my $file, $lastslash; | ||
100 | 119 | ||
101 | while (my $line = <STDIN>) { | 120 | while (my $line = <STDIN>) { |
102 | if ($line =~ m/$funcre/) { | 121 | if ($line =~ m/$funcre/) { |
@@ -136,6 +155,31 @@ while (my $line = <STDIN>) { | |||
136 | next if ($size < 100); | 155 | next if ($size < 100); |
137 | push @stack, "$intro$size\n"; | 156 | push @stack, "$intro$size\n"; |
138 | } | 157 | } |
158 | elsif (defined $dre && $line =~ m/$dre/) { | ||
159 | my $size = "Dynamic ($1)"; | ||
160 | |||
161 | next if $line !~ m/^($xs*)/; | ||
162 | my $addr = $1; | ||
163 | $addr =~ s/ /0/g; | ||
164 | $addr = "0x$addr"; | ||
165 | |||
166 | #bbox: was: my $intro = "$addr $func [$file]:"; | ||
167 | my $intro = "$func [$file]:"; | ||
168 | my $padlen = 56 - length($intro); | ||
169 | while ($padlen > 0) { | ||
170 | $intro .= ' '; | ||
171 | $padlen -= 8; | ||
172 | } | ||
173 | push @stack, "$intro$size\n"; | ||
174 | } | ||
175 | } | ||
176 | |||
177 | sub bysize($) { | ||
178 | my ($asize, $bsize); | ||
179 | ($asize = $a) =~ s/.*: *(.*)$/$1/; | ||
180 | ($bsize = $b) =~ s/.*: *(.*)$/$1/; | ||
181 | $bsize <=> $asize | ||
139 | } | 182 | } |
140 | 183 | ||
141 | print sort bysize @stack; | 184 | # Sort output by size (last field) |
185 | print sort { ($b =~ /:\t*(\d+)$/)[0] <=> ($a =~ /:\t*(\d+)$/)[0] } @stack; | ||
diff --git a/selinux/chcon.c b/selinux/chcon.c index 92eb76737..5bf91710c 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c | |||
@@ -204,7 +204,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) | |||
204 | fname[fname_len] = '\0'; | 204 | fname[fname_len] = '\0'; |
205 | 205 | ||
206 | if (recursive_action(fname, | 206 | if (recursive_action(fname, |
207 | ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSIVE : 0), | 207 | ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0), |
208 | change_filedir_context, | 208 | change_filedir_context, |
209 | change_filedir_context, | 209 | change_filedir_context, |
210 | NULL, 0) != TRUE) | 210 | NULL, 0) != TRUE) |
diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 3933fefc9..0db6a26e4 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests | |||
@@ -280,6 +280,18 @@ testing "awk 'delete a[v--]' evaluates v-- once" \ | |||
280 | " \ | 280 | " \ |
281 | "" "" | 281 | "" "" |
282 | 282 | ||
283 | testing "awk func arg parsing 1" \ | ||
284 | "awk 'func f(,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | ||
285 | |||
286 | testing "awk func arg parsing 2" \ | ||
287 | "awk 'func f(a,,b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | ||
288 | |||
289 | testing "awk func arg parsing 3" \ | ||
290 | "awk 'func f(a,) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | ||
291 | |||
292 | testing "awk func arg parsing 4" \ | ||
293 | "awk 'func f(a b) { }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | ||
294 | |||
283 | testing "awk handles empty ()" \ | 295 | testing "awk handles empty ()" \ |
284 | "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" | 296 | "awk 'BEGIN {print()}' 2>&1" "awk: cmd. line:1: Empty sequence\n" "" "" |
285 | 297 | ||
@@ -336,7 +348,13 @@ testing "awk continue" \ | |||
336 | 'BEGIN { if (1) continue; else a = 1 }' | 348 | 'BEGIN { if (1) continue; else a = 1 }' |
337 | 349 | ||
338 | testing "awk handles invalid for loop" \ | 350 | testing "awk handles invalid for loop" \ |
339 | "awk '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | 351 | "awk -e '{ for() }' 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" |
352 | |||
353 | testing "awk handles colon not preceded by ternary" \ | ||
354 | "awk -e foo:bar: 2>&1" "awk: cmd. line:1: Unexpected token\n" "" "" | ||
355 | |||
356 | testing "awk errors on missing delete arg" \ | ||
357 | "awk -e '{delete}' 2>&1" "awk: cmd. line:1: Too few arguments\n" "" "" | ||
340 | 358 | ||
341 | # testing "description" "command" "result" "infile" "stdin" | 359 | # testing "description" "command" "result" "infile" "stdin" |
342 | testing 'awk negative field access' \ | 360 | testing 'awk negative field access' \ |
diff --git a/testsuite/bc_references.bc b/testsuite/bc_references.bc new file mode 100644 index 000000000..fc48c1a56 --- /dev/null +++ b/testsuite/bc_references.bc | |||
@@ -0,0 +1,106 @@ | |||
1 | define printarray(a[], len) { | ||
2 | |||
3 | auto i | ||
4 | |||
5 | for (i = 0; i < len; ++i) { | ||
6 | a[i] | ||
7 | } | ||
8 | } | ||
9 | |||
10 | define a2(a[], len) { | ||
11 | |||
12 | auto i | ||
13 | |||
14 | for (i = 0; i < len; ++i) { | ||
15 | a[i] = a[i] * a[i] | ||
16 | } | ||
17 | |||
18 | printarray(a[], len) | ||
19 | } | ||
20 | |||
21 | define a4(a__[], len) { | ||
22 | |||
23 | auto i | ||
24 | |||
25 | for (i = 0; i < len; ++i) { | ||
26 | a__[i] = a__[i] * a__[i] | ||
27 | } | ||
28 | |||
29 | printarray(a__[], len) | ||
30 | } | ||
31 | |||
32 | define a6(*a__[], len) { | ||
33 | |||
34 | auto i | ||
35 | |||
36 | for (i = 0; i < len; ++i) { | ||
37 | a__[i] = a__[i] * a__[i] | ||
38 | } | ||
39 | |||
40 | printarray(a__[], len) | ||
41 | } | ||
42 | |||
43 | define a1(*a[], len) { | ||
44 | |||
45 | auto i | ||
46 | |||
47 | for (i = 0; i < len; ++i) { | ||
48 | a[i] = i | ||
49 | } | ||
50 | |||
51 | a2(a[], len) | ||
52 | |||
53 | printarray(a[], len) | ||
54 | } | ||
55 | |||
56 | define a3(*a__[], len) { | ||
57 | |||
58 | auto i | ||
59 | |||
60 | for (i = 0; i < len; ++i) { | ||
61 | a__[i] = i | ||
62 | } | ||
63 | |||
64 | a4(a__[], len) | ||
65 | |||
66 | printarray(a__[], len) | ||
67 | } | ||
68 | |||
69 | define a5(*a__[], len) { | ||
70 | |||
71 | auto i | ||
72 | |||
73 | for (i = 0; i < len; ++i) { | ||
74 | a__[i] = i | ||
75 | } | ||
76 | |||
77 | a2(a__[], len) | ||
78 | |||
79 | printarray(a__[], len) | ||
80 | } | ||
81 | |||
82 | define a7(*a__[], len) { | ||
83 | |||
84 | auto i | ||
85 | |||
86 | for (i = 0; i < len; ++i) { | ||
87 | a__[i] = i | ||
88 | } | ||
89 | |||
90 | a6(a__[], len) | ||
91 | |||
92 | printarray(a__[], len) | ||
93 | } | ||
94 | |||
95 | len = 16 | ||
96 | |||
97 | a1(a[], len) | ||
98 | printarray(a[], len) | ||
99 | a3(a[], len) | ||
100 | printarray(a[], len) | ||
101 | a5(a[], len) | ||
102 | printarray(a[], len) | ||
103 | a7(a[], len) | ||
104 | printarray(a[], len) | ||
105 | |||
106 | halt | ||
diff --git a/testsuite/bc_references_results.txt b/testsuite/bc_references_results.txt new file mode 100644 index 000000000..564b54a3a --- /dev/null +++ b/testsuite/bc_references_results.txt | |||
@@ -0,0 +1,212 @@ | |||
1 | 0 | ||
2 | 1 | ||
3 | 4 | ||
4 | 9 | ||
5 | 16 | ||
6 | 25 | ||
7 | 36 | ||
8 | 49 | ||
9 | 64 | ||
10 | 81 | ||
11 | 100 | ||
12 | 121 | ||
13 | 144 | ||
14 | 169 | ||
15 | 196 | ||
16 | 225 | ||
17 | 0 | ||
18 | 0 | ||
19 | 0 | ||
20 | 1 | ||
21 | 2 | ||
22 | 3 | ||
23 | 4 | ||
24 | 5 | ||
25 | 6 | ||
26 | 7 | ||
27 | 8 | ||
28 | 9 | ||
29 | 10 | ||
30 | 11 | ||
31 | 12 | ||
32 | 13 | ||
33 | 14 | ||
34 | 15 | ||
35 | 0 | ||
36 | 0 | ||
37 | 0 | ||
38 | 1 | ||
39 | 2 | ||
40 | 3 | ||
41 | 4 | ||
42 | 5 | ||
43 | 6 | ||
44 | 7 | ||
45 | 8 | ||
46 | 9 | ||
47 | 10 | ||
48 | 11 | ||
49 | 12 | ||
50 | 13 | ||
51 | 14 | ||
52 | 15 | ||
53 | 0 | ||
54 | 0 | ||
55 | 1 | ||
56 | 4 | ||
57 | 9 | ||
58 | 16 | ||
59 | 25 | ||
60 | 36 | ||
61 | 49 | ||
62 | 64 | ||
63 | 81 | ||
64 | 100 | ||
65 | 121 | ||
66 | 144 | ||
67 | 169 | ||
68 | 196 | ||
69 | 225 | ||
70 | 0 | ||
71 | 0 | ||
72 | 0 | ||
73 | 1 | ||
74 | 2 | ||
75 | 3 | ||
76 | 4 | ||
77 | 5 | ||
78 | 6 | ||
79 | 7 | ||
80 | 8 | ||
81 | 9 | ||
82 | 10 | ||
83 | 11 | ||
84 | 12 | ||
85 | 13 | ||
86 | 14 | ||
87 | 15 | ||
88 | 0 | ||
89 | 0 | ||
90 | 0 | ||
91 | 1 | ||
92 | 2 | ||
93 | 3 | ||
94 | 4 | ||
95 | 5 | ||
96 | 6 | ||
97 | 7 | ||
98 | 8 | ||
99 | 9 | ||
100 | 10 | ||
101 | 11 | ||
102 | 12 | ||
103 | 13 | ||
104 | 14 | ||
105 | 15 | ||
106 | 0 | ||
107 | 0 | ||
108 | 1 | ||
109 | 4 | ||
110 | 9 | ||
111 | 16 | ||
112 | 25 | ||
113 | 36 | ||
114 | 49 | ||
115 | 64 | ||
116 | 81 | ||
117 | 100 | ||
118 | 121 | ||
119 | 144 | ||
120 | 169 | ||
121 | 196 | ||
122 | 225 | ||
123 | 0 | ||
124 | 0 | ||
125 | 0 | ||
126 | 1 | ||
127 | 2 | ||
128 | 3 | ||
129 | 4 | ||
130 | 5 | ||
131 | 6 | ||
132 | 7 | ||
133 | 8 | ||
134 | 9 | ||
135 | 10 | ||
136 | 11 | ||
137 | 12 | ||
138 | 13 | ||
139 | 14 | ||
140 | 15 | ||
141 | 0 | ||
142 | 0 | ||
143 | 0 | ||
144 | 1 | ||
145 | 2 | ||
146 | 3 | ||
147 | 4 | ||
148 | 5 | ||
149 | 6 | ||
150 | 7 | ||
151 | 8 | ||
152 | 9 | ||
153 | 10 | ||
154 | 11 | ||
155 | 12 | ||
156 | 13 | ||
157 | 14 | ||
158 | 15 | ||
159 | 0 | ||
160 | 0 | ||
161 | 1 | ||
162 | 4 | ||
163 | 9 | ||
164 | 16 | ||
165 | 25 | ||
166 | 36 | ||
167 | 49 | ||
168 | 64 | ||
169 | 81 | ||
170 | 100 | ||
171 | 121 | ||
172 | 144 | ||
173 | 169 | ||
174 | 196 | ||
175 | 225 | ||
176 | 0 | ||
177 | 0 | ||
178 | 0 | ||
179 | 1 | ||
180 | 4 | ||
181 | 9 | ||
182 | 16 | ||
183 | 25 | ||
184 | 36 | ||
185 | 49 | ||
186 | 64 | ||
187 | 81 | ||
188 | 100 | ||
189 | 121 | ||
190 | 144 | ||
191 | 169 | ||
192 | 196 | ||
193 | 225 | ||
194 | 0 | ||
195 | 0 | ||
196 | 0 | ||
197 | 1 | ||
198 | 4 | ||
199 | 9 | ||
200 | 16 | ||
201 | 25 | ||
202 | 36 | ||
203 | 49 | ||
204 | 64 | ||
205 | 81 | ||
206 | 100 | ||
207 | 121 | ||
208 | 144 | ||
209 | 169 | ||
210 | 196 | ||
211 | 225 | ||
212 | 0 | ||
diff --git a/testsuite/grep.tests b/testsuite/grep.tests index e57889790..26f8e69cf 100755 --- a/testsuite/grep.tests +++ b/testsuite/grep.tests | |||
@@ -177,6 +177,13 @@ testing "grep -w word match second word" \ | |||
177 | "bword,word\n""wordb,word\n""bwordb,word\n" \ | 177 | "bword,word\n""wordb,word\n""bwordb,word\n" \ |
178 | "" | 178 | "" |
179 | 179 | ||
180 | |||
181 | testing "grep -x -v -e EXP1 -e EXP2 finds nothing if either EXP matches" \ | ||
182 | "grep -x -v -e '.*aa.*' -e 'bb.*'; echo \$?" \ | ||
183 | "1\n" \ | ||
184 | "" \ | ||
185 | " aa bb cc\n" | ||
186 | |||
180 | # -r on symlink to dir should recurse into dir | 187 | # -r on symlink to dir should recurse into dir |
181 | mkdir -p grep.testdir/foo | 188 | mkdir -p grep.testdir/foo |
182 | echo bar > grep.testdir/foo/file | 189 | echo bar > grep.testdir/foo/file |
diff --git a/testsuite/start-stop-daemon.tests b/testsuite/start-stop-daemon.tests index d07aeef0e..2ddb7fefb 100755 --- a/testsuite/start-stop-daemon.tests +++ b/testsuite/start-stop-daemon.tests | |||
@@ -16,4 +16,16 @@ testing "start-stop-daemon -a without -x" \ | |||
16 | "1\n" \ | 16 | "1\n" \ |
17 | "" "" | 17 | "" "" |
18 | 18 | ||
19 | testing "start-stop-daemon without -x and -a" \ | ||
20 | 'start-stop-daemon -S false 2>&1; echo $?' \ | ||
21 | "1\n" \ | ||
22 | "" "" | ||
23 | |||
24 | # Unfortunately, this does not actually check argv[0] correctness, | ||
25 | # but at least it checks that pathname to exec() is correct | ||
26 | testing "start-stop-daemon with both -x and -a" \ | ||
27 | 'start-stop-daemon -S -x /bin/false -a qwerty false 2>&1; echo $?' \ | ||
28 | "1\n" \ | ||
29 | "" "" | ||
30 | |||
19 | exit $FAILCOUNT | 31 | exit $FAILCOUNT |