aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-06-23 09:35:35 +0100
committerRon Yorston <rmy@pobox.com>2024-06-23 09:44:03 +0100
commitb07c177b446498ccd739b367f9e80337c3dfa55a (patch)
tree8230bce5f937e46ae1a6f18677904d2eccc4ae9e
parent1b094d366f808a2ebc4824004f0d6f75f13c09cb (diff)
parenta6ce017a8a2db09c6f23aa6abf7ce21fd00c2fdf (diff)
downloadbusybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.gz
busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.tar.bz2
busybox-w32-b07c177b446498ccd739b367f9e80337c3dfa55a.zip
Merge branch 'busybox' into merge
-rw-r--r--configs/TEST_nommu_defconfig1
-rw-r--r--coreutils/ls.c4
-rw-r--r--coreutils/nproc.c17
-rw-r--r--editors/awk.c4
-rw-r--r--include/libbb.h9
-rw-r--r--libbb/Kbuild.src2
-rw-r--r--libbb/alloc_affinity.c29
-rw-r--r--libbb/lineedit.c62
-rw-r--r--libbb/popcnt.c46
-rw-r--r--miscutils/crond.c2
-rw-r--r--networking/ifupdown.c8
-rw-r--r--networking/ip.c55
-rw-r--r--networking/ipcalc.c21
-rw-r--r--networking/libiproute/iplink.c288
-rw-r--r--networking/libiproute/utils.c11
-rw-r--r--networking/nc_bloaty.c2
-rw-r--r--networking/udhcp/d6_dhcpc.c2
-rw-r--r--networking/udhcp/dhcpc.c15
-rw-r--r--scripts/basic/docproc.c1
-rw-r--r--shell/ash.c5
-rw-r--r--shell/ash_test/ash-parsing/nodone1.right1
-rwxr-xr-xshell/ash_test/ash-parsing/nodone1.tests1
-rw-r--r--shell/ash_test/ash-parsing/nodone2.right1
-rwxr-xr-xshell/ash_test/ash-parsing/nodone2.tests3
-rw-r--r--shell/ash_test/ash-quoting/dollar_repl_bash2.right4
-rwxr-xr-xshell/ash_test/ash-quoting/dollar_repl_bash2.tests8
-rw-r--r--shell/hush.c73
-rw-r--r--shell/hush_test/hush-parsing/nodone1.right1
-rwxr-xr-xshell/hush_test/hush-parsing/nodone1.tests1
-rw-r--r--shell/hush_test/hush-parsing/nodone2.right1
-rwxr-xr-xshell/hush_test/hush-parsing/nodone2.tests3
-rw-r--r--shell/hush_test/hush-quoting/dollar_repl_bash2.right4
-rwxr-xr-xshell/hush_test/hush-quoting/dollar_repl_bash2.tests8
-rw-r--r--util-linux/taskset.c24
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
703CONFIG_IP=y 703CONFIG_IP=y
704CONFIG_FEATURE_IP_ADDRESS=y 704CONFIG_FEATURE_IP_ADDRESS=y
705CONFIG_FEATURE_IP_LINK=y 705CONFIG_FEATURE_IP_LINK=y
706CONFIG_FEATURE_IP_LINK_CAN=y
706CONFIG_FEATURE_IP_ROUTE=y 707CONFIG_FEATURE_IP_ROUTE=y
707CONFIG_FEATURE_IP_TUNNEL=y 708CONFIG_FEATURE_IP_TUNNEL=y
708CONFIG_FEATURE_IP_RULE=y 709CONFIG_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
29int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 28int 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;
423uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; 423uint64_t bb_bswap_64(uint64_t x) FAST_FUNC;
424#endif 424#endif
425 425
426unsigned FAST_FUNC bb_popcnt_32(uint32_t m);
427#if ULONG_MAX > 0xffffffff
428unsigned FAST_FUNC bb_popcnt_long(unsigned long m);
429#else
430#define bb_popcnt_long(m) bb_popcnt_32(m)
431#endif
432
426unsigned long FAST_FUNC isqrt(unsigned long long N); 433unsigned long FAST_FUNC isqrt(unsigned long long N);
427 434
428unsigned long long monotonic_ns(void) FAST_FUNC; 435unsigned 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
2113unsigned 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
58lib-y += perror_msg.o 58lib-y += perror_msg.o
59lib-y += perror_nomsg_and_die.o 59lib-y += perror_nomsg_and_die.o
60lib-y += platform.o 60lib-y += platform.o
61lib-y += popcnt.o
61lib-y += printable.o 62lib-y += printable.o
62lib-y += printable_string.o 63lib-y += printable_string.o
63lib-y += process_escape_sequence.o 64lib-y += process_escape_sequence.o
@@ -99,6 +100,7 @@ lib-y += xgetcwd.o
99lib-y += xreadlink.o 100lib-y += xreadlink.o
100lib-y += xrealloc_vector.o 101lib-y += xrealloc_vector.o
101 102
103lib-$(CONFIG_PLATFORM_POSIX) += alloc_affinity.o
102lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o 104lib-$(CONFIG_PLATFORM_POSIX) += bb_askpass.o
103lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o 105lib-$(CONFIG_PLATFORM_POSIX) += change_identity.o
104lib-$(CONFIG_PLATFORM_POSIX) += device_open.o 106lib-$(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
12unsigned 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... */
355static void BB_PUTCHAR(wchar_t c) 355static 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: */
415int adjust_width_and_validate_wc(unsigned *width_adj, int wc); 415int 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
537static void beep(void) 537static 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 */
545static void put_prompt_custom(bool is_full) 545static 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)
644static void draw_custom(int y, int back_cursor, bool is_full) 647static 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
3250int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) 3253int 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
11unsigned 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
37unsigned 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
75static 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
89int 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
66enum {
67 PARM_on = 0,
68 PARM_off
69};
70
58/* Exits on error */ 71/* Exits on error */
59static int get_ctl_fd(void) 72static 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
258static 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
277static 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
476static 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 */
245static int do_set(char **argv) 502static 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 */
618static int do_add_or_delete(char **argv, const unsigned rtm) 888static 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 */
154static 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 @@
1for i in 1; do echo $i
2# the next line has no EOL. It still must count as "done" keyword:
3done \ 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 @@
1axxb
2axxb
3axxb
4axxb
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 @@
1v="x/x"
2# The second / is quoted, should not be treated as separator
3echo a${v/'/'}b
4# The second / is escaped, should not be treated as separator
5echo a${v/\/}b
6
7echo "a${v/'/'}b"
8echo "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 */
9262static 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 @@
1for i in 1; do echo $i
2# the next line has no EOL. It still must count as "done" keyword:
3done \ 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 @@
1axxb
2axxb
3axxb
4axxb
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 @@
1v="x/x"
2# The second / is quoted, should not be treated as separator
3echo a${v/'/'}b
4# The second / is escaped, should not be treated as separator
5echo a${v/\/}b
6
7echo "a${v/'/'}b"
8echo "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
99static 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) {