aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--libbb/c_escape.c20
-rw-r--r--libbb/concat_path_file.c75
-rw-r--r--libbb/dump.c55
-rw-r--r--libbb/getopt32.c13
-rw-r--r--libbb/hash_md5_sha.c72
-rw-r--r--libbb/lineedit.c2
-rw-r--r--libbb/procps.c174
-rw-r--r--libbb/replace.c14
-rw-r--r--libbb/yescrypt/alg-sha256.c13
9 files changed, 305 insertions, 133 deletions
diff --git a/libbb/c_escape.c b/libbb/c_escape.c
new file mode 100644
index 000000000..6c109f2e0
--- /dev/null
+++ b/libbb/c_escape.c
@@ -0,0 +1,20 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Copyright (C) 2025 by Denys Vlasenko <vda.linux@googlemail.com>
4 *
5 * Licensed under GPLv2, see file LICENSE in this source tree.
6 */
7//kbuild:lib-y += c_escape.o
8
9#include "libbb.h"
10
11const char c_escape_conv_str00[] ALIGN1 =
12 "\\""0""\0" // [0]:00
13 "\\""a""\0" // [1]:07
14 "\\""b""\0" // [2]:08
15 "\\""t""\0" // [3]:09
16 "\\""n""\0" // [4]:0a
17 "\\""v""\0" // [5]:0b
18 "\\""f""\0" // [6]:0c
19 "\\""r" // [7]:0d
20 ;
diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c
index 3afb0e3a4..96fcd4a1d 100644
--- a/libbb/concat_path_file.c
+++ b/libbb/concat_path_file.c
@@ -17,6 +17,7 @@
17 17
18char* FAST_FUNC concat_path_file(const char *path, const char *filename) 18char* FAST_FUNC concat_path_file(const char *path, const char *filename)
19{ 19{
20#if 0
20 char *lc; 21 char *lc;
21 22
22 if (!path) 23 if (!path)
@@ -31,4 +32,78 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename)
31 filename++; 32 filename++;
32#endif 33#endif
33 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); 34 return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename);
35#else
36/* ^^^^^^^^^^^ timing of xasprintf-based code above:
37 * real 7.074s
38 * user 0.156s <<<
39 * sys 6.394s
40 * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though)
41 * real 6.989s
42 * user 0.055s <<< 3 times less CPU used
43 * sys 6.450s
44 * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes):
45 */
46 char *buf, *p;
47 size_t n1, n2, n3;
48
49 while (*filename == '/')
50 filename++;
51
52 if (!path || !path[0])
53 return xstrdup(filename);
54
55 n1 = strlen(path);
56 n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */
57 n3 = strlen(filename) + 1;
58
59 buf = xmalloc(n1 + n2 + n3);
60 p = mempcpy(buf, path, n1);
61 if (n2)
62 *p++ = '/';
63 memcpy(p, filename, n3);
64 return buf;
65#endif
34} 66}
67
68/* If second component comes from struct dirent,
69 * it's possible to eliminate one strlen() by using name length
70 * provided by kernel in struct dirent. See below.
71 * However, the win seems to be insignificant.
72 */
73
74#if 0
75
76/* Extract d_namlen from struct dirent */
77static size_t get_d_namlen(const struct dirent *de)
78{
79#if defined(_DIRENT_HAVE_D_NAMLEN)
80 return de->d_namlen;
81#elif defined(_DIRENT_HAVE_D_RECLEN)
82 const size_t prefix_sz = offsetof(struct dirent, d_name);
83 return de->d_reclen - prefix_sz;
84#else
85 return strlen(de->d_name);
86#endif
87}
88
89char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de)
90{
91 char *buf, *p;
92 size_t n1, n2, n3;
93
94 if (!path || !path[0])
95 return xstrdup(de->d_name);
96
97 n1 = strlen(path);
98 n2 = (path[n1 - 1] != '/');
99 n3 = get_d_namlen(de) + 1;
100
101 buf = xmalloc(n1 + n2 + n3);
102 p = mempcpy(buf, path, n1);
103 if (n2)
104 *p++ = '/';
105 memcpy(p, de->d_name, n3);
106 return buf;
107}
108
109#endif
diff --git a/libbb/dump.c b/libbb/dump.c
index b2abe85af..3dc53d55f 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -514,37 +514,52 @@ static void bpad(PR *pr)
514 continue; 514 continue;
515} 515}
516 516
517static const char conv_str[] ALIGN1 =
518 "\0" "\\""0""\0"
519 "\007""\\""a""\0"
520 "\b" "\\""b""\0"
521 "\f" "\\""f""\0"
522 "\n" "\\""n""\0"
523 "\r" "\\""r""\0"
524 "\t" "\\""t""\0"
525 "\v" "\\""v""\0"
526 ;
527
528static void conv_c(PR *pr, unsigned char *p) 517static void conv_c(PR *pr, unsigned char *p)
529{ 518{
530 const char *str = conv_str; 519 const char *str;
531 520 unsigned char ch;
532 do { 521
533 if (*p == *str) { 522 ch = *p;
534 ++str; 523 if (ch == 0 || (ch -= 6, (signed char)ch > 0 && ch <= 7)) {
535 goto strpr; /* map e.g. '\n' to "\\n" */ 524 /* map chars 0,7..13 to "\0","\{a,b,t,n,v,f,r}" */
536 } 525 str = c_escape_conv_str00 + 3 * ch;
537 str += 4; 526 goto strpr;
538 } while (*str); 527 }
539 528
540 if (isprint_asciionly(*p)) { 529 if (isprint_asciionly(*p)) {
541 *pr->cchar = 'c'; 530 *pr->cchar = 'c';
542 printf(pr->fmt, *p); 531 printf(pr->fmt, *p);
543 } else { 532 } else {
533#if defined(__i386__) || defined(__x86_64__)
534 /* Abuse partial register operations */
535 uint32_t buf;
536 unsigned n = *p;
537 asm ( //00000000 00000000 00000000 aabbbccc
538"\n shll $10,%%eax" //00000000 000000aa bbbccc00 00000000
539"\n shrw $5,%%ax" //00000000 000000aa 00000bbb ccc00000
540"\n shrb $5,%%al" //00000000 000000aa 00000bbb 00000ccc
541"\n shll $8,%%eax" //000000aa 00000bbb 00000ccc 00000000
542"\n bswapl %%eax" //00000000 00000ccc 00000bbb 000000aa
543"\n addl $0x303030,%%eax"
544"\n" : "=a" (n)
545 : "0" (n)
546 );
547 buf = n;
548 str = (void*)&buf;
549#elif 1
544 char buf[4]; 550 char buf[4];
545 /* gcc-8.0.1 needs lots of casts to shut up */ 551 /* gcc-8.0.1 needs lots of casts to shut up */
546 sprintf(buf, "%03o", (unsigned)(uint8_t)*p); 552 sprintf(buf, "%03o", (unsigned)(uint8_t)*p);
547 str = buf; 553 str = buf;
554#else // use faster version? +20 bytes of code relative to sprintf() method
555 char buf[4];
556 buf[3] = '\0';
557 ch = *p;
558 buf[2] = '0' + (ch & 7); ch >>= 3;
559 buf[1] = '0' + (ch & 7); ch >>= 3;
560 buf[0] = '0' + ch;
561 str = buf;
562#endif
548 strpr: 563 strpr:
549 *pr->cchar = 's'; 564 *pr->cchar = 's';
550 printf(pr->fmt, str); 565 printf(pr->fmt, str);
diff --git a/libbb/getopt32.c b/libbb/getopt32.c
index 76d29d5eb..9247588d9 100644
--- a/libbb/getopt32.c
+++ b/libbb/getopt32.c
@@ -530,6 +530,7 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
530 * "fake" short options, like this one: 530 * "fake" short options, like this one:
531 * wget $'-\203' "Test: test" http://kernel.org/ 531 * wget $'-\203' "Test: test" http://kernel.org/
532 * (supposed to act as --header, but doesn't) */ 532 * (supposed to act as --header, but doesn't) */
533 next_opt:
533#if ENABLE_LONG_OPTS 534#if ENABLE_LONG_OPTS
534 while ((c = getopt_long(argc, argv, applet_opts, 535 while ((c = getopt_long(argc, argv, applet_opts,
535 long_options, NULL)) != -1) { 536 long_options, NULL)) != -1) {
@@ -544,8 +545,16 @@ vgetopt32(char **argv, const char *applet_opts, const char *applet_long_options,
544 * but we construct long opts so that flag 545 * but we construct long opts so that flag
545 * is always NULL (see above) */ 546 * is always NULL (see above) */
546 if (on_off->opt_char == '\0' /* && c != '\0' */) { 547 if (on_off->opt_char == '\0' /* && c != '\0' */) {
547 /* c is probably '?' - "bad option" */ 548 /* We reached the end of complementary[] and did not find -c */
548 goto error; 549 if (c == '?') /* getopt says: "bad option, or option has no required argument" */
550 goto error;
551 /* if there were options beyond 32 bits (example: ls),
552 * they got no complementary[] slot, and no result bit.
553 * IOW: they must be "accept but ignore" options.
554 * For them, we end up here.
555 */
556 //bb_error_msg("ignored option '%c', skipping", c);
557 goto next_opt;
549 } 558 }
550 } 559 }
551 if (flags & on_off->incongruously) 560 if (flags & on_off->incongruously)
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 22dd890bf..fd56d831b 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -11,7 +11,7 @@
11#define STR1(s) #s 11#define STR1(s) #s
12#define STR(s) STR1(s) 12#define STR(s) STR1(s)
13 13
14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_USE_BB_CRYPT_SHA) 14#define NEED_SHA512 (ENABLE_SHA512SUM || ENABLE_SHA384SUM || ENABLE_USE_BB_CRYPT_SHA)
15 15
16#if ENABLE_FEATURE_USE_CNG_API 16#if ENABLE_FEATURE_USE_CNG_API
17# include <windows.h> 17# include <windows.h>
@@ -21,6 +21,7 @@
21# define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021) 21# define BCRYPT_MD5_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000021)
22# define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031) 22# define BCRYPT_SHA1_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000031)
23# define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041) 23# define BCRYPT_SHA256_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000041)
24# define BCRYPT_SHA384_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000051)
24# define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061) 25# define BCRYPT_SHA512_ALG_HANDLE ((BCRYPT_ALG_HANDLE) 0x00000061)
25 26
26/* Initialize structure containing state of computation. 27/* Initialize structure containing state of computation.
@@ -61,9 +62,18 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
61 generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE); 62 generic_init(ctx, BCRYPT_SHA256_ALG_HANDLE);
62} 63}
63 64
64#if NEED_SHA512 65#if ENABLE_SHA384SUM
65/* Initialize structure containing state of computation. 66/* Initialize structure containing state of computation.
66 (FIPS 180-2:5.3.3) */ 67 (FIPS 180-2:5.3.3) */
68void FAST_FUNC sha384_begin(sha384_ctx_t *ctx)
69{
70 generic_init(ctx, BCRYPT_SHA384_ALG_HANDLE);
71}
72#endif /* ENABLE_SHA384SUM */
73
74#if NEED_SHA512
75/* Initialize structure containing state of computation.
76 (FIPS 180-2:5.3.4) */
67void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) 77void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
68{ 78{
69 generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE); 79 generic_init(ctx, BCRYPT_SHA512_ALG_HANDLE);
@@ -1109,7 +1119,7 @@ static const sha_K_int sha_K[] ALIGN8 = {
1109 K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), 1119 K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL),
1110 K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), 1120 K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL),
1111 K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), 1121 K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL),
1112#if NEED_SHA512 /* [64]+ are used for sha512 only */ 1122#if NEED_SHA512 /* [64]+ are used for sha384 and sha512 only */
1113 K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), 1123 K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL),
1114 K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), 1124 K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL),
1115 K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), 1125 K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL),
@@ -1306,11 +1316,20 @@ static const uint32_t init512_lo[] ALIGN4 = {
1306 0x137e2179, 1316 0x137e2179,
1307}; 1317};
1308#endif /* NEED_SHA512 */ 1318#endif /* NEED_SHA512 */
1309 1319#if ENABLE_SHA384SUM
1310// Note: SHA-384 is identical to SHA-512, except that initial hash values are 1320static const uint64_t init384[] ALIGN8 = {
1311// 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, 1321 0,
1312// 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, 1322 0,
1313// and the output is constructed by omitting last two 64-bit words of it. 1323 0xcbbb9d5dc1059ed8,
1324 0x629a292a367cd507,
1325 0x9159015a3070dd17,
1326 0x152fecd8f70e5939,
1327 0x67332667ffc00b31,
1328 0x8eb44a8768581511,
1329 0xdb0c2e0d64f98fa7,
1330 0x47b5481dbefa4fa4,
1331};
1332#endif
1314 1333
1315/* Initialize structure containing state of computation. 1334/* Initialize structure containing state of computation.
1316 (FIPS 180-2:5.3.2) */ 1335 (FIPS 180-2:5.3.2) */
@@ -1332,9 +1351,19 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx)
1332#endif 1351#endif
1333} 1352}
1334 1353
1335#if NEED_SHA512 1354#if ENABLE_SHA384SUM
1336/* Initialize structure containing state of computation. 1355/* Initialize structure containing state of computation.
1337 (FIPS 180-2:5.3.3) */ 1356 (FIPS 180-2:5.3.3) */
1357void FAST_FUNC sha384_begin(sha512_ctx_t *ctx)
1358{
1359 memcpy(&ctx->total64, init384, sizeof(init384));
1360 /*ctx->total64[0] = ctx->total64[1] = 0; - already done */
1361}
1362#endif
1363
1364#if NEED_SHA512
1365/* Initialize structure containing state of computation.
1366 (FIPS 180-2:5.3.4) */
1338void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) 1367void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
1339{ 1368{
1340 int i; 1369 int i;
@@ -1409,7 +1438,7 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf)
1409} 1438}
1410 1439
1411#if NEED_SHA512 1440#if NEED_SHA512
1412unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) 1441static unsigned FAST_FUNC sha512384_end(sha512_ctx_t *ctx, void *resbuf, unsigned outsize)
1413{ 1442{
1414 unsigned bufpos = ctx->total64[0] & 127; 1443 unsigned bufpos = ctx->total64[0] & 127;
1415 1444
@@ -1440,12 +1469,22 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf)
1440 for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) 1469 for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i)
1441 ctx->hash[i] = SWAP_BE64(ctx->hash[i]); 1470 ctx->hash[i] = SWAP_BE64(ctx->hash[i]);
1442 } 1471 }
1443 memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); 1472 memcpy(resbuf, ctx->hash, outsize);
1444 return sizeof(ctx->hash); 1473 return outsize;
1474}
1475unsigned FAST_FUNC sha512_end(sha384_ctx_t *ctx, void *resbuf)
1476{
1477 return sha512384_end(ctx, resbuf, SHA512_OUTSIZE);
1445} 1478}
1446#endif /* NEED_SHA512 */ 1479#endif /* NEED_SHA512 */
1447#endif /* !ENABLE_FEATURE_USE_CNG_API */
1448 1480
1481#if ENABLE_SHA384SUM
1482unsigned FAST_FUNC sha384_end(sha384_ctx_t *ctx, void *resbuf)
1483{
1484 return sha512384_end(ctx, resbuf, SHA384_OUTSIZE);
1485}
1486#endif
1487#endif /* !ENABLE_FEATURE_USE_CNG_API */
1449 1488
1450/* 1489/*
1451 * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, 1490 * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
@@ -1982,6 +2021,8 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
1982 2021
1983unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) 2022unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
1984{ 2023{
2024 unsigned hash_len;
2025
1985 /* Padding */ 2026 /* Padding */
1986 uint8_t *buf = (uint8_t*)ctx->state; 2027 uint8_t *buf = (uint8_t*)ctx->state;
1987 /* 2028 /*
@@ -2004,6 +2045,7 @@ unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf)
2004 sha3_process_block72(ctx->state); 2045 sha3_process_block72(ctx->state);
2005 2046
2006 /* Output */ 2047 /* Output */
2007 memcpy(resbuf, ctx->state, 64); 2048 hash_len = (1600/8 - ctx->input_block_bytes) / 2;
2008 return 64; 2049 memcpy(resbuf, ctx->state, hash_len);
2050 return hash_len;
2009} 2051}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index c8a0f37fe..77207a427 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1754,7 +1754,7 @@ void FAST_FUNC save_history(line_input_t *st)
1754 FILE *fp; 1754 FILE *fp;
1755 1755
1756 /* bash compat: HISTFILE="" disables history saving */ 1756 /* bash compat: HISTFILE="" disables history saving */
1757 if (!st || !st->hist_file || !state->hist_file[0]) 1757 if (!st || !st->hist_file || !st->hist_file[0])
1758 return; 1758 return;
1759 if (st->cnt_history <= st->cnt_history_in_file) 1759 if (st->cnt_history <= st->cnt_history_in_file)
1760 return; /* no new entries were added */ 1760 return; /* no new entries were added */
diff --git a/libbb/procps.c b/libbb/procps.c
index 8c9cac125..c751100bc 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -110,7 +110,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp)
110} 110}
111 111
112#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 112#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
113static unsigned long long fast_strtoull_16(char **endptr) 113unsigned long long FAST_FUNC fast_strtoull_16(char **endptr)
114{ 114{
115 unsigned char c; 115 unsigned char c;
116 char *str = *endptr; 116 char *str = *endptr;
@@ -131,7 +131,7 @@ static unsigned long long fast_strtoull_16(char **endptr)
131 131
132#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 132#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
133/* We cut a lot of corners here for speed */ 133/* We cut a lot of corners here for speed */
134static unsigned long fast_strtoul_10(char **endptr) 134unsigned long FAST_FUNC fast_strtoul_10(char **endptr)
135{ 135{
136 unsigned char c; 136 unsigned char c;
137 char *str = *endptr; 137 char *str = *endptr;
@@ -144,6 +144,24 @@ static unsigned long fast_strtoul_10(char **endptr)
144 *endptr = str + 1; /* We skip trailing space! */ 144 *endptr = str + 1; /* We skip trailing space! */
145 return n; 145 return n;
146} 146}
147# if LONG_MAX < LLONG_MAX
148/* For VSZ, which can be very large */
149static unsigned long long fast_strtoull_10(char **endptr)
150{
151 unsigned char c;
152 char *str = *endptr;
153 unsigned long long n = *str - '0';
154
155 /* Need to stop on both ' ' and '\n' */
156 while ((c = *++str) > ' ')
157 n = n*10 + (c - '0');
158
159 *endptr = str + 1; /* We skip trailing space! */
160 return n;
161}
162# else
163# define fast_strtoull_10(endptr) fast_strtoul_10(endptr)
164# endif
147 165
148# if ENABLE_FEATURE_FAST_TOP 166# if ENABLE_FEATURE_FAST_TOP
149static long fast_strtol_10(char **endptr) 167static long fast_strtol_10(char **endptr)
@@ -156,7 +174,7 @@ static long fast_strtol_10(char **endptr)
156} 174}
157# endif 175# endif
158 176
159static char *skip_fields(char *str, int count) 177char* FAST_FUNC skip_fields(char *str, int count)
160{ 178{
161 do { 179 do {
162 while (*str++ != ' ') 180 while (*str++ != ' ')
@@ -167,35 +185,25 @@ static char *skip_fields(char *str, int count)
167} 185}
168#endif 186#endif
169 187
170#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP 188#if ENABLE_FEATURE_TOPMEM
171static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) 189static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp)
172{ 190{
173 char *tp = is_prefixed_with(buf, prefix); 191 // There is A LOT of /proc/PID/smaps data on a big system.
174 if (tp) { 192 // Optimize this for speed, makes "top -m" faster.
175 tp = skip_whitespace(tp); 193//TODO large speedup:
176 } 194//read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster)
177 return tp; 195//and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW)
178}
179 196
180int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
181 void (*cb)(struct smaprec *, void *), void *data)
182{
183 FILE *file; 197 FILE *file;
184 struct smaprec currec;
185 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; 198 char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3];
186 char buf[PROCPS_BUFSIZE]; 199 char buf[PROCPS_BUFSIZE];
187#if !ENABLE_PMAP
188 void (*cb)(struct smaprec *, void *) = NULL;
189 void *data = NULL;
190#endif
191 200
192 sprintf(filename, "/proc/%u/smaps", (int)pid); 201 sprintf(filename, "/proc/%u/smaps", (int)pid);
193 202
194 file = fopen_for_read(filename); 203 file = fopen_for_read(filename);
195 if (!file) 204 if (!file)
196 return 1; 205 return;
197 206
198 memset(&currec, 0, sizeof(currec));
199 while (fgets(buf, PROCPS_BUFSIZE, file)) { 207 while (fgets(buf, PROCPS_BUFSIZE, file)) {
200 // Each mapping datum has this form: 208 // Each mapping datum has this form:
201 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME 209 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
@@ -203,80 +211,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
203 // Rss: nnn kB 211 // Rss: nnn kB
204 // ..... 212 // .....
205 213
206 char *tp, *p; 214 char *tp;
207 215
216 if (buf[0] == 'S' || buf[0] == 'P') {
208#define SCAN(S, X) \ 217#define SCAN(S, X) \
209 if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ 218 if (memcmp(buf, S, sizeof(S)-1) == 0) { \
210 total->X += currec.X = fast_strtoul_10(&tp); \ 219 tp = skip_whitespace(buf + sizeof(S)-1); \
211 continue; \ 220 sp->X += fast_strtoul_10(&tp); \
212 } 221 continue; \
213 if (cb) { 222 }
214 SCAN("Pss:" , smap_pss ); 223 SCAN("Private_Dirty:", private_dirty)
215 SCAN("Swap:" , smap_swap ); 224 SCAN("Private_Clean:", private_clean)
216 } 225 SCAN("Shared_Dirty:" , shared_dirty )
217 SCAN("Private_Dirty:", private_dirty); 226 SCAN("Shared_Clean:" , shared_clean )
218 SCAN("Private_Clean:", private_clean);
219 SCAN("Shared_Dirty:" , shared_dirty );
220 SCAN("Shared_Clean:" , shared_clean );
221#undef SCAN 227#undef SCAN
228 }
222 tp = strchr(buf, '-'); 229 tp = strchr(buf, '-');
223 if (tp) { 230 if (tp) {
224 // We reached next mapping - the line of this form: 231 // We reached next mapping - the line of this form:
225 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME 232 // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME
226 233
227 if (cb) { 234 char *rwx;
228 /* If we have a previous record, there's nothing more 235 unsigned long sz;
229 * for it, call the callback and clear currec
230 */
231 if (currec.smap_size)
232 cb(&currec, data);
233 free(currec.smap_name);
234 }
235 memset(&currec, 0, sizeof(currec));
236 236
237 *tp = ' '; 237 *tp = ' ';
238 tp = buf; 238 tp = buf;
239 currec.smap_start = fast_strtoull_16(&tp); 239 sz = fast_strtoull_16(&tp); // start
240 currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; 240 sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start
241 241 // tp -> "rw-s" string
242 strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); 242 rwx = tp;
243
244 // skipping "rw-s FILEOFS M:m INODE " 243 // skipping "rw-s FILEOFS M:m INODE "
245 tp = skip_whitespace(skip_fields(tp, 4)); 244 tp = skip_whitespace(skip_fields(tp, 4));
246 // filter out /dev/something (something != zero) 245 // if not a device memory mapped...
247 if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { 246 if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something"
248 if (currec.smap_mode[1] == 'w') { 247 || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device)
249 currec.mapped_rw = currec.smap_size; 248 ) {
250 total->mapped_rw += currec.smap_size; 249 if (rwx[1] == 'w')
251 } else if (currec.smap_mode[1] == '-') { 250 sp->mapped_rw += sz;
252 currec.mapped_ro = currec.smap_size; 251 else if (rwx[0] == 'r' || rwx[2] == 'x')
253 total->mapped_ro += currec.smap_size; 252 sp->mapped_ro += sz;
254 } 253 // else: seen "---p" mappings (mmap guard gaps?),
254 // do NOT account these as VSZ, they aren't really
255 } 255 }
256
257 if (strcmp(tp, "[stack]\n") == 0) 256 if (strcmp(tp, "[stack]\n") == 0)
258 total->stack += currec.smap_size; 257 sp->stack += sz;
259 if (cb) {
260 p = skip_non_whitespace(tp);
261 if (p == tp) {
262 currec.smap_name = xstrdup(" [ anon ]");
263 } else {
264 *p = '\0';
265 currec.smap_name = xstrdup(tp);
266 }
267 }
268 total->smap_size += currec.smap_size;
269 } 258 }
270 } 259 }
271 fclose(file); 260 fclose(file);
272
273 if (cb) {
274 if (currec.smap_size)
275 cb(&currec, data);
276 free(currec.smap_name);
277 }
278
279 return 0;
280} 261}
281#endif 262#endif
282 263
@@ -371,7 +352,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
371 char *cp, *comm1; 352 char *cp, *comm1;
372 int tty; 353 int tty;
373#if !ENABLE_FEATURE_FAST_TOP 354#if !ENABLE_FEATURE_FAST_TOP
374 unsigned long vsz, rss; 355 unsigned long long vsz;
356 unsigned long rss;
375#endif 357#endif
376 /* see proc(5) for some details on this */ 358 /* see proc(5) for some details on this */
377 strcpy(filename_tail, "stat"); 359 strcpy(filename_tail, "stat");
@@ -397,7 +379,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
397 "%ld " /* nice */ 379 "%ld " /* nice */
398 "%*s %*s " /* timeout, it_real_value */ 380 "%*s %*s " /* timeout, it_real_value */
399 "%lu " /* start_time */ 381 "%lu " /* start_time */
400 "%lu " /* vsize */ 382 "%llu " /* vsize - can be very large */
401 "%lu " /* rss */ 383 "%lu " /* rss */
402# if ENABLE_FEATURE_TOP_SMP_PROCESS 384# if ENABLE_FEATURE_TOP_SMP_PROCESS
403 "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ 385 "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */
@@ -450,7 +432,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
450 cp = skip_fields(cp, 2); /* timeout, it_real_value */ 432 cp = skip_fields(cp, 2); /* timeout, it_real_value */
451 sp->start_time = fast_strtoul_10(&cp); 433 sp->start_time = fast_strtoul_10(&cp);
452 /* vsz is in bytes and we want kb */ 434 /* vsz is in bytes and we want kb */
453 sp->vsz = fast_strtoul_10(&cp) >> 10; 435 sp->vsz = fast_strtoull_10(&cp) >> 10;
454 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ 436 /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */
455 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; 437 sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb;
456# if ENABLE_FEATURE_TOP_SMP_PROCESS 438# if ENABLE_FEATURE_TOP_SMP_PROCESS
@@ -484,7 +466,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
484 466
485#if ENABLE_FEATURE_TOPMEM 467#if ENABLE_FEATURE_TOPMEM
486 if (flags & PSSCAN_SMAPS) 468 if (flags & PSSCAN_SMAPS)
487 procps_read_smaps(pid, &sp->smaps, NULL, NULL); 469 procps_read_smaps(pid, sp);
488#endif /* TOPMEM */ 470#endif /* TOPMEM */
489#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS 471#if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS
490 if (flags & PSSCAN_RUIDGID) { 472 if (flags & PSSCAN_RUIDGID) {
@@ -567,36 +549,45 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
567 return sp; 549 return sp;
568} 550}
569 551
570void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) 552int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
571{ 553{
572 int sz; 554 int sz;
573 char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; 555 char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3];
574 556
575 sprintf(filename, "/proc/%u/cmdline", pid); 557 sprintf(filename, "/proc/%u/cmdline", pid);
576 sz = open_read_close(filename, buf, col - 1); 558 sz = open_read_close(filename, buf, col - 1);
559 if (sz < 0)
560 return sz;
577 if (sz > 0) { 561 if (sz > 0) {
578 const char *base; 562 const char *program_basename;
579 int comm_len; 563 int comm_len;
580 564
581 buf[sz] = '\0'; 565 buf[sz] = '\0';
582 while (--sz >= 0 && buf[sz] == '\0') 566 while (--sz >= 0 && buf[sz] == '\0')
583 continue; 567 continue;
584 /* Prevent basename("process foo/bar") = "bar" */ 568
585 strchrnul(buf, ' ')[0] = '\0'; 569 /* Find "program" in "[-][/PATH/TO/]program" */
586 base = bb_basename(buf); /* before we replace argv0's NUL with space */ 570 strchrnul(buf, ' ')[0] = '\0'; /* prevent basename("program foo/bar") = "bar" */
571 program_basename = bb_basename(buf[0] == '-' ? buf + 1 : buf);
572 /* ^^^ note: must do it *before* replacing argv0's NUL with space */
573
574 /* Prevent stuff like this:
575 * echo 'sleep 999; exit' >`printf '\ec'`; sh ?c
576 * messing up top and ps output (or worse).
577 * This also replaces NULs with spaces, converting
578 * list of NUL-strings into one string.
579 */
587 while (sz >= 0) { 580 while (sz >= 0) {
588 if ((unsigned char)(buf[sz]) < ' ') 581 if ((unsigned char)(buf[sz]) < ' ')
589 buf[sz] = ' '; 582 buf[sz] = ' ';
590 sz--; 583 sz--;
591 } 584 }
592 if (base[0] == '-') /* "-sh" (login shell)? */
593 base++;
594 585
595 /* If comm differs from argv0, prepend "{comm} ". 586 /* If comm differs from argv0, prepend "{comm} ".
596 * It allows to see thread names set by prctl(PR_SET_NAME). 587 * It allows to see thread names set by prctl(PR_SET_NAME).
597 */ 588 */
598 if (!comm) 589 if (!comm)
599 return; 590 return 0;
600 comm_len = strlen(comm); 591 comm_len = strlen(comm);
601 /* Why compare up to comm_len, not COMM_LEN-1? 592 /* Why compare up to comm_len, not COMM_LEN-1?
602 * Well, some processes rewrite argv, and use _spaces_ there 593 * Well, some processes rewrite argv, and use _spaces_ there
@@ -604,19 +595,20 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm)
604 * I prefer to still treat argv0 "process foo bar" 595 * I prefer to still treat argv0 "process foo bar"
605 * as 'equal' to comm "process". 596 * as 'equal' to comm "process".
606 */ 597 */
607 if (strncmp(base, comm, comm_len) != 0) { 598 if (strncmp(program_basename, comm, comm_len) != 0) {
608 comm_len += 3; 599 comm_len += 3;
609 if (col > comm_len) 600 if (col > comm_len)
610 memmove(buf + comm_len, buf, col - comm_len); 601 memmove(buf + comm_len, buf, col - comm_len);
611 snprintf(buf, col, "{%s}", comm); 602 snprintf(buf, col, "{%s}", comm);
612 if (col <= comm_len) 603 if (col <= comm_len)
613 return; 604 return 0;
614 buf[comm_len - 1] = ' '; 605 buf[comm_len - 1] = ' ';
615 buf[col - 1] = '\0'; 606 buf[col - 1] = '\0';
616 } 607 }
617 } else { 608 } else {
618 snprintf(buf, col, "[%s]", comm ? comm : "?"); 609 snprintf(buf, col, "[%s]", comm ? comm : "?");
619 } 610 }
611 return 0;
620} 612}
621 613
622#endif /* ENABLE_PLATFORM_MINGW32 */ 614#endif /* ENABLE_PLATFORM_MINGW32 */
diff --git a/libbb/replace.c b/libbb/replace.c
index 6183d3e6f..bc26b04cc 100644
--- a/libbb/replace.c
+++ b/libbb/replace.c
@@ -46,3 +46,17 @@ char* FAST_FUNC xmalloc_substitute_string(const char *src, int count, const char
46 //dbg_msg("subst9:'%s'", buf); 46 //dbg_msg("subst9:'%s'", buf);
47 return buf; 47 return buf;
48} 48}
49
50#if 0 /* inlined in libbb.h */
51/* Returns strlen as a bonus */
52size_t FAST_FUNC replace_char(char *str, char from, char to)
53{
54 char *p = str;
55 while (*p) {
56 if (*p == from)
57 *p = to;
58 p++;
59 }
60 return p - str;
61}
62#endif
diff --git a/libbb/yescrypt/alg-sha256.c b/libbb/yescrypt/alg-sha256.c
index 20e8d1ee4..dc748c968 100644
--- a/libbb/yescrypt/alg-sha256.c
+++ b/libbb/yescrypt/alg-sha256.c
@@ -47,9 +47,12 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
47 47
48 /* Iterate through the blocks. */ 48 /* Iterate through the blocks. */
49 for (i = 0; dkLen != 0; ) { 49 for (i = 0; dkLen != 0; ) {
50 uint64_t U[32 / 8]; 50 long U[32 / sizeof(long)];
51 uint64_t T[32 / 8]; 51 long T[32 / sizeof(long)];
52 uint64_t j; 52// Do not make these ^^ uint64_t[]. Keep them long[].
53// Even though the XORing loop below is optimized out,
54// gcc is not smart enough to realize that 64-bit alignment of the stack
55// is no longer useful, and generates ~50 more bytes of code on i386...
53 uint32_t ivec; 56 uint32_t ivec;
54 size_t clen; 57 size_t clen;
55 int k; 58 int k;
@@ -64,13 +67,15 @@ PBKDF2_SHA256(const uint8_t *passwd, size_t passwdlen,
64//does libbb need a non-vararg version with just one (buf,len)? 67//does libbb need a non-vararg version with just one (buf,len)?
65 68
66 if (c > 1) { 69 if (c > 1) {
70//in yescrypt, c is always 1, so this if() branch is optimized out
71 uint64_t j;
67 /* T_i = U_1 ... */ 72 /* T_i = U_1 ... */
68 memcpy(U, T, 32); 73 memcpy(U, T, 32);
69 for (j = 2; j <= c; j++) { 74 for (j = 2; j <= c; j++) {
70 /* Compute U_j. */ 75 /* Compute U_j. */
71 hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL); 76 hmac_peek_hash(&Phctx, (void*)U, U, 32, NULL);
72 /* ... xor U_j ... */ 77 /* ... xor U_j ... */
73 for (k = 0; k < 32 / 8; k++) 78 for (k = 0; k < 32 / sizeof(long); k++)
74 T[k] ^= U[k]; 79 T[k] ^= U[k];
75 //TODO: xorbuf32_aligned_long(T, U); 80 //TODO: xorbuf32_aligned_long(T, U);
76 } 81 }