diff options
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/c_escape.c | 20 | ||||
-rw-r--r-- | libbb/concat_path_file.c | 75 | ||||
-rw-r--r-- | libbb/dump.c | 55 | ||||
-rw-r--r-- | libbb/getopt32.c | 13 | ||||
-rw-r--r-- | libbb/hash_md5_sha.c | 58 | ||||
-rw-r--r-- | libbb/lineedit.c | 2 | ||||
-rw-r--r-- | libbb/procps.c | 174 | ||||
-rw-r--r-- | libbb/replace.c | 14 | ||||
-rw-r--r-- | libbb/yescrypt/alg-sha256.c | 13 |
9 files changed, 293 insertions, 131 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 | |||
11 | const 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 5b4b7f113..aefb84f45 100644 --- a/libbb/concat_path_file.c +++ b/libbb/concat_path_file.c | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | char* FAST_FUNC concat_path_file(const char *path, const char *filename) | 18 | char* 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) |
@@ -25,4 +26,78 @@ char* FAST_FUNC concat_path_file(const char *path, const char *filename) | |||
25 | while (*filename == '/') | 26 | while (*filename == '/') |
26 | filename++; | 27 | filename++; |
27 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); | 28 | return xasprintf("%s%s%s", path, (lc==NULL ? "/" : ""), filename); |
29 | #else | ||
30 | /* ^^^^^^^^^^^ timing of xasprintf-based code above: | ||
31 | * real 7.074s | ||
32 | * user 0.156s <<< | ||
33 | * sys 6.394s | ||
34 | * "rm -rf" of a Linux kernel tree from tmpfs (run time still dominated by in-kernel work, though) | ||
35 | * real 6.989s | ||
36 | * user 0.055s <<< 3 times less CPU used | ||
37 | * sys 6.450s | ||
38 | * vvvvvvvvvvv timing of open-coded malloc+memcpy code below (+59 bytes): | ||
39 | */ | ||
40 | char *buf, *p; | ||
41 | size_t n1, n2, n3; | ||
42 | |||
43 | while (*filename == '/') | ||
44 | filename++; | ||
45 | |||
46 | if (!path || !path[0]) | ||
47 | return xstrdup(filename); | ||
48 | |||
49 | n1 = strlen(path); | ||
50 | n2 = (path[n1 - 1] != '/'); /* 1: "path has no trailing slash" */ | ||
51 | n3 = strlen(filename) + 1; | ||
52 | |||
53 | buf = xmalloc(n1 + n2 + n3); | ||
54 | p = mempcpy(buf, path, n1); | ||
55 | if (n2) | ||
56 | *p++ = '/'; | ||
57 | memcpy(p, filename, n3); | ||
58 | return buf; | ||
59 | #endif | ||
60 | } | ||
61 | |||
62 | /* If second component comes from struct dirent, | ||
63 | * it's possible to eliminate one strlen() by using name length | ||
64 | * provided by kernel in struct dirent. See below. | ||
65 | * However, the win seems to be insignificant. | ||
66 | */ | ||
67 | |||
68 | #if 0 | ||
69 | |||
70 | /* Extract d_namlen from struct dirent */ | ||
71 | static size_t get_d_namlen(const struct dirent *de) | ||
72 | { | ||
73 | #if defined(_DIRENT_HAVE_D_NAMLEN) | ||
74 | return de->d_namlen; | ||
75 | #elif defined(_DIRENT_HAVE_D_RECLEN) | ||
76 | const size_t prefix_sz = offsetof(struct dirent, d_name); | ||
77 | return de->d_reclen - prefix_sz; | ||
78 | #else | ||
79 | return strlen(de->d_name); | ||
80 | #endif | ||
81 | } | ||
82 | |||
83 | char* FAST_FUNC concat_path_dirent(const char *path, const struct dirent *de) | ||
84 | { | ||
85 | char *buf, *p; | ||
86 | size_t n1, n2, n3; | ||
87 | |||
88 | if (!path || !path[0]) | ||
89 | return xstrdup(de->d_name); | ||
90 | |||
91 | n1 = strlen(path); | ||
92 | n2 = (path[n1 - 1] != '/'); | ||
93 | n3 = get_d_namlen(de) + 1; | ||
94 | |||
95 | buf = xmalloc(n1 + n2 + n3); | ||
96 | p = mempcpy(buf, path, n1); | ||
97 | if (n2) | ||
98 | *p++ = '/'; | ||
99 | memcpy(p, de->d_name, n3); | ||
100 | return buf; | ||
28 | } | 101 | } |
102 | |||
103 | #endif | ||
diff --git a/libbb/dump.c b/libbb/dump.c index ac5d47d9e..d34094576 100644 --- a/libbb/dump.c +++ b/libbb/dump.c | |||
@@ -478,37 +478,52 @@ static void bpad(PR *pr) | |||
478 | continue; | 478 | continue; |
479 | } | 479 | } |
480 | 480 | ||
481 | static const char conv_str[] ALIGN1 = | ||
482 | "\0" "\\""0""\0" | ||
483 | "\007""\\""a""\0" | ||
484 | "\b" "\\""b""\0" | ||
485 | "\f" "\\""f""\0" | ||
486 | "\n" "\\""n""\0" | ||
487 | "\r" "\\""r""\0" | ||
488 | "\t" "\\""t""\0" | ||
489 | "\v" "\\""v""\0" | ||
490 | ; | ||
491 | |||
492 | static void conv_c(PR *pr, unsigned char *p) | 481 | static void conv_c(PR *pr, unsigned char *p) |
493 | { | 482 | { |
494 | const char *str = conv_str; | 483 | const char *str; |
495 | 484 | unsigned char ch; | |
496 | do { | 485 | |
497 | if (*p == *str) { | 486 | ch = *p; |
498 | ++str; | 487 | if (ch == 0 || (ch -= 6, (signed char)ch > 0 && ch <= 7)) { |
499 | goto strpr; /* map e.g. '\n' to "\\n" */ | 488 | /* map chars 0,7..13 to "\0","\{a,b,t,n,v,f,r}" */ |
500 | } | 489 | str = c_escape_conv_str00 + 3 * ch; |
501 | str += 4; | 490 | goto strpr; |
502 | } while (*str); | 491 | } |
503 | 492 | ||
504 | if (isprint_asciionly(*p)) { | 493 | if (isprint_asciionly(*p)) { |
505 | *pr->cchar = 'c'; | 494 | *pr->cchar = 'c'; |
506 | printf(pr->fmt, *p); | 495 | printf(pr->fmt, *p); |
507 | } else { | 496 | } else { |
497 | #if defined(__i386__) || defined(__x86_64__) | ||
498 | /* Abuse partial register operations */ | ||
499 | uint32_t buf; | ||
500 | unsigned n = *p; | ||
501 | asm ( //00000000 00000000 00000000 aabbbccc | ||
502 | "\n shll $10,%%eax" //00000000 000000aa bbbccc00 00000000 | ||
503 | "\n shrw $5,%%ax" //00000000 000000aa 00000bbb ccc00000 | ||
504 | "\n shrb $5,%%al" //00000000 000000aa 00000bbb 00000ccc | ||
505 | "\n shll $8,%%eax" //000000aa 00000bbb 00000ccc 00000000 | ||
506 | "\n bswapl %%eax" //00000000 00000ccc 00000bbb 000000aa | ||
507 | "\n addl $0x303030,%%eax" | ||
508 | "\n" : "=a" (n) | ||
509 | : "0" (n) | ||
510 | ); | ||
511 | buf = n; | ||
512 | str = (void*)&buf; | ||
513 | #elif 1 | ||
508 | char buf[4]; | 514 | char buf[4]; |
509 | /* gcc-8.0.1 needs lots of casts to shut up */ | 515 | /* gcc-8.0.1 needs lots of casts to shut up */ |
510 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); | 516 | sprintf(buf, "%03o", (unsigned)(uint8_t)*p); |
511 | str = buf; | 517 | str = buf; |
518 | #else // use faster version? +20 bytes of code relative to sprintf() method | ||
519 | char buf[4]; | ||
520 | buf[3] = '\0'; | ||
521 | ch = *p; | ||
522 | buf[2] = '0' + (ch & 7); ch >>= 3; | ||
523 | buf[1] = '0' + (ch & 7); ch >>= 3; | ||
524 | buf[0] = '0' + ch; | ||
525 | str = buf; | ||
526 | #endif | ||
512 | strpr: | 527 | strpr: |
513 | *pr->cchar = 's'; | 528 | *pr->cchar = 's'; |
514 | printf(pr->fmt, str); | 529 | printf(pr->fmt, str); |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index b5efa19ac..4c05dcb97 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 75a61c32c..9ebda232a 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_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL | 16 | #if ENABLE_SHA1_HWACCEL || ENABLE_SHA256_HWACCEL |
17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) | 17 | # if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) |
@@ -1032,7 +1032,7 @@ static const sha_K_int sha_K[] ALIGN8 = { | |||
1032 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), | 1032 | K(0x84c87814a1f0ab72ULL), K(0x8cc702081a6439ecULL), |
1033 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), | 1033 | K(0x90befffa23631e28ULL), K(0xa4506cebde82bde9ULL), |
1034 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), | 1034 | K(0xbef9a3f7b2c67915ULL), K(0xc67178f2e372532bULL), |
1035 | #if NEED_SHA512 /* [64]+ are used for sha512 only */ | 1035 | #if NEED_SHA512 /* [64]+ are used for sha384 and sha512 only */ |
1036 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), | 1036 | K(0xca273eceea26619cULL), K(0xd186b8c721c0c207ULL), |
1037 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), | 1037 | K(0xeada7dd6cde0eb1eULL), K(0xf57d4f7fee6ed178ULL), |
1038 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), | 1038 | K(0x06f067aa72176fbaULL), K(0x0a637dc5a2c898a6ULL), |
@@ -1229,11 +1229,20 @@ static const uint32_t init512_lo[] ALIGN4 = { | |||
1229 | 0x137e2179, | 1229 | 0x137e2179, |
1230 | }; | 1230 | }; |
1231 | #endif /* NEED_SHA512 */ | 1231 | #endif /* NEED_SHA512 */ |
1232 | 1232 | #if ENABLE_SHA384SUM | |
1233 | // Note: SHA-384 is identical to SHA-512, except that initial hash values are | 1233 | static const uint64_t init384[] ALIGN8 = { |
1234 | // 0xcbbb9d5dc1059ed8, 0x629a292a367cd507, 0x9159015a3070dd17, 0x152fecd8f70e5939, | 1234 | 0, |
1235 | // 0x67332667ffc00b31, 0x8eb44a8768581511, 0xdb0c2e0d64f98fa7, 0x47b5481dbefa4fa4, | 1235 | 0, |
1236 | // and the output is constructed by omitting last two 64-bit words of it. | 1236 | 0xcbbb9d5dc1059ed8, |
1237 | 0x629a292a367cd507, | ||
1238 | 0x9159015a3070dd17, | ||
1239 | 0x152fecd8f70e5939, | ||
1240 | 0x67332667ffc00b31, | ||
1241 | 0x8eb44a8768581511, | ||
1242 | 0xdb0c2e0d64f98fa7, | ||
1243 | 0x47b5481dbefa4fa4, | ||
1244 | }; | ||
1245 | #endif | ||
1237 | 1246 | ||
1238 | /* Initialize structure containing state of computation. | 1247 | /* Initialize structure containing state of computation. |
1239 | (FIPS 180-2:5.3.2) */ | 1248 | (FIPS 180-2:5.3.2) */ |
@@ -1255,9 +1264,19 @@ void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) | |||
1255 | #endif | 1264 | #endif |
1256 | } | 1265 | } |
1257 | 1266 | ||
1258 | #if NEED_SHA512 | 1267 | #if ENABLE_SHA384SUM |
1259 | /* Initialize structure containing state of computation. | 1268 | /* Initialize structure containing state of computation. |
1260 | (FIPS 180-2:5.3.3) */ | 1269 | (FIPS 180-2:5.3.3) */ |
1270 | void FAST_FUNC sha384_begin(sha512_ctx_t *ctx) | ||
1271 | { | ||
1272 | memcpy(&ctx->total64, init384, sizeof(init384)); | ||
1273 | /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ | ||
1274 | } | ||
1275 | #endif | ||
1276 | |||
1277 | #if NEED_SHA512 | ||
1278 | /* Initialize structure containing state of computation. | ||
1279 | (FIPS 180-2:5.3.4) */ | ||
1261 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) | 1280 | void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) |
1262 | { | 1281 | { |
1263 | int i; | 1282 | int i; |
@@ -1332,7 +1351,7 @@ unsigned FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) | |||
1332 | } | 1351 | } |
1333 | 1352 | ||
1334 | #if NEED_SHA512 | 1353 | #if NEED_SHA512 |
1335 | unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | 1354 | static unsigned FAST_FUNC sha512384_end(sha512_ctx_t *ctx, void *resbuf, unsigned outsize) |
1336 | { | 1355 | { |
1337 | unsigned bufpos = ctx->total64[0] & 127; | 1356 | unsigned bufpos = ctx->total64[0] & 127; |
1338 | 1357 | ||
@@ -1363,11 +1382,21 @@ unsigned FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) | |||
1363 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) | 1382 | for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) |
1364 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); | 1383 | ctx->hash[i] = SWAP_BE64(ctx->hash[i]); |
1365 | } | 1384 | } |
1366 | memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); | 1385 | memcpy(resbuf, ctx->hash, outsize); |
1367 | return sizeof(ctx->hash); | 1386 | return outsize; |
1387 | } | ||
1388 | unsigned FAST_FUNC sha512_end(sha384_ctx_t *ctx, void *resbuf) | ||
1389 | { | ||
1390 | return sha512384_end(ctx, resbuf, SHA512_OUTSIZE); | ||
1368 | } | 1391 | } |
1369 | #endif /* NEED_SHA512 */ | 1392 | #endif /* NEED_SHA512 */ |
1370 | 1393 | ||
1394 | #if ENABLE_SHA384SUM | ||
1395 | unsigned FAST_FUNC sha384_end(sha384_ctx_t *ctx, void *resbuf) | ||
1396 | { | ||
1397 | return sha512384_end(ctx, resbuf, SHA384_OUTSIZE); | ||
1398 | } | ||
1399 | #endif | ||
1371 | 1400 | ||
1372 | /* | 1401 | /* |
1373 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, | 1402 | * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, |
@@ -1904,6 +1933,8 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) | |||
1904 | 1933 | ||
1905 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | 1934 | unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) |
1906 | { | 1935 | { |
1936 | unsigned hash_len; | ||
1937 | |||
1907 | /* Padding */ | 1938 | /* Padding */ |
1908 | uint8_t *buf = (uint8_t*)ctx->state; | 1939 | uint8_t *buf = (uint8_t*)ctx->state; |
1909 | /* | 1940 | /* |
@@ -1926,6 +1957,7 @@ unsigned FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) | |||
1926 | sha3_process_block72(ctx->state); | 1957 | sha3_process_block72(ctx->state); |
1927 | 1958 | ||
1928 | /* Output */ | 1959 | /* Output */ |
1929 | memcpy(resbuf, ctx->state, 64); | 1960 | hash_len = (1600/8 - ctx->input_block_bytes) / 2; |
1930 | return 64; | 1961 | memcpy(resbuf, ctx->state, hash_len); |
1962 | return hash_len; | ||
1931 | } | 1963 | } |
diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 43d1da35c..10cc0433b 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c | |||
@@ -1564,7 +1564,7 @@ void FAST_FUNC save_history(line_input_t *st) | |||
1564 | FILE *fp; | 1564 | FILE *fp; |
1565 | 1565 | ||
1566 | /* bash compat: HISTFILE="" disables history saving */ | 1566 | /* bash compat: HISTFILE="" disables history saving */ |
1567 | if (!st || !st->hist_file || !state->hist_file[0]) | 1567 | if (!st || !st->hist_file || !st->hist_file[0]) |
1568 | return; | 1568 | return; |
1569 | if (st->cnt_history <= st->cnt_history_in_file) | 1569 | if (st->cnt_history <= st->cnt_history_in_file) |
1570 | return; /* no new entries were added */ | 1570 | return; /* no new entries were added */ |
diff --git a/libbb/procps.c b/libbb/procps.c index f56b71b21..fc31c075d 100644 --- a/libbb/procps.c +++ b/libbb/procps.c | |||
@@ -109,7 +109,7 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp) | |||
109 | } | 109 | } |
110 | 110 | ||
111 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 111 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
112 | static unsigned long long fast_strtoull_16(char **endptr) | 112 | unsigned long long FAST_FUNC fast_strtoull_16(char **endptr) |
113 | { | 113 | { |
114 | unsigned char c; | 114 | unsigned char c; |
115 | char *str = *endptr; | 115 | char *str = *endptr; |
@@ -130,7 +130,7 @@ static unsigned long long fast_strtoull_16(char **endptr) | |||
130 | 130 | ||
131 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 131 | #if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP |
132 | /* We cut a lot of corners here for speed */ | 132 | /* We cut a lot of corners here for speed */ |
133 | static unsigned long fast_strtoul_10(char **endptr) | 133 | unsigned long FAST_FUNC fast_strtoul_10(char **endptr) |
134 | { | 134 | { |
135 | unsigned char c; | 135 | unsigned char c; |
136 | char *str = *endptr; | 136 | char *str = *endptr; |
@@ -143,6 +143,24 @@ static unsigned long fast_strtoul_10(char **endptr) | |||
143 | *endptr = str + 1; /* We skip trailing space! */ | 143 | *endptr = str + 1; /* We skip trailing space! */ |
144 | return n; | 144 | return n; |
145 | } | 145 | } |
146 | # if LONG_MAX < LLONG_MAX | ||
147 | /* For VSZ, which can be very large */ | ||
148 | static unsigned long long fast_strtoull_10(char **endptr) | ||
149 | { | ||
150 | unsigned char c; | ||
151 | char *str = *endptr; | ||
152 | unsigned long long n = *str - '0'; | ||
153 | |||
154 | /* Need to stop on both ' ' and '\n' */ | ||
155 | while ((c = *++str) > ' ') | ||
156 | n = n*10 + (c - '0'); | ||
157 | |||
158 | *endptr = str + 1; /* We skip trailing space! */ | ||
159 | return n; | ||
160 | } | ||
161 | # else | ||
162 | # define fast_strtoull_10(endptr) fast_strtoul_10(endptr) | ||
163 | # endif | ||
146 | 164 | ||
147 | # if ENABLE_FEATURE_FAST_TOP | 165 | # if ENABLE_FEATURE_FAST_TOP |
148 | static long fast_strtol_10(char **endptr) | 166 | static long fast_strtol_10(char **endptr) |
@@ -155,7 +173,7 @@ static long fast_strtol_10(char **endptr) | |||
155 | } | 173 | } |
156 | # endif | 174 | # endif |
157 | 175 | ||
158 | static char *skip_fields(char *str, int count) | 176 | char* FAST_FUNC skip_fields(char *str, int count) |
159 | { | 177 | { |
160 | do { | 178 | do { |
161 | while (*str++ != ' ') | 179 | while (*str++ != ' ') |
@@ -166,35 +184,25 @@ static char *skip_fields(char *str, int count) | |||
166 | } | 184 | } |
167 | #endif | 185 | #endif |
168 | 186 | ||
169 | #if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP | 187 | #if ENABLE_FEATURE_TOPMEM |
170 | static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) | 188 | static NOINLINE void procps_read_smaps(pid_t pid, procps_status_t *sp) |
171 | { | 189 | { |
172 | char *tp = is_prefixed_with(buf, prefix); | 190 | // There is A LOT of /proc/PID/smaps data on a big system. |
173 | if (tp) { | 191 | // Optimize this for speed, makes "top -m" faster. |
174 | tp = skip_whitespace(tp); | 192 | //TODO large speedup: |
175 | } | 193 | //read /proc/PID/smaps_rollup (cumulative stats of all mappings, much faster) |
176 | return tp; | 194 | //and /proc/PID/maps to get mapped_ro and mapped_rw (IOW: VSZ,VSZRW) |
177 | } | ||
178 | 195 | ||
179 | int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | ||
180 | void (*cb)(struct smaprec *, void *), void *data) | ||
181 | { | ||
182 | FILE *file; | 196 | FILE *file; |
183 | struct smaprec currec; | ||
184 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; | 197 | char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; |
185 | char buf[PROCPS_BUFSIZE]; | 198 | char buf[PROCPS_BUFSIZE]; |
186 | #if !ENABLE_PMAP | ||
187 | void (*cb)(struct smaprec *, void *) = NULL; | ||
188 | void *data = NULL; | ||
189 | #endif | ||
190 | 199 | ||
191 | sprintf(filename, "/proc/%u/smaps", (int)pid); | 200 | sprintf(filename, "/proc/%u/smaps", (int)pid); |
192 | 201 | ||
193 | file = fopen_for_read(filename); | 202 | file = fopen_for_read(filename); |
194 | if (!file) | 203 | if (!file) |
195 | return 1; | 204 | return; |
196 | 205 | ||
197 | memset(&currec, 0, sizeof(currec)); | ||
198 | while (fgets(buf, PROCPS_BUFSIZE, file)) { | 206 | while (fgets(buf, PROCPS_BUFSIZE, file)) { |
199 | // Each mapping datum has this form: | 207 | // Each mapping datum has this form: |
200 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 208 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
@@ -202,80 +210,53 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, | |||
202 | // Rss: nnn kB | 210 | // Rss: nnn kB |
203 | // ..... | 211 | // ..... |
204 | 212 | ||
205 | char *tp, *p; | 213 | char *tp; |
206 | 214 | ||
215 | if (buf[0] == 'S' || buf[0] == 'P') { | ||
207 | #define SCAN(S, X) \ | 216 | #define SCAN(S, X) \ |
208 | if ((tp = skip_whitespace_if_prefixed_with(buf, S)) != NULL) { \ | 217 | if (memcmp(buf, S, sizeof(S)-1) == 0) { \ |
209 | total->X += currec.X = fast_strtoul_10(&tp); \ | 218 | tp = skip_whitespace(buf + sizeof(S)-1); \ |
210 | continue; \ | 219 | sp->X += fast_strtoul_10(&tp); \ |
211 | } | 220 | continue; \ |
212 | if (cb) { | 221 | } |
213 | SCAN("Pss:" , smap_pss ); | 222 | SCAN("Private_Dirty:", private_dirty) |
214 | SCAN("Swap:" , smap_swap ); | 223 | SCAN("Private_Clean:", private_clean) |
215 | } | 224 | SCAN("Shared_Dirty:" , shared_dirty ) |
216 | SCAN("Private_Dirty:", private_dirty); | 225 | SCAN("Shared_Clean:" , shared_clean ) |
217 | SCAN("Private_Clean:", private_clean); | ||
218 | SCAN("Shared_Dirty:" , shared_dirty ); | ||
219 | SCAN("Shared_Clean:" , shared_clean ); | ||
220 | #undef SCAN | 226 | #undef SCAN |
227 | } | ||
221 | tp = strchr(buf, '-'); | 228 | tp = strchr(buf, '-'); |
222 | if (tp) { | 229 | if (tp) { |
223 | // We reached next mapping - the line of this form: | 230 | // We reached next mapping - the line of this form: |
224 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME | 231 | // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME |
225 | 232 | ||
226 | if (cb) { | 233 | char *rwx; |
227 | /* If we have a previous record, there's nothing more | 234 | unsigned long sz; |
228 | * for it, call the callback and clear currec | ||
229 | */ | ||
230 | if (currec.smap_size) | ||
231 | cb(&currec, data); | ||
232 | free(currec.smap_name); | ||
233 | } | ||
234 | memset(&currec, 0, sizeof(currec)); | ||
235 | 235 | ||
236 | *tp = ' '; | 236 | *tp = ' '; |
237 | tp = buf; | 237 | tp = buf; |
238 | currec.smap_start = fast_strtoull_16(&tp); | 238 | sz = fast_strtoull_16(&tp); // start |
239 | currec.smap_size = (fast_strtoull_16(&tp) - currec.smap_start) >> 10; | 239 | sz = (fast_strtoull_16(&tp) - sz) >> 10; // end - start |
240 | 240 | // tp -> "rw-s" string | |
241 | strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); | 241 | rwx = tp; |
242 | |||
243 | // skipping "rw-s FILEOFS M:m INODE " | 242 | // skipping "rw-s FILEOFS M:m INODE " |
244 | tp = skip_whitespace(skip_fields(tp, 4)); | 243 | tp = skip_whitespace(skip_fields(tp, 4)); |
245 | // filter out /dev/something (something != zero) | 244 | // if not a device memory mapped... |
246 | if (!is_prefixed_with(tp, "/dev/") || strcmp(tp, "/dev/zero\n") == 0) { | 245 | if (memcmp(tp, "/dev/", 5) != 0 // not "/dev/something" |
247 | if (currec.smap_mode[1] == 'w') { | 246 | || strcmp(tp + 5, "zero\n") == 0 // or is "/dev/zero" (which isn't a device) |
248 | currec.mapped_rw = currec.smap_size; | 247 | ) { |
249 | total->mapped_rw += currec.smap_size; | 248 | if (rwx[1] == 'w') |
250 | } else if (currec.smap_mode[1] == '-') { | 249 | sp->mapped_rw += sz; |
251 | currec.mapped_ro = currec.smap_size; | 250 | else if (rwx[0] == 'r' || rwx[2] == 'x') |
252 | total->mapped_ro += currec.smap_size; | 251 | sp->mapped_ro += sz; |
253 | } | 252 | // else: seen "---p" mappings (mmap guard gaps?), |
253 | // do NOT account these as VSZ, they aren't really | ||
254 | } | 254 | } |
255 | |||
256 | if (strcmp(tp, "[stack]\n") == 0) | 255 | if (strcmp(tp, "[stack]\n") == 0) |
257 | total->stack += currec.smap_size; | 256 | sp->stack += sz; |
258 | if (cb) { | ||
259 | p = skip_non_whitespace(tp); | ||
260 | if (p == tp) { | ||
261 | currec.smap_name = xstrdup(" [ anon ]"); | ||
262 | } else { | ||
263 | *p = '\0'; | ||
264 | currec.smap_name = xstrdup(tp); | ||
265 | } | ||
266 | } | ||
267 | total->smap_size += currec.smap_size; | ||
268 | } | 257 | } |
269 | } | 258 | } |
270 | fclose(file); | 259 | fclose(file); |
271 | |||
272 | if (cb) { | ||
273 | if (currec.smap_size) | ||
274 | cb(&currec, data); | ||
275 | free(currec.smap_name); | ||
276 | } | ||
277 | |||
278 | return 0; | ||
279 | } | 260 | } |
280 | #endif | 261 | #endif |
281 | 262 | ||
@@ -370,7 +351,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
370 | char *cp, *comm1; | 351 | char *cp, *comm1; |
371 | int tty; | 352 | int tty; |
372 | #if !ENABLE_FEATURE_FAST_TOP | 353 | #if !ENABLE_FEATURE_FAST_TOP |
373 | unsigned long vsz, rss; | 354 | unsigned long long vsz; |
355 | unsigned long rss; | ||
374 | #endif | 356 | #endif |
375 | /* see proc(5) for some details on this */ | 357 | /* see proc(5) for some details on this */ |
376 | strcpy(filename_tail, "stat"); | 358 | strcpy(filename_tail, "stat"); |
@@ -396,7 +378,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
396 | "%ld " /* nice */ | 378 | "%ld " /* nice */ |
397 | "%*s %*s " /* timeout, it_real_value */ | 379 | "%*s %*s " /* timeout, it_real_value */ |
398 | "%lu " /* start_time */ | 380 | "%lu " /* start_time */ |
399 | "%lu " /* vsize */ | 381 | "%llu " /* vsize - can be very large */ |
400 | "%lu " /* rss */ | 382 | "%lu " /* rss */ |
401 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 383 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
402 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ | 384 | "%*s %*s %*s %*s %*s %*s " /*rss_rlim, start_code, end_code, start_stack, kstk_esp, kstk_eip */ |
@@ -449,7 +431,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
449 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ | 431 | cp = skip_fields(cp, 2); /* timeout, it_real_value */ |
450 | sp->start_time = fast_strtoul_10(&cp); | 432 | sp->start_time = fast_strtoul_10(&cp); |
451 | /* vsz is in bytes and we want kb */ | 433 | /* vsz is in bytes and we want kb */ |
452 | sp->vsz = fast_strtoul_10(&cp) >> 10; | 434 | sp->vsz = fast_strtoull_10(&cp) >> 10; |
453 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ | 435 | /* vsz is in bytes but rss is in *PAGES*! Can you believe that? */ |
454 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; | 436 | sp->rss = fast_strtoul_10(&cp) << sp->shift_pages_to_kb; |
455 | # if ENABLE_FEATURE_TOP_SMP_PROCESS | 437 | # if ENABLE_FEATURE_TOP_SMP_PROCESS |
@@ -483,7 +465,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
483 | 465 | ||
484 | #if ENABLE_FEATURE_TOPMEM | 466 | #if ENABLE_FEATURE_TOPMEM |
485 | if (flags & PSSCAN_SMAPS) | 467 | if (flags & PSSCAN_SMAPS) |
486 | procps_read_smaps(pid, &sp->smaps, NULL, NULL); | 468 | procps_read_smaps(pid, sp); |
487 | #endif /* TOPMEM */ | 469 | #endif /* TOPMEM */ |
488 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS | 470 | #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS |
489 | if (flags & PSSCAN_RUIDGID) { | 471 | if (flags & PSSCAN_RUIDGID) { |
@@ -566,36 +548,45 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) | |||
566 | return sp; | 548 | return sp; |
567 | } | 549 | } |
568 | 550 | ||
569 | void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | 551 | int FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) |
570 | { | 552 | { |
571 | int sz; | 553 | int sz; |
572 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; | 554 | char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; |
573 | 555 | ||
574 | sprintf(filename, "/proc/%u/cmdline", pid); | 556 | sprintf(filename, "/proc/%u/cmdline", pid); |
575 | sz = open_read_close(filename, buf, col - 1); | 557 | sz = open_read_close(filename, buf, col - 1); |
558 | if (sz < 0) | ||
559 | return sz; | ||
576 | if (sz > 0) { | 560 | if (sz > 0) { |
577 | const char *base; | 561 | const char *program_basename; |
578 | int comm_len; | 562 | int comm_len; |
579 | 563 | ||
580 | buf[sz] = '\0'; | 564 | buf[sz] = '\0'; |
581 | while (--sz >= 0 && buf[sz] == '\0') | 565 | while (--sz >= 0 && buf[sz] == '\0') |
582 | continue; | 566 | continue; |
583 | /* Prevent basename("process foo/bar") = "bar" */ | 567 | |
584 | strchrnul(buf, ' ')[0] = '\0'; | 568 | /* Find "program" in "[-][/PATH/TO/]program" */ |
585 | base = bb_basename(buf); /* before we replace argv0's NUL with space */ | 569 | strchrnul(buf, ' ')[0] = '\0'; /* prevent basename("program foo/bar") = "bar" */ |
570 | program_basename = bb_basename(buf[0] == '-' ? buf + 1 : buf); | ||
571 | /* ^^^ note: must do it *before* replacing argv0's NUL with space */ | ||
572 | |||
573 | /* Prevent stuff like this: | ||
574 | * echo 'sleep 999; exit' >`printf '\ec'`; sh ?c | ||
575 | * messing up top and ps output (or worse). | ||
576 | * This also replaces NULs with spaces, converting | ||
577 | * list of NUL-strings into one string. | ||
578 | */ | ||
586 | while (sz >= 0) { | 579 | while (sz >= 0) { |
587 | if ((unsigned char)(buf[sz]) < ' ') | 580 | if ((unsigned char)(buf[sz]) < ' ') |
588 | buf[sz] = ' '; | 581 | buf[sz] = ' '; |
589 | sz--; | 582 | sz--; |
590 | } | 583 | } |
591 | if (base[0] == '-') /* "-sh" (login shell)? */ | ||
592 | base++; | ||
593 | 584 | ||
594 | /* If comm differs from argv0, prepend "{comm} ". | 585 | /* If comm differs from argv0, prepend "{comm} ". |
595 | * It allows to see thread names set by prctl(PR_SET_NAME). | 586 | * It allows to see thread names set by prctl(PR_SET_NAME). |
596 | */ | 587 | */ |
597 | if (!comm) | 588 | if (!comm) |
598 | return; | 589 | return 0; |
599 | comm_len = strlen(comm); | 590 | comm_len = strlen(comm); |
600 | /* Why compare up to comm_len, not COMM_LEN-1? | 591 | /* Why compare up to comm_len, not COMM_LEN-1? |
601 | * Well, some processes rewrite argv, and use _spaces_ there | 592 | * Well, some processes rewrite argv, and use _spaces_ there |
@@ -603,19 +594,20 @@ void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) | |||
603 | * I prefer to still treat argv0 "process foo bar" | 594 | * I prefer to still treat argv0 "process foo bar" |
604 | * as 'equal' to comm "process". | 595 | * as 'equal' to comm "process". |
605 | */ | 596 | */ |
606 | if (strncmp(base, comm, comm_len) != 0) { | 597 | if (strncmp(program_basename, comm, comm_len) != 0) { |
607 | comm_len += 3; | 598 | comm_len += 3; |
608 | if (col > comm_len) | 599 | if (col > comm_len) |
609 | memmove(buf + comm_len, buf, col - comm_len); | 600 | memmove(buf + comm_len, buf, col - comm_len); |
610 | snprintf(buf, col, "{%s}", comm); | 601 | snprintf(buf, col, "{%s}", comm); |
611 | if (col <= comm_len) | 602 | if (col <= comm_len) |
612 | return; | 603 | return 0; |
613 | buf[comm_len - 1] = ' '; | 604 | buf[comm_len - 1] = ' '; |
614 | buf[col - 1] = '\0'; | 605 | buf[col - 1] = '\0'; |
615 | } | 606 | } |
616 | } else { | 607 | } else { |
617 | snprintf(buf, col, "[%s]", comm ? comm : "?"); | 608 | snprintf(buf, col, "[%s]", comm ? comm : "?"); |
618 | } | 609 | } |
610 | return 0; | ||
619 | } | 611 | } |
620 | 612 | ||
621 | /* from kernel: | 613 | /* from kernel: |
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 */ | ||
52 | size_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 | } |