diff options
author | Ron Yorston <rmy@pobox.com> | 2024-06-23 09:35:35 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2024-06-23 09:44:03 +0100 |
commit | b07c177b446498ccd739b367f9e80337c3dfa55a (patch) | |
tree | 8230bce5f937e46ae1a6f18677904d2eccc4ae9e | |
parent | 1b094d366f808a2ebc4824004f0d6f75f13c09cb (diff) | |
parent | a6ce017a8a2db09c6f23aa6abf7ce21fd00c2fdf (diff) | |
download | busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.gz busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.bz2 busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.zip |
Merge branch 'busybox' into merge
34 files changed, 562 insertions, 155 deletions
diff --git a/configs/TEST_nommu_defconfig b/configs/TEST_nommu_defconfig index 415f5a802..fa3e96326 100644 --- a/configs/TEST_nommu_defconfig +++ b/configs/TEST_nommu_defconfig | |||
@@ -703,6 +703,7 @@ CONFIG_FEATURE_INETD_RPC=y | |||
703 | CONFIG_IP=y | 703 | CONFIG_IP=y |
704 | CONFIG_FEATURE_IP_ADDRESS=y | 704 | CONFIG_FEATURE_IP_ADDRESS=y |
705 | CONFIG_FEATURE_IP_LINK=y | 705 | CONFIG_FEATURE_IP_LINK=y |
706 | CONFIG_FEATURE_IP_LINK_CAN=y | ||
706 | CONFIG_FEATURE_IP_ROUTE=y | 707 | CONFIG_FEATURE_IP_ROUTE=y |
707 | CONFIG_FEATURE_IP_TUNNEL=y | 708 | CONFIG_FEATURE_IP_TUNNEL=y |
708 | CONFIG_FEATURE_IP_RULE=y | 709 | CONFIG_FEATURE_IP_RULE=y |
diff --git a/coreutils/ls.c b/coreutils/ls.c index 52c43c731..5d2e96a1e 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -540,10 +540,10 @@ static NOINLINE unsigned display_single(const struct dnode *dn) | |||
540 | #if ENABLE_FEATURE_LS_USERNAME | 540 | #if ENABLE_FEATURE_LS_USERNAME |
541 | else { | 541 | else { |
542 | if (opt & OPT_g) { | 542 | if (opt & OPT_g) { |
543 | column += printf("%-8.8s ", | 543 | column += printf("%-8s ", |
544 | get_cached_groupname(dn->dn_gid)); | 544 | get_cached_groupname(dn->dn_gid)); |
545 | } else { | 545 | } else { |
546 | column += printf("%-8.8s %-8.8s ", | 546 | column += printf("%-8s %-8s ", |
547 | get_cached_username(dn->dn_uid), | 547 | get_cached_username(dn->dn_uid), |
548 | get_cached_groupname(dn->dn_gid)); | 548 | get_cached_groupname(dn->dn_gid)); |
549 | } | 549 | } |
diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 7c91a286f..5faa57a65 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c | |||
@@ -23,7 +23,6 @@ | |||
23 | //usage: "\n --ignore=N Exclude N CPUs" | 23 | //usage: "\n --ignore=N Exclude N CPUs" |
24 | //usage: ) | 24 | //usage: ) |
25 | 25 | ||
26 | #include <sched.h> | ||
27 | #include "libbb.h" | 26 | #include "libbb.h" |
28 | 27 | ||
29 | int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 28 | int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -59,16 +58,16 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
59 | } | 58 | } |
60 | } else | 59 | } else |
61 | #endif | 60 | #endif |
62 | if (sched_getaffinity(0, sizeof(mask), (void*)mask) == 0) { | 61 | { |
63 | int i; | 62 | int i; |
64 | for (i = 0; i < ARRAY_SIZE(mask); i++) { | 63 | unsigned sz = 2 * 1024; |
65 | unsigned long m = mask[i]; | 64 | unsigned long *mask = get_malloc_cpu_affinity(0, &sz); |
66 | while (m) { | 65 | sz /= sizeof(long); |
67 | if (m & 1) | 66 | for (i = 0; i < sz; i++) { |
68 | count++; | 67 | if (mask[i] != 0) /* most mask[i] are usually 0 */ |
69 | m >>= 1; | 68 | count += bb_popcnt_long(mask[i]); |
70 | } | ||
71 | } | 69 | } |
70 | IF_FEATURE_CLEAN_UP(free(mask);) | ||
72 | } | 71 | } |
73 | #else /* ENABLE_PLATFORM_MINGW32 */ | 72 | #else /* ENABLE_PLATFORM_MINGW32 */ |
74 | if (GetProcessAffinityMask(GetCurrentProcess(), &process_affinity, | 73 | if (GetProcessAffinityMask(GetCurrentProcess(), &process_affinity, |
diff --git a/editors/awk.c b/editors/awk.c index 8d88fce76..cb4b2958f 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -3029,11 +3029,7 @@ static var *evaluate(node *op, var *res) | |||
3029 | if (old_Fields_ptr) { | 3029 | if (old_Fields_ptr) { |
3030 | //if (old_Fields_ptr != Fields) | 3030 | //if (old_Fields_ptr != Fields) |
3031 | // debug_printf_eval("L.v moved\n"); | 3031 | // debug_printf_eval("L.v moved\n"); |
3032 | #if !ENABLE_PLATFORM_MINGW32 | ||
3033 | L.v += Fields - old_Fields_ptr; | ||
3034 | #else | ||
3035 | L.v = Fields + (L.v - old_Fields_ptr); | 3032 | L.v = Fields + (L.v - old_Fields_ptr); |
3036 | #endif | ||
3037 | } | 3033 | } |
3038 | if (opinfo & OF_STR2) { | 3034 | if (opinfo & OF_STR2) { |
3039 | R.s = getvar_s(R.v); | 3035 | R.s = getvar_s(R.v); |
diff --git a/include/libbb.h b/include/libbb.h index 9055ed066..e5000831f 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -423,6 +423,13 @@ extern int *BB_GLOBAL_CONST bb_errno; | |||
423 | uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; | 423 | uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; |
424 | #endif | 424 | #endif |
425 | 425 | ||
426 | unsigned FAST_FUNC bb_popcnt_32(uint32_t m); | ||
427 | #if ULONG_MAX > 0xffffffff | ||
428 | unsigned FAST_FUNC bb_popcnt_long(unsigned long m); | ||
429 | #else | ||
430 | #define bb_popcnt_long(m) bb_popcnt_32(m) | ||
431 | #endif | ||
432 | |||
426 | unsigned long FAST_FUNC isqrt(unsigned long long N); | 433 | unsigned long FAST_FUNC isqrt(unsigned long long N); |
427 | 434 | ||
428 | unsigned long long monotonic_ns(void) FAST_FUNC; | 435 | unsigned long long monotonic_ns(void) FAST_FUNC; |
@@ -2103,6 +2110,8 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; | |||
2103 | read_line_input(prompt, command, maxsize) | 2110 | read_line_input(prompt, command, maxsize) |
2104 | #endif | 2111 | #endif |
2105 | 2112 | ||
2113 | unsigned long* FAST_FUNC get_malloc_cpu_affinity(int pid, unsigned *sz); | ||
2114 | |||
2106 | #if ENABLE_PLATFORM_MINGW32 | 2115 | #if ENABLE_PLATFORM_MINGW32 |
2107 | # undef COMM_LEN | 2116 | # undef COMM_LEN |
2108 | # define COMM_LEN 32 | 2117 | # define COMM_LEN 32 |
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 7785ef152..32fde90e6 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src | |||
@@ -58,6 +58,7 @@ lib-y += parse_mode.o | |||
58 | lib-y += perror_msg.o | 58 | lib-y += perror_msg.o |
59 | lib-y += perror_nomsg_and_die.o | 59 | lib-y += perror_nomsg_and_die.o |
60 | lib-y += platform.o | 60 | lib-y += platform.o |
61 | lib-y += popcnt.o | ||
61 | lib-y += printable.o | 62 | lib-y += printable.o |
62 | lib-y += printable_string.o | 63 | lib-y += printable_string.o |
63 | lib-y += process_escape_sequence.o | 64 | lib-y += process_escape_sequence.o |
@@ -99,6 +100,7 @@ lib-y += xgetcwd.o | |||
99 | lib-y += xreadlink.o | 100 | lib-y += xreadlink.o |
100 | lib-y += xrealloc_vector.o | 101 | lib-y += xrealloc_vector.o |
101 | 102 | ||
103 | lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o | ||
102 | lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o | 104 | lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o |
103 | lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o | 105 | lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o |
104 | lib-$(CONFIG_PLATFORM_POSIX) += device_open.o | 106 | lib-$(CONFIG_PLATFORM_POSIX) += device_open.o |
diff --git a/libbb/alloc_affinity.c b/libbb/alloc_affinity.c new file mode 100644 index 000000000..b6d9f649a --- /dev/null +++ b/libbb/alloc_affinity.c | |||
@@ -0,0 +1,29 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 2024 Denys Vlasenko | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | #include <sched.h> | ||
10 | #include "libbb.h" | ||
11 | |||
12 | unsigned long* FAST_FUNC get_malloc_cpu_affinity(int pid, unsigned *sz) | ||
13 | { | ||
14 | unsigned long *mask = NULL; | ||
15 | unsigned sz_in_bytes = *sz; | ||
16 | |||
17 | for (;;) { | ||
18 | mask = xrealloc(mask, sz_in_bytes); | ||
19 | if (sched_getaffinity(pid, sz_in_bytes, (void*)mask) == 0) | ||
20 | break; /* got it */ | ||
21 | sz_in_bytes *= 2; | ||
22 | if (errno == EINVAL && (int)sz_in_bytes > 0) | ||
23 | continue; | ||
24 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid); | ||
25 | } | ||
26 | //bb_error_msg("get mask[0]:%lx sz_in_bytes:%d", mask[0], sz_in_bytes); | ||
27 | *sz = sz_in_bytes; | ||
28 | return mask; | ||
29 | } | ||
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 811e3e475..bd4a17348 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -351,7 +351,7 @@ static unsigned save_string(char *dst, unsigned maxsize) | |||
351 | return i; | 351 | return i; |
352 | } | 352 | } |
353 | } | 353 | } |
354 | /* I thought just fputwc(c, stdout) would work. But no... */ | 354 | /* I thought just fputwc(c, stderr) would work. But no... */ |
355 | static void BB_PUTCHAR(wchar_t c) | 355 | static void BB_PUTCHAR(wchar_t c) |
356 | { | 356 | { |
357 | if (unicode_status == UNICODE_ON) { | 357 | if (unicode_status == UNICODE_ON) { |
@@ -360,11 +360,11 @@ static void BB_PUTCHAR(wchar_t c) | |||
360 | ssize_t len = wcrtomb(buf, c, &mbst); | 360 | ssize_t len = wcrtomb(buf, c, &mbst); |
361 | if (len > 0) { | 361 | if (len > 0) { |
362 | buf[len] = '\0'; | 362 | buf[len] = '\0'; |
363 | fputs_stdout(buf); | 363 | fputs(buf, stderr); |
364 | } | 364 | } |
365 | } else { | 365 | } else { |
366 | /* In this case, c is always one byte */ | 366 | /* In this case, c is always one byte */ |
367 | putchar(c); | 367 | bb_putchar_stderr(c); |
368 | } | 368 | } |
369 | } | 369 | } |
370 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS | 370 | # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS |
@@ -410,7 +410,7 @@ static void save_string(char *dst, unsigned maxsize) | |||
410 | safe_strncpy(dst, command_ps, maxsize); | 410 | safe_strncpy(dst, command_ps, maxsize); |
411 | } | 411 | } |
412 | # endif | 412 | # endif |
413 | # define BB_PUTCHAR(c) bb_putchar(c) | 413 | # define BB_PUTCHAR(c) bb_putchar_stderr(c) |
414 | /* Should never be called: */ | 414 | /* Should never be called: */ |
415 | int adjust_width_and_validate_wc(unsigned *width_adj, int wc); | 415 | int adjust_width_and_validate_wc(unsigned *width_adj, int wc); |
416 | #endif | 416 | #endif |
@@ -469,7 +469,7 @@ static void put_cur_glyph_and_inc_cursor(void) | |||
469 | if (c == BB_NUL) | 469 | if (c == BB_NUL) |
470 | c = ' '; | 470 | c = ' '; |
471 | BB_PUTCHAR(c); | 471 | BB_PUTCHAR(c); |
472 | bb_putchar('\b'); | 472 | bb_putchar_stderr('\b'); |
473 | #endif | 473 | #endif |
474 | cmdedit_y++; | 474 | cmdedit_y++; |
475 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { | 475 | if (!ENABLE_UNICODE_WIDE_WCHARS || ofs_to_right == 0) { |
@@ -531,12 +531,12 @@ static void goto_new_line(void) | |||
531 | put_till_end_and_adv_cursor(); | 531 | put_till_end_and_adv_cursor(); |
532 | /* "cursor == 0" is only if prompt is "" and user input is empty */ | 532 | /* "cursor == 0" is only if prompt is "" and user input is empty */ |
533 | if (cursor == 0 || cmdedit_x != 0) | 533 | if (cursor == 0 || cmdedit_x != 0) |
534 | bb_putchar('\n'); | 534 | bb_putchar_stderr('\n'); |
535 | } | 535 | } |
536 | 536 | ||
537 | static void beep(void) | 537 | static void beep(void) |
538 | { | 538 | { |
539 | bb_putchar('\007'); | 539 | bb_putchar_stderr('\007'); |
540 | } | 540 | } |
541 | 541 | ||
542 | /* Full or last/sole prompt line, reset edit cursor, calculate terminal cursor. | 542 | /* Full or last/sole prompt line, reset edit cursor, calculate terminal cursor. |
@@ -544,7 +544,10 @@ static void beep(void) | |||
544 | */ | 544 | */ |
545 | static void put_prompt_custom(bool is_full) | 545 | static void put_prompt_custom(bool is_full) |
546 | { | 546 | { |
547 | fputs_stdout((is_full ? cmdedit_prompt : prompt_last_line)); | 547 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
548 | * says that shells must write $PSn to stderr, not stdout. | ||
549 | */ | ||
550 | fputs((is_full ? cmdedit_prompt : prompt_last_line), stderr); | ||
548 | cursor = 0; | 551 | cursor = 0; |
549 | cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */ | 552 | cmdedit_y = cmdedit_prmt_len / cmdedit_termw; /* new quasireal y */ |
550 | cmdedit_x = cmdedit_prmt_len % cmdedit_termw; | 553 | cmdedit_x = cmdedit_prmt_len % cmdedit_termw; |
@@ -582,16 +585,16 @@ static void input_backward(unsigned num) | |||
582 | /* This is longer by 5 bytes on x86. | 585 | /* This is longer by 5 bytes on x86. |
583 | * Also gets miscompiled for ARM users | 586 | * Also gets miscompiled for ARM users |
584 | * (busybox.net/bugs/view.php?id=2274). | 587 | * (busybox.net/bugs/view.php?id=2274). |
585 | * printf(("\b\b\b\b" + 4) - num); | 588 | * fprintf(("\b\b\b\b" + 4) - num, stderr); |
586 | * return; | 589 | * return; |
587 | */ | 590 | */ |
588 | do { | 591 | do { |
589 | bb_putchar('\b'); | 592 | bb_putchar_stderr('\b'); |
590 | } while (--num); | 593 | } while (--num); |
591 | return; | 594 | return; |
592 | } | 595 | } |
593 | #endif | 596 | #endif |
594 | printf(ESC"[%uD", num); | 597 | fprintf(stderr, ESC"[%uD", num); |
595 | return; | 598 | return; |
596 | } | 599 | } |
597 | 600 | ||
@@ -616,7 +619,7 @@ static void input_backward(unsigned num) | |||
616 | */ | 619 | */ |
617 | unsigned sv_cursor; | 620 | unsigned sv_cursor; |
618 | /* go to 1st column; go up to first line */ | 621 | /* go to 1st column; go up to first line */ |
619 | printf("\r" ESC"[%uA", cmdedit_y); | 622 | fprintf(stderr, "\r" ESC"[%uA", cmdedit_y); |
620 | cmdedit_y = 0; | 623 | cmdedit_y = 0; |
621 | sv_cursor = cursor; | 624 | sv_cursor = cursor; |
622 | put_prompt_last_line(); /* sets cursor to 0 */ | 625 | put_prompt_last_line(); /* sets cursor to 0 */ |
@@ -631,12 +634,12 @@ static void input_backward(unsigned num) | |||
631 | cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw; | 634 | cmdedit_x = (cmdedit_termw * cmdedit_y - num) % cmdedit_termw; |
632 | cmdedit_y -= lines_up; | 635 | cmdedit_y -= lines_up; |
633 | /* go to 1st column; go up */ | 636 | /* go to 1st column; go up */ |
634 | printf("\r" ESC"[%uA", lines_up); | 637 | fprintf(stderr, "\r" ESC"[%uA", lines_up); |
635 | /* go to correct column. | 638 | /* go to correct column. |
636 | * xterm, konsole, Linux VT interpret 0 as 1 below! wow. | 639 | * xterm, konsole, Linux VT interpret 0 as 1 below! wow. |
637 | * need to *make sure* we skip it if cmdedit_x == 0 */ | 640 | * need to *make sure* we skip it if cmdedit_x == 0 */ |
638 | if (cmdedit_x) | 641 | if (cmdedit_x) |
639 | printf(ESC"[%uC", cmdedit_x); | 642 | fprintf(stderr, ESC"[%uC", cmdedit_x); |
640 | } | 643 | } |
641 | } | 644 | } |
642 | 645 | ||
@@ -644,11 +647,11 @@ static void input_backward(unsigned num) | |||
644 | static void draw_custom(int y, int back_cursor, bool is_full) | 647 | static void draw_custom(int y, int back_cursor, bool is_full) |
645 | { | 648 | { |
646 | if (y > 0) /* up y lines */ | 649 | if (y > 0) /* up y lines */ |
647 | printf(ESC"[%uA", y); | 650 | fprintf(stderr, ESC"[%uA", y); |
648 | bb_putchar('\r'); | 651 | bb_putchar_stderr('\r'); |
649 | put_prompt_custom(is_full); | 652 | put_prompt_custom(is_full); |
650 | put_till_end_and_adv_cursor(); | 653 | put_till_end_and_adv_cursor(); |
651 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 654 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
652 | input_backward(back_cursor); | 655 | input_backward(back_cursor); |
653 | } | 656 | } |
654 | 657 | ||
@@ -693,7 +696,7 @@ static void input_delete(int save) | |||
693 | command_len--; | 696 | command_len--; |
694 | put_till_end_and_adv_cursor(); | 697 | put_till_end_and_adv_cursor(); |
695 | /* Last char is still visible, erase it (and more) */ | 698 | /* Last char is still visible, erase it (and more) */ |
696 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 699 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
697 | input_backward(cursor - j); /* back to old pos cursor */ | 700 | input_backward(cursor - j); /* back to old pos cursor */ |
698 | } | 701 | } |
699 | 702 | ||
@@ -1110,8 +1113,8 @@ static void remove_chunk(int16_t *int_buf, int beg, int end) | |||
1110 | if (dbg_bmp) { | 1113 | if (dbg_bmp) { |
1111 | int i; | 1114 | int i; |
1112 | for (i = 0; int_buf[i]; i++) | 1115 | for (i = 0; int_buf[i]; i++) |
1113 | bb_putchar((unsigned char)int_buf[i]); | 1116 | bb_putchar_stderr((unsigned char)int_buf[i]); |
1114 | bb_putchar('\n'); | 1117 | bb_putchar_stderr('\n'); |
1115 | } | 1118 | } |
1116 | } | 1119 | } |
1117 | /* Caller ensures that match_buf points to a malloced buffer | 1120 | /* Caller ensures that match_buf points to a malloced buffer |
@@ -1294,7 +1297,7 @@ static void showfiles(void) | |||
1294 | int nc; | 1297 | int nc; |
1295 | 1298 | ||
1296 | for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { | 1299 | for (nc = 1; nc < ncols && n+nrows < nfiles; n += nrows, nc++) { |
1297 | printf("%s%-*s", matches[n], | 1300 | fprintf(stderr, "%s%-*s", matches[n], |
1298 | (int)(column_width - unicode_strwidth(matches[n])), "" | 1301 | (int)(column_width - unicode_strwidth(matches[n])), "" |
1299 | ); | 1302 | ); |
1300 | } | 1303 | } |
@@ -1650,7 +1653,7 @@ void FAST_FUNC show_history(const line_input_t *st) | |||
1650 | if (!st) | 1653 | if (!st) |
1651 | return; | 1654 | return; |
1652 | for (i = 0; i < st->cnt_history; i++) | 1655 | for (i = 0; i < st->cnt_history; i++) |
1653 | printf("%4d %s\n", i, st->history[i]); | 1656 | fprintf(stderr, "%4d %s\n", i, st->history[i]); |
1654 | } | 1657 | } |
1655 | 1658 | ||
1656 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY | 1659 | # if ENABLE_FEATURE_EDITING_SAVEHISTORY |
@@ -2090,7 +2093,7 @@ static void ask_terminal(void) | |||
2090 | pfd.events = POLLIN; | 2093 | pfd.events = POLLIN; |
2091 | if (safe_poll(&pfd, 1, 0) == 0) { | 2094 | if (safe_poll(&pfd, 1, 0) == 0) { |
2092 | S.sent_ESC_br6n = 1; | 2095 | S.sent_ESC_br6n = 1; |
2093 | fputs_stdout(ESC"[6n"); | 2096 | fputs(ESC"[6n", stderr); |
2094 | fflush_all(); /* make terminal see it ASAP! */ | 2097 | fflush_all(); /* make terminal see it ASAP! */ |
2095 | } | 2098 | } |
2096 | } | 2099 | } |
@@ -2857,13 +2860,13 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
2857 | /* Control-k -- clear to end of line */ | 2860 | /* Control-k -- clear to end of line */ |
2858 | command_ps[cursor] = BB_NUL; | 2861 | command_ps[cursor] = BB_NUL; |
2859 | command_len = cursor; | 2862 | command_len = cursor; |
2860 | printf(SEQ_CLEAR_TILL_END_OF_SCREEN); | 2863 | fputs(SEQ_CLEAR_TILL_END_OF_SCREEN, stderr); |
2861 | break; | 2864 | break; |
2862 | case CTRL('L'): | 2865 | case CTRL('L'): |
2863 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) | 2866 | vi_case(CTRL('L')|VI_CMDMODE_BIT:) |
2864 | /* Control-l -- clear screen */ | 2867 | /* Control-l -- clear screen */ |
2865 | /* cursor to top,left; clear to the end of screen */ | 2868 | /* cursor to top,left; clear to the end of screen */ |
2866 | printf(ESC"[H" ESC"[J"); | 2869 | fputs(ESC"[H" ESC"[J", stderr); |
2867 | draw_full(command_len - cursor); | 2870 | draw_full(command_len - cursor); |
2868 | break; | 2871 | break; |
2869 | #if MAX_HISTORY > 0 | 2872 | #if MAX_HISTORY > 0 |
@@ -3050,8 +3053,8 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
3050 | beep(); | 3053 | beep(); |
3051 | } else { | 3054 | } else { |
3052 | command_ps[cursor] = ic; | 3055 | command_ps[cursor] = ic; |
3053 | bb_putchar(ic); | 3056 | bb_putchar_stderr(ic); |
3054 | bb_putchar('\b'); | 3057 | bb_putchar_stderr('\b'); |
3055 | } | 3058 | } |
3056 | break; | 3059 | break; |
3057 | case '\x1b': /* ESC */ | 3060 | case '\x1b': /* ESC */ |
@@ -3249,7 +3252,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman | |||
3249 | #undef read_line_input | 3252 | #undef read_line_input |
3250 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) | 3253 | int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) |
3251 | { | 3254 | { |
3252 | fputs_stdout(prompt); | 3255 | /* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html |
3256 | * says that shells must write $PSn to stderr, not stdout. | ||
3257 | */ | ||
3258 | fputs(prompt, stderr); | ||
3253 | fflush_all(); | 3259 | fflush_all(); |
3254 | if (!fgets(command, maxsize, stdin)) | 3260 | if (!fgets(command, maxsize, stdin)) |
3255 | return -1; | 3261 | return -1; |
diff --git a/libbb/popcnt.c b/libbb/popcnt.c new file mode 100644 index 000000000..fe8cd240f --- /dev/null +++ b/libbb/popcnt.c | |||
@@ -0,0 +1,46 @@ | |||
1 | /* vi: set sw=4 ts=4: */ | ||
2 | /* | ||
3 | * Utility routines. | ||
4 | * | ||
5 | * Copyright (C) 2024 Denys Vlasenko | ||
6 | * | ||
7 | * Licensed under GPLv2, see file LICENSE in this source tree. | ||
8 | */ | ||
9 | #include "libbb.h" | ||
10 | |||
11 | unsigned FAST_FUNC bb_popcnt_32(uint32_t m) | ||
12 | { | ||
13 | /* replace each 2 bit group with the count of set bits in it */ | ||
14 | /* 00->00 01->01 10->01 11->10 */ | ||
15 | m = m - ((m >> 1) & 0x55555555); | ||
16 | /* in each 4 bit group, add two 2-bit counts */ | ||
17 | m = (m & 0x33333333) + ((m >> 2) & 0x33333333); | ||
18 | /* in each 8 bit group, add two 4-bit counts (in fact, 3-bit, 0nnn with n=0..4) */ | ||
19 | m = (m + (m >> 4)) & 0x0f0f0f0f; | ||
20 | #if 1 /* assume 32*32->32 multiply is fast */ | ||
21 | m = m * 0x01010101; /* top byte = m + (m<<8) + (m<<16) + (m<<24) */ | ||
22 | return m >> 24; | ||
23 | #else | ||
24 | /* 0000aaaa0000bbbb0000cccc0000dddd */ | ||
25 | /* + 0000aaaa0000bbbb0000cccc */ | ||
26 | /* = 0000xxxx000_a+b_000xxxxx000_c+d_ (we don't care about x bits) */ | ||
27 | m += m >> 8; /* in each 16-bit group, lowest 5 bits is the count */ | ||
28 | /* 0000xxxx000_a+b_000xxxxx000_c+d_ */ | ||
29 | /* + 0000xxxx000_a+b_ */ | ||
30 | /* = 0000xxxx000xxxxx00xxxxxx00a+b+cd */ | ||
31 | m += m >> 16; /* in each 32-bit group, lowest 6 bits is the count */ | ||
32 | return m & 0x3f; /* clear x bits */ | ||
33 | #endif | ||
34 | } | ||
35 | |||
36 | #if ULONG_MAX > 0xffffffff | ||
37 | unsigned FAST_FUNC bb_popcnt_long(unsigned long m) | ||
38 | { | ||
39 | BUILD_BUG_ON(sizeof(m) != 8); | ||
40 | /* 64-bit version of bb_popcnt_32 exists, but it uses 64-bit constants, | ||
41 | * which are awkward to generate on assembly level on most CPUs. | ||
42 | * For now, just add two 32-bit counts: | ||
43 | */ | ||
44 | return bb_popcnt_32((uint32_t)m) + bb_popcnt_32((uint32_t)(m >> 32)); | ||
45 | } | ||
46 | #endif | ||
diff --git a/miscutils/crond.c b/miscutils/crond.c index 3bbb5ac83..b3762d327 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c | |||
@@ -190,7 +190,7 @@ static void log5(const char *msg, ...) | |||
190 | { | 190 | { |
191 | va_list va; | 191 | va_list va; |
192 | va_start(va, msg); | 192 | va_start(va, msg); |
193 | crondlog(4, msg, va); | 193 | crondlog(5, msg, va); |
194 | va_end(va); | 194 | va_end(va); |
195 | } | 195 | } |
196 | 196 | ||
diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 6c4ae27f2..9c3640be7 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c | |||
@@ -306,7 +306,6 @@ static int count_netmask_bits(const char *dotted_quad) | |||
306 | // d = ~d; /* 11110000 -> 00001111 */ | 306 | // d = ~d; /* 11110000 -> 00001111 */ |
307 | 307 | ||
308 | /* Shorter version */ | 308 | /* Shorter version */ |
309 | int result; | ||
310 | struct in_addr ip; | 309 | struct in_addr ip; |
311 | unsigned d; | 310 | unsigned d; |
312 | 311 | ||
@@ -316,12 +315,7 @@ static int count_netmask_bits(const char *dotted_quad) | |||
316 | d = ~d; /* 11110000 -> 00001111 */ | 315 | d = ~d; /* 11110000 -> 00001111 */ |
317 | if (d & (d+1)) /* check that it is in 00001111 form */ | 316 | if (d & (d+1)) /* check that it is in 00001111 form */ |
318 | return -1; /* no it is not */ | 317 | return -1; /* no it is not */ |
319 | result = 32; | 318 | return bb_popcnt_32(~d); |
320 | while (d) { | ||
321 | d >>= 1; | ||
322 | result--; | ||
323 | } | ||
324 | return result; | ||
325 | } | 319 | } |
326 | # endif | 320 | # endif |
327 | 321 | ||
diff --git a/networking/ip.c b/networking/ip.c index 36126b747..02f93adbf 100644 --- a/networking/ip.c +++ b/networking/ip.c | |||
@@ -74,6 +74,12 @@ | |||
74 | //config: help | 74 | //config: help |
75 | //config: Configure network devices with "ip". | 75 | //config: Configure network devices with "ip". |
76 | //config: | 76 | //config: |
77 | //config:config FEATURE_IP_LINK_CAN | ||
78 | //config: bool "ip link set type can" | ||
79 | //config: default y | ||
80 | //config: help | ||
81 | //config: Configure CAN devices with "ip". | ||
82 | //config: | ||
77 | //config:config FEATURE_IP_ROUTE | 83 | //config:config FEATURE_IP_ROUTE |
78 | //config: bool "ip route" | 84 | //config: bool "ip route" |
79 | //config: default y | 85 | //config: default y |
@@ -152,16 +158,61 @@ | |||
152 | //usage:#define iplink_trivial_usage | 158 | //usage:#define iplink_trivial_usage |
153 | //usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" | 159 | //usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" |
154 | //usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" | 160 | //usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" |
155 | //usage: " [master IFACE | nomaster] [netns PID]" | 161 | //usage: " [master IFACE | nomaster] [netns PID]"IF_FEATURE_IP_LINK_CAN(" [type TYPE ARGS]") |
156 | // * short help shows only "set" command, long help continues (with just one "\n") | 162 | // * short help shows only "set" command, long help continues (with just one "\n") |
157 | // * and shows all other commands: | 163 | // * and shows all other commands: |
158 | //usage:#define iplink_full_usage "\n" | 164 | //usage:#define iplink_full_usage "\n" |
159 | //usage: "iplink add [link IFACE] IFACE [address MAC] type TYPE [ARGS]\n" | 165 | //usage: "iplink add [link IFACE] IFACE [address MAC] type TYPE [ARGS]\n" |
160 | //usage: "iplink delete IFACE type TYPE [ARGS]\n" | 166 | //usage: "iplink delete IFACE type TYPE [ARGS]\n" |
161 | //usage: " TYPE ARGS := vlan VLANARGS | vrf table NUM\n" | 167 | //usage: " TYPE ARGS := vlan VLANARGS | vrf table NUM"IF_FEATURE_IP_LINK_CAN(" | can CANARGS")"\n" |
162 | //usage: " VLANARGS := id VLANID [protocol 802.1q|802.1ad] [reorder_hdr on|off]\n" | 168 | //usage: " VLANARGS := id VLANID [protocol 802.1q|802.1ad] [reorder_hdr on|off]\n" |
163 | //usage: " [gvrp on|off] [mvrp on|off] [loose_binding on|off]\n" | 169 | //usage: " [gvrp on|off] [mvrp on|off] [loose_binding on|off]\n" |
170 | //usage: IF_FEATURE_IP_LINK_CAN( | ||
171 | //usage: " CANARGS := [bitrate BITRATE [sample-point SAMPLE-POINT]] |\n" | ||
172 | //usage: " [tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1\n" | ||
173 | //usage: " phase-seg2 PHASE-SEG2 [sjw SJW]]\n" | ||
174 | //usage: " [dbitrate BITRATE [dsample-point SAMPLE-POINT]] |\n" | ||
175 | //usage: " [dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1\n" | ||
176 | //usage: " dphase-seg2 PHASE-SEG2 [dsjw SJW]]\n" | ||
177 | //usage: " [loopback on|off] [listen-only on|off] [triple-sampling on|off]\n" | ||
178 | //usage: " [one-shot on|off] [berr-reporting on|off]\n" | ||
179 | //usage: " [fd on|off] [fd-non-iso on|off] [presume-ack on|off]\n" | ||
180 | //usage: " [restart-ms TIME-MS] [restart]\n" | ||
181 | //usage: " [termination 0..65535]\n" | ||
182 | //usage: ) | ||
164 | //usage: "iplink show [IFACE]" | 183 | //usage: "iplink show [IFACE]" |
184 | //upstream man ip-link-can: | ||
185 | //Usage: ip link set DEVICE type can | ||
186 | // [ bitrate BITRATE [ sample-point SAMPLE-POINT] ] | | ||
187 | // [ tq TQ prop-seg PROP_SEG phase-seg1 PHASE-SEG1 | ||
188 | // phase-seg2 PHASE-SEG2 [ sjw SJW ] ] | ||
189 | // | ||
190 | // [ dbitrate BITRATE [ dsample-point SAMPLE-POINT] ] | | ||
191 | // [ dtq TQ dprop-seg PROP_SEG dphase-seg1 PHASE-SEG1 | ||
192 | // dphase-seg2 PHASE-SEG2 [ dsjw SJW ] ] | ||
193 | // | ||
194 | // [ loopback { on | off } ] | ||
195 | // [ listen-only { on | off } ] | ||
196 | // [ triple-sampling { on | off } ] | ||
197 | // [ one-shot { on | off } ] | ||
198 | // [ berr-reporting { on | off } ] | ||
199 | // [ fd { on | off } ] | ||
200 | // [ fd-non-iso { on | off } ] | ||
201 | // [ presume-ack { on | off } ] | ||
202 | // | ||
203 | // [ restart-ms TIME-MS ] | ||
204 | // [ restart ] | ||
205 | // | ||
206 | // [ termination { 0..65535 } ] | ||
207 | // | ||
208 | // Where: BITRATE := { 1..1000000 } | ||
209 | // SAMPLE-POINT := { 0.000..0.999 } | ||
210 | // TQ := { NUMBER } | ||
211 | // PROP-SEG := { 1..8 } | ||
212 | // PHASE-SEG1 := { 1..8 } | ||
213 | // PHASE-SEG2 := { 1..8 } | ||
214 | // SJW := { 1..4 } | ||
215 | // RESTART-MS := { 0 | NUMBER } | ||
165 | //upstream man ip-link: | 216 | //upstream man ip-link: |
166 | //===================== | 217 | //===================== |
167 | //ip link add [link DEV] [ name ] NAME | 218 | //ip link add [link DEV] [ name ] NAME |
diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 92e7b289d..3ec473c6b 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c | |||
@@ -71,25 +71,6 @@ static unsigned long get_netmask(unsigned long ipaddr) | |||
71 | return 0; | 71 | return 0; |
72 | } | 72 | } |
73 | 73 | ||
74 | #if ENABLE_FEATURE_IPCALC_FANCY | ||
75 | static int get_prefix(unsigned long netmask) | ||
76 | { | ||
77 | unsigned long msk = 0x80000000; | ||
78 | int ret = 0; | ||
79 | |||
80 | netmask = htonl(netmask); | ||
81 | while (msk) { | ||
82 | if (netmask & msk) | ||
83 | ret++; | ||
84 | msk >>= 1; | ||
85 | } | ||
86 | return ret; | ||
87 | } | ||
88 | #else | ||
89 | int get_prefix(unsigned long netmask); | ||
90 | #endif | ||
91 | |||
92 | |||
93 | #define NETMASK 0x01 | 74 | #define NETMASK 0x01 |
94 | #define BROADCAST 0x02 | 75 | #define BROADCAST 0x02 |
95 | #define NETWORK 0x04 | 76 | #define NETWORK 0x04 |
@@ -210,7 +191,7 @@ int ipcalc_main(int argc UNUSED_PARAM, char **argv) | |||
210 | 191 | ||
211 | if (ENABLE_FEATURE_IPCALC_FANCY) { | 192 | if (ENABLE_FEATURE_IPCALC_FANCY) { |
212 | if (opt & NETPREFIX) { | 193 | if (opt & NETPREFIX) { |
213 | printf("PREFIX=%i\n", get_prefix(netmask)); | 194 | printf("PREFIX=%i\n", bb_popcnt_32(netmask)); |
214 | } | 195 | } |
215 | 196 | ||
216 | if (opt & HOSTNAME) { | 197 | if (opt & HOSTNAME) { |
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 9eb0b4f5f..37ed114bc 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c | |||
@@ -11,6 +11,9 @@ | |||
11 | #include <netinet/if_ether.h> | 11 | #include <netinet/if_ether.h> |
12 | 12 | ||
13 | #include <linux/if_vlan.h> | 13 | #include <linux/if_vlan.h> |
14 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
15 | # include <linux/can/netlink.h> | ||
16 | #endif | ||
14 | #include "ip_common.h" /* #include "libbb.h" is inside */ | 17 | #include "ip_common.h" /* #include "libbb.h" is inside */ |
15 | #include "rt_names.h" | 18 | #include "rt_names.h" |
16 | #include "utils.h" | 19 | #include "utils.h" |
@@ -28,6 +31,11 @@ | |||
28 | #undef IFLA_VLAN_PROTOCOL | 31 | #undef IFLA_VLAN_PROTOCOL |
29 | #define IFLA_VLAN_PROTOCOL 5 | 32 | #define IFLA_VLAN_PROTOCOL 5 |
30 | 33 | ||
34 | #ifndef NLMSG_TAIL | ||
35 | #define NLMSG_TAIL(nmsg) \ | ||
36 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) | ||
37 | #endif | ||
38 | |||
31 | #ifndef IFLA_LINKINFO | 39 | #ifndef IFLA_LINKINFO |
32 | # define IFLA_LINKINFO 18 | 40 | # define IFLA_LINKINFO 18 |
33 | # define IFLA_INFO_KIND 1 | 41 | # define IFLA_INFO_KIND 1 |
@@ -55,6 +63,11 @@ struct ifla_vlan_flags { | |||
55 | 63 | ||
56 | #define str_on_off "on\0""off\0" | 64 | #define str_on_off "on\0""off\0" |
57 | 65 | ||
66 | enum { | ||
67 | PARM_on = 0, | ||
68 | PARM_off | ||
69 | }; | ||
70 | |||
58 | /* Exits on error */ | 71 | /* Exits on error */ |
59 | static int get_ctl_fd(void) | 72 | static int get_ctl_fd(void) |
60 | { | 73 | { |
@@ -241,10 +254,257 @@ static void die_must_be_on_off(const char *msg) | |||
241 | bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg); | 254 | bb_error_msg_and_die("argument of \"%s\" must be \"on\" or \"off\"", msg); |
242 | } | 255 | } |
243 | 256 | ||
257 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
258 | static uint32_t get_float_1000(char *arg, const char *errmsg) | ||
259 | { | ||
260 | uint32_t ret; | ||
261 | double d; | ||
262 | char *ptr; | ||
263 | |||
264 | errno = 0; | ||
265 | //TODO: needs setlocale(LC_NUMERIC, "C")? | ||
266 | d = strtod(arg, &ptr); | ||
267 | if (errno || ptr == arg || *ptr | ||
268 | || d > (0xFFFFFFFFU / 1000) || d < 0 | ||
269 | ) { | ||
270 | invarg_1_to_2(arg, errmsg); /* does not return */ | ||
271 | } | ||
272 | ret = d * 1000; | ||
273 | |||
274 | return ret; | ||
275 | } | ||
276 | |||
277 | static void do_set_can(char *dev, char **argv) | ||
278 | { | ||
279 | struct can_bittiming bt = {}, dbt = {}; | ||
280 | struct can_ctrlmode cm = {}; | ||
281 | char *keyword; | ||
282 | static const char keywords[] ALIGN1 = | ||
283 | "bitrate\0""sample-point\0""tq\0" | ||
284 | "prop-seg\0""phase-seg1\0""phase-seg2\0""sjw\0" | ||
285 | "dbitrate\0""dsample-point\0""dtq\0" | ||
286 | "dprop-seg\0""dphase-seg1\0""dphase-seg2\0""dsjw\0" | ||
287 | "loopback\0""listen-only\0""triple-sampling\0" | ||
288 | "one-shot\0""berr-reporting\0" | ||
289 | "fd\0""fd-non-iso\0""presume-ack\0" | ||
290 | "cc-len8-dlc\0""restart\0""restart-ms\0" | ||
291 | "termination\0"; | ||
292 | enum { ARG_bitrate = 0, ARG_sample_point, ARG_tq, | ||
293 | ARG_prop_seg, ARG_phase_seg1, ARG_phase_seg2, ARG_sjw, | ||
294 | ARG_dbitrate, ARG_dsample_point, ARG_dtq, | ||
295 | ARG_dprop_seg, ARG_dphase_seg1, ARG_dphase_seg2, ARG_dsjw, | ||
296 | ARG_loopback, ARG_listen_only, ARG_triple_sampling, | ||
297 | ARG_one_shot, ARG_berr_reporting, | ||
298 | ARG_fd, ARG_fd_non_iso, ARG_presume_ack, | ||
299 | ARG_cc_len8_dlc, ARG_restart, ARG_restart_ms, | ||
300 | ARG_termination }; | ||
301 | struct rtnl_handle rth; | ||
302 | struct { | ||
303 | struct nlmsghdr n; | ||
304 | struct ifinfomsg i; | ||
305 | char buf[1024]; | ||
306 | } req; | ||
307 | size_t dev_len; | ||
308 | struct rtattr *linkinfo, *data; | ||
309 | smalluint key, param; | ||
310 | |||
311 | memset(&req, 0, sizeof(req)); | ||
312 | |||
313 | req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); | ||
314 | req.n.nlmsg_flags = NLM_F_REQUEST; | ||
315 | req.n.nlmsg_type = RTM_NEWLINK; | ||
316 | req.i.ifi_family = preferred_family; | ||
317 | xrtnl_open(&rth); | ||
318 | req.i.ifi_index = xll_name_to_index(dev); | ||
319 | dev_len = strlen(dev); | ||
320 | if (dev_len < 2 || dev_len > IFNAMSIZ) | ||
321 | invarg_1_to_2(dev, "dev"); | ||
322 | |||
323 | addattr_l(&req.n, sizeof(req), IFLA_IFNAME, dev, dev_len); | ||
324 | linkinfo = NLMSG_TAIL(&req.n); | ||
325 | addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); | ||
326 | addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, (void *)"can", | ||
327 | strlen("can")); | ||
328 | data = NLMSG_TAIL(&req.n); | ||
329 | addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); | ||
330 | while (*argv) { | ||
331 | key = index_in_substrings(keywords, *argv); | ||
332 | keyword = *argv; | ||
333 | //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); | ||
334 | switch (key) { | ||
335 | case ARG_bitrate: | ||
336 | case ARG_tq: | ||
337 | case ARG_prop_seg: | ||
338 | case ARG_phase_seg1: | ||
339 | case ARG_phase_seg2: | ||
340 | case ARG_sjw: { | ||
341 | uint32_t *val; | ||
342 | NEXT_ARG(); | ||
343 | if (key == ARG_bitrate) | ||
344 | val = &bt.bitrate; | ||
345 | else if (key == ARG_tq) | ||
346 | val = &bt.tq; | ||
347 | else if (key == ARG_prop_seg) | ||
348 | val = &bt.prop_seg; | ||
349 | else if (key == ARG_phase_seg1) | ||
350 | val = &bt.phase_seg1; | ||
351 | else if (key == ARG_phase_seg2) | ||
352 | val = &bt.phase_seg2; | ||
353 | else | ||
354 | val = &bt.sjw; | ||
355 | |||
356 | *val = get_u32(*argv, keyword); | ||
357 | break; | ||
358 | } | ||
359 | case ARG_sample_point: { | ||
360 | NEXT_ARG(); | ||
361 | bt.sample_point = get_float_1000(*argv, keyword); | ||
362 | break; | ||
363 | } | ||
364 | case ARG_dbitrate: | ||
365 | case ARG_dtq: | ||
366 | case ARG_dprop_seg: | ||
367 | case ARG_dphase_seg1: | ||
368 | case ARG_dphase_seg2: | ||
369 | case ARG_dsjw: { | ||
370 | uint32_t *val; | ||
371 | NEXT_ARG(); | ||
372 | if (key == ARG_dbitrate) | ||
373 | val = &dbt.bitrate; | ||
374 | else if (key == ARG_dtq) | ||
375 | val = &dbt.tq; | ||
376 | else if (key == ARG_dprop_seg) | ||
377 | val = &dbt.prop_seg; | ||
378 | else if (key == ARG_dphase_seg1) | ||
379 | val = &dbt.phase_seg1; | ||
380 | else if (key == ARG_dphase_seg2) | ||
381 | val = &dbt.phase_seg2; | ||
382 | else | ||
383 | val = &dbt.sjw; | ||
384 | |||
385 | *val = get_u32(*argv, keyword); | ||
386 | break; | ||
387 | } | ||
388 | case ARG_dsample_point: { | ||
389 | NEXT_ARG(); | ||
390 | dbt.sample_point = get_float_1000(*argv, keyword); | ||
391 | break; | ||
392 | } | ||
393 | case ARG_loopback: | ||
394 | case ARG_listen_only: | ||
395 | case ARG_triple_sampling: | ||
396 | case ARG_one_shot: | ||
397 | case ARG_berr_reporting: | ||
398 | case ARG_fd: | ||
399 | case ARG_fd_non_iso: | ||
400 | case ARG_presume_ack: | ||
401 | case ARG_cc_len8_dlc: { | ||
402 | uint32_t flag = 0; | ||
403 | |||
404 | NEXT_ARG(); | ||
405 | param = index_in_strings(str_on_off, *argv); | ||
406 | if (param < 0) | ||
407 | die_must_be_on_off(keyword); | ||
408 | |||
409 | if (key == ARG_loopback) | ||
410 | flag = CAN_CTRLMODE_LOOPBACK; | ||
411 | else if (key == ARG_listen_only) | ||
412 | flag = CAN_CTRLMODE_LISTENONLY; | ||
413 | else if (key == ARG_triple_sampling) | ||
414 | flag = CAN_CTRLMODE_3_SAMPLES; | ||
415 | else if (key == ARG_one_shot) | ||
416 | flag = CAN_CTRLMODE_ONE_SHOT; | ||
417 | else if (key == ARG_berr_reporting) | ||
418 | flag = CAN_CTRLMODE_BERR_REPORTING; | ||
419 | else if (key == ARG_fd) | ||
420 | flag = CAN_CTRLMODE_FD; | ||
421 | else if (key == ARG_fd_non_iso) | ||
422 | flag = CAN_CTRLMODE_FD_NON_ISO; | ||
423 | else if (key == ARG_presume_ack) | ||
424 | flag = CAN_CTRLMODE_PRESUME_ACK; | ||
425 | else | ||
426 | #if defined(CAN_CTRLMODE_CC_LEN8_DLC) | ||
427 | flag = CAN_CTRLMODE_CC_LEN8_DLC; | ||
428 | #else | ||
429 | die_must_be_on_off(keyword); | ||
430 | #endif | ||
431 | cm.mask |= flag; | ||
432 | if (param == PARM_on) | ||
433 | cm.flags |= flag; | ||
434 | |||
435 | break; | ||
436 | } | ||
437 | case ARG_restart: { | ||
438 | uint32_t val = 1; | ||
439 | /*NEXT_ARG(); - WRONG? */ | ||
440 | addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART, &val, sizeof(val)); | ||
441 | break; | ||
442 | } | ||
443 | case ARG_restart_ms: { | ||
444 | uint32_t val; | ||
445 | NEXT_ARG(); | ||
446 | val = get_u32(*argv, keyword); | ||
447 | addattr_l(&req.n, sizeof(req), IFLA_CAN_RESTART_MS, &val, sizeof(val)); | ||
448 | break; | ||
449 | } | ||
450 | case ARG_termination: { | ||
451 | uint16_t val; | ||
452 | NEXT_ARG(); | ||
453 | val = get_u16(*argv, keyword); | ||
454 | addattr_l(&req.n, sizeof(req), IFLA_CAN_TERMINATION, &val, sizeof(val)); | ||
455 | break; | ||
456 | } | ||
457 | default: | ||
458 | break; | ||
459 | } | ||
460 | argv++; | ||
461 | } | ||
462 | |||
463 | if (bt.bitrate || bt.tq) | ||
464 | addattr_l(&req.n, sizeof(req), IFLA_CAN_BITTIMING, &bt, sizeof(bt)); | ||
465 | |||
466 | if (cm.mask) | ||
467 | addattr_l(&req.n, sizeof(req), IFLA_CAN_CTRLMODE, &cm, sizeof(cm)); | ||
468 | |||
469 | data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; | ||
470 | linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; | ||
471 | |||
472 | if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) | ||
473 | xfunc_die(); | ||
474 | } | ||
475 | |||
476 | static void set_type(char *type, char *dev, char **argv) | ||
477 | { | ||
478 | /* When we have more than just "type can ARGS" supported, maybe: | ||
479 | static const char keywords[] ALIGN1 = "" | ||
480 | IF_FEATURE_IP_LINK_CAN("can\0") | ||
481 | ; | ||
482 | typedef void FAST_FUNC(*ip_type_set_func_ptr_t)(char*, char**); | ||
483 | static const ip_type_set_func_ptr_t funcs[] ALIGN_PTR = { | ||
484 | IF_FEATURE_IP_LINK_CAN(do_set_can,) | ||
485 | }; | ||
486 | ip_type_set_func_ptr_t func; | ||
487 | int key; | ||
488 | |||
489 | key = index_in_substrings(keywords, type); | ||
490 | if (key < 0) | ||
491 | invarg_1_to_2(type, "type"); | ||
492 | func = funcs[key]; | ||
493 | func(dev, argv); | ||
494 | */ | ||
495 | if (strcmp(type, "can") != 0) | ||
496 | invarg_1_to_2(type, "type"); | ||
497 | do_set_can(dev, argv); | ||
498 | } | ||
499 | #endif | ||
500 | |||
244 | /* Return value becomes exitcode. It's okay to not return at all */ | 501 | /* Return value becomes exitcode. It's okay to not return at all */ |
245 | static int do_set(char **argv) | 502 | static int do_set(char **argv) |
246 | { | 503 | { |
247 | char *dev = NULL; | 504 | char *dev = NULL; |
505 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
506 | char *type = NULL; | ||
507 | #endif | ||
248 | uint32_t mask = 0; | 508 | uint32_t mask = 0; |
249 | uint32_t flags = 0; | 509 | uint32_t flags = 0; |
250 | int qlen = -1; | 510 | int qlen = -1; |
@@ -261,18 +521,24 @@ static int do_set(char **argv) | |||
261 | "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" | 521 | "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" |
262 | "arp\0""promisc\0""address\0""netns\0" | 522 | "arp\0""promisc\0""address\0""netns\0" |
263 | "master\0""nomaster\0" | 523 | "master\0""nomaster\0" |
524 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
525 | "type\0" | ||
526 | #endif | ||
264 | "dev\0" /* must be last */; | 527 | "dev\0" /* must be last */; |
265 | enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, | 528 | enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, |
266 | ARG_arp, ARG_promisc, ARG_addr, ARG_netns, | 529 | ARG_arp, ARG_promisc, ARG_addr, ARG_netns, |
267 | ARG_master, ARG_nomaster, | 530 | ARG_master, ARG_nomaster, |
531 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
532 | ARG_type, | ||
533 | #endif | ||
268 | ARG_dev }; | 534 | ARG_dev }; |
269 | enum { PARM_on = 0, PARM_off }; | ||
270 | smalluint key; | 535 | smalluint key; |
271 | 536 | ||
272 | while (*argv) { | 537 | while (*argv) { |
273 | /* substring search ensures that e.g. "addr" and "address" | 538 | /* substring search ensures that e.g. "addr" and "address" |
274 | * are both accepted */ | 539 | * are both accepted */ |
275 | key = index_in_substrings(keywords, *argv); | 540 | key = index_in_substrings(keywords, *argv); |
541 | //printf("%s: key: %d, *argv: %s\n", __func__, key, *argv); | ||
276 | if (key == ARG_up) { | 542 | if (key == ARG_up) { |
277 | mask |= IFF_UP; | 543 | mask |= IFF_UP; |
278 | flags |= IFF_UP; | 544 | flags |= IFF_UP; |
@@ -304,6 +570,13 @@ static int do_set(char **argv) | |||
304 | } else if (key == ARG_netns) { | 570 | } else if (key == ARG_netns) { |
305 | NEXT_ARG(); | 571 | NEXT_ARG(); |
306 | netns = get_unsigned(*argv, "netns"); | 572 | netns = get_unsigned(*argv, "netns"); |
573 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
574 | } else if (key == ARG_type) { | ||
575 | NEXT_ARG(); | ||
576 | type = *argv; | ||
577 | argv++; | ||
578 | break; | ||
579 | #endif | ||
307 | } else if (key >= ARG_dev) { | 580 | } else if (key >= ARG_dev) { |
308 | /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ | 581 | /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ |
309 | if (key == ARG_dev) { | 582 | if (key == ARG_dev) { |
@@ -311,6 +584,7 @@ static int do_set(char **argv) | |||
311 | } | 584 | } |
312 | if (dev) | 585 | if (dev) |
313 | duparg2("dev", *argv); | 586 | duparg2("dev", *argv); |
587 | |||
314 | dev = *argv; | 588 | dev = *argv; |
315 | } else { | 589 | } else { |
316 | /* "on|off" options */ | 590 | /* "on|off" options */ |
@@ -496,6 +770,10 @@ static int do_set(char **argv) | |||
496 | } | 770 | } |
497 | if (mask) | 771 | if (mask) |
498 | do_chflags(dev, flags, mask); | 772 | do_chflags(dev, flags, mask); |
773 | #if ENABLE_FEATURE_IP_LINK_CAN | ||
774 | if (type) | ||
775 | set_type(type, dev, argv); | ||
776 | #endif | ||
499 | return 0; | 777 | return 0; |
500 | } | 778 | } |
501 | 779 | ||
@@ -531,10 +809,6 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | |||
531 | PROTO_8021Q = 0, | 809 | PROTO_8021Q = 0, |
532 | PROTO_8021AD, | 810 | PROTO_8021AD, |
533 | }; | 811 | }; |
534 | enum { | ||
535 | PARM_on = 0, | ||
536 | PARM_off | ||
537 | }; | ||
538 | int arg; | 812 | int arg; |
539 | uint16_t id, proto; | 813 | uint16_t id, proto; |
540 | struct ifla_vlan_flags flags = {}; | 814 | struct ifla_vlan_flags flags = {}; |
@@ -610,10 +884,6 @@ static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | |||
610 | addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table)); | 884 | addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table)); |
611 | } | 885 | } |
612 | 886 | ||
613 | #ifndef NLMSG_TAIL | ||
614 | #define NLMSG_TAIL(nmsg) \ | ||
615 | ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) | ||
616 | #endif | ||
617 | /* Return value becomes exitcode. It's okay to not return at all */ | 887 | /* Return value becomes exitcode. It's okay to not return at all */ |
618 | static int do_add_or_delete(char **argv, const unsigned rtm) | 888 | static int do_add_or_delete(char **argv, const unsigned rtm) |
619 | { | 889 | { |
diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index 4ce230356..3cce4a06e 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c | |||
@@ -175,14 +175,13 @@ static void get_prefix_1(inet_prefix *dst, char *arg, int family) | |||
175 | if (netmask_pfx.family == AF_INET) { | 175 | if (netmask_pfx.family == AF_INET) { |
176 | /* fill in prefix length of dotted quad */ | 176 | /* fill in prefix length of dotted quad */ |
177 | uint32_t mask = ntohl(netmask_pfx.data[0]); | 177 | uint32_t mask = ntohl(netmask_pfx.data[0]); |
178 | uint32_t host = ~mask; | 178 | uint32_t inv = ~mask; |
179 | 179 | ||
180 | /* a valid netmask must be 2^n - 1 */ | 180 | /* a valid netmask must be 11..10..00 */ |
181 | if (host & (host + 1)) | 181 | if (inv & (inv + 1)) |
182 | goto bad; | 182 | goto bad; /* inv is not 00..01..11 */ |
183 | 183 | ||
184 | for (plen = 0; mask; mask <<= 1) | 184 | plen = bb_popcnt_32(mask); |
185 | ++plen; | ||
186 | if (plen > dst->bitlen) | 185 | if (plen > dst->bitlen) |
187 | goto bad; | 186 | goto bad; |
188 | /* dst->flags |= PREFIXLEN_SPECIFIED; */ | 187 | /* dst->flags |= PREFIXLEN_SPECIFIED; */ |
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index cfa133eae..d35c9e140 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c | |||
@@ -31,7 +31,7 @@ | |||
31 | * Much of author's comments are still retained in the code. | 31 | * Much of author's comments are still retained in the code. |
32 | * | 32 | * |
33 | * Functionality removed (rationale): | 33 | * Functionality removed (rationale): |
34 | * - miltiple-port ranges, randomized port scanning (use nmap) | 34 | * - multiple-port ranges, randomized port scanning (use nmap) |
35 | * - telnet support (use telnet) | 35 | * - telnet support (use telnet) |
36 | * - source routing | 36 | * - source routing |
37 | * - multiple DNS checks | 37 | * - multiple DNS checks |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index a72fd31bd..79cef1999 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -604,7 +604,7 @@ static NOINLINE int send_d6_info_request(void) | |||
604 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); | 604 | return d6_mcast_from_client_data_ifindex(&packet, opt_ptr); |
605 | } | 605 | } |
606 | 606 | ||
607 | /* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. | 607 | /* Multicast a DHCPv6 Solicit packet to the network, with an optionally requested IP. |
608 | * | 608 | * |
609 | * RFC 3315 17.1.1. Creation of Solicit Messages | 609 | * RFC 3315 17.1.1. Creation of Solicit Messages |
610 | * | 610 | * |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 07e2eadfe..e44086c2e 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -150,18 +150,6 @@ static int sprint_nip(char *dest, const char *pre, const uint8_t *ip) | |||
150 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); | 150 | return sprintf(dest, "%s%u.%u.%u.%u", pre, ip[0], ip[1], ip[2], ip[3]); |
151 | } | 151 | } |
152 | 152 | ||
153 | /* really simple implementation, just count the bits */ | ||
154 | static int mton(uint32_t mask) | ||
155 | { | ||
156 | int i = 0; | ||
157 | mask = ntohl(mask); /* 111110000-like bit pattern */ | ||
158 | while (mask) { | ||
159 | i++; | ||
160 | mask <<= 1; | ||
161 | } | ||
162 | return i; | ||
163 | } | ||
164 | |||
165 | #if ENABLE_FEATURE_UDHCPC_SANITIZEOPT | 153 | #if ENABLE_FEATURE_UDHCPC_SANITIZEOPT |
166 | /* Check if a given name represents a valid DNS name */ | 154 | /* Check if a given name represents a valid DNS name */ |
167 | /* See RFC1035, 2.3.1 */ | 155 | /* See RFC1035, 2.3.1 */ |
@@ -508,7 +496,8 @@ static void fill_envp(struct dhcp_packet *packet) | |||
508 | /* Generate extra envvar for DHCP_SUBNET, $mask */ | 496 | /* Generate extra envvar for DHCP_SUBNET, $mask */ |
509 | uint32_t subnet; | 497 | uint32_t subnet; |
510 | move_from_unaligned32(subnet, opt_item->data); | 498 | move_from_unaligned32(subnet, opt_item->data); |
511 | putenvp(xasprintf("mask=%u", mton(subnet))); | 499 | //FIXME: we do not check that subnet has bit pattern 11..10..0 |
500 | putenvp(xasprintf("mask=%u", bb_popcnt_32(subnet))); | ||
512 | } | 501 | } |
513 | } else { | 502 | } else { |
514 | unsigned ofs; | 503 | unsigned ofs; |
diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 2c7a19b83..c488cd53e 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c | |||
@@ -195,6 +195,7 @@ void find_export_symbols(char * filename) | |||
195 | { | 195 | { |
196 | fprintf(stderr, "docproc: "); | 196 | fprintf(stderr, "docproc: "); |
197 | perror(real_filename); | 197 | perror(real_filename); |
198 | exit(1); | ||
198 | } | 199 | } |
199 | while (fgets(line, MAXLINESZ, fp)) { | 200 | while (fgets(line, MAXLINESZ, fp)) { |
200 | unsigned char *p; | 201 | unsigned char *p; |
diff --git a/shell/ash.c b/shell/ash.c index 817b5635f..9ef8f7742 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -7884,6 +7884,11 @@ subevalvar(char *start, char *str, int strloc, | |||
7884 | repl = NULL; | 7884 | repl = NULL; |
7885 | break; | 7885 | break; |
7886 | } | 7886 | } |
7887 | /* Skip over quoted 'str'. Example: ${var/'/'} - second / is not a separator */ | ||
7888 | if ((unsigned char)*repl == CTLQUOTEMARK) { | ||
7889 | while ((unsigned char)*++repl != CTLQUOTEMARK) | ||
7890 | continue; | ||
7891 | } | ||
7887 | if (*repl == '/') { | 7892 | if (*repl == '/') { |
7888 | *repl = '\0'; | 7893 | *repl = '\0'; |
7889 | break; | 7894 | break; |
diff --git a/shell/ash_test/ash-parsing/nodone1.right b/shell/ash_test/ash-parsing/nodone1.right new file mode 100644 index 000000000..0150ccad5 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone1.right | |||
@@ -0,0 +1 @@ | |||
./nodone1.tests: line 2: syntax error: unexpected end of file (expecting "done") | |||
diff --git a/shell/ash_test/ash-parsing/nodone1.tests b/shell/ash_test/ash-parsing/nodone1.tests new file mode 100755 index 000000000..de286c5a2 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone1.tests | |||
@@ -0,0 +1 @@ | |||
for i; do : | |||
diff --git a/shell/ash_test/ash-parsing/nodone2.right b/shell/ash_test/ash-parsing/nodone2.right new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone2.right | |||
@@ -0,0 +1 @@ | |||
1 | |||
diff --git a/shell/ash_test/ash-parsing/nodone2.tests b/shell/ash_test/ash-parsing/nodone2.tests new file mode 100755 index 000000000..69537b3b1 --- /dev/null +++ b/shell/ash_test/ash-parsing/nodone2.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | for i in 1; do echo $i | ||
2 | # the next line has no EOL. It still must count as "done" keyword: | ||
3 | done \ No newline at end of file | ||
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash2.right b/shell/ash_test/ash-quoting/dollar_repl_bash2.right new file mode 100644 index 000000000..e3fcd5807 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_bash2.right | |||
@@ -0,0 +1,4 @@ | |||
1 | axxb | ||
2 | axxb | ||
3 | axxb | ||
4 | axxb | ||
diff --git a/shell/ash_test/ash-quoting/dollar_repl_bash2.tests b/shell/ash_test/ash-quoting/dollar_repl_bash2.tests new file mode 100755 index 000000000..45c7a10e2 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_bash2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | v="x/x" | ||
2 | # The second / is quoted, should not be treated as separator | ||
3 | echo a${v/'/'}b | ||
4 | # The second / is escaped, should not be treated as separator | ||
5 | echo a${v/\/}b | ||
6 | |||
7 | echo "a${v/'/'}b" | ||
8 | echo "a${v/\/}b" | ||
diff --git a/shell/hush.c b/shell/hush.c index ca01e2b5b..3e6a13b32 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -5497,6 +5497,15 @@ static struct pipe *parse_stream(char **pstring, | |||
5497 | } | 5497 | } |
5498 | o_free_and_set_NULL(&ctx.word); | 5498 | o_free_and_set_NULL(&ctx.word); |
5499 | done_pipe(&ctx, PIPE_SEQ); | 5499 | done_pipe(&ctx, PIPE_SEQ); |
5500 | |||
5501 | /* Do we sit inside of any if's, loops or case's? */ | ||
5502 | if (HAS_KEYWORDS | ||
5503 | IF_HAS_KEYWORDS(&& (ctx.ctx_res_w != RES_NONE || ctx.old_flag != 0)) | ||
5504 | ) { | ||
5505 | syntax_error_unterm_str("compound statement"); | ||
5506 | goto parse_error_exitcode1; | ||
5507 | } | ||
5508 | |||
5500 | pi = ctx.list_head; | 5509 | pi = ctx.list_head; |
5501 | /* If we got nothing... */ | 5510 | /* If we got nothing... */ |
5502 | /* (this makes bare "&" cmd a no-op. | 5511 | /* (this makes bare "&" cmd a no-op. |
@@ -5519,7 +5528,7 @@ static struct pipe *parse_stream(char **pstring, | |||
5519 | // *heredoc_cnt_ptr = heredoc_cnt; | 5528 | // *heredoc_cnt_ptr = heredoc_cnt; |
5520 | debug_leave(); | 5529 | debug_leave(); |
5521 | debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt); | 5530 | debug_printf_heredoc("parse_stream return heredoc_cnt:%d\n", heredoc_cnt); |
5522 | debug_printf_parse("parse_stream return %p\n", pi); | 5531 | debug_printf_parse("parse_stream return %p: EOF\n", pi); |
5523 | return pi; | 5532 | return pi; |
5524 | } | 5533 | } |
5525 | 5534 | ||
@@ -9250,6 +9259,37 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) | |||
9250 | * backgrounded: cmd & { list } & | 9259 | * backgrounded: cmd & { list } & |
9251 | * subshell: ( list ) [&] | 9260 | * subshell: ( list ) [&] |
9252 | */ | 9261 | */ |
9262 | static void set_G_ifs(void) | ||
9263 | { | ||
9264 | /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" | ||
9265 | * Result should be 3 lines: q w e, qwe, q w e | ||
9266 | */ | ||
9267 | if (G.ifs_whitespace != G.ifs) | ||
9268 | free(G.ifs_whitespace); | ||
9269 | G.ifs = get_local_var_value("IFS"); | ||
9270 | if (G.ifs) { | ||
9271 | char *p; | ||
9272 | G.ifs_whitespace = (char*)G.ifs; | ||
9273 | p = skip_whitespace(G.ifs); | ||
9274 | if (*p) { | ||
9275 | /* Not all $IFS is whitespace */ | ||
9276 | char *d; | ||
9277 | int len = p - G.ifs; | ||
9278 | p = skip_non_whitespace(p); | ||
9279 | G.ifs_whitespace = xmalloc(len + strlen(p) + 1); /* can overestimate */ | ||
9280 | d = mempcpy(G.ifs_whitespace, G.ifs, len); | ||
9281 | while (*p) { | ||
9282 | if (isspace(*p)) | ||
9283 | *d++ = *p; | ||
9284 | p++; | ||
9285 | } | ||
9286 | *d = '\0'; | ||
9287 | } | ||
9288 | } else { | ||
9289 | G.ifs = defifs; | ||
9290 | G.ifs_whitespace = (char*)G.ifs; | ||
9291 | } | ||
9292 | } | ||
9253 | #if !ENABLE_HUSH_MODE_X | 9293 | #if !ENABLE_HUSH_MODE_X |
9254 | #define redirect_and_varexp_helper(command, sqp, argv_expanded) \ | 9294 | #define redirect_and_varexp_helper(command, sqp, argv_expanded) \ |
9255 | redirect_and_varexp_helper(command, sqp) | 9295 | redirect_and_varexp_helper(command, sqp) |
@@ -9286,34 +9326,7 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9286 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); | 9326 | debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); |
9287 | debug_enter(); | 9327 | debug_enter(); |
9288 | 9328 | ||
9289 | /* Testcase: set -- q w e; (IFS='' echo "$*"; IFS=''; echo "$*"); echo "$*" | 9329 | set_G_ifs(); |
9290 | * Result should be 3 lines: q w e, qwe, q w e | ||
9291 | */ | ||
9292 | if (G.ifs_whitespace != G.ifs) | ||
9293 | free(G.ifs_whitespace); | ||
9294 | G.ifs = get_local_var_value("IFS"); | ||
9295 | if (G.ifs) { | ||
9296 | char *p; | ||
9297 | G.ifs_whitespace = (char*)G.ifs; | ||
9298 | p = skip_whitespace(G.ifs); | ||
9299 | if (*p) { | ||
9300 | /* Not all $IFS is whitespace */ | ||
9301 | char *d; | ||
9302 | int len = p - G.ifs; | ||
9303 | p = skip_non_whitespace(p); | ||
9304 | G.ifs_whitespace = xmalloc(len + strlen(p) + 1); /* can overestimate */ | ||
9305 | d = mempcpy(G.ifs_whitespace, G.ifs, len); | ||
9306 | while (*p) { | ||
9307 | if (isspace(*p)) | ||
9308 | *d++ = *p; | ||
9309 | p++; | ||
9310 | } | ||
9311 | *d = '\0'; | ||
9312 | } | ||
9313 | } else { | ||
9314 | G.ifs = defifs; | ||
9315 | G.ifs_whitespace = (char*)G.ifs; | ||
9316 | } | ||
9317 | 9330 | ||
9318 | IF_HUSH_JOB(pi->pgrp = -1;) | 9331 | IF_HUSH_JOB(pi->pgrp = -1;) |
9319 | pi->stopped_cmds = 0; | 9332 | pi->stopped_cmds = 0; |
@@ -9758,6 +9771,8 @@ static int run_list(struct pipe *pi) | |||
9758 | debug_printf_exec("run_list lvl %d start\n", G.run_list_level); | 9771 | debug_printf_exec("run_list lvl %d start\n", G.run_list_level); |
9759 | debug_enter(); | 9772 | debug_enter(); |
9760 | 9773 | ||
9774 | set_G_ifs(); | ||
9775 | |||
9761 | #if ENABLE_HUSH_LOOPS | 9776 | #if ENABLE_HUSH_LOOPS |
9762 | /* Check syntax for "for" */ | 9777 | /* Check syntax for "for" */ |
9763 | { | 9778 | { |
diff --git a/shell/hush_test/hush-parsing/nodone1.right b/shell/hush_test/hush-parsing/nodone1.right new file mode 100644 index 000000000..3dc1bcfbe --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone1.right | |||
@@ -0,0 +1 @@ | |||
hush: syntax error: unterminated compound statement | |||
diff --git a/shell/hush_test/hush-parsing/nodone1.tests b/shell/hush_test/hush-parsing/nodone1.tests new file mode 100755 index 000000000..de286c5a2 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone1.tests | |||
@@ -0,0 +1 @@ | |||
for i; do : | |||
diff --git a/shell/hush_test/hush-parsing/nodone2.right b/shell/hush_test/hush-parsing/nodone2.right new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone2.right | |||
@@ -0,0 +1 @@ | |||
1 | |||
diff --git a/shell/hush_test/hush-parsing/nodone2.tests b/shell/hush_test/hush-parsing/nodone2.tests new file mode 100755 index 000000000..69537b3b1 --- /dev/null +++ b/shell/hush_test/hush-parsing/nodone2.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | for i in 1; do echo $i | ||
2 | # the next line has no EOL. It still must count as "done" keyword: | ||
3 | done \ No newline at end of file | ||
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash2.right b/shell/hush_test/hush-quoting/dollar_repl_bash2.right new file mode 100644 index 000000000..e3fcd5807 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_bash2.right | |||
@@ -0,0 +1,4 @@ | |||
1 | axxb | ||
2 | axxb | ||
3 | axxb | ||
4 | axxb | ||
diff --git a/shell/hush_test/hush-quoting/dollar_repl_bash2.tests b/shell/hush_test/hush-quoting/dollar_repl_bash2.tests new file mode 100755 index 000000000..45c7a10e2 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_bash2.tests | |||
@@ -0,0 +1,8 @@ | |||
1 | v="x/x" | ||
2 | # The second / is quoted, should not be treated as separator | ||
3 | echo a${v/'/'}b | ||
4 | # The second / is escaped, should not be treated as separator | ||
5 | echo a${v/\/}b | ||
6 | |||
7 | echo "a${v/'/'}b" | ||
8 | echo "a${v/\/}b" | ||
diff --git a/util-linux/taskset.c b/util-linux/taskset.c index 55c915e8d..a3aa06119 100644 --- a/util-linux/taskset.c +++ b/util-linux/taskset.c | |||
@@ -56,7 +56,6 @@ | |||
56 | * -a/--all-tasks (affect all threads) | 56 | * -a/--all-tasks (affect all threads) |
57 | * needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in sched_setaffinity(pid) | 57 | * needs to get TIDs from /proc/PID/task/ and use _them_ as "pid" in sched_setaffinity(pid) |
58 | */ | 58 | */ |
59 | |||
60 | #include <sched.h> | 59 | #include <sched.h> |
61 | #include "libbb.h" | 60 | #include "libbb.h" |
62 | 61 | ||
@@ -96,27 +95,6 @@ static unsigned long from_mask(ul *mask, unsigned sz_in_bytes UNUSED_PARAM) | |||
96 | } | 95 | } |
97 | #endif | 96 | #endif |
98 | 97 | ||
99 | static unsigned long *get_aff(int pid, unsigned *sz) | ||
100 | { | ||
101 | int r; | ||
102 | unsigned long *mask = NULL; | ||
103 | unsigned sz_in_bytes = *sz; | ||
104 | |||
105 | for (;;) { | ||
106 | mask = xrealloc(mask, sz_in_bytes); | ||
107 | r = sched_getaffinity(pid, sz_in_bytes, (void*)mask); | ||
108 | if (r == 0) | ||
109 | break; | ||
110 | sz_in_bytes *= 2; | ||
111 | if (errno == EINVAL && (int)sz_in_bytes > 0) | ||
112 | continue; | ||
113 | bb_perror_msg_and_die("can't %cet pid %d's affinity", 'g', pid); | ||
114 | } | ||
115 | //bb_error_msg("get mask[0]:%lx sz_in_bytes:%d", mask[0], sz_in_bytes); | ||
116 | *sz = sz_in_bytes; | ||
117 | return mask; | ||
118 | } | ||
119 | |||
120 | #if ENABLE_FEATURE_TASKSET_CPULIST | 98 | #if ENABLE_FEATURE_TASKSET_CPULIST |
121 | /* | 99 | /* |
122 | * Parse the CPU list and set the mask accordingly. | 100 | * Parse the CPU list and set the mask accordingly. |
@@ -222,7 +200,7 @@ static int process_pid_str(const char *pid_str, unsigned opts, char *aff) | |||
222 | mask_size_in_bytes = SZOF_UL; | 200 | mask_size_in_bytes = SZOF_UL; |
223 | current_new = "current"; | 201 | current_new = "current"; |
224 | print_aff: | 202 | print_aff: |
225 | mask = get_aff(pid, &mask_size_in_bytes); | 203 | mask = get_malloc_cpu_affinity(pid, &mask_size_in_bytes); |
226 | if (opts & OPT_p) { | 204 | if (opts & OPT_p) { |
227 | #if ENABLE_FEATURE_TASKSET_CPULIST | 205 | #if ENABLE_FEATURE_TASKSET_CPULIST |
228 | if (opts & OPT_c) { | 206 | if (opts & OPT_c) { |