aboutsummaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
Diffstat (limited to 'libbb')
-rw-r--r--libbb/Config.src15
-rw-r--r--libbb/Kbuild.src6
-rw-r--r--libbb/appletlib.c2
-rw-r--r--libbb/bb_askpass.c22
-rw-r--r--libbb/getpty.c18
-rw-r--r--libbb/hash_md5_sha.c32
-rw-r--r--libbb/hash_md5prime.c26
-rw-r--r--libbb/inet_cksum.c36
-rw-r--r--libbb/lineedit.c110
-rw-r--r--libbb/loop.c10
-rw-r--r--libbb/match_fstype.c4
-rw-r--r--libbb/percent_decode.c69
-rw-r--r--libbb/procps.c34
-rw-r--r--libbb/read_key.c11
-rw-r--r--libbb/read_printf.c2
-rw-r--r--libbb/udp_io.c2
-rw-r--r--libbb/uuencode.c155
-rw-r--r--libbb/vdprintf.c4
18 files changed, 436 insertions, 122 deletions
diff --git a/libbb/Config.src b/libbb/Config.src
index aa442365a..ee1b66a45 100644
--- a/libbb/Config.src
+++ b/libbb/Config.src
@@ -14,9 +14,9 @@ config PASSWORD_MINLEN
14 help 14 help
15 Minimum allowable password length. 15 Minimum allowable password length.
16 16
17config MD5_SIZE_VS_SPEED 17config MD5_SMALL
18 int "MD5: Trade bytes for speed (0:fast, 3:slow)" 18 int "MD5: Trade bytes for speed (0:fast, 3:slow)"
19 default 2 19 default 1
20 range 0 3 20 range 0 3
21 help 21 help
22 Trade binary size versus speed for the md5sum algorithm. 22 Trade binary size versus speed for the md5sum algorithm.
@@ -94,6 +94,13 @@ config FEATURE_EDITING_SAVEHISTORY
94 help 94 help
95 Enable history saving in shells. 95 Enable history saving in shells.
96 96
97config FEATURE_EDITING_SAVE_ON_EXIT
98 bool "Save history on shell exit, not after every command"
99 default n
100 depends on FEATURE_EDITING_SAVEHISTORY
101 help
102 Save history on shell exit, not after every command.
103
97config FEATURE_REVERSE_SEARCH 104config FEATURE_REVERSE_SEARCH
98 bool "Reverse history search" 105 bool "Reverse history search"
99 default y 106 default y
@@ -184,8 +191,8 @@ config FEATURE_SKIP_ROOTFS
184 191
185 However, some systems do not mount anything on /. 192 However, some systems do not mount anything on /.
186 If you need to configure busybox for one of these systems, 193 If you need to configure busybox for one of these systems,
187 you may find useful to turn this option off to make df show 194 you may find it useful to turn this option off to make df show
188 initramfs statistic. 195 initramfs statistics.
189 196
190 Otherwise, choose Y. 197 Otherwise, choose Y.
191 198
diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src
index b5e9afc78..4cb063f89 100644
--- a/libbb/Kbuild.src
+++ b/libbb/Kbuild.src
@@ -168,6 +168,12 @@ lib-$(CONFIG_IOSTAT) += get_cpu_count.o
168lib-$(CONFIG_MPSTAT) += get_cpu_count.o 168lib-$(CONFIG_MPSTAT) += get_cpu_count.o
169lib-$(CONFIG_POWERTOP) += get_cpu_count.o 169lib-$(CONFIG_POWERTOP) += get_cpu_count.o
170 170
171lib-$(CONFIG_PING) += inet_cksum.o
172lib-$(CONFIG_TRACEROUTE) += inet_cksum.o
173lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o
174lib-$(CONFIG_UDHCPC) += inet_cksum.o
175lib-$(CONFIG_UDHCPD) += inet_cksum.o
176
171# We shouldn't build xregcomp.c if we don't need it - this ensures we don't 177# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
172# require regex.h to be in the include dir even if we don't need it thereby 178# require regex.h to be in the include dir even if we don't need it thereby
173# allowing us to build busybox even if uclibc regex support is disabled. 179# allowing us to build busybox even if uclibc regex support is disabled.
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 6d002b0dd..0c675db4d 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -62,7 +62,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE;
62#if ENABLE_FEATURE_COMPRESS_USAGE 62#if ENABLE_FEATURE_COMPRESS_USAGE
63 63
64static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; 64static const char packed_usage[] ALIGN1 = { PACKED_USAGE };
65# include "archive.h" 65# include "bb_archive.h"
66static const char *unpack_usage_messages(void) 66static const char *unpack_usage_messages(void)
67{ 67{
68 char *outbuf = NULL; 68 char *outbuf = NULL;
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index 9a4188f52..fe2b50677 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -30,14 +30,23 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
30 struct sigaction sa, oldsa; 30 struct sigaction sa, oldsa;
31 struct termios tio, oldtio; 31 struct termios tio, oldtio;
32 32
33 tcgetattr(fd, &oldtio); 33 fputs(prompt, stdout);
34 fflush_all();
34 tcflush(fd, TCIFLUSH); 35 tcflush(fd, TCIFLUSH);
36
37 tcgetattr(fd, &oldtio);
35 tio = oldtio; 38 tio = oldtio;
36#ifndef IUCLC 39#if 0
37# define IUCLC 0 40 /* Switch off UPPERCASE->lowercase conversion (never used since 198x)
38#endif 41 * and XON/XOFF (why we want to mess with this??)
42 */
43# ifndef IUCLC
44# define IUCLC 0
45# endif
39 tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); 46 tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY);
40 tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); 47#endif
48 /* Switch off echo */
49 tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL);
41 tcsetattr(fd, TCSANOW, &tio); 50 tcsetattr(fd, TCSANOW, &tio);
42 51
43 memset(&sa, 0, sizeof(sa)); 52 memset(&sa, 0, sizeof(sa));
@@ -50,9 +59,6 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt)
50 alarm(timeout); 59 alarm(timeout);
51 } 60 }
52 61
53 fputs(prompt, stdout);
54 fflush_all();
55
56 if (!passwd) 62 if (!passwd)
57 passwd = xmalloc(sizeof_passwd); 63 passwd = xmalloc(sizeof_passwd);
58 ret = passwd; 64 ret = passwd;
diff --git a/libbb/getpty.c b/libbb/getpty.c
index 6a15cff2f..435e4d09f 100644
--- a/libbb/getpty.c
+++ b/libbb/getpty.c
@@ -19,20 +19,22 @@ int FAST_FUNC xgetpty(char *line)
19 if (p > 0) { 19 if (p > 0) {
20 grantpt(p); /* chmod+chown corresponding slave pty */ 20 grantpt(p); /* chmod+chown corresponding slave pty */
21 unlockpt(p); /* (what does this do?) */ 21 unlockpt(p); /* (what does this do?) */
22#ifndef HAVE_PTSNAME_R 22# ifndef HAVE_PTSNAME_R
23 const char *name; 23 {
24 name = ptsname(p); /* find out the name of slave pty */ 24 const char *name;
25 if (!name) { 25 name = ptsname(p); /* find out the name of slave pty */
26 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); 26 if (!name) {
27 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
28 }
29 safe_strncpy(line, name, GETPTY_BUFSIZE);
27 } 30 }
28 safe_strncpy(line, name, GETPTY_BUFSIZE); 31# else
29#else
30 /* find out the name of slave pty */ 32 /* find out the name of slave pty */
31 if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) { 33 if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) {
32 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); 34 bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)");
33 } 35 }
34 line[GETPTY_BUFSIZE-1] = '\0'; 36 line[GETPTY_BUFSIZE-1] = '\0';
35#endif 37# endif
36 return p; 38 return p;
37 } 39 }
38#else 40#else
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index b87d1dde8..a313c2a65 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -104,12 +104,12 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
104 */ 104 */
105 105
106/* 0: fastest, 3: smallest */ 106/* 0: fastest, 3: smallest */
107#if CONFIG_MD5_SIZE_VS_SPEED < 0 107#if CONFIG_MD5_SMALL < 0
108# define MD5_SIZE_VS_SPEED 0 108# define MD5_SMALL 0
109#elif CONFIG_MD5_SIZE_VS_SPEED > 3 109#elif CONFIG_MD5_SMALL > 3
110# define MD5_SIZE_VS_SPEED 3 110# define MD5_SMALL 3
111#else 111#else
112# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED 112# define MD5_SMALL CONFIG_MD5_SMALL
113#endif 113#endif
114 114
115/* These are the four functions used in the four steps of the MD5 algorithm 115/* These are the four functions used in the four steps of the MD5 algorithm
@@ -129,7 +129,7 @@ static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
129/* Hash a single block, 64 bytes long and 4-byte aligned */ 129/* Hash a single block, 64 bytes long and 4-byte aligned */
130static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) 130static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
131{ 131{
132#if MD5_SIZE_VS_SPEED > 0 132#if MD5_SMALL > 0
133 /* Before we start, one word to the strange constants. 133 /* Before we start, one word to the strange constants.
134 They are defined in RFC 1321 as 134 They are defined in RFC 1321 as
135 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64 135 T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64
@@ -157,7 +157,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
157 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 157 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
158 }; 158 };
159 static const char P_array[] ALIGN1 = { 159 static const char P_array[] ALIGN1 = {
160# if MD5_SIZE_VS_SPEED > 1 160# if MD5_SMALL > 1
161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ 161 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */
162# endif 162# endif
163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ 163 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */
@@ -171,7 +171,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
171 uint32_t C = ctx->hash[2]; 171 uint32_t C = ctx->hash[2];
172 uint32_t D = ctx->hash[3]; 172 uint32_t D = ctx->hash[3];
173 173
174#if MD5_SIZE_VS_SPEED >= 2 /* 2 or 3 */ 174#if MD5_SMALL >= 2 /* 2 or 3 */
175 175
176 static const char S_array[] ALIGN1 = { 176 static const char S_array[] ALIGN1 = {
177 7, 12, 17, 22, 177 7, 12, 17, 22,
@@ -190,7 +190,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
190 words[i] = SWAP_LE32(words[i]); 190 words[i] = SWAP_LE32(words[i]);
191# endif 191# endif
192 192
193# if MD5_SIZE_VS_SPEED == 3 193# if MD5_SMALL == 3
194 pc = C_array; 194 pc = C_array;
195 pp = P_array; 195 pp = P_array;
196 ps = S_array - 4; 196 ps = S_array - 4;
@@ -220,7 +220,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
220 C = B; 220 C = B;
221 B = temp; 221 B = temp;
222 } 222 }
223# else /* MD5_SIZE_VS_SPEED == 2 */ 223# else /* MD5_SMALL == 2 */
224 pc = C_array; 224 pc = C_array;
225 pp = P_array; 225 pp = P_array;
226 ps = S_array; 226 ps = S_array;
@@ -271,13 +271,13 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
271 ctx->hash[2] += C; 271 ctx->hash[2] += C;
272 ctx->hash[3] += D; 272 ctx->hash[3] += D;
273 273
274#else /* MD5_SIZE_VS_SPEED == 0 or 1 */ 274#else /* MD5_SMALL == 0 or 1 */
275 275
276 uint32_t A_save = A; 276 uint32_t A_save = A;
277 uint32_t B_save = B; 277 uint32_t B_save = B;
278 uint32_t C_save = C; 278 uint32_t C_save = C;
279 uint32_t D_save = D; 279 uint32_t D_save = D;
280# if MD5_SIZE_VS_SPEED == 1 280# if MD5_SMALL == 1
281 const uint32_t *pc; 281 const uint32_t *pc;
282 const char *pp; 282 const char *pp;
283 int i; 283 int i;
@@ -299,7 +299,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
299 } while (0) 299 } while (0)
300 300
301 /* Round 1 */ 301 /* Round 1 */
302# if MD5_SIZE_VS_SPEED == 1 302# if MD5_SMALL == 1
303 pc = C_array; 303 pc = C_array;
304 for (i = 0; i < 4; i++) { 304 for (i = 0; i < 4; i++) {
305 OP(A, B, C, D, 7, *pc++); 305 OP(A, B, C, D, 7, *pc++);
@@ -339,7 +339,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
339 } while (0) 339 } while (0)
340 340
341 /* Round 2 */ 341 /* Round 2 */
342# if MD5_SIZE_VS_SPEED == 1 342# if MD5_SMALL == 1
343 pp = P_array; 343 pp = P_array;
344 for (i = 0; i < 4; i++) { 344 for (i = 0; i < 4; i++) {
345 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); 345 OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++);
@@ -367,7 +367,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
367# endif 367# endif
368 368
369 /* Round 3 */ 369 /* Round 3 */
370# if MD5_SIZE_VS_SPEED == 1 370# if MD5_SMALL == 1
371 for (i = 0; i < 4; i++) { 371 for (i = 0; i < 4; i++) {
372 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); 372 OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++);
373 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); 373 OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++);
@@ -394,7 +394,7 @@ static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx)
394# endif 394# endif
395 395
396 /* Round 4 */ 396 /* Round 4 */
397# if MD5_SIZE_VS_SPEED == 1 397# if MD5_SMALL == 1
398 for (i = 0; i < 4; i++) { 398 for (i = 0; i < 4; i++) {
399 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); 399 OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++);
400 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); 400 OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++);
diff --git a/libbb/hash_md5prime.c b/libbb/hash_md5prime.c
index 7986f4d29..e089a15f5 100644
--- a/libbb/hash_md5prime.c
+++ b/libbb/hash_md5prime.c
@@ -59,7 +59,7 @@
59 * Completely removed static PADDING array. 59 * Completely removed static PADDING array.
60 * 60 *
61 * Reintroduced the loop unrolling in md5_transform and added the 61 * Reintroduced the loop unrolling in md5_transform and added the
62 * MD5_SIZE_VS_SPEED option for configurability. Define below as: 62 * MD5_SMALL option for configurability. Define below as:
63 * 0 fully unrolled loops 63 * 0 fully unrolled loops
64 * 1 partially unrolled (4 ops per loop) 64 * 1 partially unrolled (4 ops per loop)
65 * 2 no unrolling -- introduces the need to swap 4 variables (slow) 65 * 2 no unrolling -- introduces the need to swap 4 variables (slow)
@@ -75,12 +75,12 @@
75#include "libbb.h" 75#include "libbb.h"
76 76
77/* 1: fastest, 3: smallest */ 77/* 1: fastest, 3: smallest */
78#if CONFIG_MD5_SIZE_VS_SPEED < 1 78#if CONFIG_MD5_SMALL < 1
79# define MD5_SIZE_VS_SPEED 1 79# define MD5_SMALL 1
80#elif CONFIG_MD5_SIZE_VS_SPEED > 3 80#elif CONFIG_MD5_SMALL > 3
81# define MD5_SIZE_VS_SPEED 3 81# define MD5_SMALL 3
82#else 82#else
83# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED 83# define MD5_SMALL CONFIG_MD5_SMALL
84#endif 84#endif
85 85
86#if BB_LITTLE_ENDIAN 86#if BB_LITTLE_ENDIAN
@@ -152,7 +152,7 @@ memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len)
152static void md5_transform(uint32_t state[4], const unsigned char block[64]) 152static void md5_transform(uint32_t state[4], const unsigned char block[64])
153{ 153{
154 uint32_t a, b, c, d, x[16]; 154 uint32_t a, b, c, d, x[16];
155#if MD5_SIZE_VS_SPEED > 1 155#if MD5_SMALL > 1
156 uint32_t temp; 156 uint32_t temp;
157 const unsigned char *ps; 157 const unsigned char *ps;
158 158
@@ -162,9 +162,9 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
162 4, 11, 16, 23, 162 4, 11, 16, 23,
163 6, 10, 15, 21 163 6, 10, 15, 21
164 }; 164 };
165#endif /* MD5_SIZE_VS_SPEED > 1 */ 165#endif /* MD5_SMALL > 1 */
166 166
167#if MD5_SIZE_VS_SPEED > 0 167#if MD5_SMALL > 0
168 const uint32_t *pc; 168 const uint32_t *pc;
169 const unsigned char *pp; 169 const unsigned char *pp;
170 int i; 170 int i;
@@ -198,7 +198,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
198 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ 198 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */
199 }; 199 };
200 200
201#endif /* MD5_SIZE_VS_SPEED > 0 */ 201#endif /* MD5_SMALL > 0 */
202 202
203 memcpy32_le2cpu(x, block, 64); 203 memcpy32_le2cpu(x, block, 64);
204 204
@@ -207,7 +207,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
207 c = state[2]; 207 c = state[2];
208 d = state[3]; 208 d = state[3];
209 209
210#if MD5_SIZE_VS_SPEED > 2 210#if MD5_SMALL > 2
211 pc = C; 211 pc = C;
212 pp = P; 212 pp = P;
213 ps = S - 4; 213 ps = S - 4;
@@ -233,7 +233,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
233 temp += b; 233 temp += b;
234 a = d; d = c; c = b; b = temp; 234 a = d; d = c; c = b; b = temp;
235 } 235 }
236#elif MD5_SIZE_VS_SPEED > 1 236#elif MD5_SMALL > 1
237 pc = C; 237 pc = C;
238 pp = P; 238 pp = P;
239 ps = S; 239 ps = S;
@@ -260,7 +260,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64])
260 II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; 260 II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++;
261 temp = d; d = c; c = b; b = a; a = temp; 261 temp = d; d = c; c = b; b = a; a = temp;
262 } 262 }
263#elif MD5_SIZE_VS_SPEED > 0 263#elif MD5_SMALL > 0
264 pc = C; 264 pc = C;
265 pp = P; 265 pp = P;
266 /* Round 1 */ 266 /* Round 1 */
diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c
new file mode 100644
index 000000000..3d5dc3adf
--- /dev/null
+++ b/libbb/inet_cksum.c
@@ -0,0 +1,36 @@
1/*
2 * Checksum routine for Internet Protocol family headers (C Version)
3 *
4 * Licensed under GPLv2, see file LICENSE in this source tree.
5 */
6
7#include "libbb.h"
8
9uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft)
10{
11 /*
12 * Our algorithm is simple, using a 32 bit accumulator,
13 * we add sequential 16 bit words to it, and at the end, fold
14 * back all the carry bits from the top 16 bits into the lower
15 * 16 bits.
16 */
17 unsigned sum = 0;
18 while (nleft > 1) {
19 sum += *addr++;
20 nleft -= 2;
21 }
22
23 /* Mop up an odd byte, if necessary */
24 if (nleft == 1) {
25 if (BB_LITTLE_ENDIAN)
26 sum += *(uint8_t*)addr;
27 else
28 sum += *(uint8_t*)addr << 8;
29 }
30
31 /* Add back carry outs from top 16 bits to low 16 bits */
32 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
33 sum += (sum >> 16); /* add carry */
34
35 return (uint16_t)~sum;
36}
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 1b97e8609..c89c829ed 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -1359,7 +1359,9 @@ static void load_history(line_input_t *st_parm)
1359 1359
1360 /* fill temp_h[], retaining only last MAX_HISTORY lines */ 1360 /* fill temp_h[], retaining only last MAX_HISTORY lines */
1361 memset(temp_h, 0, sizeof(temp_h)); 1361 memset(temp_h, 0, sizeof(temp_h));
1362 st_parm->cnt_history_in_file = idx = 0; 1362 idx = 0;
1363 if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1364 st_parm->cnt_history_in_file = 0;
1363 while ((line = xmalloc_fgetline(fp)) != NULL) { 1365 while ((line = xmalloc_fgetline(fp)) != NULL) {
1364 if (line[0] == '\0') { 1366 if (line[0] == '\0') {
1365 free(line); 1367 free(line);
@@ -1367,7 +1369,8 @@ static void load_history(line_input_t *st_parm)
1367 } 1369 }
1368 free(temp_h[idx]); 1370 free(temp_h[idx]);
1369 temp_h[idx] = line; 1371 temp_h[idx] = line;
1370 st_parm->cnt_history_in_file++; 1372 if (!ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1373 st_parm->cnt_history_in_file++;
1371 idx++; 1374 idx++;
1372 if (idx == st_parm->max_history) 1375 if (idx == st_parm->max_history)
1373 idx = 0; 1376 idx = 0;
@@ -1397,15 +1400,62 @@ static void load_history(line_input_t *st_parm)
1397 st_parm->history[i++] = line; 1400 st_parm->history[i++] = line;
1398 } 1401 }
1399 st_parm->cnt_history = i; 1402 st_parm->cnt_history = i;
1403 if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT)
1404 st_parm->cnt_history_in_file = i;
1400 } 1405 }
1401} 1406}
1402 1407
1403/* state->flags is already checked to be nonzero */ 1408# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1409void save_history(line_input_t *st)
1410{
1411 FILE *fp;
1412
1413 if (!st->hist_file)
1414 return;
1415 if (st->cnt_history <= st->cnt_history_in_file)
1416 return;
1417
1418 fp = fopen(st->hist_file, "a");
1419 if (fp) {
1420 int i, fd;
1421 char *new_name;
1422 line_input_t *st_temp;
1423
1424 for (i = st->cnt_history_in_file; i < st->cnt_history; i++)
1425 fprintf(fp, "%s\n", st->history[i]);
1426 fclose(fp);
1427
1428 /* we may have concurrently written entries from others.
1429 * load them */
1430 st_temp = new_line_input_t(st->flags);
1431 st_temp->hist_file = st->hist_file;
1432 st_temp->max_history = st->max_history;
1433 load_history(st_temp);
1434
1435 /* write out temp file and replace hist_file atomically */
1436 new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid());
1437 fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1438 if (fd >= 0) {
1439 fp = xfdopen_for_write(fd);
1440 for (i = 0; i < st_temp->cnt_history; i++)
1441 fprintf(fp, "%s\n", st_temp->history[i]);
1442 fclose(fp);
1443 if (rename(new_name, st->hist_file) == 0)
1444 st->cnt_history_in_file = st_temp->cnt_history;
1445 }
1446 free(new_name);
1447 free_line_input_t(st_temp);
1448 }
1449}
1450# else
1404static void save_history(char *str) 1451static void save_history(char *str)
1405{ 1452{
1406 int fd; 1453 int fd;
1407 int len, len2; 1454 int len, len2;
1408 1455
1456 if (!state->hist_file)
1457 return;
1458
1409 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); 1459 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600);
1410 if (fd < 0) 1460 if (fd < 0)
1411 return; 1461 return;
@@ -1433,7 +1483,7 @@ static void save_history(char *str)
1433 1483
1434 /* write out temp file and replace hist_file atomically */ 1484 /* write out temp file and replace hist_file atomically */
1435 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); 1485 new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid());
1436 fd = open(state->hist_file, O_WRONLY | O_CREAT | O_TRUNC, 0600); 1486 fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600);
1437 if (fd >= 0) { 1487 if (fd >= 0) {
1438 FILE *fp; 1488 FILE *fp;
1439 int i; 1489 int i;
@@ -1449,6 +1499,7 @@ static void save_history(char *str)
1449 free_line_input_t(st_temp); 1499 free_line_input_t(st_temp);
1450 } 1500 }
1451} 1501}
1502# endif
1452# else 1503# else
1453# define load_history(a) ((void)0) 1504# define load_history(a) ((void)0)
1454# define save_history(a) ((void)0) 1505# define save_history(a) ((void)0)
@@ -1477,15 +1528,18 @@ static void remember_in_history(char *str)
1477 for (i = 0; i < state->max_history-1; i++) 1528 for (i = 0; i < state->max_history-1; i++)
1478 state->history[i] = state->history[i+1]; 1529 state->history[i] = state->history[i+1];
1479 /* i == state->max_history-1 */ 1530 /* i == state->max_history-1 */
1531# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1532 if (state->cnt_history_in_file)
1533 state->cnt_history_in_file--;
1534# endif
1480 } 1535 }
1481 /* i <= state->max_history-1 */ 1536 /* i <= state->max_history-1 */
1482 state->history[i++] = xstrdup(str); 1537 state->history[i++] = xstrdup(str);
1483 /* i <= state->max_history */ 1538 /* i <= state->max_history */
1484 state->cur_history = i; 1539 state->cur_history = i;
1485 state->cnt_history = i; 1540 state->cnt_history = i;
1486# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY 1541# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
1487 if ((state->flags & SAVE_HISTORY) && state->hist_file) 1542 save_history(str);
1488 save_history(str);
1489# endif 1543# endif
1490 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) 1544 IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
1491} 1545}
@@ -2147,7 +2201,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2147 state = st ? st : (line_input_t*) &const_int_0; 2201 state = st ? st : (line_input_t*) &const_int_0;
2148#if MAX_HISTORY > 0 2202#if MAX_HISTORY > 0
2149# if ENABLE_FEATURE_EDITING_SAVEHISTORY 2203# if ENABLE_FEATURE_EDITING_SAVEHISTORY
2150 if ((state->flags & SAVE_HISTORY) && state->hist_file) 2204 if (state->hist_file)
2151 if (state->cnt_history == 0) 2205 if (state->cnt_history == 0)
2152 load_history(state); 2206 load_history(state);
2153# endif 2207# endif
@@ -2467,6 +2521,44 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2467 vi_cmdmode = 1; 2521 vi_cmdmode = 1;
2468 input_backward(1); 2522 input_backward(1);
2469 } 2523 }
2524 /* Handle a few ESC-<key> combinations the same way
2525 * standard readline bindings (IOW: bash) do.
2526 * Often, Alt-<key> generates ESC-<key>.
2527 */
2528 ic = lineedit_read_key(read_key_buffer, timeout);
2529 switch (ic) {
2530 //case KEYCODE_LEFT: - bash doesn't do this
2531 case 'b':
2532 ctrl_left();
2533 break;
2534 //case KEYCODE_RIGHT: - bash doesn't do this
2535 case 'f':
2536 ctrl_right();
2537 break;
2538 //case KEYCODE_DELETE: - bash doesn't do this
2539 case 'd': /* Alt-D */
2540 {
2541 /* Delete word forward */
2542 int nc, sc = cursor;
2543 ctrl_right();
2544 nc = cursor;
2545 input_backward(cursor - sc);
2546 while (--nc >= cursor)
2547 input_delete(1);
2548 break;
2549 }
2550 case '\b': /* Alt-Backspace(?) */
2551 case '\x7f': /* Alt-Backspace(?) */
2552 //case 'w': - bash doesn't do this
2553 {
2554 /* Delete word backward */
2555 int sc = cursor;
2556 ctrl_left();
2557 while (sc-- > cursor)
2558 input_delete(1);
2559 break;
2560 }
2561 }
2470 break; 2562 break;
2471#endif /* FEATURE_COMMAND_EDITING_VI */ 2563#endif /* FEATURE_COMMAND_EDITING_VI */
2472 2564
@@ -2495,9 +2587,11 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman
2495 input_backward(1); 2587 input_backward(1);
2496 break; 2588 break;
2497 case KEYCODE_CTRL_LEFT: 2589 case KEYCODE_CTRL_LEFT:
2590 case KEYCODE_ALT_LEFT: /* bash doesn't do it */
2498 ctrl_left(); 2591 ctrl_left();
2499 break; 2592 break;
2500 case KEYCODE_CTRL_RIGHT: 2593 case KEYCODE_CTRL_RIGHT:
2594 case KEYCODE_ALT_RIGHT: /* bash doesn't do it */
2501 ctrl_right(); 2595 ctrl_right();
2502 break; 2596 break;
2503 case KEYCODE_HOME: 2597 case KEYCODE_HOME:
diff --git a/libbb/loop.c b/libbb/loop.c
index b798932fa..b3a520848 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -84,7 +84,7 @@ int FAST_FUNC del_loop(const char *device)
84 search will re-use an existing loop device already bound to that 84 search will re-use an existing loop device already bound to that
85 file/offset if it finds one. 85 file/offset if it finds one.
86 */ 86 */
87int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset) 87int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, int ro)
88{ 88{
89 char dev[LOOP_NAMESIZE]; 89 char dev[LOOP_NAMESIZE];
90 char *try; 90 char *try;
@@ -93,11 +93,13 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
93 int i, dfd, ffd, mode, rc = -1; 93 int i, dfd, ffd, mode, rc = -1;
94 94
95 /* Open the file. Barf if this doesn't work. */ 95 /* Open the file. Barf if this doesn't work. */
96 mode = O_RDWR; 96 mode = ro ? O_RDONLY : O_RDWR;
97 ffd = open(file, mode); 97 ffd = open(file, mode);
98 if (ffd < 0) { 98 if (ffd < 0) {
99 mode = O_RDONLY; 99 if (mode != O_RDONLY) {
100 ffd = open(file, mode); 100 mode = O_RDONLY;
101 ffd = open(file, mode);
102 }
101 if (ffd < 0) 103 if (ffd < 0)
102 return -errno; 104 return -errno;
103 } 105 }
diff --git a/libbb/match_fstype.c b/libbb/match_fstype.c
index 83d6e6770..32c3d7f18 100644
--- a/libbb/match_fstype.c
+++ b/libbb/match_fstype.c
@@ -12,6 +12,8 @@
12 12
13#include "libbb.h" 13#include "libbb.h"
14 14
15#ifdef HAVE_MNTENT_H
16
15int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) 17int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
16{ 18{
17 int match = 1; 19 int match = 1;
@@ -40,3 +42,5 @@ int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype)
40 42
41 return !match; 43 return !match;
42} 44}
45
46#endif /* HAVE_MNTENT_H */
diff --git a/libbb/percent_decode.c b/libbb/percent_decode.c
new file mode 100644
index 000000000..9a9d80c4a
--- /dev/null
+++ b/libbb/percent_decode.c
@@ -0,0 +1,69 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6//kbuild:lib-y += percent_decode.o
7
8#include "libbb.h"
9
10static unsigned hex_to_bin(unsigned char c)
11{
12 unsigned v;
13
14 v = c - '0';
15 if (v <= 9)
16 return v;
17 /* c | 0x20: letters to lower case, non-letters
18 * to (potentially different) non-letters */
19 v = (unsigned)(c | 0x20) - 'a';
20 if (v <= 5)
21 return v + 10;
22 return ~0;
23/* For testing:
24void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); }
25int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f');
26t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; }
27*/
28}
29
30char* FAST_FUNC percent_decode_in_place(char *str, int strict)
31{
32 /* note that decoded string is always shorter than original */
33 char *src = str;
34 char *dst = str;
35 char c;
36
37 while ((c = *src++) != '\0') {
38 unsigned v;
39
40 if (!strict && c == '+') {
41 *dst++ = ' ';
42 continue;
43 }
44 if (c != '%') {
45 *dst++ = c;
46 continue;
47 }
48 v = hex_to_bin(src[0]);
49 if (v > 15) {
50 bad_hex:
51 if (strict)
52 return NULL;
53 *dst++ = '%';
54 continue;
55 }
56 v = (v * 16) | hex_to_bin(src[1]);
57 if (v > 255)
58 goto bad_hex;
59 if (strict && (v == '/' || v == '\0')) {
60 /* caller takes it as indication of invalid
61 * (dangerous wrt exploits) chars */
62 return str + 1;
63 }
64 *dst++ = v;
65 src += 2;
66 }
67 *dst = '\0';
68 return str;
69}
diff --git a/libbb/procps.c b/libbb/procps.c
index b5582edfa..39ddd2c12 100644
--- a/libbb/procps.c
+++ b/libbb/procps.c
@@ -285,27 +285,25 @@ int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total,
285void BUG_comm_size(void); 285void BUG_comm_size(void);
286procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) 286procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
287{ 287{
288 struct dirent *entry;
289 char buf[PROCPS_BUFSIZE];
290 char filename[sizeof("/proc//cmdline") + sizeof(int)*3];
291 char *filename_tail;
292 long tasknice;
293 unsigned pid;
294 int n;
295 struct stat sb;
296
297 if (!sp) 288 if (!sp)
298 sp = alloc_procps_scan(); 289 sp = alloc_procps_scan();
299 290
300 for (;;) { 291 for (;;) {
292 struct dirent *entry;
293 char buf[PROCPS_BUFSIZE];
294 long tasknice;
295 unsigned pid;
296 int n;
297 char filename[sizeof("/proc/%u/task/%u/cmdline") + sizeof(int)*3 * 2];
298 char *filename_tail;
299
301#if ENABLE_FEATURE_SHOW_THREADS 300#if ENABLE_FEATURE_SHOW_THREADS
302 if ((flags & PSSCAN_TASKS) && sp->task_dir) { 301 if (sp->task_dir) {
303 entry = readdir(sp->task_dir); 302 entry = readdir(sp->task_dir);
304 if (entry) 303 if (entry)
305 goto got_entry; 304 goto got_entry;
306 closedir(sp->task_dir); 305 closedir(sp->task_dir);
307 sp->task_dir = NULL; 306 sp->task_dir = NULL;
308 sp->main_thread_pid = 0;
309 } 307 }
310#endif 308#endif
311 entry = readdir(sp->dir); 309 entry = readdir(sp->dir);
@@ -322,9 +320,9 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
322 /* We found another /proc/PID. Do not use it, 320 /* We found another /proc/PID. Do not use it,
323 * there will be /proc/PID/task/PID (same PID!), 321 * there will be /proc/PID/task/PID (same PID!),
324 * so just go ahead and dive into /proc/PID/task. */ 322 * so just go ahead and dive into /proc/PID/task. */
325 char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; 323 sprintf(filename, "/proc/%u/task", pid);
326 sprintf(task_dir, "/proc/%u/task", pid); 324 /* Note: if opendir fails, we just go to next /proc/XXX */
327 sp->task_dir = xopendir(task_dir); 325 sp->task_dir = opendir(filename);
328 sp->main_thread_pid = pid; 326 sp->main_thread_pid = pid;
329 continue; 327 continue;
330 } 328 }
@@ -348,9 +346,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags)
348 } 346 }
349#endif 347#endif
350 348
351 filename_tail = filename + sprintf(filename, "/proc/%u/", pid); 349#if ENABLE_FEATURE_SHOW_THREADS
350 if (sp->task_dir)
351 filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->main_thread_pid, pid);
352 else
353#endif
354 filename_tail = filename + sprintf(filename, "/proc/%u/", pid);
352 355
353 if (flags & PSSCAN_UIDGID) { 356 if (flags & PSSCAN_UIDGID) {
357 struct stat sb;
354 if (stat(filename, &sb)) 358 if (stat(filename, &sb))
355 continue; /* process probably exited */ 359 continue; /* process probably exited */
356 /* Effective UID/GID, not real */ 360 /* Effective UID/GID, not real */
diff --git a/libbb/read_key.c b/libbb/read_key.c
index 5dcd19c3f..8d72d2a63 100644
--- a/libbb/read_key.c
+++ b/libbb/read_key.c
@@ -40,13 +40,14 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
40 '[','C' |0x80,KEYCODE_RIGHT , 40 '[','C' |0x80,KEYCODE_RIGHT ,
41 '[','D' |0x80,KEYCODE_LEFT , 41 '[','D' |0x80,KEYCODE_LEFT ,
42 /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */ 42 /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift-<arrow> */
43 /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> */ 43 /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt-<arrow> - implemented below */
44 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */ 44 /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift-<arrow> */
45 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */ 45 /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl-<arrow> - implemented below */
46 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */ 46 /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift-<arrow> */
47 '[','H' |0x80,KEYCODE_HOME , /* xterm */ 47 '[','H' |0x80,KEYCODE_HOME , /* xterm */
48 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */
49 '[','F' |0x80,KEYCODE_END , /* xterm */ 48 '[','F' |0x80,KEYCODE_END , /* xterm */
49 /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */
50 /* '[','Z' |0x80,KEYCODE_SHIFT_TAB, */
50 '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ 51 '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */
51 '[','2','~' |0x80,KEYCODE_INSERT , 52 '[','2','~' |0x80,KEYCODE_INSERT ,
52 /* ESC [ 2 ; 3 ~ - Alt-Insert */ 53 /* ESC [ 2 ; 3 ~ - Alt-Insert */
@@ -86,8 +87,12 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout)
86 /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */ 87 /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */
87 '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT, 88 '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT,
88 '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT , 89 '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT ,
90 /* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP , - unused */
91 /* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN , - unused */
92 '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT,
93 '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT ,
94 /* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */
89 0 95 0
90 /* ESC [ Z - Shift-Tab */
91 }; 96 };
92 97
93 pfd.fd = fd; 98 pfd.fd = fd;
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index 192f83d6e..0bbf7802a 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -15,7 +15,7 @@
15) 15)
16 16
17#if ZIPPED 17#if ZIPPED
18# include "archive.h" 18# include "bb_archive.h"
19#endif 19#endif
20 20
21 21
diff --git a/libbb/udp_io.c b/libbb/udp_io.c
index b8fb6755d..7985a9723 100644
--- a/libbb/udp_io.c
+++ b/libbb/udp_io.c
@@ -13,7 +13,7 @@
13 * We don't check for errors here. Not supported == won't be used 13 * We don't check for errors here. Not supported == won't be used
14 */ 14 */
15void FAST_FUNC 15void FAST_FUNC
16socket_want_pktinfo(int fd) 16socket_want_pktinfo(int fd UNUSED_PARAM)
17{ 17{
18#ifdef IP_PKTINFO 18#ifdef IP_PKTINFO
19 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); 19 setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int));
diff --git a/libbb/uuencode.c b/libbb/uuencode.c
index 03e708fd5..f7b248492 100644
--- a/libbb/uuencode.c
+++ b/libbb/uuencode.c
@@ -10,7 +10,7 @@
10#include "libbb.h" 10#include "libbb.h"
11 11
12/* Conversion table. for base 64 */ 12/* Conversion table. for base 64 */
13const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { 13const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = {
14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 14 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 15 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 16 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
@@ -20,7 +20,7 @@ const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = {
20 'w', 'x', 'y', 'z', '0', '1', '2', '3', 20 'w', 'x', 'y', 'z', '0', '1', '2', '3',
21 '4', '5', '6', '7', '8', '9', '+', '/', 21 '4', '5', '6', '7', '8', '9', '+', '/',
22 '=' /* termination character */, 22 '=' /* termination character */,
23 '\n', '\0' /* needed for uudecode.c */ 23 '\0' /* needed for uudecode.c only */
24}; 24};
25 25
26const char bb_uuenc_tbl_std[65] ALIGN1 = { 26const char bb_uuenc_tbl_std[65] ALIGN1 = {
@@ -73,23 +73,23 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl
73} 73}
74 74
75/* 75/*
76 * Decode base64 encoded stream. 76 * Decode base64 encoded string. Stops on '\0'.
77 * Can stop on EOF, specified char, or on uuencode-style "====" line: 77 *
78 * flags argument controls it. 78 * Returns: pointer to the undecoded part of source.
79 * If points to '\0', then the source was fully decoded.
80 * (*pp_dst): advanced past the last written byte.
79 */ 81 */
80void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) 82const char* FAST_FUNC decode_base64(char **pp_dst, const char *src)
81{ 83{
82/* Note that EOF _can_ be passed as exit_char too */ 84 char *dst = *pp_dst;
83#define exit_char ((int)(signed char)flags) 85 const char *src_tail;
84#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
85
86 int term_count = 0;
87 86
88 while (1) { 87 while (1) {
89 unsigned char translated[4]; 88 unsigned char six_bit[4];
90 int count = 0; 89 int count = 0;
91 90
92 /* Process one group of 4 chars */ 91 /* Fetch up to four 6-bit values */
92 src_tail = src;
93 while (count < 4) { 93 while (count < 4) {
94 char *table_ptr; 94 char *table_ptr;
95 int ch; 95 int ch;
@@ -97,49 +97,128 @@ void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
97 /* Get next _valid_ character. 97 /* Get next _valid_ character.
98 * bb_uuenc_tbl_base64[] contains this string: 98 * bb_uuenc_tbl_base64[] contains this string:
99 * 0 1 2 3 4 5 6 99 * 0 1 2 3 4 5 6
100 * 012345678901234567890123456789012345678901234567890123456789012345 100 * 01234567890123456789012345678901234567890123456789012345678901234
101 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" 101 * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
102 */ 102 */
103 do { 103 do {
104 ch = fgetc(src_stream); 104 ch = *src;
105 if (ch == exit_char && count == 0) 105 if (ch == '\0') {
106 return; 106 if (count == 0) {
107 if (ch == EOF) 107 /* Example:
108 bb_error_msg_and_die("truncated base64 input"); 108 * If we decode "QUJD <NUL>", we want
109 * to return ptr to NUL, not to ' ',
110 * because we did fully decode
111 * the string (to "ABC").
112 */
113 src_tail = src;
114 }
115 goto ret;
116 }
117 src++;
109 table_ptr = strchr(bb_uuenc_tbl_base64, ch); 118 table_ptr = strchr(bb_uuenc_tbl_base64, ch);
110//TODO: add BASE64_FLAG_foo to die on bad char? 119//TODO: add BASE64_FLAG_foo to die on bad char?
111//Note that then we may need to still allow '\r' (for mail processing)
112 } while (!table_ptr); 120 } while (!table_ptr);
113 121
114 /* Convert encoded character to decimal */ 122 /* Convert encoded character to decimal */
115 ch = table_ptr - bb_uuenc_tbl_base64; 123 ch = table_ptr - bb_uuenc_tbl_base64;
116 124
117 if (ch == 65 /* '\n' */) {
118 /* Terminating "====" line? */
119 if (uu_style_end && term_count == 4)
120 return; /* yes */
121 term_count = 0;
122 continue;
123 }
124 /* ch is 64 if char was '=', otherwise 0..63 */ 125 /* ch is 64 if char was '=', otherwise 0..63 */
125 translated[count] = ch & 63; /* 64 -> 0 */ 126 if (ch == 64)
126 if (ch == 64) {
127 term_count++;
128 break; 127 break;
129 } 128 six_bit[count] = ch;
130 count++; 129 count++;
131 term_count = 0;
132 } 130 }
133 131
134 /* Merge 6 bit chars to 8 bit. 132 /* Transform 6-bit values to 8-bit ones.
135 * count can be < 4 when we decode the tail: 133 * count can be < 4 when we decode the tail:
136 * "eQ==" -> "y", not "y NUL NUL" 134 * "eQ==" -> "y", not "y NUL NUL".
135 * Note that (count > 1) is always true,
136 * "x===" encoding is not valid:
137 * even a single zero byte encodes as "AA==".
138 * However, with current logic we come here with count == 1
139 * when we decode "==" tail.
137 */ 140 */
138 if (count > 1) 141 if (count > 1)
139 fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); 142 *dst++ = six_bit[0] << 2 | six_bit[1] >> 4;
140 if (count > 2) 143 if (count > 2)
141 fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); 144 *dst++ = six_bit[1] << 4 | six_bit[2] >> 2;
142 if (count > 3) 145 if (count > 3)
143 fputc(translated[2] << 6 | translated[3], dst_stream); 146 *dst++ = six_bit[2] << 6 | six_bit[3];
147 /* Note that if we decode "AA==" and ate first '=',
148 * we just decoded one char (count == 2) and now we'll
149 * do the loop once more to decode second '='.
150 */
144 } /* while (1) */ 151 } /* while (1) */
152 ret:
153 *pp_dst = dst;
154 return src_tail;
155}
156
157/*
158 * Decode base64 encoded stream.
159 * Can stop on EOF, specified char, or on uuencode-style "====" line:
160 * flags argument controls it.
161 */
162void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags)
163{
164/* Note that EOF _can_ be passed as exit_char too */
165#define exit_char ((int)(signed char)flags)
166#define uu_style_end (flags & BASE64_FLAG_UU_STOP)
167
168 /* uuencoded files have 61 byte lines. Use 64 byte buffer
169 * to process line at a time.
170 */
171 enum { BUFFER_SIZE = 64 };
172
173 char in_buf[BUFFER_SIZE + 2];
174 char out_buf[BUFFER_SIZE / 4 * 3 + 2];
175 char *out_tail;
176 const char *in_tail;
177 int term_seen = 0;
178 int in_count = 0;
179
180 while (1) {
181 while (in_count < BUFFER_SIZE) {
182 int ch = fgetc(src_stream);
183 if (ch == exit_char) {
184 if (in_count == 0)
185 return;
186 term_seen = 1;
187 break;
188 }
189 if (ch == EOF) {
190 term_seen = 1;
191 break;
192 }
193 /* Prevent "====" line to be split: stop if we see '\n'.
194 * We can also skip other whitespace and skirt the problem
195 * of files with NULs by stopping on any control char or space:
196 */
197 if (ch <= ' ')
198 break;
199 in_buf[in_count++] = ch;
200 }
201 in_buf[in_count] = '\0';
202
203 /* Did we encounter "====" line? */
204 if (uu_style_end && strcmp(in_buf, "====") == 0)
205 return;
206
207 out_tail = out_buf;
208 in_tail = decode_base64(&out_tail, in_buf);
209
210 fwrite(out_buf, (out_tail - out_buf), 1, dst_stream);
211
212 if (term_seen) {
213 /* Did we consume ALL characters? */
214 if (*in_tail == '\0')
215 return;
216 /* No */
217 bb_error_msg_and_die("truncated base64 input");
218 }
219
220 /* It was partial decode */
221 in_count = strlen(in_tail);
222 memmove(in_buf, in_tail, in_count);
223 }
145} 224}
diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c
index feeb403a0..05426873e 100644
--- a/libbb/vdprintf.c
+++ b/libbb/vdprintf.c
@@ -12,10 +12,10 @@
12#if defined(__GLIBC__) && __GLIBC__ < 2 12#if defined(__GLIBC__) && __GLIBC__ < 2
13int FAST_FUNC vdprintf(int d, const char *format, va_list ap) 13int FAST_FUNC vdprintf(int d, const char *format, va_list ap)
14{ 14{
15 char buf[BUF_SIZE]; 15 char buf[8 * 1024];
16 int len; 16 int len;
17 17
18 len = vsnprintf(buf, BUF_SIZE, format, ap); 18 len = vsnprintf(buf, sizeof(buf), format, ap);
19 return write(d, buf, len); 19 return write(d, buf, len);
20} 20}
21#endif 21#endif