aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
committerRon Yorston <rmy@pobox.com>2021-01-14 13:28:49 +0000
commit89963b524d211e1aec12b72b3725be05ee95c8cf (patch)
tree48590aef62b7ee7686b7898256f29def8d9c50b9 /libbb
parent9aa5a829070392c2ac6494d0c4e674c0c2bc7dab (diff)
parent2b7c1aa92c68524559a2067609d09309d5c09adc (diff)
downloadbusybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.gz
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.tar.bz2
busybox-w32-89963b524d211e1aec12b72b3725be05ee95c8cf.zip
Merge branch 'busybox' into merge
Diffstat (limited to 'libbb')
-rw-r--r--libbb/bb_do_delay.c59
-rw-r--r--libbb/capability.c2
-rw-r--r--libbb/copyfd.c5
-rw-r--r--libbb/die_if_bad_username.c4
-rw-r--r--libbb/duration.c2
-rw-r--r--libbb/executable.c9
-rw-r--r--libbb/hash_md5_sha.c22
-rw-r--r--libbb/lineedit.c129
-rw-r--r--libbb/loop.c139
-rw-r--r--libbb/mode_string.c2
-rw-r--r--libbb/platform.c4
-rw-r--r--libbb/procps.c51
-rw-r--r--libbb/pw_encrypt.c15
-rw-r--r--libbb/pw_encrypt_des.c40
-rw-r--r--libbb/rtc.c6
-rw-r--r--libbb/run_shell.c32
-rw-r--r--libbb/speed_table.c2
-rw-r--r--libbb/time.c13
-rw-r--r--libbb/unicode.c22
-rw-r--r--libbb/uuencode.c235
-rw-r--r--libbb/xatonum.c6
-rw-r--r--libbb/xconnect.c20
-rw-r--r--libbb/xfuncs.c12
-rw-r--r--libbb/xfuncs_printf.c71
24 files changed, 543 insertions, 359 deletions
diff --git a/libbb/bb_do_delay.c b/libbb/bb_do_delay.c
index 65541704b..9a84fa24b 100644
--- a/libbb/bb_do_delay.c
+++ b/libbb/bb_do_delay.c
@@ -8,13 +8,60 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11void FAST_FUNC bb_do_delay(int seconds) 11/* void FAST_FUNC bb_do_delay(unsigned seconds) { ... } - no users yet */
12
13#ifndef LOGIN_FAIL_DELAY
14#define LOGIN_FAIL_DELAY 3
15#endif
16void FAST_FUNC pause_after_failed_login(void)
12{ 17{
13 time_t start, now; 18#if 0 /* over-engineered madness */
19 time_t end, diff;
14 20
15 start = time(NULL); 21 end = time(NULL) + LOGIN_FAIL_DELAY;
22 diff = LOGIN_FAIL_DELAY;
16 do { 23 do {
17 sleep(seconds); 24 sleep(diff);
18 now = time(NULL); 25 diff = end - time(NULL);
19 } while ((now - start) < seconds); 26 } while (diff > 0);
27#else
28 sleep(LOGIN_FAIL_DELAY);
29#endif
30}
31
32void FAST_FUNC sleep1(void)
33{
34 sleep(1);
35}
36
37void FAST_FUNC msleep(unsigned ms)
38{
39#if 0
40 /* 1. usleep(n) is not guaranteed by standards to accept n >= 1000000
41 * 2. multiplication in usleep(ms * 1000) can overflow if ms > 4294967
42 * (sleep of ~71.5 minutes)
43 * Let's play safe and loop:
44 */
45 while (ms > 500) {
46 usleep(500000);
47 ms -= 500;
48 }
49 usleep(ms * 1000);
50#else
51//usleep is often implemented as a call to nanosleep.
52//Simply do the same to implement msleep.
53//it's marginally larger, but wakes your CPU less often:
54//function old new delta
55//msleep 45 52 +7
56 struct timespec ts;
57 ts.tv_sec = ms / 1000;
58 ts.tv_nsec = (ms % 1000) * 1000000;
59 /*
60 * If a signal has non-default handler, nanosleep returns early.
61 * Our version of msleep doesn't return early
62 * if interrupted by such signals:
63 */
64 while (nanosleep(&ts, &ts) != 0)
65 continue;
66#endif
20} 67}
diff --git a/libbb/capability.c b/libbb/capability.c
index 23afd8eb9..e3c252a5a 100644
--- a/libbb/capability.c
+++ b/libbb/capability.c
@@ -17,7 +17,7 @@ extern int capget(cap_user_header_t header, const cap_user_data_t data);
17// This way, libcap needs not be installed in build environment. 17// This way, libcap needs not be installed in build environment.
18#include "libbb.h" 18#include "libbb.h"
19 19
20static const char *const capabilities[] = { 20static const char *const capabilities[] ALIGN_PTR = {
21 "chown", 21 "chown",
22 "dac_override", 22 "dac_override",
23 "dac_read_search", 23 "dac_read_search",
diff --git a/libbb/copyfd.c b/libbb/copyfd.c
index d41fd10f0..7f9d92ea9 100644
--- a/libbb/copyfd.c
+++ b/libbb/copyfd.c
@@ -75,10 +75,7 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size)
75 goto use_small_buf; 75 goto use_small_buf;
76 /* We want page-aligned buffer, just in case kernel is clever 76 /* We want page-aligned buffer, just in case kernel is clever
77 * and can do page-aligned io more efficiently */ 77 * and can do page-aligned io more efficiently */
78 buffer = mmap(NULL, CONFIG_FEATURE_COPYBUF_KB * 1024, 78 buffer = mmap_anon(CONFIG_FEATURE_COPYBUF_KB * 1024);
79 PROT_READ | PROT_WRITE,
80 MAP_PRIVATE | MAP_ANON,
81 /* ignored: */ -1, 0);
82 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024; 79 buffer_size = CONFIG_FEATURE_COPYBUF_KB * 1024;
83 if (buffer == MAP_FAILED) { 80 if (buffer == MAP_FAILED) {
84 use_small_buf: 81 use_small_buf:
diff --git a/libbb/die_if_bad_username.c b/libbb/die_if_bad_username.c
index e5e1160c4..d05dc74c5 100644
--- a/libbb/die_if_bad_username.c
+++ b/libbb/die_if_bad_username.c
@@ -8,6 +8,10 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11#ifndef LOGIN_NAME_MAX
12#define LOGIN_NAME_MAX 256
13#endif
14
11/* To avoid problems, the username should consist only of 15/* To avoid problems, the username should consist only of
12 * letters, digits, underscores, periods, at signs and dashes, 16 * letters, digits, underscores, periods, at signs and dashes,
13 * and not start with a dash (as defined by IEEE Std 1003.1-2001). 17 * and not start with a dash (as defined by IEEE Std 1003.1-2001).
diff --git a/libbb/duration.c b/libbb/duration.c
index 22b209f4d..086da15fb 100644
--- a/libbb/duration.c
+++ b/libbb/duration.c
@@ -21,7 +21,7 @@
21 21
22#include "libbb.h" 22#include "libbb.h"
23 23
24static const struct suffix_mult duration_suffixes[] = { 24static const struct suffix_mult duration_suffixes[] ALIGN_SUFFIX = {
25 { "s", 1 }, 25 { "s", 1 },
26 { "m", 60 }, 26 { "m", 60 },
27 { "h", 60*60 }, 27 { "h", 60*60 },
diff --git a/libbb/executable.c b/libbb/executable.c
index f549a7aae..bd3022b13 100644
--- a/libbb/executable.c
+++ b/libbb/executable.c
@@ -100,12 +100,3 @@ void FAST_FUNC BB_EXECVP_or_die(char **argv)
100 xfunc_error_retval = (errno == ENOENT) ? 127 : 126; 100 xfunc_error_retval = (errno == ENOENT) ? 127 : 126;
101 bb_perror_msg_and_die("can't execute '%s'", argv[0]); 101 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
102} 102}
103
104/* Typical idiom for applets which exec *optional* PROG [ARGS] */
105void FAST_FUNC exec_prog_or_SHELL(char **argv)
106{
107 if (argv[0]) {
108 BB_EXECVP_or_die(argv);
109 }
110 run_shell(getenv("SHELL"), /*login:*/ 1, NULL);
111}
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index d8f210173..e0db8ce67 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -111,7 +111,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
111 They are defined in RFC 1321 as 111 They are defined in RFC 1321 as
112 T[i] = (int)(2^32 * fabs(sin(i))), i=1..64 112 T[i] = (int)(2^32 * fabs(sin(i))), i=1..64
113 */ 113 */
114 static const uint32_t C_array[] = { 114 static const uint32_t C_array[] ALIGN4 = {
115 /* round 1 */ 115 /* round 1 */
116 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, 116 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
117 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, 117 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
@@ -492,7 +492,7 @@ unsigned FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf)
492 492
493static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) 493static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx)
494{ 494{
495 static const uint32_t rconsts[] = { 495 static const uint32_t rconsts[] ALIGN4 = {
496 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 496 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6
497 }; 497 };
498 int i, j; 498 int i, j;
@@ -567,7 +567,7 @@ typedef uint64_t sha_K_int;
567typedef uint32_t sha_K_int; 567typedef uint32_t sha_K_int;
568# define K(v) (uint32_t)(v >> 32) 568# define K(v) (uint32_t)(v >> 32)
569#endif 569#endif
570static const sha_K_int sha_K[] = { 570static const sha_K_int sha_K[] ALIGN8 = {
571 K(0x428a2f98d728ae22ULL), K(0x7137449123ef65cdULL), 571 K(0x428a2f98d728ae22ULL), K(0x7137449123ef65cdULL),
572 K(0xb5c0fbcfec4d3b2fULL), K(0xe9b5dba58189dbbcULL), 572 K(0xb5c0fbcfec4d3b2fULL), K(0xe9b5dba58189dbbcULL),
573 K(0x3956c25bf348b538ULL), K(0x59f111f1b605d019ULL), 573 K(0x3956c25bf348b538ULL), K(0x59f111f1b605d019ULL),
@@ -760,7 +760,7 @@ void FAST_FUNC sha1_begin(sha1_ctx_t *ctx)
760 ctx->process_block = sha1_process_block64; 760 ctx->process_block = sha1_process_block64;
761} 761}
762 762
763static const uint32_t init256[] = { 763static const uint32_t init256[] ALIGN4 = {
764 0, 764 0,
765 0, 765 0,
766 0x6a09e667, 766 0x6a09e667,
@@ -773,7 +773,7 @@ static const uint32_t init256[] = {
773 0x5be0cd19, 773 0x5be0cd19,
774}; 774};
775#if NEED_SHA512 775#if NEED_SHA512
776static const uint32_t init512_lo[] = { 776static const uint32_t init512_lo[] ALIGN4 = {
777 0, 777 0,
778 0, 778 0,
779 0xf3bcc908, 779 0xf3bcc908,
@@ -1009,7 +1009,7 @@ static void sha3_process_block72(uint64_t *state)
1009 1009
1010#if OPTIMIZE_SHA3_FOR_32 1010#if OPTIMIZE_SHA3_FOR_32
1011 /* 1011 /*
1012 static const uint32_t IOTA_CONST_0[NROUNDS] = { 1012 static const uint32_t IOTA_CONST_0[NROUNDS] ALIGN4 = {
1013 0x00000001UL, 1013 0x00000001UL,
1014 0x00000000UL, 1014 0x00000000UL,
1015 0x00000000UL, 1015 0x00000000UL,
@@ -1038,7 +1038,7 @@ static void sha3_process_block72(uint64_t *state)
1038 ** bits are in lsb: 0101 0000 1111 0100 1111 0001 1038 ** bits are in lsb: 0101 0000 1111 0100 1111 0001
1039 */ 1039 */
1040 uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1); 1040 uint32_t IOTA_CONST_0bits = (uint32_t)(0x0050f4f1);
1041 static const uint32_t IOTA_CONST_1[NROUNDS] = { 1041 static const uint32_t IOTA_CONST_1[NROUNDS] ALIGN4 = {
1042 0x00000000UL, 1042 0x00000000UL,
1043 0x00000089UL, 1043 0x00000089UL,
1044 0x8000008bUL, 1044 0x8000008bUL,
@@ -1174,7 +1174,7 @@ static void sha3_process_block72(uint64_t *state)
1174 combine_halves(state); 1174 combine_halves(state);
1175#else 1175#else
1176 /* Native 64-bit algorithm */ 1176 /* Native 64-bit algorithm */
1177 static const uint16_t IOTA_CONST[NROUNDS] = { 1177 static const uint16_t IOTA_CONST[NROUNDS] ALIGN2 = {
1178 /* Elements should be 64-bit, but top half is always zero 1178 /* Elements should be 64-bit, but top half is always zero
1179 * or 0x80000000. We encode 63rd bits in a separate word below. 1179 * or 0x80000000. We encode 63rd bits in a separate word below.
1180 * Same is true for 31th bits, which lets us use 16-bit table 1180 * Same is true for 31th bits, which lets us use 16-bit table
@@ -1210,15 +1210,15 @@ static void sha3_process_block72(uint64_t *state)
1210 /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */ 1210 /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */
1211 const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00); 1211 const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00);
1212 1212
1213 static const uint8_t ROT_CONST[24] = { 1213 static const uint8_t ROT_CONST[24] ALIGN1 = {
1214 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 1214 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14,
1215 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, 1215 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44,
1216 }; 1216 };
1217 static const uint8_t PI_LANE[24] = { 1217 static const uint8_t PI_LANE[24] ALIGN1 = {
1218 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 1218 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4,
1219 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, 1219 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1,
1220 }; 1220 };
1221 /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/ 1221 /*static const uint8_t MOD5[10] ALIGN1 = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/
1222 1222
1223 unsigned x; 1223 unsigned x;
1224 unsigned round; 1224 unsigned round;
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index b35da1874..f3cbc512c 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -57,12 +57,23 @@
57#if ENABLE_FEATURE_EDITING 57#if ENABLE_FEATURE_EDITING
58 58
59 59
60#if !ENABLE_SHELL_ASH && !ENABLE_SHELL_HUSH
61/* so far only shells use these features */
62# undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
63# undef ENABLE_FEATURE_TAB_COMPLETION
64# undef ENABLE_FEATURE_USERNAME_COMPLETION
65# define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
66# define ENABLE_FEATURE_TAB_COMPLETION 0
67# define ENABLE_FEATURE_USERNAME_COMPLETION 0
68#endif
69
70
60#define ENABLE_USERNAME_OR_HOMEDIR \ 71#define ENABLE_USERNAME_OR_HOMEDIR \
61 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) 72 (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
62#define IF_USERNAME_OR_HOMEDIR(...)
63#if ENABLE_USERNAME_OR_HOMEDIR 73#if ENABLE_USERNAME_OR_HOMEDIR
64# undef IF_USERNAME_OR_HOMEDIR
65# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__ 74# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__
75#else
76# define IF_USERNAME_OR_HOMEDIR(...) /*nothing*/
66#endif 77#endif
67 78
68 79
@@ -205,9 +216,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics;
205#define INIT_S() do { \ 216#define INIT_S() do { \
206 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \ 217 (*(struct lineedit_statics**)not_const_pp(&lineedit_ptr_to_statics)) = xzalloc(sizeof(S)); \
207 barrier(); \ 218 barrier(); \
208 cmdedit_termw = 80; \
209 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \
210 IF_FEATURE_EDITING_VI(delptr = delbuf;) \
211} while (0) 219} while (0)
212 220
213static void deinit_S(void) 221static void deinit_S(void)
@@ -796,16 +804,18 @@ enum {
796 FIND_FILE_ONLY = 2, 804 FIND_FILE_ONLY = 2,
797}; 805};
798 806
799static int path_parse(char ***p) 807static unsigned path_parse(char ***p)
800{ 808{
801 int npth; 809 unsigned npth;
802 const char *pth; 810 const char *pth;
803 char *tmp; 811 char *tmp;
804 char **res; 812 char **res;
805 813
814# if EDITING_HAS_path_lookup
806 if (state->flags & WITH_PATH_LOOKUP) 815 if (state->flags & WITH_PATH_LOOKUP)
807 pth = state->path_lookup; 816 pth = state->path_lookup;
808 else 817 else
818# endif
809 pth = getenv("PATH"); 819 pth = getenv("PATH");
810 820
811 /* PATH="" or PATH=":"? */ 821 /* PATH="" or PATH=":"? */
@@ -824,7 +834,7 @@ static int path_parse(char ***p)
824 npth++; 834 npth++;
825 } 835 }
826 836
827 *p = res = xmalloc(npth * sizeof(res[0])); 837 *p = res = xzalloc((npth + 1) * sizeof(res[0]));
828 res[0] = tmp = xstrdup(pth); 838 res[0] = tmp = xstrdup(pth);
829 npth = 1; 839 npth = 1;
830 while (1) { 840 while (1) {
@@ -836,6 +846,8 @@ static int path_parse(char ***p)
836 break; /* :<empty> */ 846 break; /* :<empty> */
837 res[npth++] = tmp; 847 res[npth++] = tmp;
838 } 848 }
849 /* special case: "match subdirectories of the current directory" */
850 /*res[npth++] = NULL; - filled by xzalloc() */
839 return npth; 851 return npth;
840} 852}
841 853
@@ -846,49 +858,49 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
846{ 858{
847 char *path1[1]; 859 char *path1[1];
848 char **paths = path1; 860 char **paths = path1;
849 int npaths; 861 unsigned npaths;
850 int i; 862 unsigned i;
851 unsigned pf_len; 863 unsigned baselen;
852 const char *pfind; 864 const char *basecmd;
853 char *dirbuf = NULL; 865 char *dirbuf = NULL;
854 866
855 npaths = 1; 867 npaths = 1;
856 path1[0] = (char*)"."; 868 path1[0] = (char*)".";
857 869
858 pfind = strrchr(command, '/'); 870 basecmd = strrchr(command, '/');
859#if ENABLE_PLATFORM_MINGW32 871#if ENABLE_PLATFORM_MINGW32
860 if (!pfind && has_dos_drive_prefix(command) && command[2] != '\0') { 872 if (!basecmd && has_dos_drive_prefix(command) && command[2] != '\0') {
861 char buffer[PATH_MAX]; 873 char buffer[PATH_MAX];
862 874
863 /* path is of form c:path with no '/' */ 875 /* path is of form c:path with no '/' */
864 if (get_drive_cwd(command, buffer, PATH_MAX)) { 876 if (get_drive_cwd(command, buffer, PATH_MAX)) {
865 pfind = command + 2; 877 basecmd = command + 2;
866 path1[0] = dirbuf = xstrdup(buffer); 878 path1[0] = dirbuf = xstrdup(buffer);
867 } 879 }
868 } else 880 } else
869#endif 881#endif
870 if (!pfind) { 882 if (!basecmd) {
871 if (type == FIND_EXE_ONLY) 883 if (type == FIND_EXE_ONLY)
872 npaths = path_parse(&paths); 884 npaths = path_parse(&paths);
873 pfind = command; 885 basecmd = command;
874 } else { 886 } else {
875 /* point to 'l' in "..../last_component" */ 887 /* point to 'l' in "..../last_component" */
876 pfind++; 888 basecmd++;
877 /* dirbuf = ".../.../.../" */ 889 /* dirbuf = ".../.../.../" */
878 dirbuf = xstrndup(command, pfind - command); 890 dirbuf = xstrndup(command, basecmd - command);
879# if ENABLE_FEATURE_USERNAME_COMPLETION 891# if ENABLE_FEATURE_USERNAME_COMPLETION
880 if (dirbuf[0] == '~') /* ~/... or ~user/... */ 892 if (dirbuf[0] == '~') /* ~/... or ~user/... */
881 dirbuf = username_path_completion(dirbuf); 893 dirbuf = username_path_completion(dirbuf);
882# endif 894# endif
883 path1[0] = dirbuf; 895 path1[0] = dirbuf;
884 } 896 }
885 pf_len = strlen(pfind); 897 baselen = strlen(basecmd);
886 898
887 if (type == FIND_EXE_ONLY && !dirbuf) { 899 if (type == FIND_EXE_ONLY && !dirbuf) {
888# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 900# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1
889 const char *p = applet_names; 901 const char *p = applet_names;
890 while (*p) { 902 while (*p) {
891 if (strncmp(pfind, p, pf_len) == 0) 903 if (strncmp(basecmd, p, baselen) == 0)
892 add_match(xstrdup(p)); 904 add_match(xstrdup(p));
893 while (*p++ != '\0') 905 while (*p++ != '\0')
894 continue; 906 continue;
@@ -901,7 +913,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
901 const char *b = state->get_exe_name(i++); 913 const char *b = state->get_exe_name(i++);
902 if (!b) 914 if (!b)
903 break; 915 break;
904 if (strncmp(pfind, b, pf_len) == 0) 916 if (strncmp(basecmd, b, baselen) == 0)
905 add_match(xstrdup(b)); 917 add_match(xstrdup(b));
906 } 918 }
907 } 919 }
@@ -913,9 +925,20 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
913 struct dirent *next; 925 struct dirent *next;
914 struct stat st; 926 struct stat st;
915 char *found; 927 char *found;
928#if ENABLE_PLATFORM_MINGW32
929 char *lpath;
930#endif
931
932 if (paths[i] == NULL) { /* path_parse()'s last component? */
933 /* in PATH completion, current dir's subdir names
934 * can be completions (but only subdirs, not files).
935 */
936 type = FIND_DIR_ONLY;
937 paths[i] = (char *)".";
938 }
916 939
917#if ENABLE_PLATFORM_MINGW32 940#if ENABLE_PLATFORM_MINGW32
918 char *lpath = auto_string(alloc_system_drive(paths[i])); 941 lpath = auto_string(alloc_system_drive(paths[i]));
919 dir = opendir(lpath); 942 dir = opendir(lpath);
920#else 943#else
921 dir = opendir(paths[i]); 944 dir = opendir(paths[i]);
@@ -928,10 +951,10 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
928 const char *name_found = next->d_name; 951 const char *name_found = next->d_name;
929 952
930 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */ 953 /* .../<tab>: bash 3.2.0 shows dotfiles, but not . and .. */
931 if (!pfind[0] && DOT_OR_DOTDOT(name_found)) 954 if (!basecmd[0] && DOT_OR_DOTDOT(name_found))
932 continue; 955 continue;
933 /* match? */ 956 /* match? */
934 if (!is_prefixed_with(name_found, pfind)) 957 if (strncmp(basecmd, name_found, baselen) != 0)
935 continue; /* no */ 958 continue; /* no */
936 959
937#if ENABLE_PLATFORM_MINGW32 960#if ENABLE_PLATFORM_MINGW32
@@ -957,6 +980,9 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
957 strcpy(found, name_found); 980 strcpy(found, name_found);
958 981
959 if (S_ISDIR(st.st_mode)) { 982 if (S_ISDIR(st.st_mode)) {
983 /* skip directories if searching PATH */
984 if (type == FIND_EXE_ONLY && !dirbuf)
985 goto cont;
960 /* name is a directory, add slash */ 986 /* name is a directory, add slash */
961 found[len] = '/'; 987 found[len] = '/';
962 found[len + 1] = '\0'; 988 found[len + 1] = '\0';
@@ -980,7 +1006,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type)
980 } 1006 }
981 free(dirbuf); 1007 free(dirbuf);
982 1008
983 return pf_len; 1009 return baselen;
984} 1010}
985 1011
986/* build_match_prefix: 1012/* build_match_prefix:
@@ -1492,15 +1518,19 @@ void FAST_FUNC show_history(const line_input_t *st)
1492 printf("%4d %s\n", i, st->history[i]); 1518 printf("%4d %s\n", i, st->history[i]);
1493} 1519}
1494 1520
1521# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1495void FAST_FUNC free_line_input_t(line_input_t *n) 1522void FAST_FUNC free_line_input_t(line_input_t *n)
1496{ 1523{
1497# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1524 if (n) {
1498 int i = n->cnt_history; 1525 int i = n->cnt_history;
1499 while (i > 0) 1526 while (i > 0)
1500 free(n->history[--i]); 1527 free(n->history[--i]);
1501#endif 1528 free(n);
1502 free(n); 1529 }
1503} 1530}
1531# else
1532/* #defined to free() in libbb.h */
1533# endif
1504 1534
1505# if ENABLE_FEATURE_EDITING_SAVEHISTORY 1535# if ENABLE_FEATURE_EDITING_SAVEHISTORY
1506/* We try to ensure that concurrent additions to the history 1536/* We try to ensure that concurrent additions to the history
@@ -1581,7 +1611,7 @@ void save_history(line_input_t *st)
1581{ 1611{
1582 FILE *fp; 1612 FILE *fp;
1583 1613
1584 if (!st->hist_file) 1614 if (!st || !st->hist_file)
1585 return; 1615 return;
1586 if (st->cnt_history <= st->cnt_history_in_file) 1616 if (st->cnt_history <= st->cnt_history_in_file)
1587 return; 1617 return;
@@ -1971,9 +2001,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
1971{ 2001{
1972 int prmt_size = 0; 2002 int prmt_size = 0;
1973 char *prmt_mem_ptr = xzalloc(1); 2003 char *prmt_mem_ptr = xzalloc(1);
1974# if ENABLE_USERNAME_OR_HOMEDIR
1975 char *cwd_buf = NULL; 2004 char *cwd_buf = NULL;
1976# endif
1977 char flg_not_length = '['; 2005 char flg_not_length = '[';
1978 char cbuf[2]; 2006 char cbuf[2];
1979 2007
@@ -2040,11 +2068,9 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2040 c = *prmt_ptr++; 2068 c = *prmt_ptr++;
2041 2069
2042 switch (c) { 2070 switch (c) {
2043# if ENABLE_USERNAME_OR_HOMEDIR
2044 case 'u': 2071 case 'u':
2045 pbuf = user_buf ? user_buf : (char*)""; 2072 pbuf = user_buf ? user_buf : (char*)"";
2046 break; 2073 break;
2047# endif
2048 case 'H': 2074 case 'H':
2049 case 'h': 2075 case 'h':
2050 pbuf = free_me = safe_gethostname(); 2076 pbuf = free_me = safe_gethostname();
@@ -2062,7 +2088,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2062 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0'; 2088 strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0';
2063 pbuf = timebuf; 2089 pbuf = timebuf;
2064 break; 2090 break;
2065# if ENABLE_USERNAME_OR_HOMEDIR
2066 case 'w': /* current dir */ 2091 case 'w': /* current dir */
2067 case 'W': /* basename of cur dir */ 2092 case 'W': /* basename of cur dir */
2068 if (!cwd_buf) { 2093 if (!cwd_buf) {
@@ -2089,7 +2114,6 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2089 if (cp) 2114 if (cp)
2090 pbuf = (char*)cp + 1; 2115 pbuf = (char*)cp + 1;
2091 break; 2116 break;
2092# endif
2093// bb_process_escape_sequence does this now: 2117// bb_process_escape_sequence does this now:
2094// case 'e': case 'E': /* \e \E = \033 */ 2118// case 'e': case 'E': /* \e \E = \033 */
2095// c = '\033'; 2119// c = '\033';
@@ -2130,10 +2154,17 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2130 if (c == '\n') 2154 if (c == '\n')
2131 cmdedit_prmt_len = 0; 2155 cmdedit_prmt_len = 0;
2132 else if (flg_not_length != ']') { 2156 else if (flg_not_length != ']') {
2133#if 0 /*ENABLE_UNICODE_SUPPORT*/ 2157#if ENABLE_UNICODE_SUPPORT
2134/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */ 2158 if (n == 1) {
2135/* FIXME */ 2159 /* Only count single-byte characters and the first of multi-byte characters */
2136 cmdedit_prmt_len += unicode_strwidth(pbuf); 2160 if ((unsigned char)*pbuf < 0x80 /* single byte character */
2161 || (unsigned char)*pbuf >= 0xc0 /* first of multi-byte characters */
2162 ) {
2163 cmdedit_prmt_len += n;
2164 }
2165 } else {
2166 cmdedit_prmt_len += unicode_strwidth(pbuf);
2167 }
2137#else 2168#else
2138 cmdedit_prmt_len += n; 2169 cmdedit_prmt_len += n;
2139#endif 2170#endif
@@ -2143,10 +2174,8 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2143 free(free_me); 2174 free(free_me);
2144 } /* while */ 2175 } /* while */
2145 2176
2146# if ENABLE_USERNAME_OR_HOMEDIR
2147 if (cwd_buf != (char *)bb_msg_unknown) 2177 if (cwd_buf != (char *)bb_msg_unknown)
2148 free(cwd_buf); 2178 free(cwd_buf);
2149# endif
2150 /* see comment (above this function) about multiline prompt redrawing */ 2179 /* see comment (above this function) about multiline prompt redrawing */
2151 cmdedit_prompt = prompt_last_line = prmt_mem_ptr; 2180 cmdedit_prompt = prompt_last_line = prmt_mem_ptr;
2152 prmt_ptr = strrchr(cmdedit_prompt, '\n'); 2181 prmt_ptr = strrchr(cmdedit_prompt, '\n');
@@ -2154,7 +2183,7 @@ static void parse_and_put_prompt(const char *prmt_ptr)
2154 prompt_last_line = prmt_ptr + 1; 2183 prompt_last_line = prmt_ptr + 1;
2155 put_prompt(); 2184 put_prompt();
2156} 2185}
2157#endif 2186#endif /* FEATURE_EDITING_FANCY_PROMPT */
2158 2187
2159#if ENABLE_FEATURE_EDITING_WINCH 2188#if ENABLE_FEATURE_EDITING_WINCH
2160static void cmdedit_setwidth(void) 2189static void cmdedit_setwidth(void)
@@ -2467,6 +2496,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2467 char read_key_buffer[KEYCODE_BUFFER_SIZE]; 2496 char read_key_buffer[KEYCODE_BUFFER_SIZE];
2468 2497
2469 INIT_S(); 2498 INIT_S();
2499 //command_len = 0; - done by INIT_S()
2500 //cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2501 cmdedit_termw = 80;
2502 IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;)
2503 IF_FEATURE_EDITING_VI(delptr = delbuf;)
2470 2504
2471#if !ENABLE_PLATFORM_MINGW32 2505#if !ENABLE_PLATFORM_MINGW32
2472 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0 2506 n = get_termios_and_make_raw(STDIN_FILENO, &new_settings, &initial_settings, 0
@@ -2521,8 +2555,6 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2521#endif 2555#endif
2522 2556
2523 /* prepare before init handlers */ 2557 /* prepare before init handlers */
2524 cmdedit_y = 0; /* quasireal y, not true if line > xt*yt */
2525 command_len = 0;
2526#if ENABLE_UNICODE_SUPPORT 2558#if ENABLE_UNICODE_SUPPORT
2527 command_ps = xzalloc(maxsize * sizeof(command_ps[0])); 2559 command_ps = xzalloc(maxsize * sizeof(command_ps[0]));
2528#else 2560#else
@@ -3005,6 +3037,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
3005 * before it comes in. UGLY! 3037 * before it comes in. UGLY!
3006 */ 3038 */
3007 usleep(20*1000); 3039 usleep(20*1000);
3040// MAYBE? tcflush(STDIN_FILENO, TCIFLUSH); /* flushes data received but not read */
3008 } 3041 }
3009#endif 3042#endif
3010 3043
diff --git a/libbb/loop.c b/libbb/loop.c
index 85b2724e5..cb8fa2442 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -98,9 +98,7 @@ int FAST_FUNC get_free_loop(void)
98 98
99/* Returns opened fd to the loop device, <0 on error. 99/* Returns opened fd to the loop device, <0 on error.
100 * *device is loop device to use, or if *device==NULL finds a loop device to 100 * *device is loop device to use, or if *device==NULL finds a loop device to
101 * mount it on and sets *device to a strdup of that loop device name. This 101 * mount it on and sets *device to a strdup of that loop device name.
102 * search will re-use an existing loop device already bound to that
103 * file/offset if it finds one.
104 */ 102 */
105int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, 103int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset,
106 unsigned long long sizelimit, unsigned flags) 104 unsigned long long sizelimit, unsigned flags)
@@ -109,9 +107,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
109 char *try; 107 char *try;
110 bb_loop_info loopinfo; 108 bb_loop_info loopinfo;
111 struct stat statbuf; 109 struct stat statbuf;
112 int i, dfd, ffd, mode, rc; 110 int i, lfd, ffd, mode, rc;
113
114 rc = dfd = -1;
115 111
116 /* Open the file. Barf if this doesn't work. */ 112 /* Open the file. Barf if this doesn't work. */
117 mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR; 113 mode = (flags & BB_LO_FLAGS_READ_ONLY) ? O_RDONLY : O_RDWR;
@@ -127,24 +123,23 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
127 123
128 try = *device; 124 try = *device;
129 if (!try) { 125 if (!try) {
126 get_free_loopN:
130 i = get_free_loop(); 127 i = get_free_loop();
131 if (i == -2) { /* no /dev/loop-control */
132 i = 0;
133 try = dev;
134 goto old_style;
135 }
136 if (i == -1) { 128 if (i == -1) {
137 close(ffd); 129 close(ffd);
138 return -1; /* no free loop devices */ 130 return -1; /* no free loop devices */
139 } 131 }
140 try = *device = xasprintf(LOOP_FORMAT, i); 132 if (i >= 0) {
141 goto try_to_open; 133 try = xasprintf(LOOP_FORMAT, i);
134 goto open_lfd;
135 }
136 /* i == -2: no /dev/loop-control. Do an old-style search for a free device */
137 try = dev;
142 } 138 }
143 139
144 old_style: 140 /* Find a loop device */
145 /* Find a loop device. */ 141 /* 0xfffff is a max possible minor number in Linux circa 2010 */
146 /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */ 142 for (i = 0; i <= 0xfffff; i++) {
147 for (i = 0; rc && i < 1048576; i++) {
148 sprintf(dev, LOOP_FORMAT, i); 143 sprintf(dev, LOOP_FORMAT, i);
149 144
150 IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;) 145 IF_FEATURE_MOUNT_LOOP_CREATE(errno = 0;)
@@ -153,72 +148,86 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
153 && errno == ENOENT 148 && errno == ENOENT
154 && try == dev 149 && try == dev
155 ) { 150 ) {
156 /* Node doesn't exist, try to create it. */ 151 /* Node doesn't exist, try to create it */
157 if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0) 152 if (mknod(dev, S_IFBLK|0644, makedev(7, i)) == 0)
158 goto try_to_open; 153 goto open_lfd;
159 } 154 }
160 /* Ran out of block devices, return failure. */ 155 /* Ran out of block devices, return failure */
161 rc = -1; 156 rc = -1;
162 break; 157 break;
163 } 158 }
164 try_to_open: 159 open_lfd:
165 /* Open the sucker and check its loopiness. */ 160 /* Open the sucker and check its loopiness */
166 dfd = open(try, mode); 161 lfd = rc = open(try, mode);
167 if (dfd < 0 && errno == EROFS) { 162 if (lfd < 0 && errno == EROFS) {
168 mode = O_RDONLY; 163 mode = O_RDONLY;
169 dfd = open(try, mode); 164 lfd = rc = open(try, mode);
170 } 165 }
171 if (dfd < 0) { 166 if (lfd < 0) {
172 if (errno == ENXIO) { 167 if (errno == ENXIO) {
173 /* Happens if loop module is not loaded */ 168 /* Happens if loop module is not loaded */
174 rc = -1; 169 /* rc is -1; */
175 break; 170 break;
176 } 171 }
177 goto try_again; 172 goto try_next_loopN;
178 } 173 }
179 174
180 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo); 175 rc = ioctl(lfd, BB_LOOP_GET_STATUS, &loopinfo);
181 176
182 /* If device is free, claim it. */ 177 /* If device is free, try to claim it */
183 if (rc && errno == ENXIO) { 178 if (rc && errno == ENXIO) {
184 /* Associate free loop device with file. */ 179 /* Associate free loop device with file */
185 if (ioctl(dfd, LOOP_SET_FD, ffd) == 0) { 180 if (ioctl(lfd, LOOP_SET_FD, ffd)) {
186 memset(&loopinfo, 0, sizeof(loopinfo)); 181 /* Ouch. Are we racing with other mount? */
187 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE); 182 if (!*device /* yes */
188 loopinfo.lo_offset = offset; 183 && try != dev /* tried a _kernel-offered_ loopN? */
189 loopinfo.lo_sizelimit = sizelimit; 184 ) {
190 /* 185 free(try);
191 * Used by mount to set LO_FLAGS_AUTOCLEAR. 186 close(lfd);
192 * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file. 187//TODO: add "if (--failcount != 0) ..."?
193 * Note that closing LO_FLAGS_AUTOCLEARed dfd before mount 188 goto get_free_loopN;
194 * is wrong (would free the loop device!)
195 */
196 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY);
197 rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo);
198 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) {
199 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */
200 /* (this code path is not tested) */
201 loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR;
202 rc = ioctl(dfd, BB_LOOP_SET_STATUS, &loopinfo);
203 }
204 if (rc != 0) {
205 ioctl(dfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
206 } 189 }
190 goto close_and_try_next_loopN;
207 } 191 }
208 } else { 192 memset(&loopinfo, 0, sizeof(loopinfo));
209 rc = -1; 193 safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
210 } 194 loopinfo.lo_offset = offset;
211 if (rc != 0) { 195 loopinfo.lo_sizelimit = sizelimit;
212 close(dfd); 196 /*
197 * Used by mount to set LO_FLAGS_AUTOCLEAR.
198 * LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file.
199 * Note that closing LO_FLAGS_AUTOCLEARed lfd before mount
200 * is wrong (would free the loop device!)
201 */
202 loopinfo.lo_flags = (flags & ~BB_LO_FLAGS_READ_ONLY);
203 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo);
204 if (rc != 0 && (loopinfo.lo_flags & BB_LO_FLAGS_AUTOCLEAR)) {
205 /* Old kernel, does not support LO_FLAGS_AUTOCLEAR? */
206 /* (this code path is not tested) */
207 loopinfo.lo_flags -= BB_LO_FLAGS_AUTOCLEAR;
208 rc = ioctl(lfd, BB_LOOP_SET_STATUS, &loopinfo);
209 }
210 if (rc == 0) {
211 /* SUCCESS! */
212 if (try != dev) /* tried a kernel-offered free loopN? */
213 *device = try; /* malloced */
214 if (!*device) /* was looping in search of free "/dev/loopN"? */
215 *device = xstrdup(dev);
216 rc = lfd; /* return this */
217 break;
218 }
219 /* failure, undo LOOP_SET_FD */
220 ioctl(lfd, LOOP_CLR_FD, 0); // actually, 0 param is unnecessary
213 } 221 }
214 try_again: 222 /* else: device is not free (rc == 0) or error other than ENXIO */
215 if (*device) break; 223 close_and_try_next_loopN:
216 } 224 close(lfd);
225 try_next_loopN:
226 rc = -1;
227 if (*device) /* was looking for a particular "/dev/loopN"? */
228 break; /* yes, do not try other names */
229 } /* for() */
230
217 close(ffd); 231 close(ffd);
218 if (rc == 0) {
219 if (!*device)
220 *device = xstrdup(dev);
221 return dfd;
222 }
223 return rc; 232 return rc;
224} 233}
diff --git a/libbb/mode_string.c b/libbb/mode_string.c
index 6c5c08acd..dc3f9f88c 100644
--- a/libbb/mode_string.c
+++ b/libbb/mode_string.c
@@ -27,7 +27,7 @@
27#define mode_t unsigned short 27#define mode_t unsigned short
28#endif 28#endif
29 29
30static const mode_t mode_flags[] = { 30static const mode_t mode_flags[] ALIGN4 = {
31 S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID, 31 S_IRUSR, S_IWUSR, S_IXUSR, S_ISUID,
32 S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID, 32 S_IRGRP, S_IWGRP, S_IXGRP, S_ISGID,
33 S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX 33 S_IROTH, S_IWOTH, S_IXOTH, S_ISVTX
diff --git a/libbb/platform.c b/libbb/platform.c
index 03bbb798b..329b0237e 100644
--- a/libbb/platform.c
+++ b/libbb/platform.c
@@ -27,7 +27,6 @@ int FAST_FUNC usleep(unsigned usec)
27 * If a signal has non-default handler, nanosleep returns early. 27 * If a signal has non-default handler, nanosleep returns early.
28 * Our version of usleep doesn't return early 28 * Our version of usleep doesn't return early
29 * if interrupted by such signals: 29 * if interrupted by such signals:
30 *
31 */ 30 */
32 while (nanosleep(&ts, &ts) != 0) 31 while (nanosleep(&ts, &ts) != 0)
33 continue; 32 continue;
@@ -107,7 +106,8 @@ void* FAST_FUNC memrchr(const void *s, int c, size_t n)
107/* This is now actually part of POSIX.1, but was only added in 2008 */ 106/* This is now actually part of POSIX.1, but was only added in 2008 */
108char* FAST_FUNC mkdtemp(char *template) 107char* FAST_FUNC mkdtemp(char *template)
109{ 108{
110 if (mktemp(template) == NULL || mkdir(template, 0700) != 0) 109 /* NB: on error, mktemp returns an empty string, not NULL */
110 if (mktemp(template)[0] == '\0' || mkdir(template, 0700) != 0)
111 return NULL; 111 return NULL;
112 return template; 112 return template;
113} 113}
diff --git a/libbb/procps.c b/libbb/procps.c
index 4f9705bc1..8c9cac125 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -21,40 +21,29 @@ typedef struct cache_t {
21 int size; 21 int size;
22} cache_t; 22} cache_t;
23 23
24static cache_t username, groupname; 24static cache_t *cache_user_group;
25 25
26static void clear_cache(cache_t *cp)
27{
28 free(cp->cache);
29 cp->cache = NULL;
30 cp->size = 0;
31}
32void FAST_FUNC clear_username_cache(void) 26void FAST_FUNC clear_username_cache(void)
33{ 27{
34 clear_cache(&username); 28 if (cache_user_group) {
35 clear_cache(&groupname); 29 free(cache_user_group[0].cache);
36} 30 free(cache_user_group[1].cache);
37 31 free(cache_user_group);
38#if 0 /* more generic, but we don't need that yet */ 32 cache_user_group = NULL;
39/* Returns -N-1 if not found. */ 33 }
40/* cp->cache[N] is allocated and must be filled in this case */
41static int get_cached(cache_t *cp, uid_t id)
42{
43 int i;
44 for (i = 0; i < cp->size; i++)
45 if (cp->cache[i].id == id)
46 return i;
47 i = cp->size++;
48 cp->cache = xrealloc_vector(cp->cache, 2, i);
49 cp->cache[i++].id = id;
50 return -i;
51} 34}
52#endif
53 35
54static char* get_cached(cache_t *cp, uid_t id, 36static char* get_cached(int user_group, uid_t id,
55 char* FAST_FUNC x2x_utoa(uid_t id)) 37 char* FAST_FUNC x2x_utoa(uid_t id))
56{ 38{
39 cache_t *cp;
57 int i; 40 int i;
41
42 if (!cache_user_group)
43 cache_user_group = xzalloc(sizeof(cache_user_group[0]) * 2);
44
45 cp = &cache_user_group[user_group];
46
58 for (i = 0; i < cp->size; i++) 47 for (i = 0; i < cp->size; i++)
59 if (cp->cache[i].id == id) 48 if (cp->cache[i].id == id)
60 return cp->cache[i].name; 49 return cp->cache[i].name;
@@ -67,11 +56,11 @@ static char* get_cached(cache_t *cp, uid_t id,
67} 56}
68const char* FAST_FUNC get_cached_username(uid_t uid) 57const char* FAST_FUNC get_cached_username(uid_t uid)
69{ 58{
70 return get_cached(&username, uid, uid2uname_utoa); 59 return get_cached(0, uid, uid2uname_utoa);
71} 60}
72const char* FAST_FUNC get_cached_groupname(gid_t gid) 61const char* FAST_FUNC get_cached_groupname(gid_t gid)
73{ 62{
74 return get_cached(&groupname, gid, gid2group_utoa); 63 return get_cached(1, gid, gid2group_utoa);
75} 64}
76 65
77#if !ENABLE_PLATFORM_MINGW32 66#if !ENABLE_PLATFORM_MINGW32
@@ -95,15 +84,15 @@ static int read_to_buf(const char *filename, void *buf)
95 84
96static procps_status_t* FAST_FUNC alloc_procps_scan(void) 85static procps_status_t* FAST_FUNC alloc_procps_scan(void)
97{ 86{
98 unsigned n = getpagesize();
99 procps_status_t* sp = xzalloc(sizeof(procps_status_t)); 87 procps_status_t* sp = xzalloc(sizeof(procps_status_t));
100 sp->dir = xopendir("/proc"); 88 unsigned n = bb_getpagesize();
101 while (1) { 89 while (1) {
102 n >>= 1; 90 n >>= 1;
103 if (!n) break; 91 if (!n) break;
104 sp->shift_pages_to_bytes++; 92 sp->shift_pages_to_bytes++;
105 } 93 }
106 sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10; 94 sp->shift_pages_to_kb = sp->shift_pages_to_bytes - 10;
95 sp->dir = xopendir("/proc");
107 return sp; 96 return sp;
108} 97}
109 98
@@ -178,6 +167,7 @@ static char *skip_fields(char *str, int count)
178} 167}
179#endif 168#endif
180 169
170#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
181static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix) 171static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix)
182{ 172{
183 char *tp = is_prefixed_with(buf, prefix); 173 char *tp = is_prefixed_with(buf, prefix);
@@ -187,7 +177,6 @@ static char* skip_whitespace_if_prefixed_with(char *buf, const char *prefix)
187 return tp; 177 return tp;
188} 178}
189 179
190#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP
191int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, 180int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
192 void (*cb)(struct smaprec *, void *), void *data) 181 void (*cb)(struct smaprec *, void *), void *data)
193{ 182{
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 47c20690f..3463fd95b 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -7,7 +7,9 @@
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree. 7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */ 8 */
9#if !ENABLE_USE_BB_CRYPT 9#if !ENABLE_USE_BB_CRYPT
10#include <crypt.h> 10# if !defined(__FreeBSD__)
11# include <crypt.h>
12# endif
11#endif 13#endif
12#include "libbb.h" 14#include "libbb.h"
13 15
@@ -120,6 +122,7 @@ static char *my_crypt(const char *key, const char *salt)
120 if (!des_cctx) 122 if (!des_cctx)
121 des_cctx = const_des_init(); 123 des_cctx = const_des_init();
122 des_ctx = des_init(des_ctx, des_cctx); 124 des_ctx = des_init(des_ctx, des_cctx);
125 /* Can return NULL if salt is bad ("" or "<one_char>") */
123 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt); 126 return des_crypt(des_ctx, xzalloc(DES_OUT_BUFSIZE), (unsigned char*)key, (unsigned char*)salt);
124} 127}
125 128
@@ -137,6 +140,8 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
137 char *encrypted; 140 char *encrypted;
138 141
139 encrypted = my_crypt(clear, salt); 142 encrypted = my_crypt(clear, salt);
143 if (!encrypted)
144 bb_simple_error_msg_and_die("bad salt");
140 145
141 if (cleanup) 146 if (cleanup)
142 my_crypt_cleanup(); 147 my_crypt_cleanup();
@@ -148,14 +153,16 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
148 153
149char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) 154char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
150{ 155{
151 char *s; 156 char *encrypted;
152 157
153 s = crypt(clear, salt); 158 encrypted = crypt(clear, salt);
154 /* 159 /*
155 * glibc used to return "" on malformed salts (for example, ""), 160 * glibc used to return "" on malformed salts (for example, ""),
156 * but since 2.17 it returns NULL. 161 * but since 2.17 it returns NULL.
157 */ 162 */
158 return xstrdup(s ? s : ""); 163 if (!encrypted || !encrypted[0])
164 bb_simple_error_msg_and_die("bad salt");
165 return xstrdup(encrypted);
159} 166}
160 167
161#endif 168#endif
diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c
index 19a9ab15b..dcd3521e2 100644
--- a/libbb/pw_encrypt_des.c
+++ b/libbb/pw_encrypt_des.c
@@ -65,25 +65,25 @@
65 65
66 66
67/* A pile of data */ 67/* A pile of data */
68static const uint8_t IP[64] = { 68static const uint8_t IP[64] ALIGN1 = {
69 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4, 69 58, 50, 42, 34, 26, 18, 10, 2, 60, 52, 44, 36, 28, 20, 12, 4,
70 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8, 70 62, 54, 46, 38, 30, 22, 14, 6, 64, 56, 48, 40, 32, 24, 16, 8,
71 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3, 71 57, 49, 41, 33, 25, 17, 9, 1, 59, 51, 43, 35, 27, 19, 11, 3,
72 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7 72 61, 53, 45, 37, 29, 21, 13, 5, 63, 55, 47, 39, 31, 23, 15, 7
73}; 73};
74 74
75static const uint8_t key_perm[56] = { 75static const uint8_t key_perm[56] ALIGN1 = {
76 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18, 76 57, 49, 41, 33, 25, 17, 9, 1, 58, 50, 42, 34, 26, 18,
77 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36, 77 10, 2, 59, 51, 43, 35, 27, 19, 11, 3, 60, 52, 44, 36,
78 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22, 78 63, 55, 47, 39, 31, 23, 15, 7, 62, 54, 46, 38, 30, 22,
79 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4 79 14, 6, 61, 53, 45, 37, 29, 21, 13, 5, 28, 20, 12, 4
80}; 80};
81 81
82static const uint8_t key_shifts[16] = { 82static const uint8_t key_shifts[16] ALIGN1 = {
83 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1 83 1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
84}; 84};
85 85
86static const uint8_t comp_perm[48] = { 86static const uint8_t comp_perm[48] ALIGN1 = {
87 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10, 87 14, 17, 11, 24, 1, 5, 3, 28, 15, 6, 21, 10,
88 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2, 88 23, 19, 12, 4, 26, 8, 16, 7, 27, 20, 13, 2,
89 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48, 89 41, 52, 31, 37, 47, 55, 30, 40, 51, 45, 33, 48,
@@ -181,13 +181,12 @@ static const uint8_t u_sbox[8][32] = {
181}; 181};
182#endif 182#endif
183 183
184static const uint8_t pbox[32] = { 184static const uint8_t pbox[32] ALIGN1 = {
185 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10, 185 16, 7, 20, 21, 29, 12, 28, 17, 1, 15, 23, 26, 5, 18, 31, 10,
186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25 186 2, 8, 24, 14, 32, 27, 3, 9, 19, 13, 30, 6, 22, 11, 4, 25
187}; 187};
188 188
189static const uint32_t bits32[32] = 189static const uint32_t bits32[32] ALIGN4 = {
190{
191 0x80000000, 0x40000000, 0x20000000, 0x10000000, 190 0x80000000, 0x40000000, 0x20000000, 0x10000000,
192 0x08000000, 0x04000000, 0x02000000, 0x01000000, 191 0x08000000, 0x04000000, 0x02000000, 0x01000000,
193 0x00800000, 0x00400000, 0x00200000, 0x00100000, 192 0x00800000, 0x00400000, 0x00200000, 0x00100000,
@@ -198,7 +197,7 @@ static const uint32_t bits32[32] =
198 0x00000008, 0x00000004, 0x00000002, 0x00000001 197 0x00000008, 0x00000004, 0x00000002, 0x00000001
199}; 198};
200 199
201static const uint8_t bits8[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; 200static const uint8_t bits8[8] ALIGN1 = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
202 201
203 202
204static int 203static int
@@ -714,11 +713,15 @@ to64_msb_first(char *s, unsigned v)
714static char * 713static char *
715NOINLINE 714NOINLINE
716des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE], 715des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
717 const unsigned char *key, const unsigned char *setting) 716 const unsigned char *key, const unsigned char *salt_str)
718{ 717{
719 uint32_t salt, r0, r1, keybuf[2]; 718 uint32_t salt, r0, r1, keybuf[2];
720 uint8_t *q; 719 uint8_t *q;
721 720
721 /* Bad salt? Mimic crypt() API - return NULL */
722 if (!salt_str[0] || !salt_str[1])
723 return NULL;
724
722 /* 725 /*
723 * Copy the key, shifting each character up by one bit 726 * Copy the key, shifting each character up by one bit
724 * and padding with zeros. 727 * and padding with zeros.
@@ -733,22 +736,15 @@ des_crypt(struct des_ctx *ctx, char output[DES_OUT_BUFSIZE],
733 des_setkey(ctx, (char *)keybuf); 736 des_setkey(ctx, (char *)keybuf);
734 737
735 /* 738 /*
736 * setting - 2 bytes of salt 739 * salt_str - 2 bytes of salt
737 * key - up to 8 characters 740 * key - up to 8 characters
738 */ 741 */
739 salt = (ascii_to_bin(setting[1]) << 6) 742 output[0] = salt_str[0];
740 | ascii_to_bin(setting[0]); 743 output[1] = salt_str[1];
741 744 salt = (ascii_to_bin(salt_str[1]) << 6)
742 output[0] = setting[0]; 745 | ascii_to_bin(salt_str[0]);
743 /*
744 * If the encrypted password that the salt was extracted from
745 * is only 1 character long, the salt will be corrupted. We
746 * need to ensure that the output string doesn't have an extra
747 * NUL in it!
748 */
749 output[1] = setting[1] ? setting[1] : output[0];
750
751 setup_salt(ctx, salt); 746 setup_salt(ctx, salt);
747
752 /* Do it. */ 748 /* Do it. */
753 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */); 749 do_des(ctx, /*0, 0,*/ &r0, &r1, 25 /* count */);
754 750
diff --git a/libbb/rtc.c b/libbb/rtc.c
index c4117ba34..54b52f23a 100644
--- a/libbb/rtc.c
+++ b/libbb/rtc.c
@@ -7,12 +7,6 @@
7#include "libbb.h" 7#include "libbb.h"
8#include "rtc_.h" 8#include "rtc_.h"
9 9
10#if ENABLE_FEATURE_HWCLOCK_ADJTIME_FHS
11# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
12#else
13# define ADJTIME_PATH "/etc/adjtime"
14#endif
15
16int FAST_FUNC rtc_adjtime_is_utc(void) 10int FAST_FUNC rtc_adjtime_is_utc(void)
17{ 11{
18 int utc = 0; 12 int utc = 0;
diff --git a/libbb/run_shell.c b/libbb/run_shell.c
index a0420d982..c22bba87b 100644
--- a/libbb/run_shell.c
+++ b/libbb/run_shell.c
@@ -48,10 +48,10 @@ void FAST_FUNC set_current_security_context(security_context_t sid)
48 48
49#endif 49#endif
50 50
51/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL. 51/* Exec SHELL, or DEFAULT_SHELL if SHELL is "" or NULL.
52 * If ADDITIONAL_ARGS is not NULL, pass them to the shell. 52 * If ADDITIONAL_ARGS is not NULL, pass them to the shell.
53 */ 53 */
54void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additional_args) 54void FAST_FUNC exec_shell(const char *shell, int loginshell, const char **additional_args)
55{ 55{
56 const char **args; 56 const char **args;
57 57
@@ -59,7 +59,7 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
59 while (args && *args) 59 while (args && *args)
60 args++; 60 args++;
61 61
62 args = xmalloc(sizeof(char*) * (2 + (args - additional_args))); 62 args = xzalloc(sizeof(args[0]) * (2 + (args - additional_args)));
63 63
64 if (!shell || !shell[0]) 64 if (!shell || !shell[0])
65 shell = DEFAULT_SHELL; 65 shell = DEFAULT_SHELL;
@@ -67,12 +67,11 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
67 args[0] = bb_get_last_path_component_nostrip(shell); 67 args[0] = bb_get_last_path_component_nostrip(shell);
68 if (loginshell) 68 if (loginshell)
69 args[0] = xasprintf("-%s", args[0]); 69 args[0] = xasprintf("-%s", args[0]);
70 args[1] = NULL; 70 /*args[1] = NULL; - already is */
71 if (additional_args) { 71 if (additional_args) {
72 int cnt = 1; 72 int cnt = 0;
73 for (;;) 73 while (*additional_args)
74 if ((args[cnt++] = *additional_args++) == NULL) 74 args[++cnt] = *additional_args++;
75 break;
76 } 75 }
77 76
78#if ENABLE_SELINUX 77#if ENABLE_SELINUX
@@ -84,3 +83,20 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char **additio
84 execv(shell, (char **) args); 83 execv(shell, (char **) args);
85 bb_perror_msg_and_die("can't execute '%s'", shell); 84 bb_perror_msg_and_die("can't execute '%s'", shell);
86} 85}
86
87void FAST_FUNC exec_login_shell(const char *shell)
88{
89 exec_shell(shell, 1, NULL);
90}
91
92/* Typical idiom for applets which exec *optional* PROG [ARGS] */
93void FAST_FUNC exec_prog_or_SHELL(char **argv)
94{
95 if (argv[0]) {
96 BB_EXECVP_or_die(argv);
97 }
98 /* Both users (nsenter and unshare) do indeed exec
99 * a _login_ shell (with dash in argv[0])!
100 */
101 exec_login_shell(getenv("SHELL"));
102}
diff --git a/libbb/speed_table.c b/libbb/speed_table.c
index 967cf8de8..cf7101e64 100644
--- a/libbb/speed_table.c
+++ b/libbb/speed_table.c
@@ -28,7 +28,7 @@ struct speed_map {
28}; 28};
29 29
30/* On Linux, Bxx constants are 0..15 (up to B38400) and 0x1001..0x100f */ 30/* On Linux, Bxx constants are 0..15 (up to B38400) and 0x1001..0x100f */
31static const struct speed_map speeds[] = { 31static const struct speed_map speeds[] ALIGN4 = {
32 {B0, 0}, 32 {B0, 0},
33 {B50, 50}, 33 {B50, 50},
34 {B75, 75}, 34 {B75, 75},
diff --git a/libbb/time.c b/libbb/time.c
index e66a9cba8..cf5f2e5c8 100644
--- a/libbb/time.c
+++ b/libbb/time.c
@@ -90,7 +90,11 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm)
90 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ 90 ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */
91 } else 91 } else
92 if (date_str[0] == '@') { 92 if (date_str[0] == '@') {
93 time_t t = bb_strtol(date_str + 1, NULL, 10); 93 time_t t;
94 if (sizeof(t) <= sizeof(long))
95 t = bb_strtol(date_str + 1, NULL, 10);
96 else /* time_t is 64 bits but longs are smaller */
97 t = bb_strtoll(date_str + 1, NULL, 10);
94 if (!errno) { 98 if (!errno) {
95 struct tm *lt = localtime(&t); 99 struct tm *lt = localtime(&t);
96 if (lt) { 100 if (lt) {
@@ -246,7 +250,6 @@ char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp)
246 250
247#if ENABLE_MONOTONIC_SYSCALL 251#if ENABLE_MONOTONIC_SYSCALL
248 252
249#include <sys/syscall.h>
250/* Old glibc (< 2.3.4) does not provide this constant. We use syscall 253/* Old glibc (< 2.3.4) does not provide this constant. We use syscall
251 * directly so this definition is safe. */ 254 * directly so this definition is safe. */
252#ifndef CLOCK_MONOTONIC 255#ifndef CLOCK_MONOTONIC
@@ -288,19 +291,19 @@ unsigned FAST_FUNC monotonic_sec(void)
288unsigned long long FAST_FUNC monotonic_ns(void) 291unsigned long long FAST_FUNC monotonic_ns(void)
289{ 292{
290 struct timeval tv; 293 struct timeval tv;
291 gettimeofday(&tv, NULL); 294 xgettimeofday(&tv);
292 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; 295 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
293} 296}
294unsigned long long FAST_FUNC monotonic_us(void) 297unsigned long long FAST_FUNC monotonic_us(void)
295{ 298{
296 struct timeval tv; 299 struct timeval tv;
297 gettimeofday(&tv, NULL); 300 xgettimeofday(&tv);
298 return tv.tv_sec * 1000000ULL + tv.tv_usec; 301 return tv.tv_sec * 1000000ULL + tv.tv_usec;
299} 302}
300unsigned long long FAST_FUNC monotonic_ms(void) 303unsigned long long FAST_FUNC monotonic_ms(void)
301{ 304{
302 struct timeval tv; 305 struct timeval tv;
303 gettimeofday(&tv, NULL); 306 xgettimeofday(&tv);
304 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000; 307 return tv.tv_sec * 1000ULL + tv.tv_usec / 1000;
305} 308}
306unsigned FAST_FUNC monotonic_sec(void) 309unsigned FAST_FUNC monotonic_sec(void)
diff --git a/libbb/unicode.c b/libbb/unicode.c
index 79481f159..e98cbbf35 100644
--- a/libbb/unicode.c
+++ b/libbb/unicode.c
@@ -25,7 +25,7 @@ uint8_t unicode_status;
25 25
26void FAST_FUNC reinit_unicode(const char *LANG) 26void FAST_FUNC reinit_unicode(const char *LANG)
27{ 27{
28 static const char unicode_0x394[] = { 0xce, 0x94, 0 }; 28 static const char unicode_0x394[] ALIGN1 = { 0xce, 0x94, 0 };
29 size_t width; 29 size_t width;
30 30
31 /* We pass "" instead of "C" because some libc's have 31 /* We pass "" instead of "C" because some libc's have
@@ -306,8 +306,10 @@ static int in_uint16_table(unsigned ucs, const uint16_t *table, unsigned max)
306 unsigned first, last; 306 unsigned first, last;
307 307
308 first = table[0] >> 2; 308 first = table[0] >> 2;
309 last = first + (table[0] & 3); 309 if (ucs < first)
310 if (ucs < first || ucs > last) 310 return 0;
311 last = (table[max] >> 2) + (table[max] & 3);
312 if (ucs > last)
311 return 0; 313 return 0;
312 314
313 min = 0; 315 min = 0;
@@ -587,12 +589,12 @@ int FAST_FUNC wcwidth(unsigned ucs)
587 BIG_(0xFE20, 0xFE23) \ 589 BIG_(0xFE20, 0xFE23) \
588 BIG_(0xFEFF, 0xFEFF) \ 590 BIG_(0xFEFF, 0xFEFF) \
589 BIG_(0xFFF9, 0xFFFB) 591 BIG_(0xFFF9, 0xFFFB)
590 static const struct interval combining[] = { ARRAY }; 592 static const struct interval combining[] ALIGN4 = { ARRAY };
591# undef BIG_ 593# undef BIG_
592# undef PAIR 594# undef PAIR
593# define BIG_(a,b) 595# define BIG_(a,b)
594# define PAIR(a,b) (a << 2) | (b-a), 596# define PAIR(a,b) (a << 2) | (b-a),
595 static const uint16_t combining1[] = { ARRAY }; 597 static const uint16_t combining1[] ALIGN2 = { ARRAY };
596# undef BIG_ 598# undef BIG_
597# undef PAIR 599# undef PAIR
598# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 600# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
@@ -646,7 +648,7 @@ int FAST_FUNC wcwidth(unsigned ucs)
646# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000 648# if CONFIG_LAST_SUPPORTED_WCHAR >= 0x10000
647 if (ucs >= 0x10000) { 649 if (ucs >= 0x10000) {
648 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */ 650 /* Combining chars in Supplementary Multilingual Plane 0x1xxxx */
649 static const struct interval combining0x10000[] = { 651 static const struct interval combining0x10000[] ALIGN4 = {
650 { 0x0A01, 0x0A03 }, { 0x0A05, 0x0A06 }, { 0x0A0C, 0x0A0F }, 652 { 0x0A01, 0x0A03 }, { 0x0A05, 0x0A06 }, { 0x0A0C, 0x0A0F },
651 { 0x0A38, 0x0A3A }, { 0x0A3F, 0x0A3F }, { 0xD167, 0xD169 }, 653 { 0x0A38, 0x0A3A }, { 0x0A3F, 0x0A3F }, { 0xD167, 0xD169 },
652 { 0xD173, 0xD182 }, { 0xD185, 0xD18B }, { 0xD1AA, 0xD1AD }, 654 { 0xD173, 0xD182 }, { 0xD185, 0xD18B }, { 0xD1AA, 0xD1AD },
@@ -757,12 +759,12 @@ int FAST_FUNC unicode_bidi_isrtl(wint_t wc)
757 {0x10E7F, 0x10FFF}, 759 {0x10E7F, 0x10FFF},
758 {0x1E800, 0x1EFFF} 760 {0x1E800, 0x1EFFF}
759 */ 761 */
760 static const struct interval rtl_b[] = { ARRAY }; 762 static const struct interval rtl_b[] ALIGN4 = { ARRAY };
761# undef BIG_ 763# undef BIG_
762# undef PAIR 764# undef PAIR
763# define BIG_(a,b) 765# define BIG_(a,b)
764# define PAIR(a,b) (a << 2) | (b-a), 766# define PAIR(a,b) (a << 2) | (b-a),
765 static const uint16_t rtl_p[] = { ARRAY }; 767 static const uint16_t rtl_p[] ALIGN2 = { ARRAY };
766# undef BIG_ 768# undef BIG_
767# undef PAIR 769# undef PAIR
768# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 770# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
@@ -961,12 +963,12 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc)
961 {0x1F030, 0x1F093}, 963 {0x1F030, 0x1F093},
962 {0x1F100, 0x1F10A} 964 {0x1F100, 0x1F10A}
963 */ 965 */
964 static const struct interval neutral_b[] = { ARRAY }; 966 static const struct interval neutral_b[] ALIGN4 = { ARRAY };
965# undef BIG_ 967# undef BIG_
966# undef PAIR 968# undef PAIR
967# define BIG_(a,b) 969# define BIG_(a,b)
968# define PAIR(a,b) (a << 2) | (b-a), 970# define PAIR(a,b) (a << 2) | (b-a),
969 static const uint16_t neutral_p[] = { ARRAY }; 971 static const uint16_t neutral_p[] ALIGN2 = { ARRAY };
970# undef BIG_ 972# undef BIG_
971# undef PAIR 973# undef PAIR
972# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1]; 974# define BIG_(a,b) char big_##a[b < 0x4000 && b-a <= 3 ? -1 : 1];
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index d36b34f63..21af7a8c9 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -8,8 +8,18 @@
8 */ 8 */
9#include "libbb.h" 9#include "libbb.h"
10 10
11/* Conversion table. for base 64 */ 11/* Conversion tables */
12const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = { 12#if ENABLE_BASE32
13const char bb_uuenc_tbl_base32[] ALIGN1 = {
14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
17 'Y', 'Z', '2', '3', '4', '5', '6', '7',
18 /* unused: '=', */
19};
20#endif
21/* for base 64 */
22const char bb_uuenc_tbl_base64[] ALIGN1 = {
13 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 23 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
14 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 24 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
15 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 25 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -18,11 +28,9 @@ const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
18 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 28 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
19 'w', 'x', 'y', 'z', '0', '1', '2', '3', 29 'w', 'x', 'y', 'z', '0', '1', '2', '3',
20 '4', '5', '6', '7', '8', '9', '+', '/', 30 '4', '5', '6', '7', '8', '9', '+', '/',
21 '=' /* termination character */, 31 '=' /* termination character */
22 '\0' /* needed for uudecode.c only */
23}; 32};
24 33const char bb_uuenc_tbl_std[] ALIGN1 = {
25const char bb_uuenc_tbl_std[65] ALIGN1 = {
26 '`', '!', '"', '#', '$', '%', '&', '\'', 34 '`', '!', '"', '#', '$', '%', '&', '\'',
27 '(', ')', '*', '+', ',', '-', '.', '/', 35 '(', ')', '*', '+', ',', '-', '.', '/',
28 '0', '1', '2', '3', '4', '5', '6', '7', 36 '0', '1', '2', '3', '4', '5', '6', '7',
@@ -30,7 +38,7 @@ const char bb_uuenc_tbl_std[65] ALIGN1 = {
30 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 38 '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
31 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 39 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
32 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 40 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
33 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', 41 'X', 'Y', 'Z', '[', '\\',']', '^', '_',
34 '`' /* termination character */ 42 '`' /* termination character */
35}; 43};
36 44
@@ -72,86 +80,124 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl
72} 80}
73 81
74/* 82/*
75 * Decode base64 encoded string. Stops on '\0'. 83 * Decode base64 encoded string.
76 * 84 *
77 * Returns: pointer to the undecoded part of source. 85 * Returns: pointer past the last written output byte,
86 * the result is not NUL-terminated.
87 * (*pp_src) is advanced past the last read byte.
78 * If points to '\0', then the source was fully decoded. 88 * If points to '\0', then the source was fully decoded.
79 * (*pp_dst): advanced past the last written byte.
80 */ 89 */
81const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) 90char* FAST_FUNC decode_base64(char *dst, const char **pp_src)
82{ 91{
83 char *dst = *pp_dst; 92 const char *src = pp_src ? *pp_src : dst; /* for httpd.c, support NULL 2nd param */
84 const char *src_tail; 93 unsigned ch = 0;
94 unsigned t;
95 int i = 0;
85 96
86 while (1) { 97 while ((t = (unsigned char)*src) != '\0') {
87 unsigned char six_bit[4]; 98 src++;
88 int count = 0;
89
90 /* Fetch up to four 6-bit values */
91 src_tail = src;
92 while (count < 4) {
93 char *table_ptr;
94 int ch;
95
96 /* Get next _valid_ character.
97 * bb_uuenc_tbl_base64[] contains this string:
98 * 0 1 2 3 4 5 6
99 * 01234567890123456789012345678901234567890123456789012345678901234
100 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
101 */
102 do {
103 ch = *src;
104 if (ch == '\0') {
105 if (count == 0) {
106 /* Example:
107 * If we decode "QUJD <NUL>", we want
108 * to return ptr to NUL, not to ' ',
109 * because we did fully decode
110 * the string (to "ABC").
111 */
112 src_tail = src;
113 }
114 goto ret;
115 }
116 src++;
117 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
118//TODO: add BASE64_FLAG_foo to die on bad char?
119 } while (!table_ptr);
120 99
121 /* Convert encoded character to decimal */ 100 /* "if" forest is faster than strchr(bb_uuenc_tbl_base64, t) */
122 ch = table_ptr - bb_uuenc_tbl_base64; 101 if (t >= '0' && t <= '9')
102 t = t - '0' + 52;
103 else if (t >= 'A' && t <= 'Z')
104 t = t - 'A';
105 else if (t >= 'a' && t <= 'z')
106 t = t - 'a' + 26;
107 else if (t == '+')
108 t = 62;
109 else if (t == '/')
110 t = 63;
111 else if (t == '=' && (i == 3 || (i == 2 && *src == '=')))
112 /* the above disallows "==AA", "A===", "AA=A" etc */
113 t = 0x1000000;
114 else
115//TODO: add BASE64_FLAG_foo to die on bad char?
116 continue;
123 117
124 /* ch is 64 if char was '=', otherwise 0..63 */ 118 ch = (ch << 6) | t;
125 if (ch == 64) 119 i = (i + 1) & 3;
120 if (i == 0) {
121 *dst++ = (char) (ch >> 16);
122 *dst++ = (char) (ch >> 8);
123 *dst++ = (char) ch;
124 if (ch & 0x1000000) { /* was last input char '='? */
125 dst--;
126 if (ch & (0x1000000 << 6)) /* was it "=="? */
127 dst--;
126 break; 128 break;
127 six_bit[count] = ch; 129 }
128 count++; 130 ch = 0;
131 }
132 }
133 /* i is zero here if full 4-char block was decoded */
134 if (pp_src)
135 *pp_src = src - i; /* -i signals truncation: e.g. "MQ" and "MQ=" (correct encoding is "MQ==" -> "1") */
136 return dst;
137}
138
139#if ENABLE_BASE32
140char* FAST_FUNC decode_base32(char *dst, const char **pp_src)
141{
142 const char *src = *pp_src;
143 uint64_t ch = 0;
144 unsigned t;
145 int i = 0;
146
147 while ((t = (unsigned char)*src) != '\0') {
148 src++;
149
150 /* "if" forest is faster than strchr(bb_uuenc_tbl_base32, t) */
151 if (t >= '2' && t <= '7')
152 t = t - '2' + 26;
153 else if (t == '=' && i > 1)
154 t = 0;
155 else {
156 t = (t | 0x20) - 'a';
157 if (t > 25)
158//TODO: add BASE64_FLAG_foo to die on bad char?
159 continue;
129 } 160 }
130 161
131 /* Transform 6-bit values to 8-bit ones. 162 ch = (ch << 5) | t;
132 * count can be < 4 when we decode the tail: 163 i = (i + 1) & 7;
133 * "eQ==" -> "y", not "y NUL NUL". 164 if (i == 0) {
134 * Note that (count > 1) is always true, 165 *dst++ = (char) (ch >> 32);
135 * "x===" encoding is not valid: 166 if (src[-1] == '=') /* was last input char '='? */
136 * even a single zero byte encodes as "AA==". 167 goto tail;
137 * However, with current logic we come here with count == 1 168 *dst++ = (char) (ch >> 24);
138 * when we decode "==" tail. 169 *dst++ = (char) (ch >> 16);
139 */ 170 *dst++ = (char) (ch >> 8);
140 if (count > 1) 171 *dst++ = (char) ch;
141 *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; 172 }
142 if (count > 2) 173 }
143 *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; 174 /* i is zero here if full 8-char block was decoded */
144 if (count > 3) 175 *pp_src = src - i;
145 *dst++ = six_bit[2] << 6 | six_bit[3]; 176 return dst;
146 /* Note that if we decode "AA==" and ate first '=', 177 tail:
147 * we just decoded one char (count == 2) and now we'll 178 {
148 * do the loop once more to decode second '='. 179 const char *s = src;
180 while (*--s == '=')
181 i++;
182 /* Why duplicate the below code? Testcase:
183 * echo ' 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18' | base32 | base32 -d
184 * IOW, decoding of
185 * EAYSAMRAGMQDIIBVEA3CANZAHAQDSIBRGAQDCMJAGEZCAMJTEAYTIIBRGUQDCNRAGE3SAMJYBI==
186 * ====
187 * must correctly stitch together the tail, must not overwrite
188 * the tail before it is analyzed! (we can be decoding in-place)
189 * Else testcase fails, prints trailing extra NUL bytes.
149 */ 190 */
150 } /* while (1) */ 191 *dst++ = (char) (ch >> 24);
151 ret: 192 *dst++ = (char) (ch >> 16);
152 *pp_dst = dst; 193 *dst++ = (char) (ch >> 8);
153 return src_tail; 194 *dst++ = (char) ch;
195 dst -= (i+1) * 2 / 3; /* discard last 1, 2, 3 or 4 bytes */
196 }
197 *pp_src = src;
198 return dst;
154} 199}
200#endif
155 201
156/* 202/*
157 * Decode base64 encoded stream. 203 * Decode base64 encoded stream.
@@ -163,20 +209,22 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
163/* Note that EOF _can_ be passed as exit_char too */ 209/* Note that EOF _can_ be passed as exit_char too */
164#define exit_char ((int)(signed char)flags) 210#define exit_char ((int)(signed char)flags)
165#define uu_style_end (flags & BASE64_FLAG_UU_STOP) 211#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
212#define base32 (flags & BASE64_32)
166 213
167 /* uuencoded files have 61 byte lines. Use 64 byte buffer 214 /* uuencoded files have 61 byte lines.
168 * to process line at a time. 215 * base32/64 have 76 byte lines by default.
216 * Use 80 byte buffer to process one line at a time.
169 */ 217 */
170 enum { BUFFER_SIZE = 64 }; 218 enum { BUFFER_SIZE = 80 };
171 219 /* decoded data is shorter than input, can use single buffer for both */
172 char in_buf[BUFFER_SIZE + 2]; 220 char buf[BUFFER_SIZE + 2];
173 char out_buf[BUFFER_SIZE / 4 * 3 + 2];
174 char *out_tail;
175 const char *in_tail;
176 int term_seen = 0; 221 int term_seen = 0;
177 int in_count = 0; 222 int in_count = 0;
178 223
179 while (1) { 224 while (1) {
225 char *out_tail;
226 const char *in_tail;
227
180 while (in_count < BUFFER_SIZE) { 228 while (in_count < BUFFER_SIZE) {
181 int ch = fgetc(src_stream); 229 int ch = fgetc(src_stream);
182 if (ch == exit_char) { 230 if (ch == exit_char) {
@@ -195,29 +243,34 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
195 */ 243 */
196 if (ch <= ' ') 244 if (ch <= ' ')
197 break; 245 break;
198 in_buf[in_count++] = ch; 246 buf[in_count++] = ch;
199 } 247 }
200 in_buf[in_count] = '\0'; 248 buf[in_count] = '\0';
201 249
202 /* Did we encounter "====" line? */ 250 /* Did we encounter "====" line? */
203 if (uu_style_end && strcmp(in_buf, "====") == 0) 251 if (uu_style_end && strcmp(buf, "====") == 0)
204 return; 252 return;
205 253
206 out_tail = out_buf; 254 in_tail = buf;
207 in_tail = decode_base64(&out_tail, in_buf); 255#if ENABLE_BASE32
256 if (base32)
257 out_tail = decode_base32(buf, &in_tail);
258 else
259#endif
260 out_tail = decode_base64(buf, &in_tail);
208 261
209 fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); 262 fwrite(buf, (out_tail - buf), 1, dst_stream);
210 263
211 if (term_seen) { 264 if (term_seen) {
212 /* Did we consume ALL characters? */ 265 /* Did we consume ALL characters? */
213 if (*in_tail == '\0') 266 if (*in_tail == '\0')
214 return; 267 return;
215 /* No */ 268 /* No */
216 bb_simple_error_msg_and_die("truncated base64 input"); 269 bb_simple_error_msg_and_die("truncated input");
217 } 270 }
218 271
219 /* It was partial decode */ 272 /* It was partial decode */
220 in_count = strlen(in_tail); 273 in_count = strlen(in_tail);
221 memmove(in_buf, in_tail, in_count); 274 memmove(buf, in_tail, in_count);
222 } 275 }
223} 276}
diff --git a/libbb/xatonum.c b/libbb/xatonum.c
index 7639a62aa..36b06c849 100644
--- a/libbb/xatonum.c
+++ b/libbb/xatonum.c
@@ -68,14 +68,14 @@ uint16_t FAST_FUNC xatou16(const char *numstr)
68 return xatou_range(numstr, 0, 0xffff); 68 return xatou_range(numstr, 0, 0xffff);
69} 69}
70 70
71const struct suffix_mult bkm_suffixes[] = { 71const struct suffix_mult bkm_suffixes[] ALIGN_SUFFIX = {
72 { "b", 512 }, 72 { "b", 512 },
73 { "k", 1024 }, 73 { "k", 1024 },
74 { "m", 1024*1024 }, 74 { "m", 1024*1024 },
75 { "", 0 } 75 { "", 0 }
76}; 76};
77 77
78const struct suffix_mult cwbkMG_suffixes[] = { 78const struct suffix_mult cwbkMG_suffixes[] ALIGN_SUFFIX = {
79 { "c", 1 }, 79 { "c", 1 },
80 { "w", 2 }, 80 { "w", 2 },
81 { "b", 512 }, 81 { "b", 512 },
@@ -96,7 +96,7 @@ const struct suffix_mult cwbkMG_suffixes[] = {
96 { "", 0 } 96 { "", 0 }
97}; 97};
98 98
99const struct suffix_mult kmg_i_suffixes[] = { 99const struct suffix_mult kmg_i_suffixes[] ALIGN_SUFFIX = {
100 { "KiB", 1024 }, 100 { "KiB", 1024 },
101 { "kiB", 1024 }, 101 { "kiB", 1024 },
102 { "K", 1024 }, 102 { "K", 1024 },
diff --git a/libbb/xconnect.c b/libbb/xconnect.c
index 38faef38e..f5c514b2c 100644
--- a/libbb/xconnect.c
+++ b/libbb/xconnect.c
@@ -428,17 +428,14 @@ int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf)
428 struct sockaddr_nl sa; 428 struct sockaddr_nl sa;
429 int fd; 429 int fd;
430 430
431 memset(&sa, 0, sizeof(sa));
432 sa.nl_family = AF_NETLINK;
433 sa.nl_pid = getpid();
434 sa.nl_groups = grp;
435 fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto); 431 fd = xsocket(AF_NETLINK, SOCK_DGRAM, proto);
436 xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
437 close_on_exec_on(fd);
438 432
433 /* Set receive buffer size before binding the socket
434 * We want to have enough space before we start receiving messages.
435 */
439 if (rcvbuf != 0) { 436 if (rcvbuf != 0) {
440 // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl 437 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf);
441 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUF, rcvbuf); 438 /* SO_RCVBUFFORCE (root only) can go above net.core.rmem_max */
442 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf); 439 setsockopt_SOL_SOCKET_int(fd, SO_RCVBUFFORCE, rcvbuf);
443# if 0 440# if 0
444 { 441 {
@@ -450,6 +447,13 @@ int FAST_FUNC create_and_bind_to_netlink(int proto, int grp, unsigned rcvbuf)
450# endif 447# endif
451 } 448 }
452 449
450 memset(&sa, 0, sizeof(sa));
451 sa.nl_family = AF_NETLINK;
452 sa.nl_pid = getpid();
453 sa.nl_groups = grp;
454 xbind(fd, (struct sockaddr *) &sa, sizeof(sa));
455 close_on_exec_on(fd);
456
453 return fd; 457 return fd;
454} 458}
455#endif 459#endif
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c
index c92436683..ef990118e 100644
--- a/libbb/xfuncs.c
+++ b/libbb/xfuncs.c
@@ -421,15 +421,3 @@ int FAST_FUNC wait4pid(pid_t pid)
421 return WTERMSIG(status) + 0x180; 421 return WTERMSIG(status) + 0x180;
422 return 0; 422 return 0;
423} 423}
424
425// Useful when we do know that pid is valid, and we just want to wait
426// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
427int FAST_FUNC wait_for_exitstatus(pid_t pid)
428{
429 int exit_status, n;
430
431 n = safe_waitpid(pid, &exit_status, 0);
432 if (n < 0)
433 bb_simple_perror_msg_and_die("waitpid");
434 return exit_status;
435}
diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c
index 6fdc0f6a4..4bd19d471 100644
--- a/libbb/xfuncs_printf.c
+++ b/libbb/xfuncs_printf.c
@@ -111,6 +111,29 @@ void* FAST_FUNC xmemdup(const void *s, int n)
111 return memcpy(xmalloc(n), s, n); 111 return memcpy(xmalloc(n), s, n);
112} 112}
113 113
114#if !ENABLE_PLATFORM_MINGW32
115void* FAST_FUNC mmap_read(int fd, size_t size)
116{
117 return mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
118}
119
120void* FAST_FUNC mmap_anon(size_t size)
121{
122 return mmap(NULL, size,
123 PROT_READ | PROT_WRITE,
124 MAP_PRIVATE | MAP_ANONYMOUS,
125 /* ignored: */ -1, 0);
126}
127
128void* FAST_FUNC xmmap_anon(size_t size)
129{
130 void *p = mmap_anon(size);
131 if (p == MAP_FAILED)
132 bb_die_memory_exhausted();
133 return p;
134}
135#endif
136
114// Die if we can't open a file and return a FILE* to it. 137// Die if we can't open a file and return a FILE* to it.
115// Notice we haven't got xfread(), This is for use with fscanf() and friends. 138// Notice we haven't got xfread(), This is for use with fscanf() and friends.
116FILE* FAST_FUNC xfopen(const char *path, const char *mode) 139FILE* FAST_FUNC xfopen(const char *path, const char *mode)
@@ -502,22 +525,22 @@ void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg)
502 bb_simple_perror_msg_and_die(errmsg); 525 bb_simple_perror_msg_and_die(errmsg);
503} 526}
504 527
505#if !ENABLE_PLATFORM_MINGW32 528#if ENABLE_SELINUX
506// selinux_or_die() - die if SELinux is disabled. 529// selinux_or_die() - die if SELinux is disabled.
507void FAST_FUNC selinux_or_die(void) 530void FAST_FUNC selinux_or_die(void)
508{ 531{
509#if ENABLE_SELINUX
510 int rc = is_selinux_enabled(); 532 int rc = is_selinux_enabled();
511 if (rc == 0) { 533 if (rc == 0) {
512 bb_simple_error_msg_and_die("SELinux is disabled"); 534 bb_simple_error_msg_and_die("SELinux is disabled");
513 } else if (rc < 0) { 535 } else if (rc < 0) {
514 bb_simple_error_msg_and_die("is_selinux_enabled() failed"); 536 bb_simple_error_msg_and_die("is_selinux_enabled() failed");
515 } 537 }
538}
516#else 539#else
517 bb_simple_error_msg_and_die("SELinux support is disabled"); 540/* not defined, other code must have no calls to it */
518#endif 541#endif
519}
520 542
543#if !ENABLE_PLATFORM_MINGW32
521int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...) 544int FAST_FUNC ioctl_or_perror_and_die(int fd, unsigned request, void *argp, const char *fmt,...)
522{ 545{
523 int ret; 546 int ret;
@@ -634,14 +657,11 @@ void FAST_FUNC generate_uuid(uint8_t *buf)
634 pid_t pid; 657 pid_t pid;
635 int i; 658 int i;
636 659
637 i = open("/dev/urandom", O_RDONLY); 660 open_read_close("/dev/urandom", buf, 16);
638 if (i >= 0) {
639 read(i, buf, 16);
640 close(i);
641 }
642 /* Paranoia. /dev/urandom may be missing. 661 /* Paranoia. /dev/urandom may be missing.
643 * rand() is guaranteed to generate at least [0, 2^15) range, 662 * rand() is guaranteed to generate at least [0, 2^15) range,
644 * but lowest bits in some libc are not so "random". */ 663 * but lowest bits in some libc are not so "random".
664 */
645 srand(monotonic_us()); /* pulls in printf */ 665 srand(monotonic_us()); /* pulls in printf */
646 pid = getpid(); 666 pid = getpid();
647 while (1) { 667 while (1) {
@@ -686,3 +706,34 @@ void FAST_FUNC xvfork_parent_waits_and_exits(void)
686 /* Child continues */ 706 /* Child continues */
687} 707}
688#endif /* !ENABLE_PLATFORM_MINGW32 */ 708#endif /* !ENABLE_PLATFORM_MINGW32 */
709
710// Useful when we do know that pid is valid, and we just want to wait
711// for it to exit. Not existing pid is fatal. waitpid() status is not returned.
712int FAST_FUNC wait_for_exitstatus(pid_t pid)
713{
714 int exit_status, n;
715
716 n = safe_waitpid(pid, &exit_status, 0);
717 if (n < 0)
718 bb_simple_perror_msg_and_die("waitpid");
719 return exit_status;
720}
721
722#if !ENABLE_PLATFORM_MINGW32
723void FAST_FUNC xsettimeofday(const struct timeval *tv)
724{
725 if (settimeofday(tv, NULL))
726 bb_simple_perror_msg_and_die("settimeofday");
727}
728#endif
729
730void FAST_FUNC xgettimeofday(struct timeval *tv)
731{
732#if 0
733 if (gettimeofday(tv, NULL))
734 bb_simple_perror_msg_and_die("gettimeofday");
735#else
736 /* Never fails on Linux */
737 gettimeofday(tv, NULL);
738#endif
739}