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