aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Config.in12
-rw-r--r--archival/bbunzip.c5
-rw-r--r--archival/libarchive/decompress_unlzma.c23
-rw-r--r--archival/libarchive/get_header_tar.c2
-rw-r--r--archival/libarchive/open_transformer.c10
-rw-r--r--archival/rpm.c2
-rw-r--r--archival/rpm2cpio.c2
-rw-r--r--archival/tar.c2
-rw-r--r--coreutils/catv.c16
-rw-r--r--coreutils/ls.c2
-rw-r--r--coreutils/shuf.c153
-rw-r--r--coreutils/uname.c10
-rw-r--r--examples/var_service/README13
-rw-r--r--examples/var_service/dhcp_if/README5
-rw-r--r--examples/var_service/dhcp_if_pinger/README5
-rw-r--r--examples/var_service/ftpd/README5
-rw-r--r--examples/var_service/fw/README5
-rw-r--r--examples/var_service/getty_tty1/README5
-rw-r--r--examples/var_service/gpm/README5
-rw-r--r--examples/var_service/httpd/README5
-rw-r--r--examples/var_service/ifplugd_if/README5
-rw-r--r--examples/var_service/inetd/README5
-rw-r--r--examples/var_service/nmeter/README5
-rw-r--r--examples/var_service/ntpd/README5
-rw-r--r--examples/var_service/tftpd/README5
-rw-r--r--findutils/find.c34
-rw-r--r--findutils/grep.c33
-rw-r--r--findutils/xargs.c153
-rw-r--r--include/libbb.h8
-rw-r--r--init/init.c2
-rw-r--r--libbb/appletlib.c6
-rw-r--r--libbb/inode_hash.c36
-rw-r--r--libbb/loop.c18
-rw-r--r--libbb/pw_encrypt.c9
-rw-r--r--libbb/replace.c45
-rw-r--r--loginutils/Config.src7
-rw-r--r--mailutils/sendmail.c71
-rw-r--r--miscutils/fbsplash.c2
-rw-r--r--miscutils/less.c17
-rw-r--r--miscutils/man.c27
-rw-r--r--networking/ifplugd.c22
-rw-r--r--networking/ifupdown.c13
-rw-r--r--networking/libiproute/iplink.c200
-rw-r--r--networking/nc_bloaty.c6
-rw-r--r--networking/ntpd.c15
-rw-r--r--networking/ntpd_simple.c10
-rw-r--r--networking/ssl_helper/README16
-rw-r--r--networking/ssl_helper/ssl_helper.c406
-rwxr-xr-xnetworking/ssl_helper/ssl_helper.sh11
-rw-r--r--networking/udhcp/d6_dhcpc.c2
-rw-r--r--networking/udhcp/dhcpc.c121
-rw-r--r--networking/wget.c181
-rw-r--r--procps/sysctl.c3
-rwxr-xr-xtestsuite/grep.tests12
-rw-r--r--testsuite/which/which-uses-default-path2
-rw-r--r--util-linux/hwclock.c12
-rw-r--r--util-linux/mkfs_reiser.c4
57 files changed, 1537 insertions, 279 deletions
diff --git a/Config.in b/Config.in
index 8c0e64988..c4b6f40bd 100644
--- a/Config.in
+++ b/Config.in
@@ -280,6 +280,13 @@ config UNICODE_PRESERVE_BROKEN
280 at shell prompt will list file named 0xff (single char name 280 at shell prompt will list file named 0xff (single char name
281 with char value 255), not file named '?'. 281 with char value 255), not file named '?'.
282 282
283config PAM
284 bool "Support for PAM (Pluggable Authentication Modules)"
285 default n
286 help
287 Use PAM in some busybox applets (currently login and httpd) instead
288 of direct access to password database.
289
283config LONG_OPTS 290config LONG_OPTS
284 bool "Support for --long-options" 291 bool "Support for --long-options"
285 default y 292 default y
@@ -439,10 +446,7 @@ config SELINUX
439 the option of compiling in SELinux applets. 446 the option of compiling in SELinux applets.
440 447
441 If you do not have a complete SELinux userland installed, this stuff 448 If you do not have a complete SELinux userland installed, this stuff
442 will not compile. Go visit 449 will not compile. Specifially, libselinux 1.28 or better is
443 http://www.nsa.gov/selinux/index.html
444 to download the necessary stuff to allow busybox to compile with
445 this option enabled. Specifially, libselinux 1.28 or better is
446 directly required by busybox. If the installation is located in a 450 directly required by busybox. If the installation is located in a
447 non-standard directory, provide it by invoking make as follows: 451 non-standard directory, provide it by invoking make as follows:
448 CFLAGS=-I<libselinux-include-path> \ 452 CFLAGS=-I<libselinux-include-path> \
diff --git a/archival/bbunzip.c b/archival/bbunzip.c
index 3de8e1d48..4d417f3f1 100644
--- a/archival/bbunzip.c
+++ b/archival/bbunzip.c
@@ -72,7 +72,8 @@ int FAST_FUNC bbunpack(char **argv,
72 goto err; 72 goto err;
73 } else { 73 } else {
74 /* "clever zcat" with FILE */ 74 /* "clever zcat" with FILE */
75 int fd = open_zipped(filename); 75 /* fail_if_not_compressed because zcat refuses uncompressed input */
76 int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1);
76 if (fd < 0) 77 if (fd < 0)
77 goto err_name; 78 goto err_name;
78 xmove_fd(fd, STDIN_FILENO); 79 xmove_fd(fd, STDIN_FILENO);
@@ -80,7 +81,7 @@ int FAST_FUNC bbunpack(char **argv,
80 } else 81 } else
81 if (option_mask32 & SEAMLESS_MAGIC) { 82 if (option_mask32 & SEAMLESS_MAGIC) {
82 /* "clever zcat" on stdin */ 83 /* "clever zcat" on stdin */
83 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) 84 if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1))
84 goto err; 85 goto err;
85 } 86 }
86 87
diff --git a/archival/libarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c
index ca32bd82c..3d99e1388 100644
--- a/archival/libarchive/decompress_unlzma.c
+++ b/archival/libarchive/decompress_unlzma.c
@@ -214,8 +214,6 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
214 uint32_t pos_state_mask; 214 uint32_t pos_state_mask;
215 uint32_t literal_pos_mask; 215 uint32_t literal_pos_mask;
216 uint16_t *p; 216 uint16_t *p;
217 int num_bits;
218 int num_probs;
219 rc_t *rc; 217 rc_t *rc;
220 int i; 218 int i;
221 uint8_t *buffer; 219 uint8_t *buffer;
@@ -239,6 +237,9 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
239 pos_state_mask = (1 << pb) - 1; 237 pos_state_mask = (1 << pb) - 1;
240 literal_pos_mask = (1 << lp) - 1; 238 literal_pos_mask = (1 << lp) - 1;
241 239
240 /* Example values from linux-3.3.4.tar.lzma:
241 * dict_size: 64M, dst_size: 2^64-1
242 */
242 header.dict_size = SWAP_LE32(header.dict_size); 243 header.dict_size = SWAP_LE32(header.dict_size);
243 header.dst_size = SWAP_LE64(header.dst_size); 244 header.dst_size = SWAP_LE64(header.dst_size);
244 245
@@ -247,11 +248,15 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
247 248
248 buffer = xmalloc(MIN(header.dst_size, header.dict_size)); 249 buffer = xmalloc(MIN(header.dst_size, header.dict_size));
249 250
250 num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); 251 {
251 p = xmalloc(num_probs * sizeof(*p)); 252 int num_probs;
252 num_probs += LZMA_LITERAL - LZMA_BASE_SIZE; 253
253 for (i = 0; i < num_probs; i++) 254 num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
254 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; 255 p = xmalloc(num_probs * sizeof(*p));
256 num_probs += LZMA_LITERAL - LZMA_BASE_SIZE;
257 for (i = 0; i < num_probs; i++)
258 p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
259 }
255 260
256 rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */ 261 rc = rc_init(src_fd); /*, RC_BUFFER_SIZE); */
257 262
@@ -310,6 +315,7 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
310 goto one_byte2; 315 goto one_byte2;
311#endif 316#endif
312 } else { 317 } else {
318 int num_bits;
313 int offset; 319 int offset;
314 uint16_t *prob2; 320 uint16_t *prob2;
315#define prob_len prob2 321#define prob_len prob2
@@ -440,6 +446,9 @@ unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst
440 } 446 }
441 len--; 447 len--;
442 } while (len != 0 && buffer_pos < header.dst_size); 448 } while (len != 0 && buffer_pos < header.dst_size);
449 /* FIXME: ...........^^^^^
450 * shouldn't it be "global_pos + buffer_pos < header.dst_size"?
451 */
443 } 452 }
444 } 453 }
445 454
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index 54d910431..ba43bb073 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -243,7 +243,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
243 * or not first block (false positive, it's not .gz/.bz2!) */ 243 * or not first block (false positive, it's not .gz/.bz2!) */
244 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) 244 if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0)
245 goto err; 245 goto err;
246 if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0) 246 if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 0) != 0)
247 err: 247 err:
248 bb_error_msg_and_die("invalid tar magic"); 248 bb_error_msg_and_die("invalid tar magic");
249 archive_handle->offset = 0; 249 archive_handle->offset = 0;
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index b11bf46af..e49eab409 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -120,7 +120,7 @@ void FAST_FUNC open_transformer(int fd, const char *transform_prog)
120/* Used by e.g. rpm which gives us a fd without filename, 120/* Used by e.g. rpm which gives us a fd without filename,
121 * thus we can't guess the format from filename's extension. 121 * thus we can't guess the format from filename's extension.
122 */ 122 */
123int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected) 123int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed)
124{ 124{
125 union { 125 union {
126 uint8_t b[4]; 126 uint8_t b[4];
@@ -161,7 +161,7 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
161 } 161 }
162 162
163 /* No known magic seen */ 163 /* No known magic seen */
164 if (fail_if_not_detected) 164 if (fail_if_not_compressed)
165 bb_error_msg_and_die("no gzip" 165 bb_error_msg_and_die("no gzip"
166 IF_FEATURE_SEAMLESS_BZ2("/bzip2") 166 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
167 IF_FEATURE_SEAMLESS_XZ("/xz") 167 IF_FEATURE_SEAMLESS_XZ("/xz")
@@ -182,7 +182,7 @@ int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected)
182 return 0; 182 return 0;
183} 183}
184 184
185int FAST_FUNC open_zipped(const char *fname) 185int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed)
186{ 186{
187 int fd; 187 int fd;
188 188
@@ -202,7 +202,7 @@ int FAST_FUNC open_zipped(const char *fname)
202 || (ENABLE_FEATURE_SEAMLESS_BZ2) 202 || (ENABLE_FEATURE_SEAMLESS_BZ2)
203 || (ENABLE_FEATURE_SEAMLESS_XZ) 203 || (ENABLE_FEATURE_SEAMLESS_XZ)
204 ) { 204 ) {
205 setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1); 205 setup_unzip_on_fd(fd, fail_if_not_compressed);
206 } 206 }
207 207
208 return fd; 208 return fd;
@@ -215,7 +215,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
215 int fd; 215 int fd;
216 char *image; 216 char *image;
217 217
218 fd = open_zipped(fname); 218 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0);
219 if (fd < 0) 219 if (fd < 0)
220 return NULL; 220 return NULL;
221 221
diff --git a/archival/rpm.c b/archival/rpm.c
index 885eddd64..105394481 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -122,7 +122,7 @@ static void extract_cpio(int fd, const char *source_rpm)
122 archive_handle->src_fd = fd; 122 archive_handle->src_fd = fd;
123 /*archive_handle->offset = 0; - init_handle() did it */ 123 /*archive_handle->offset = 0; - init_handle() did it */
124 124
125 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1); 125 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1);
126 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 126 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
127 continue; 127 continue;
128} 128}
diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c
index 61adde795..7057570f5 100644
--- a/archival/rpm2cpio.c
+++ b/archival/rpm2cpio.c
@@ -80,7 +80,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
80 // signal(SIGCHLD, check_errors_in_children); 80 // signal(SIGCHLD, check_errors_in_children);
81 81
82 /* This works, but doesn't report uncompress errors (they happen in child) */ 82 /* This works, but doesn't report uncompress errors (they happen in child) */
83 setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1); 83 setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1);
84 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) 84 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
85 bb_error_msg_and_die("error unpacking"); 85 bb_error_msg_and_die("error unpacking");
86 86
diff --git a/archival/tar.c b/archival/tar.c
index d7938c09e..f2e4bedbe 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1143,7 +1143,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1143 && flags == O_RDONLY 1143 && flags == O_RDONLY
1144 && !(opt & OPT_ANY_COMPRESS) 1144 && !(opt & OPT_ANY_COMPRESS)
1145 ) { 1145 ) {
1146 tar_handle->src_fd = open_zipped(tar_filename); 1146 tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0);
1147 if (tar_handle->src_fd < 0) 1147 if (tar_handle->src_fd < 0)
1148 bb_perror_msg_and_die("can't open '%s'", tar_filename); 1148 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1149 } else { 1149 } else {
diff --git a/coreutils/catv.c b/coreutils/catv.c
index e3499c597..6bb73ba63 100644
--- a/coreutils/catv.c
+++ b/coreutils/catv.c
@@ -20,20 +20,22 @@
20 20
21#include "libbb.h" 21#include "libbb.h"
22 22
23int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
24int catv_main(int argc UNUSED_PARAM, char **argv)
25{
26 int retval = EXIT_SUCCESS;
27 int fd;
28 unsigned opts;
29#define CATV_OPT_e (1<<0) 23#define CATV_OPT_e (1<<0)
30#define CATV_OPT_t (1<<1) 24#define CATV_OPT_t (1<<1)
31#define CATV_OPT_v (1<<2) 25#define CATV_OPT_v (1<<2)
32 typedef char BUG_const_mismatch[ 26struct BUG_const_mismatch {
27 char BUG_const_mismatch[
33 CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS 28 CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS
34 ? 1 : -1 29 ? 1 : -1
35 ]; 30 ];
31};
36 32
33int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
34int catv_main(int argc UNUSED_PARAM, char **argv)
35{
36 int retval = EXIT_SUCCESS;
37 int fd;
38 unsigned opts;
37 opts = getopt32(argv, "etv"); 39 opts = getopt32(argv, "etv");
38 argv += optind; 40 argv += optind;
39#if 0 /* These consts match, we can just pass "opts" to visible() */ 41#if 0 /* These consts match, we can just pass "opts" to visible() */
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 166473d4d..1b63be56d 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -1032,7 +1032,7 @@ static void scan_and_display_dirs_recur(struct dnode **dn, int first)
1032 } 1032 }
1033 subdnp = scan_one_dir((*dn)->fullname, &nfiles); 1033 subdnp = scan_one_dir((*dn)->fullname, &nfiles);
1034#if ENABLE_DESKTOP 1034#if ENABLE_DESKTOP
1035 if ((G.all_fmt & STYLE_MASK) == STYLE_LONG) 1035 if ((G.all_fmt & STYLE_MASK) == STYLE_LONG || (G.all_fmt & LIST_BLOCKS))
1036 printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); 1036 printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp));
1037#endif 1037#endif
1038 if (nfiles > 0) { 1038 if (nfiles > 0) {
diff --git a/coreutils/shuf.c b/coreutils/shuf.c
new file mode 100644
index 000000000..6d0a68fc1
--- /dev/null
+++ b/coreutils/shuf.c
@@ -0,0 +1,153 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * shuf: Write a random permutation of the input lines to standard output.
4 *
5 * Copyright (C) 2014 by Bartosz Golaszewski <bartekgola@gmail.com>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10//config:config SHUF
11//config: bool "shuf"
12//config: default y
13//config: help
14//config: Generate random permutations
15
16//kbuild:lib-$(CONFIG_SHUF) += shuf.o
17//applet:IF_SHUF(APPLET_NOEXEC(shuf, shuf, BB_DIR_USR_BIN, BB_SUID_DROP, shuf))
18
19//usage:#define shuf_trivial_usage
20//usage: "[-e|-i L-H] [-n NUM] [-o FILE] [-z] [FILE|ARG...]"
21//usage:#define shuf_full_usage "\n\n"
22//usage: "Randomly permute lines\n"
23//usage: "\n -e Treat ARGs as lines"
24//usage: "\n -i L-H Treat numbers L-H as lines"
25//usage: "\n -n NUM Output at most NUM lines"
26//usage: "\n -o FILE Write to FILE, not standard output"
27//usage: "\n -z End lines with zero byte, not newline"
28
29#include "libbb.h"
30
31/* This is a NOEXEC applet. Be very careful! */
32
33#define OPT_e (1 << 0)
34#define OPT_i (1 << 1)
35#define OPT_n (1 << 2)
36#define OPT_o (1 << 3)
37#define OPT_z (1 << 4)
38#define OPT_STR "ei:n:o:z"
39
40/*
41 * Use the Fisher-Yates shuffle algorithm on an array of lines.
42 */
43static void shuffle_lines(char **lines, unsigned numlines)
44{
45 unsigned i;
46 unsigned r;
47 char *tmp;
48
49 srand(monotonic_us());
50
51 for (i = numlines-1; i > 0; i--) {
52 r = rand();
53 /* RAND_MAX can be as small as 32767 */
54 if (i > RAND_MAX)
55 r ^= rand() << 15;
56 r %= i;
57 tmp = lines[i];
58 lines[i] = lines[r];
59 lines[r] = tmp;
60 }
61}
62
63int shuf_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
64int shuf_main(int argc, char **argv)
65{
66 unsigned opts;
67 char *opt_i_str, *opt_n_str, *opt_o_str;
68 unsigned i;
69 char **lines;
70 unsigned numlines;
71 char eol;
72
73 opt_complementary = "e--i:i--e"; /* mutually exclusive */
74 opts = getopt32(argv, OPT_STR, &opt_i_str, &opt_n_str, &opt_o_str);
75
76 argc -= optind;
77 argv += optind;
78
79 /* Prepare lines for shuffling - either: */
80 if (opts & OPT_e) {
81 /* make lines from command-line arguments */
82 numlines = argc;
83 lines = argv;
84 } else
85 if (opts & OPT_i) {
86 /* create a range of numbers */
87 char *dash;
88 unsigned lo, hi;
89
90 dash = strchr(opt_i_str, '-');
91 if (!dash) {
92 bb_error_msg_and_die("bad range '%s'", opt_i_str);
93 }
94 *dash = '\0';
95 lo = xatou(opt_i_str);
96 hi = xatou(dash + 1);
97 *dash = '-';
98 if (hi < lo) {
99 bb_error_msg_and_die("bad range '%s'", opt_i_str);
100 }
101
102 numlines = (hi+1) - lo;
103 lines = xmalloc(numlines * sizeof(lines[0]));
104 for (i = 0; i < numlines; i++) {
105 lines[i] = (char*)(uintptr_t)lo;
106 lo++;
107 }
108 } else {
109 /* default - read lines from stdin or the input file */
110 FILE *fp;
111
112 if (argc > 1)
113 bb_show_usage();
114
115 fp = xfopen_stdin(argv[0] ? argv[0] : "-");
116 lines = NULL;
117 numlines = 0;
118 for (;;) {
119 char *line = xmalloc_fgetline(fp);
120 if (!line)
121 break;
122 lines = xrealloc_vector(lines, 6, numlines);
123 lines[numlines++] = line;
124 }
125 fclose_if_not_stdin(fp);
126 }
127
128 if (numlines != 0)
129 shuffle_lines(lines, numlines);
130
131 if (opts & OPT_o)
132 xmove_fd(xopen(opt_o_str, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO);
133
134 if (opts & OPT_n) {
135 unsigned maxlines;
136 maxlines = xatou(opt_n_str);
137 if (numlines > maxlines)
138 numlines = maxlines;
139 }
140
141 eol = '\n';
142 if (opts & OPT_z)
143 eol = '\0';
144
145 for (i = 0; i < numlines; i++) {
146 if (opts & OPT_i)
147 printf("%u%c", (unsigned)(uintptr_t)lines[i], eol);
148 else
149 printf("%s%c", lines[i], eol);
150 }
151
152 fflush_stdout_and_exit(EXIT_SUCCESS);
153}
diff --git a/coreutils/uname.c b/coreutils/uname.c
index b4827de25..56d985eb0 100644
--- a/coreutils/uname.c
+++ b/coreutils/uname.c
@@ -49,16 +49,18 @@
49 */ 49 */
50 50
51//usage:#define uname_trivial_usage 51//usage:#define uname_trivial_usage
52//usage: "[-amnrspv]" 52//usage: "[-amnrspvio]"
53//usage:#define uname_full_usage "\n\n" 53//usage:#define uname_full_usage "\n\n"
54//usage: "Print system information\n" 54//usage: "Print system information\n"
55//usage: "\n -a Print all" 55//usage: "\n -a Print all"
56//usage: "\n -m The machine (hardware) type" 56//usage: "\n -m The machine (hardware) type"
57//usage: "\n -n Hostname" 57//usage: "\n -n Hostname"
58//usage: "\n -r OS release" 58//usage: "\n -r Kernel release"
59//usage: "\n -s OS name (default)" 59//usage: "\n -s Kernel name (default)"
60//usage: "\n -p Processor type" 60//usage: "\n -p Processor type"
61//usage: "\n -v OS version" 61//usage: "\n -v Kernel version"
62//usage: "\n -i The hardware platform"
63//usage: "\n -o OS name"
62//usage: 64//usage:
63//usage:#define uname_example_usage 65//usage:#define uname_example_usage
64//usage: "$ uname -a\n" 66//usage: "$ uname -a\n"
diff --git a/examples/var_service/README b/examples/var_service/README
index 06817c8bc..9ad1b2581 100644
--- a/examples/var_service/README
+++ b/examples/var_service/README
@@ -9,6 +9,15 @@ env - PATH=... <other vars=...> runsvdir /var/service &
9from one of system startup scripts. (Google "man runsvdir" and "man runsv" 9from one of system startup scripts. (Google "man runsvdir" and "man runsv"
10for more info about these tools). 10for more info about these tools).
11 11
12You can try or debug an individual service by running its SERVICE_DIR/run script.
13In this case, its stdout and stderr go to your terminal.
14
15You can also run "runsv SERVICE_DIR", which runs both the service
16and its logger service (SERVICE_DIR/log/run) if logger service exists.
17If logger service exists, the output will go to it instead of the terminal.
18
19"runsvdir DIR" merely runs "runsv SERVICE_DIR" for every subdirectory in DIR.
20
12Some existing examples: 21Some existing examples:
13 22
14var_service/dhcp_if - 23var_service/dhcp_if -
@@ -47,8 +56,8 @@ This even works while fw service runs: if dhcp signals fw to (re)start
47while fw runs, fw will not stop after its execution, but will re-execute once, 56while fw runs, fw will not stop after its execution, but will re-execute once,
48picking up dhcp's new configuration. 57picking up dhcp's new configuration.
49This is achieved very simply by having 58This is achieved very simply by having
50# Make ourself one-shot 59 # Make ourself one-shot
51sv o . 60 sv o .
52at the very beginning of fw/run script, not at the end. 61at the very beginning of fw/run script, not at the end.
53Therefore, any "sv u /var/run/service/fw" command by any other 62Therefore, any "sv u /var/run/service/fw" command by any other
54script "undoes" o(ne-shot) command if fw still runs, thus 63script "undoes" o(ne-shot) command if fw still runs, thus
diff --git a/examples/var_service/dhcp_if/README b/examples/var_service/dhcp_if/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/dhcp_if/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/dhcp_if_pinger/README b/examples/var_service/dhcp_if_pinger/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/dhcp_if_pinger/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ftpd/README b/examples/var_service/ftpd/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/ftpd/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/fw/README b/examples/var_service/fw/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/fw/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/getty_tty1/README b/examples/var_service/getty_tty1/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/getty_tty1/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/gpm/README b/examples/var_service/gpm/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/gpm/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/httpd/README b/examples/var_service/httpd/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/httpd/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ifplugd_if/README b/examples/var_service/ifplugd_if/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/ifplugd_if/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/inetd/README b/examples/var_service/inetd/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/inetd/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/nmeter/README b/examples/var_service/nmeter/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/nmeter/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/ntpd/README b/examples/var_service/ntpd/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/ntpd/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/examples/var_service/tftpd/README b/examples/var_service/tftpd/README
new file mode 100644
index 000000000..4ddccb22d
--- /dev/null
+++ b/examples/var_service/tftpd/README
@@ -0,0 +1,5 @@
1The real README file is one directory up.
2
3This directory's run script can have useful comments.
4If it doesn't but you feel it should, please send a patch
5to busybox's mailing list.
diff --git a/findutils/find.c b/findutils/find.c
index 5d5e24bfb..6d34f4d68 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -402,36 +402,6 @@ struct globals {
402 G.recurse_flags = ACTION_RECURSE; \ 402 G.recurse_flags = ACTION_RECURSE; \
403} while (0) 403} while (0)
404 404
405#if ENABLE_FEATURE_FIND_EXEC
406static unsigned count_subst(const char *str)
407{
408 unsigned count = 0;
409 while ((str = strstr(str, "{}")) != NULL) {
410 count++;
411 str++;
412 }
413 return count;
414}
415
416
417static char* subst(const char *src, unsigned count, const char* filename)
418{
419 char *buf, *dst, *end;
420 size_t flen = strlen(filename);
421 /* we replace each '{}' with filename: growth by strlen-2 */
422 buf = dst = xmalloc(strlen(src) + count*(flen-2) + 1);
423 while ((end = strstr(src, "{}"))) {
424 memcpy(dst, src, end - src);
425 dst += end - src;
426 src = end + 2;
427 memcpy(dst, filename, flen);
428 dst += flen;
429 }
430 strcpy(dst, src);
431 return buf;
432}
433#endif
434
435/* Return values of ACTFs ('action functions') are a bit mask: 405/* Return values of ACTFs ('action functions') are a bit mask:
436 * bit 1=1: prune (use SKIP constant for setting it) 406 * bit 1=1: prune (use SKIP constant for setting it)
437 * bit 0=1: matched successfully (TRUE) 407 * bit 0=1: matched successfully (TRUE)
@@ -615,7 +585,7 @@ ACTF(exec)
615 char *argv[ap->exec_argc + 1]; 585 char *argv[ap->exec_argc + 1];
616#endif 586#endif
617 for (i = 0; i < ap->exec_argc; i++) 587 for (i = 0; i < ap->exec_argc; i++)
618 argv[i] = subst(ap->exec_argv[i], ap->subst_count[i], fileName); 588 argv[i] = xmalloc_substitute_string(ap->exec_argv[i], ap->subst_count[i], "{}", fileName);
619 argv[i] = NULL; /* terminate the list */ 589 argv[i] = NULL; /* terminate the list */
620 590
621 rc = spawn_and_wait(argv); 591 rc = spawn_and_wait(argv);
@@ -1093,7 +1063,7 @@ static action*** parse_params(char **argv)
1093 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); 1063 ap->subst_count = xmalloc(ap->exec_argc * sizeof(int));
1094 i = ap->exec_argc; 1064 i = ap->exec_argc;
1095 while (i--) 1065 while (i--)
1096 ap->subst_count[i] = count_subst(ap->exec_argv[i]); 1066 ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}");
1097 } 1067 }
1098#endif 1068#endif
1099#if ENABLE_FEATURE_FIND_PAREN 1069#if ENABLE_FEATURE_FIND_PAREN
diff --git a/findutils/grep.c b/findutils/grep.c
index f5f95cb95..615cacac4 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -383,6 +383,8 @@ static int grep_file(FILE *file)
383 } else { 383 } else {
384#if ENABLE_EXTRA_COMPAT 384#if ENABLE_EXTRA_COMPAT
385 unsigned start_pos; 385 unsigned start_pos;
386#else
387 int match_flg;
386#endif 388#endif
387 char *match_at; 389 char *match_at;
388 390
@@ -400,6 +402,7 @@ static int grep_file(FILE *file)
400#if !ENABLE_EXTRA_COMPAT 402#if !ENABLE_EXTRA_COMPAT
401 gl->matched_range.rm_so = 0; 403 gl->matched_range.rm_so = 0;
402 gl->matched_range.rm_eo = 0; 404 gl->matched_range.rm_eo = 0;
405 match_flg = 0;
403#else 406#else
404 start_pos = 0; 407 start_pos = 0;
405#endif 408#endif
@@ -408,7 +411,7 @@ static int grep_file(FILE *file)
408//bb_error_msg("'%s' start_pos:%d line_len:%d", match_at, start_pos, line_len); 411//bb_error_msg("'%s' start_pos:%d line_len:%d", match_at, start_pos, line_len);
409 if ( 412 if (
410#if !ENABLE_EXTRA_COMPAT 413#if !ENABLE_EXTRA_COMPAT
411 regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, 0) == 0 414 regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, match_flg) == 0
412#else 415#else
413 re_search(&gl->compiled_regex, match_at, line_len, 416 re_search(&gl->compiled_regex, match_at, line_len,
414 start_pos, /*range:*/ line_len, 417 start_pos, /*range:*/ line_len,
@@ -423,13 +426,15 @@ static int grep_file(FILE *file)
423 found = 1; 426 found = 1;
424 } else { 427 } else {
425 char c = ' '; 428 char c = ' ';
426 if (gl->matched_range.rm_so) 429 if (match_at > line || gl->matched_range.rm_so != 0) {
427 c = match_at[gl->matched_range.rm_so - 1]; 430 c = match_at[gl->matched_range.rm_so - 1];
431 }
428 if (!isalnum(c) && c != '_') { 432 if (!isalnum(c) && c != '_') {
429 c = match_at[gl->matched_range.rm_eo]; 433 c = match_at[gl->matched_range.rm_eo];
430 if (!c || (!isalnum(c) && c != '_')) { 434 }
431 found = 1; 435 if (!isalnum(c) && c != '_') {
432 } else { 436 found = 1;
437 } else {
433 /* 438 /*
434 * Why check gl->matched_range.rm_eo? 439 * Why check gl->matched_range.rm_eo?
435 * Zero-length match makes -w skip the line: 440 * Zero-length match makes -w skip the line:
@@ -438,17 +443,17 @@ static int grep_file(FILE *file)
438 * Without such check, we can loop forever. 443 * Without such check, we can loop forever.
439 */ 444 */
440#if !ENABLE_EXTRA_COMPAT 445#if !ENABLE_EXTRA_COMPAT
441 if (gl->matched_range.rm_eo != 0) { 446 if (gl->matched_range.rm_eo != 0) {
442 match_at += gl->matched_range.rm_eo; 447 match_at += gl->matched_range.rm_eo;
443 goto opt_w_again; 448 match_flg |= REG_NOTBOL;
444 } 449 goto opt_w_again;
450 }
445#else 451#else
446 if (gl->matched_range.rm_eo > start_pos) { 452 if (gl->matched_range.rm_eo > start_pos) {
447 start_pos = gl->matched_range.rm_eo; 453 start_pos = gl->matched_range.rm_eo;
448 goto opt_w_again; 454 goto opt_w_again;
449 }
450#endif
451 } 455 }
456#endif
452 } 457 }
453 } 458 }
454 } 459 }
diff --git a/findutils/xargs.c b/findutils/xargs.c
index 0d1bb43fc..0ba5b566d 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -53,6 +53,13 @@
53//config: Support -0: input items are terminated by a NUL character 53//config: Support -0: input items are terminated by a NUL character
54//config: instead of whitespace, and the quotes and backslash 54//config: instead of whitespace, and the quotes and backslash
55//config: are not special. 55//config: are not special.
56//config:
57//config:config FEATURE_XARGS_SUPPORT_REPL_STR
58//config: bool "Enable -I STR: string to replace"
59//config: default y
60//config: depends on XARGS
61//config: help
62//config: Support -I STR and -i[STR] options.
56 63
57//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs)) 64//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs))
58 65
@@ -85,19 +92,22 @@
85 92
86struct globals { 93struct globals {
87 char **args; 94 char **args;
95#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
96 char **argv;
97 const char *repl_str;
98 char eol_ch;
99#endif
88 const char *eof_str; 100 const char *eof_str;
89 int idx; 101 int idx;
90} FIX_ALIASING; 102} FIX_ALIASING;
91#define G (*(struct globals*)&bb_common_bufsiz1) 103#define G (*(struct globals*)&bb_common_bufsiz1)
92#define INIT_G() do { \ 104#define INIT_G() do { \
93 G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ 105 G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \
106 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \
107 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \
94} while (0) 108} while (0)
95 109
96 110
97/*
98 * This function has special algorithm.
99 * Don't use fork and include to main!
100 */
101static int xargs_exec(void) 111static int xargs_exec(void)
102{ 112{
103 int status; 113 int status;
@@ -301,7 +311,7 @@ static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
301 c = '\0'; 311 c = '\0';
302 } 312 }
303 *p++ = c; 313 *p++ = c;
304 if (c == '\0') { /* word's delimiter or EOF detected */ 314 if (c == '\0') { /* NUL or EOF detected */
305 /* A full word is loaded */ 315 /* A full word is loaded */
306 store_param(s); 316 store_param(s);
307 dbg_msg("args[]:'%s'", s); 317 dbg_msg("args[]:'%s'", s);
@@ -323,10 +333,71 @@ static char* FAST_FUNC process0_stdin(int n_max_chars, int n_max_arg, char *buf)
323} 333}
324#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */ 334#endif /* FEATURE_XARGS_SUPPORT_ZERO_TERM */
325 335
336#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
337/*
338 * Used if -I<repl> was specified.
339 * In this mode, words aren't appended to PROG ARGS.
340 * Instead, entire input line is read, then <repl> string
341 * in every PROG and ARG is replaced with the line:
342 * echo -e "ho ho\nhi" | xargs -I_ cmd __ _
343 * results in "cmd 'ho hoho ho' 'ho ho'"; "cmd 'hihi' 'hi'".
344 * -n MAX_ARGS seems to be ignored.
345 * Tested with GNU findutils 4.5.10.
346 */
347//FIXME: n_max_chars is not handled the same way as in GNU findutils.
348//FIXME: quoting is not implemented.
349static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg UNUSED_PARAM, char *buf)
350{
351 int i;
352 char *end, *p;
353
354 /* Free strings from last invocation, if any */
355 for (i = 0; G.args && G.args[i]; i++)
356 if (G.args[i] != G.argv[i])
357 free(G.args[i]);
358
359 end = buf + n_max_chars;
360 p = buf;
361
362 while (1) {
363 int c = getchar();
364 if (c == EOF || c == G.eol_ch) {
365 if (p == buf)
366 goto ret; /* empty line */
367 c = '\0';
368 }
369 *p++ = c;
370 if (c == '\0') { /* EOL or EOF detected */
371 i = 0;
372 while (G.argv[i]) {
373 char *arg = G.argv[i];
374 int count = count_strstr(arg, G.repl_str);
375 if (count != 0)
376 arg = xmalloc_substitute_string(arg, count, G.repl_str, buf);
377 store_param(arg);
378 dbg_msg("args[]:'%s'", arg);
379 i++;
380 }
381 p = buf;
382 goto ret;
383 }
384 if (p == end) {
385 goto ret;
386 }
387 }
388 ret:
389 *p = '\0';
390 /* store_param(NULL) - caller will do it */
391 dbg_msg("return:'%s'", buf);
392 return buf;
393}
394#endif
395
326#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION 396#if ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
327/* Prompt the user for a response, and 397/* Prompt the user for a response, and
328 if the user responds affirmatively, return true; 398 * if user responds affirmatively, return true;
329 otherwise, return false. Uses "/dev/tty", not stdin. */ 399 * otherwise, return false. Uses "/dev/tty", not stdin.
400 */
330static int xargs_ask_confirmation(void) 401static int xargs_ask_confirmation(void)
331{ 402{
332 FILE *tty_stream; 403 FILE *tty_stream;
@@ -360,6 +431,9 @@ static int xargs_ask_confirmation(void)
360//usage: "\n -e[STR] STR stops input processing" 431//usage: "\n -e[STR] STR stops input processing"
361//usage: "\n -n N Pass no more than N args to PROG" 432//usage: "\n -n N Pass no more than N args to PROG"
362//usage: "\n -s N Pass command line of no more than N bytes" 433//usage: "\n -s N Pass command line of no more than N bytes"
434//usage: IF_FEATURE_XARGS_SUPPORT_REPL_STR(
435//usage: "\n -I STR Replace STR within PROG ARGS with input line"
436//usage: )
363//usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT( 437//usage: IF_FEATURE_XARGS_SUPPORT_TERMOPT(
364//usage: "\n -x Exit if size is exceeded" 438//usage: "\n -x Exit if size is exceeded"
365//usage: ) 439//usage: )
@@ -378,6 +452,8 @@ enum {
378 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,) 452 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
379 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,) 453 IF_FEATURE_XARGS_SUPPORT_TERMOPT( OPTBIT_TERMINATE ,)
380 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,) 454 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( OPTBIT_ZEROTERM ,)
455 IF_FEATURE_XARGS_SUPPORT_REPL_STR( OPTBIT_REPLSTR ,)
456 IF_FEATURE_XARGS_SUPPORT_REPL_STR( OPTBIT_REPLSTR1 ,)
381 457
382 OPT_VERBOSE = 1 << OPTBIT_VERBOSE , 458 OPT_VERBOSE = 1 << OPTBIT_VERBOSE ,
383 OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY , 459 OPT_NO_EMPTY = 1 << OPTBIT_NO_EMPTY ,
@@ -388,11 +464,14 @@ enum {
388 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0, 464 OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
389 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0, 465 OPT_TERMINATE = IF_FEATURE_XARGS_SUPPORT_TERMOPT( (1 << OPTBIT_TERMINATE )) + 0,
390 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0, 466 OPT_ZEROTERM = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( (1 << OPTBIT_ZEROTERM )) + 0,
467 OPT_REPLSTR = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR )) + 0,
468 OPT_REPLSTR1 = IF_FEATURE_XARGS_SUPPORT_REPL_STR( (1 << OPTBIT_REPLSTR1 )) + 0,
391}; 469};
392#define OPTION_STR "+trn:s:e::E:" \ 470#define OPTION_STR "+trn:s:e::E:" \
393 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \ 471 IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
394 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \ 472 IF_FEATURE_XARGS_SUPPORT_TERMOPT( "x") \
395 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") 473 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( "0") \
474 IF_FEATURE_XARGS_SUPPORT_REPL_STR( "I:i::")
396 475
397int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 476int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
398int xargs_main(int argc, char **argv) 477int xargs_main(int argc, char **argv)
@@ -405,7 +484,8 @@ int xargs_main(int argc, char **argv)
405 unsigned opt; 484 unsigned opt;
406 int n_max_chars; 485 int n_max_chars;
407 int n_max_arg; 486 int n_max_arg;
408#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM 487#if ENABLE_FEATURE_XARGS_SUPPORT_ZERO_TERM \
488 || ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
409 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin; 489 char* FAST_FUNC (*read_args)(int, int, char*) = process_stdin;
410#else 490#else
411#define read_args process_stdin 491#define read_args process_stdin
@@ -419,7 +499,10 @@ int xargs_main(int argc, char **argv)
419 "no-run-if-empty\0" No_argument "r" 499 "no-run-if-empty\0" No_argument "r"
420 ; 500 ;
421#endif 501#endif
422 opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); 502 opt = getopt32(argv, OPTION_STR,
503 &max_args, &max_chars, &G.eof_str, &G.eof_str
504 IF_FEATURE_XARGS_SUPPORT_REPL_STR(, &G.repl_str, &G.repl_str)
505 );
423 506
424 /* -E ""? You may wonder why not just omit -E? 507 /* -E ""? You may wonder why not just omit -E?
425 * This is used for portability: 508 * This is used for portability:
@@ -427,8 +510,10 @@ int xargs_main(int argc, char **argv)
427 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0') 510 if ((opt & OPT_EOF_STRING1) && G.eof_str[0] == '\0')
428 G.eof_str = NULL; 511 G.eof_str = NULL;
429 512
430 if (opt & OPT_ZEROTERM) 513 if (opt & OPT_ZEROTERM) {
431 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin); 514 IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin;)
515 IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\0';)
516 }
432 517
433 argv += optind; 518 argv += optind;
434 argc -= optind; 519 argc -= optind;
@@ -486,20 +571,36 @@ int xargs_main(int argc, char **argv)
486 /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ 571 /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */
487 } 572 }
488 573
489 /* Allocate pointers for execvp */ 574#if ENABLE_FEATURE_XARGS_SUPPORT_REPL_STR
490 /* We can statically allocate (argc + n_max_arg + 1) elements 575 if (opt & (OPT_REPLSTR | OPT_REPLSTR1)) {
491 * and do not bother with resizing args[], but on 64-bit machines 576 /*
492 * this results in args[] vector which is ~8 times bigger 577 * -I<str>:
493 * than n_max_chars! That is, with n_max_chars == 20k, 578 * Unmodified args are kept in G.argv[i],
494 * args[] will take 160k (!), which will most likely be 579 * G.args[i] receives malloced G.argv[i] with <str> replaced
495 * almost entirely unused. 580 * with input line. Setting this up:
496 */ 581 */
497 /* See store_param() for matching 256-step growth logic */ 582 G.args = NULL;
498 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff)); 583 G.argv = argv;
499 584 argc = 0;
500 /* Store the command to be executed, part 1 */ 585 read_args = process_stdin_with_replace;
501 for (i = 0; argv[i]; i++) 586 } else
502 G.args[i] = argv[i]; 587#endif
588 {
589 /* Allocate pointers for execvp.
590 * We can statically allocate (argc + n_max_arg + 1) elements
591 * and do not bother with resizing args[], but on 64-bit machines
592 * this results in args[] vector which is ~8 times bigger
593 * than n_max_chars! That is, with n_max_chars == 20k,
594 * args[] will take 160k (!), which will most likely be
595 * almost entirely unused.
596 *
597 * See store_param() for matching 256-step growth logic
598 */
599 G.args = xmalloc(sizeof(G.args[0]) * ((argc + 0xff) & ~0xff));
600 /* Store the command to be executed, part 1 */
601 for (i = 0; argv[i]; i++)
602 G.args[i] = argv[i];
603 }
503 604
504 while (1) { 605 while (1) {
505 char *rem; 606 char *rem;
diff --git a/include/libbb.h b/include/libbb.h
index e516f0ee3..1cc2a48b9 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -663,6 +663,8 @@ char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC;
663void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; 663void overlapping_strcpy(char *dst, const char *src) FAST_FUNC;
664char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; 664char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC;
665char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; 665char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC;
666unsigned count_strstr(const char *str, const char *sub) FAST_FUNC;
667char *xmalloc_substitute_string(const char *src, int count, const char *sub, const char *repl) FAST_FUNC;
666/* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc. 668/* Guaranteed to NOT be a macro (smallest code). Saves nearly 2k on uclibc.
667 * But potentially slow, don't use in one-billion-times loops */ 669 * But potentially slow, don't use in one-billion-times loops */
668int bb_putchar(int ch) FAST_FUNC; 670int bb_putchar(int ch) FAST_FUNC;
@@ -749,12 +751,12 @@ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAS
749 751
750#if SEAMLESS_COMPRESSION 752#if SEAMLESS_COMPRESSION
751/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ 753/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */
752extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; 754extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC;
753/* Autodetects .gz etc */ 755/* Autodetects .gz etc */
754extern int open_zipped(const char *fname) FAST_FUNC; 756extern int open_zipped(const char *fname, int fail_if_not_compressed) FAST_FUNC;
755#else 757#else
756# define setup_unzip_on_fd(...) (0) 758# define setup_unzip_on_fd(...) (0)
757# define open_zipped(fname) open((fname), O_RDONLY); 759# define open_zipped(fname, fail_if_not_compressed) open((fname), O_RDONLY);
758#endif 760#endif
759extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 761extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
760 762
diff --git a/init/init.c b/init/init.c
index d29328c36..de438be20 100644
--- a/init/init.c
+++ b/init/init.c
@@ -1135,7 +1135,9 @@ int init_main(int argc UNUSED_PARAM, char **argv)
1135 struct sigaction sa; 1135 struct sigaction sa;
1136 1136
1137 bb_signals(0 1137 bb_signals(0
1138#ifdef SIGPWR
1138 + (1 << SIGPWR) /* halt */ 1139 + (1 << SIGPWR) /* halt */
1140#endif
1139 + (1 << SIGUSR1) /* halt */ 1141 + (1 << SIGUSR1) /* halt */
1140 + (1 << SIGTERM) /* reboot */ 1142 + (1 << SIGTERM) /* reboot */
1141 + (1 << SIGUSR2) /* poweroff */ 1143 + (1 << SIGUSR2) /* poweroff */
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 44161a219..14b21f827 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -608,7 +608,11 @@ static void install_links(const char *busybox, int use_symbolic_links,
608 } 608 }
609} 609}
610# else 610# else
611# define install_links(x,y,z) ((void)0) 611static void install_links(const char *busybox UNUSED_PARAM,
612 int use_symbolic_links UNUSED_PARAM,
613 char *custom_install_dir UNUSED_PARAM)
614{
615}
612# endif 616# endif
613 617
614/* If we were called as "busybox..." */ 618/* If we were called as "busybox..." */
diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c
index 715535ef5..f11c2afb2 100644
--- a/libbb/inode_hash.c
+++ b/libbb/inode_hash.c
@@ -11,14 +11,23 @@
11#include "libbb.h" 11#include "libbb.h"
12 12
13typedef struct ino_dev_hash_bucket_struct { 13typedef struct ino_dev_hash_bucket_struct {
14 struct ino_dev_hash_bucket_struct *next;
15 ino_t ino; 14 ino_t ino;
16 dev_t dev; 15 dev_t dev;
16 /*
17 * Above fields can be 64-bit, while pointer may be 32-bit.
18 * Putting "next" field here may reduce size of this struct:
19 */
20 struct ino_dev_hash_bucket_struct *next;
21 /*
22 * Reportedly, on cramfs a file and a dir can have same ino.
23 * Need to also remember "file/dir" bit:
24 */
25 char isdir; /* bool */
17 char name[1]; 26 char name[1];
18} ino_dev_hashtable_bucket_t; 27} ino_dev_hashtable_bucket_t;
19 28
20#define HASH_SIZE 311 /* Should be prime */ 29#define HASH_SIZE 311u /* Should be prime */
21#define hash_inode(i) ((i) % HASH_SIZE) 30#define hash_inode(i) ((unsigned)(i) % HASH_SIZE)
22 31
23/* array of [HASH_SIZE] elements */ 32/* array of [HASH_SIZE] elements */
24static ino_dev_hashtable_bucket_t **ino_dev_hashtable; 33static ino_dev_hashtable_bucket_t **ino_dev_hashtable;
@@ -38,6 +47,7 @@ char* FAST_FUNC is_in_ino_dev_hashtable(const struct stat *statbuf)
38 while (bucket != NULL) { 47 while (bucket != NULL) {
39 if ((bucket->ino == statbuf->st_ino) 48 if ((bucket->ino == statbuf->st_ino)
40 && (bucket->dev == statbuf->st_dev) 49 && (bucket->dev == statbuf->st_dev)
50 && (bucket->isdir == !!S_ISDIR(statbuf->st_mode))
41 ) { 51 ) {
42 return bucket->name; 52 return bucket->name;
43 } 53 }
@@ -52,17 +62,18 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
52 int i; 62 int i;
53 ino_dev_hashtable_bucket_t *bucket; 63 ino_dev_hashtable_bucket_t *bucket;
54 64
55 i = hash_inode(statbuf->st_ino);
56 if (!name) 65 if (!name)
57 name = ""; 66 name = "";
58 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name)); 67 bucket = xmalloc(sizeof(ino_dev_hashtable_bucket_t) + strlen(name));
59 bucket->ino = statbuf->st_ino; 68 bucket->ino = statbuf->st_ino;
60 bucket->dev = statbuf->st_dev; 69 bucket->dev = statbuf->st_dev;
70 bucket->isdir = !!S_ISDIR(statbuf->st_mode);
61 strcpy(bucket->name, name); 71 strcpy(bucket->name, name);
62 72
63 if (!ino_dev_hashtable) 73 if (!ino_dev_hashtable)
64 ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable)); 74 ino_dev_hashtable = xzalloc(HASH_SIZE * sizeof(*ino_dev_hashtable));
65 75
76 i = hash_inode(statbuf->st_ino);
66 bucket->next = ino_dev_hashtable[i]; 77 bucket->next = ino_dev_hashtable[i];
67 ino_dev_hashtable[i] = bucket; 78 ino_dev_hashtable[i] = bucket;
68} 79}
@@ -72,13 +83,18 @@ void FAST_FUNC add_to_ino_dev_hashtable(const struct stat *statbuf, const char *
72void FAST_FUNC reset_ino_dev_hashtable(void) 83void FAST_FUNC reset_ino_dev_hashtable(void)
73{ 84{
74 int i; 85 int i;
75 ino_dev_hashtable_bucket_t *bucket; 86 ino_dev_hashtable_bucket_t *bucket, *next;
87
88 if (!ino_dev_hashtable)
89 return;
90
91 for (i = 0; i < HASH_SIZE; i++) {
92 bucket = ino_dev_hashtable[i];
76 93
77 for (i = 0; ino_dev_hashtable && i < HASH_SIZE; i++) { 94 while (bucket != NULL) {
78 while (ino_dev_hashtable[i] != NULL) { 95 next = bucket->next;
79 bucket = ino_dev_hashtable[i]->next; 96 free(bucket);
80 free(ino_dev_hashtable[i]); 97 bucket = next;
81 ino_dev_hashtable[i] = bucket;
82 } 98 }
83 } 99 }
84 free(ino_dev_hashtable); 100 free(ino_dev_hashtable);
diff --git a/libbb/loop.c b/libbb/loop.c
index 823fba079..c96c5e070 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -94,19 +94,19 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
94 94
95 /* Open the file. Barf if this doesn't work. */ 95 /* Open the file. Barf if this doesn't work. */
96 mode = ro ? O_RDONLY : O_RDWR; 96 mode = ro ? O_RDONLY : O_RDWR;
97 open_ffd:
97 ffd = open(file, mode); 98 ffd = open(file, mode);
98 if (ffd < 0) { 99 if (ffd < 0) {
99 if (mode != O_RDONLY) { 100 if (mode != O_RDONLY) {
100 mode = O_RDONLY; 101 mode = O_RDONLY;
101 ffd = open(file, mode); 102 goto open_ffd;
102 } 103 }
103 if (ffd < 0) 104 return -errno;
104 return -errno;
105 } 105 }
106 106
107 /* Find a loop device. */ 107 /* Find a loop device. */
108 try = *device ? *device : dev; 108 try = *device ? *device : dev;
109 /* 1048575 is a max possible minor number in Linux circa 2010 */ 109 /* 1048575 (0xfffff) is a max possible minor number in Linux circa 2010 */
110 for (i = 0; rc && i < 1048576; i++) { 110 for (i = 0; rc && i < 1048576; i++) {
111 sprintf(dev, LOOP_FORMAT, i); 111 sprintf(dev, LOOP_FORMAT, i);
112 112
@@ -121,7 +121,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
121 goto try_to_open; 121 goto try_to_open;
122 } 122 }
123 /* Ran out of block devices, return failure. */ 123 /* Ran out of block devices, return failure. */
124 rc = -ENOENT; 124 rc = -1;
125 break; 125 break;
126 } 126 }
127 try_to_open: 127 try_to_open:
@@ -131,8 +131,14 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
131 mode = O_RDONLY; 131 mode = O_RDONLY;
132 dfd = open(try, mode); 132 dfd = open(try, mode);
133 } 133 }
134 if (dfd < 0) 134 if (dfd < 0) {
135 if (errno == ENXIO) {
136 /* Happens if loop module is not loaded */
137 rc = -1;
138 break;
139 }
135 goto try_again; 140 goto try_again;
141 }
136 142
137 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo); 143 rc = ioctl(dfd, BB_LOOP_GET_STATUS, &loopinfo);
138 144
diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c
index 39ffa084f..bfc7030a8 100644
--- a/libbb/pw_encrypt.c
+++ b/libbb/pw_encrypt.c
@@ -142,7 +142,14 @@ char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
142 142
143char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) 143char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup)
144{ 144{
145 return xstrdup(crypt(clear, salt)); 145 char *s;
146
147 s = crypt(clear, salt);
148 /*
149 * glibc used to return "" on malformed salts (for example, ""),
150 * but since 2.17 it returns NULL.
151 */
152 return xstrdup(s ? s : "");
146} 153}
147 154
148#endif 155#endif
diff --git a/libbb/replace.c b/libbb/replace.c
new file mode 100644
index 000000000..8711f957d
--- /dev/null
+++ b/libbb/replace.c
@@ -0,0 +1,45 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8 */
9
10//kbuild:lib-y += replace.o
11
12#include "libbb.h"
13
14unsigned FAST_FUNC count_strstr(const char *str, const char *sub)
15{
16 size_t sub_len = strlen(sub);
17 unsigned count = 0;
18
19 while ((str = strstr(str, sub)) != NULL) {
20 count++;
21 str += sub_len;
22 }
23 return count;
24}
25
26char* FAST_FUNC xmalloc_substitute_string(const char *src, int count, const char *sub, const char *repl)
27{
28 char *buf, *dst, *end;
29 size_t sub_len = strlen(sub);
30 size_t repl_len = strlen(repl);
31
32 //dbg_msg("subst(s:'%s',count:%d,sub:'%s',repl:'%s'", src, count, sub, repl);
33
34 buf = dst = xmalloc(strlen(src) + count * ((int)repl_len - (int)sub_len) + 1);
35 /* we replace each sub with repl */
36 while ((end = strstr(src, sub)) != NULL) {
37 dst = mempcpy(dst, src, end - src);
38 dst = mempcpy(dst, repl, repl_len);
39 /*src = end + 1; - GNU findutils 4.5.10 doesn't do this... */
40 src = end + sub_len; /* but this. Try "xargs -Iaa echo aaa" */
41 }
42 strcpy(dst, src);
43 //dbg_msg("subst9:'%s'", buf);
44 return buf;
45}
diff --git a/loginutils/Config.src b/loginutils/Config.src
index b78d7c38e..fa2b4f8c0 100644
--- a/loginutils/Config.src
+++ b/loginutils/Config.src
@@ -223,13 +223,6 @@ config LOGIN_SESSION_AS_CHILD
223 almost always would want this to be set to Y, else PAM session 223 almost always would want this to be set to Y, else PAM session
224 will not be cleaned up. 224 will not be cleaned up.
225 225
226config PAM
227 bool "Support for PAM (Pluggable Authentication Modules)"
228 default n
229 depends on LOGIN
230 help
231 Use PAM in login(1) instead of direct access to password database.
232
233config LOGIN_SCRIPTS 226config LOGIN_SCRIPTS
234 bool "Support for login scripts" 227 bool "Support for login scripts"
235 depends on LOGIN 228 depends on LOGIN
diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c
index b5aa1d17b..9455b4e7a 100644
--- a/mailutils/sendmail.c
+++ b/mailutils/sendmail.c
@@ -15,7 +15,8 @@
15//usage: "Read email from stdin and send it\n" 15//usage: "Read email from stdin and send it\n"
16//usage: "\nStandard options:" 16//usage: "\nStandard options:"
17//usage: "\n -t Read additional recipients from message body" 17//usage: "\n -t Read additional recipients from message body"
18//usage: "\n -f SENDER Sender (required)" 18//usage: "\n -f SENDER For use in MAIL FROM:<sender>. Can be empty string"
19//usage: "\n Default: -auUSER, or username of current UID"
19//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" 20//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored"
20//usage: "\n -i -oi synonym. implied and ignored" 21//usage: "\n -i -oi synonym. implied and ignored"
21//usage: "\n" 22//usage: "\n"
@@ -40,6 +41,52 @@
40//usage: "\nUse makemime to create emails with attachments" 41//usage: "\nUse makemime to create emails with attachments"
41//usage: ) 42//usage: )
42 43
44/* Currently we don't sanitize or escape user-supplied SENDER and RECIPIENT_EMAILs.
45 * We may need to do so. For one, '.' in usernames seems to require escaping!
46 *
47 * From http://cr.yp.to/smtp/address.html:
48 *
49 * SMTP offers three ways to encode a character inside an address:
50 *
51 * "safe": the character, if it is not <>()[].,;:@, backslash,
52 * double-quote, space, or an ASCII control character;
53 * "quoted": the character, if it is not \012, \015, backslash,
54 * or double-quote; or
55 * "slashed": backslash followed by the character.
56 *
57 * An encoded box part is either (1) a sequence of one or more slashed
58 * or safe characters or (2) a double quote, a sequence of zero or more
59 * slashed or quoted characters, and a double quote. It represents
60 * the concatenation of the characters encoded inside it.
61 *
62 * For example, the encoded box parts
63 * angels
64 * \a\n\g\e\l\s
65 * "\a\n\g\e\l\s"
66 * "angels"
67 * "ang\els"
68 * all represent the 6-byte string "angels", and the encoded box parts
69 * a\,comma
70 * \a\,\c\o\m\m\a
71 * "a,comma"
72 * all represent the 7-byte string "a,comma".
73 *
74 * An encoded address contains
75 * the byte <;
76 * optionally, a route followed by a colon;
77 * an encoded box part, the byte @, and a domain; and
78 * the byte >.
79 *
80 * It represents an Internet mail address, given by concatenating
81 * the string represented by the encoded box part, the byte @,
82 * and the domain. For example, the encoded addresses
83 * <God@heaven.af.mil>
84 * <\God@heaven.af.mil>
85 * <"God"@heaven.af.mil>
86 * <@gateway.af.mil,@uucp.local:"\G\o\d"@heaven.af.mil>
87 * all represent the Internet mail address "God@heaven.af.mil".
88 */
89
43#include "libbb.h" 90#include "libbb.h"
44#include "mail.h" 91#include "mail.h"
45 92
@@ -163,7 +210,7 @@ int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
163int sendmail_main(int argc UNUSED_PARAM, char **argv) 210int sendmail_main(int argc UNUSED_PARAM, char **argv)
164{ 211{
165 char *opt_connect = opt_connect; 212 char *opt_connect = opt_connect;
166 char *opt_from; 213 char *opt_from = NULL;
167 char *s; 214 char *s;
168 llist_t *list = NULL; 215 llist_t *list = NULL;
169 char *host = sane_address(safe_gethostname()); 216 char *host = sane_address(safe_gethostname());
@@ -199,8 +246,8 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
199 G.fp0 = xfdopen_for_read(3); 246 G.fp0 = xfdopen_for_read(3);
200 247
201 // parse options 248 // parse options
202 // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list 249 // -v is a counter, -H and -S are mutually exclusive, -a is a list
203 opt_complementary = "vv:f:w+:H--S:S--H:a::"; 250 opt_complementary = "vv:w+:H--S:S--H:a::";
204 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect 251 // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect
205 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, 252 // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility,
206 // it is still under development. 253 // it is still under development.
@@ -279,7 +326,6 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
279 // we should start with modern EHLO 326 // we should start with modern EHLO
280 if (250 != smtp_checkp("EHLO %s", host, -1)) 327 if (250 != smtp_checkp("EHLO %s", host, -1))
281 smtp_checkp("HELO %s", host, 250); 328 smtp_checkp("HELO %s", host, 250);
282 free(host);
283 329
284 // perform authentication 330 // perform authentication
285 if (opts & OPT_a) { 331 if (opts & OPT_a) {
@@ -304,13 +350,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv)
304 // Since reading from console may defeat usability, the solution is either to read from a predefined 350 // Since reading from console may defeat usability, the solution is either to read from a predefined
305 // file descriptor (e.g. 4), or again from a secured file. 351 // file descriptor (e.g. 4), or again from a secured file.
306 352
307 // got no sender address? -> use system username as a resort 353 // got no sender address? use auth name, then UID username as a last resort
308 // N.B. we marked -f as required option! 354 if (!opt_from) {
309 //if (!G.user) { 355 opt_from = xasprintf("%s@%s",
310 // // N.B. IMHO getenv("USER") can be way easily spoofed! 356 G.user ? G.user : xuid2uname(getuid()),
311 // G.user = xuid2uname(getuid()); 357 xgethostbyname(host)->h_name);
312 // opt_from = xasprintf("%s@%s", G.user, domain); 358 }
313 //} 359 free(host);
360
314 smtp_checkp("MAIL FROM:<%s>", opt_from, 250); 361 smtp_checkp("MAIL FROM:<%s>", opt_from, 250);
315 362
316 // process message 363 // process message
diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c
index 12a77b70f..7b695b26f 100644
--- a/miscutils/fbsplash.c
+++ b/miscutils/fbsplash.c
@@ -353,7 +353,7 @@ static void fb_drawimage(void)
353 if (LONE_DASH(G.image_filename)) { 353 if (LONE_DASH(G.image_filename)) {
354 theme_file = stdin; 354 theme_file = stdin;
355 } else { 355 } else {
356 int fd = open_zipped(G.image_filename); 356 int fd = open_zipped(G.image_filename, /*fail_if_not_compressed:*/ 0);
357 if (fd < 0) 357 if (fd < 0)
358 bb_simple_perror_msg_and_die(G.image_filename); 358 bb_simple_perror_msg_and_die(G.image_filename);
359 theme_file = xfdopen_for_read(fd); 359 theme_file = xfdopen_for_read(fd);
diff --git a/miscutils/less.c b/miscutils/less.c
index 60105f42b..574f222e0 100644
--- a/miscutils/less.c
+++ b/miscutils/less.c
@@ -98,16 +98,18 @@
98//config: Enables "-N" command. 98//config: Enables "-N" command.
99 99
100//usage:#define less_trivial_usage 100//usage:#define less_trivial_usage
101//usage: "[-E" IF_FEATURE_LESS_FLAGS("Mm") "Nh~I?] [FILE]..." 101//usage: "[-E" IF_FEATURE_LESS_REGEXP("I")IF_FEATURE_LESS_FLAGS("Mm") "Nh~] [FILE]..."
102//usage:#define less_full_usage "\n\n" 102//usage:#define less_full_usage "\n\n"
103//usage: "View FILE (or stdin) one screenful at a time\n" 103//usage: "View FILE (or stdin) one screenful at a time\n"
104//usage: "\n -E Quit once the end of a file is reached" 104//usage: "\n -E Quit once the end of a file is reached"
105//usage: IF_FEATURE_LESS_REGEXP(
106//usage: "\n -I Ignore case in all searches"
107//usage: )
105//usage: IF_FEATURE_LESS_FLAGS( 108//usage: IF_FEATURE_LESS_FLAGS(
106//usage: "\n -M,-m Display status line with line numbers" 109//usage: "\n -M,-m Display status line with line numbers"
107//usage: "\n and percentage through the file" 110//usage: "\n and percentage through the file"
108//usage: ) 111//usage: )
109//usage: "\n -N Prefix line number to each line" 112//usage: "\n -N Prefix line number to each line"
110//usage: "\n -I Ignore case in all searches"
111//usage: "\n -~ Suppress ~s displayed past EOF" 113//usage: "\n -~ Suppress ~s displayed past EOF"
112 114
113#include <sched.h> /* sched_yield() */ 115#include <sched.h> /* sched_yield() */
@@ -1613,10 +1615,13 @@ int less_main(int argc, char **argv)
1613 1615
1614 INIT_G(); 1616 INIT_G();
1615 1617
1616 /* TODO: -x: do not interpret backspace, -xx: tab also */ 1618 /* TODO: -x: do not interpret backspace, -xx: tab also
1617 /* -xxx: newline also */ 1619 * -xxx: newline also
1618 /* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */ 1620 * -w N: assume width N (-xxx -w 32: hex viewer of sorts)
1619 getopt32(argv, "EMmN~I" IF_FEATURE_LESS_DASHCMD("S")); 1621 * -s: condense many empty lines to one
1622 * (used by some setups for manpage display)
1623 */
1624 getopt32(argv, "EMmN~I" IF_FEATURE_LESS_DASHCMD("S") /*ignored:*/"s");
1620 argc -= optind; 1625 argc -= optind;
1621 argv += optind; 1626 argv += optind;
1622 num_files = argc; 1627 num_files = argc;
diff --git a/miscutils/man.c b/miscutils/man.c
index 429898643..0e0b1cba6 100644
--- a/miscutils/man.c
+++ b/miscutils/man.c
@@ -102,11 +102,12 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level)
102 102
103 ordinary_manpage: 103 ordinary_manpage:
104 close(STDIN_FILENO); 104 close(STDIN_FILENO);
105 open_zipped(man_filename); /* guaranteed to use fd 0 (STDIN_FILENO) */ 105 open_zipped(man_filename, /*fail_if_not_compressed:*/ 0); /* guaranteed to use fd 0 (STDIN_FILENO) */
106 /* "2>&1" is added so that nroff errors are shown in pager too. 106 /* "2>&1" is added so that nroff errors are shown in pager too.
107 * Otherwise it may show just empty screen */ 107 * Otherwise it may show just empty screen */
108 cmd = xasprintf( 108 cmd = xasprintf(
109 man ? "gtbl | nroff -Tlatin1 -mandoc 2>&1 | %s" 109 /* replaced -Tlatin1 with -Tascii for non-UTF8 displays */
110 man ? "gtbl | nroff -Tascii -mandoc 2>&1 | %s"
110 : "%s", 111 : "%s",
111 pager); 112 pager);
112 system(cmd); 113 system(cmd);
@@ -150,7 +151,7 @@ int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
150int man_main(int argc UNUSED_PARAM, char **argv) 151int man_main(int argc UNUSED_PARAM, char **argv)
151{ 152{
152 parser_t *parser; 153 parser_t *parser;
153 const char *pager; 154 const char *pager = ENABLE_LESS ? "less" : "more";
154 char **man_path_list; 155 char **man_path_list;
155 char *sec_list; 156 char *sec_list;
156 char *cur_path, *cur_sect; 157 char *cur_path, *cur_sect;
@@ -171,12 +172,6 @@ int man_main(int argc UNUSED_PARAM, char **argv)
171 man_path_list[0] = (char*)"/usr/man"; 172 man_path_list[0] = (char*)"/usr/man";
172 else 173 else
173 count_mp++; 174 count_mp++;
174 pager = getenv("MANPAGER");
175 if (!pager) {
176 pager = getenv("PAGER");
177 if (!pager)
178 pager = "more";
179 }
180 175
181 /* Parse man.conf[ig] or man_db.conf */ 176 /* Parse man.conf[ig] or man_db.conf */
182 /* man version 1.6f uses man.config */ 177 /* man version 1.6f uses man.config */
@@ -190,6 +185,11 @@ int man_main(int argc UNUSED_PARAM, char **argv)
190 while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) { 185 while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) {
191 if (!token[1]) 186 if (!token[1])
192 continue; 187 continue;
188 if (strcmp("DEFINE", token[0]) == 0) {
189 if (strncmp("pager", token[1], 5) == 0) {
190 pager = xstrdup(skip_whitespace(token[1]) + 5);
191 }
192 } else
193 if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ 193 if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */
194 || strcmp("MANDATORY_MANPATH", token[0]) == 0 194 || strcmp("MANDATORY_MANPATH", token[0]) == 0
195 ) { 195 ) {
@@ -234,6 +234,15 @@ int man_main(int argc UNUSED_PARAM, char **argv)
234 } 234 }
235 config_close(parser); 235 config_close(parser);
236 236
237 {
238 /* environment overrides setting from man.config */
239 char *env_pager = getenv("MANPAGER");
240 if (!env_pager)
241 env_pager = getenv("PAGER");
242 if (env_pager)
243 pager = env_pager;
244 }
245
237 not_found = 0; 246 not_found = 0;
238 do { /* for each argv[] */ 247 do { /* for each argv[] */
239 int found = 0; 248 int found = 0;
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index b578f4c61..fef7a5ac9 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -289,8 +289,6 @@ static const struct {
289 { "IFF_RUNNING" , &detect_link_iff }, 289 { "IFF_RUNNING" , &detect_link_iff },
290}; 290};
291 291
292
293
294static const char *strstatus(int status) 292static const char *strstatus(int status)
295{ 293{
296 if (status == IFSTATUS_ERR) 294 if (status == IFSTATUS_ERR)
@@ -652,7 +650,6 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
652 delay_time = 0; 650 delay_time = 0;
653 while (1) { 651 while (1) {
654 int iface_status_old; 652 int iface_status_old;
655 int iface_exists_old;
656 653
657 switch (bb_got_signal) { 654 switch (bb_got_signal) {
658 case SIGINT: 655 case SIGINT:
@@ -678,12 +675,12 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
678 goto exiting; 675 goto exiting;
679 } 676 }
680 677
681 iface_status_old = iface_status;
682 iface_exists_old = G.iface_exists;
683
684 if ((opts & FLAG_MONITOR) 678 if ((opts & FLAG_MONITOR)
685 && (netlink_pollfd[0].revents & POLLIN) 679 && (netlink_pollfd[0].revents & POLLIN)
686 ) { 680 ) {
681 int iface_exists_old;
682
683 iface_exists_old = G.iface_exists;
687 G.iface_exists = check_existence_through_netlink(); 684 G.iface_exists = check_existence_through_netlink();
688 if (G.iface_exists < 0) /* error */ 685 if (G.iface_exists < 0) /* error */
689 goto exiting; 686 goto exiting;
@@ -696,6 +693,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
696 } 693 }
697 694
698 /* note: if !G.iface_exists, returns DOWN */ 695 /* note: if !G.iface_exists, returns DOWN */
696 iface_status_old = iface_status;
699 iface_status = detect_link(); 697 iface_status = detect_link();
700 if (iface_status == IFSTATUS_ERR) { 698 if (iface_status == IFSTATUS_ERR) {
701 if (!(opts & FLAG_MONITOR)) 699 if (!(opts & FLAG_MONITOR))
@@ -709,7 +707,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
709 707
710 if (delay_time) { 708 if (delay_time) {
711 /* link restored its old status before 709 /* link restored its old status before
712 * we run script. don't run the script: */ 710 * we ran script. don't run the script: */
713 delay_time = 0; 711 delay_time = 0;
714 } else { 712 } else {
715 delay_time = monotonic_sec(); 713 delay_time = monotonic_sec();
@@ -717,15 +715,19 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
717 delay_time += G.delay_up; 715 delay_time += G.delay_up;
718 if (iface_status == IFSTATUS_DOWN) 716 if (iface_status == IFSTATUS_DOWN)
719 delay_time += G.delay_down; 717 delay_time += G.delay_down;
720 if (delay_time == 0) 718#if 0 /* if you are back in 1970... */
721 delay_time++; 719 if (delay_time == 0) {
720 sleep(1);
721 delay_time = 1;
722 }
723#endif
722 } 724 }
723 } 725 }
724 726
725 if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) { 727 if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) {
726 delay_time = 0;
727 if (run_script(iface_status_str) != 0) 728 if (run_script(iface_status_str) != 0)
728 goto exiting; 729 goto exiting;
730 delay_time = 0;
729 } 731 }
730 } /* while (1) */ 732 } /* while (1) */
731 733
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 0f0857cb4..e1ea351a4 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -685,6 +685,18 @@ static const struct address_family_t addr_inet = {
685 685
686#endif /* FEATURE_IFUPDOWN_IPV4 */ 686#endif /* FEATURE_IFUPDOWN_IPV4 */
687 687
688static int FAST_FUNC link_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM)
689{
690 return 1;
691}
692
693static const struct method_t link_methods[] = {
694 { "none", link_up_down, link_up_down }
695};
696
697static const struct address_family_t addr_link = {
698 "link", ARRAY_SIZE(link_methods), link_methods
699};
688 700
689/* Returns pointer to the next word, or NULL. 701/* Returns pointer to the next word, or NULL.
690 * In 1st case, advances *buf to the word after this one. 702 * In 1st case, advances *buf to the word after this one.
@@ -831,6 +843,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename, struct in
831#if ENABLE_FEATURE_IFUPDOWN_IPV6 843#if ENABLE_FEATURE_IFUPDOWN_IPV6
832 &addr_inet6, 844 &addr_inet6,
833#endif 845#endif
846 &addr_link,
834 NULL 847 NULL
835 }; 848 };
836 char *iface_name; 849 char *iface_name;
diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c
index 286e59ebf..5c27c2de3 100644
--- a/networking/libiproute/iplink.c
+++ b/networking/libiproute/iplink.c
@@ -31,11 +31,27 @@
31#ifndef IFLA_LINKINFO 31#ifndef IFLA_LINKINFO
32# define IFLA_LINKINFO 18 32# define IFLA_LINKINFO 18
33# define IFLA_INFO_KIND 1 33# define IFLA_INFO_KIND 1
34# define IFLA_INFO_DATA 2
35#endif
36
37#ifndef IFLA_VLAN_MAX
38# define IFLA_VLAN_ID 1
39# define IFLA_VLAN_FLAGS 2
40struct ifla_vlan_flags {
41 uint32_t flags;
42 uint32_t mask;
43};
34#endif 44#endif
35 45
36/* taken from linux/sockios.h */ 46/* taken from linux/sockios.h */
37#define SIOCSIFNAME 0x8923 /* set interface name */ 47#define SIOCSIFNAME 0x8923 /* set interface name */
38 48
49#if 0
50# define dbg(...) bb_error_msg(__VA_ARGS__)
51#else
52# define dbg(...) ((void)0)
53#endif
54
39/* Exits on error */ 55/* Exits on error */
40static int get_ctl_fd(void) 56static int get_ctl_fd(void)
41{ 57{
@@ -391,12 +407,13 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size)
391static int do_add_or_delete(char **argv, const unsigned rtm) 407static int do_add_or_delete(char **argv, const unsigned rtm)
392{ 408{
393 static const char keywords[] ALIGN1 = 409 static const char keywords[] ALIGN1 =
394 "link\0""name\0""type\0""dev\0"; 410 "link\0""name\0""type\0""dev\0""address\0";
395 enum { 411 enum {
396 ARG_link, 412 ARG_link,
397 ARG_name, 413 ARG_name,
398 ARG_type, 414 ARG_type,
399 ARG_dev, 415 ARG_dev,
416 ARG_address,
400 }; 417 };
401 struct rtnl_handle rth; 418 struct rtnl_handle rth;
402 struct { 419 struct {
@@ -405,7 +422,11 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
405 char buf[1024]; 422 char buf[1024];
406 } req; 423 } req;
407 smalluint arg; 424 smalluint arg;
408 char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; 425 char *name_str = NULL;
426 char *link_str = NULL;
427 char *type_str = NULL;
428 char *dev_str = NULL;
429 char *address_str = NULL;
409 430
410 memset(&req, 0, sizeof(req)); 431 memset(&req, 0, sizeof(req));
411 432
@@ -421,14 +442,21 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
421 if (arg == ARG_type) { 442 if (arg == ARG_type) {
422 NEXT_ARG(); 443 NEXT_ARG();
423 type_str = *argv++; 444 type_str = *argv++;
445 dbg("type_str:'%s'", type_str);
424 break; 446 break;
425 } 447 }
426 if (arg == ARG_link) { 448 if (arg == ARG_link) {
427 NEXT_ARG(); 449 NEXT_ARG();
428 link_str = *argv; 450 link_str = *argv;
451 dbg("link_str:'%s'", link_str);
429 } else if (arg == ARG_name) { 452 } else if (arg == ARG_name) {
430 NEXT_ARG(); 453 NEXT_ARG();
431 name_str = *argv; 454 name_str = *argv;
455 dbg("name_str:'%s'", name_str);
456 } else if (arg == ARG_address) {
457 NEXT_ARG();
458 address_str = *argv;
459 dbg("address_str:'%s'", name_str);
432 } else { 460 } else {
433 if (arg == ARG_dev) { 461 if (arg == ARG_dev) {
434 if (dev_str) 462 if (dev_str)
@@ -436,6 +464,7 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
436 NEXT_ARG(); 464 NEXT_ARG();
437 } 465 }
438 dev_str = *argv; 466 dev_str = *argv;
467 dbg("dev_str:'%s'", dev_str);
439 } 468 }
440 argv++; 469 argv++;
441 } 470 }
@@ -471,6 +500,14 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
471 int idx = xll_name_to_index(link_str); 500 int idx = xll_name_to_index(link_str);
472 addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4); 501 addattr_l(&req.n, sizeof(req), IFLA_LINK, &idx, 4);
473 } 502 }
503 if (address_str) {
504 unsigned char abuf[32];
505 int len = ll_addr_a2n(abuf, sizeof(abuf), address_str);
506 dbg("address len:%d", len);
507 if (len < 0)
508 return -1;
509 addattr_l(&req.n, sizeof(req), IFLA_ADDRESS, abuf, len);
510 }
474 } 511 }
475 if (name_str) { 512 if (name_str) {
476 const size_t name_len = strlen(name_str) + 1; 513 const size_t name_len = strlen(name_str) + 1;
@@ -483,6 +520,165 @@ static int do_add_or_delete(char **argv, const unsigned rtm)
483 return 0; 520 return 0;
484} 521}
485 522
523/* Other keywords recognized by iproute2-3.12.0: */
524#if 0
525 } else if (matches(*argv, "broadcast") == 0 ||
526 strcmp(*argv, "brd") == 0) {
527 NEXT_ARG();
528 len = ll_addr_a2n(abuf, sizeof(abuf), *argv);
529 if (len < 0)
530 return -1;
531 addattr_l(&req->n, sizeof(*req), IFLA_BROADCAST, abuf, len);
532 } else if (matches(*argv, "txqueuelen") == 0 ||
533 strcmp(*argv, "qlen") == 0 ||
534 matches(*argv, "txqlen") == 0) {
535 NEXT_ARG();
536 if (qlen != -1)
537 duparg("txqueuelen", *argv);
538 if (get_integer(&qlen, *argv, 0))
539 invarg("Invalid \"txqueuelen\" value\n", *argv);
540 addattr_l(&req->n, sizeof(*req), IFLA_TXQLEN, &qlen, 4);
541 } else if (strcmp(*argv, "mtu") == 0) {
542 NEXT_ARG();
543 if (mtu != -1)
544 duparg("mtu", *argv);
545 if (get_integer(&mtu, *argv, 0))
546 invarg("Invalid \"mtu\" value\n", *argv);
547 addattr_l(&req->n, sizeof(*req), IFLA_MTU, &mtu, 4);
548 } else if (strcmp(*argv, "netns") == 0) {
549 NEXT_ARG();
550 if (netns != -1)
551 duparg("netns", *argv);
552 if ((netns = get_netns_fd(*argv)) >= 0)
553 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_FD, &netns, 4);
554 else if (get_integer(&netns, *argv, 0) == 0)
555 addattr_l(&req->n, sizeof(*req), IFLA_NET_NS_PID, &netns, 4);
556 else
557 invarg("Invalid \"netns\" value\n", *argv);
558 } else if (strcmp(*argv, "multicast") == 0) {
559 NEXT_ARG();
560 req->i.ifi_change |= IFF_MULTICAST;
561 if (strcmp(*argv, "on") == 0) {
562 req->i.ifi_flags |= IFF_MULTICAST;
563 } else if (strcmp(*argv, "off") == 0) {
564 req->i.ifi_flags &= ~IFF_MULTICAST;
565 } else
566 return on_off("multicast", *argv);
567 } else if (strcmp(*argv, "allmulticast") == 0) {
568 NEXT_ARG();
569 req->i.ifi_change |= IFF_ALLMULTI;
570 if (strcmp(*argv, "on") == 0) {
571 req->i.ifi_flags |= IFF_ALLMULTI;
572 } else if (strcmp(*argv, "off") == 0) {
573 req->i.ifi_flags &= ~IFF_ALLMULTI;
574 } else
575 return on_off("allmulticast", *argv);
576 } else if (strcmp(*argv, "promisc") == 0) {
577 NEXT_ARG();
578 req->i.ifi_change |= IFF_PROMISC;
579 if (strcmp(*argv, "on") == 0) {
580 req->i.ifi_flags |= IFF_PROMISC;
581 } else if (strcmp(*argv, "off") == 0) {
582 req->i.ifi_flags &= ~IFF_PROMISC;
583 } else
584 return on_off("promisc", *argv);
585 } else if (strcmp(*argv, "trailers") == 0) {
586 NEXT_ARG();
587 req->i.ifi_change |= IFF_NOTRAILERS;
588 if (strcmp(*argv, "off") == 0) {
589 req->i.ifi_flags |= IFF_NOTRAILERS;
590 } else if (strcmp(*argv, "on") == 0) {
591 req->i.ifi_flags &= ~IFF_NOTRAILERS;
592 } else
593 return on_off("trailers", *argv);
594 } else if (strcmp(*argv, "arp") == 0) {
595 NEXT_ARG();
596 req->i.ifi_change |= IFF_NOARP;
597 if (strcmp(*argv, "on") == 0) {
598 req->i.ifi_flags &= ~IFF_NOARP;
599 } else if (strcmp(*argv, "off") == 0) {
600 req->i.ifi_flags |= IFF_NOARP;
601 } else
602 return on_off("noarp", *argv);
603 } else if (strcmp(*argv, "vf") == 0) {
604 struct rtattr *vflist;
605 NEXT_ARG();
606 if (get_integer(&vf, *argv, 0)) {
607 invarg("Invalid \"vf\" value\n", *argv);
608 }
609 vflist = addattr_nest(&req->n, sizeof(*req),
610 IFLA_VFINFO_LIST);
611 len = iplink_parse_vf(vf, &argc, &argv, req);
612 if (len < 0)
613 return -1;
614 addattr_nest_end(&req->n, vflist);
615 } else if (matches(*argv, "master") == 0) {
616 int ifindex;
617 NEXT_ARG();
618 ifindex = ll_name_to_index(*argv);
619 if (!ifindex)
620 invarg("Device does not exist\n", *argv);
621 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
622 &ifindex, 4);
623 } else if (matches(*argv, "nomaster") == 0) {
624 int ifindex = 0;
625 addattr_l(&req->n, sizeof(*req), IFLA_MASTER,
626 &ifindex, 4);
627 } else if (matches(*argv, "dynamic") == 0) {
628 NEXT_ARG();
629 req->i.ifi_change |= IFF_DYNAMIC;
630 if (strcmp(*argv, "on") == 0) {
631 req->i.ifi_flags |= IFF_DYNAMIC;
632 } else if (strcmp(*argv, "off") == 0) {
633 req->i.ifi_flags &= ~IFF_DYNAMIC;
634 } else
635 return on_off("dynamic", *argv);
636 } else if (matches(*argv, "alias") == 0) {
637 NEXT_ARG();
638 addattr_l(&req->n, sizeof(*req), IFLA_IFALIAS,
639 *argv, strlen(*argv));
640 argc--; argv++;
641 break;
642 } else if (strcmp(*argv, "group") == 0) {
643 NEXT_ARG();
644 if (*group != -1)
645 duparg("group", *argv);
646 if (rtnl_group_a2n(group, *argv))
647 invarg("Invalid \"group\" value\n", *argv);
648 } else if (strcmp(*argv, "mode") == 0) {
649 int mode;
650 NEXT_ARG();
651 mode = get_link_mode(*argv);
652 if (mode < 0)
653 invarg("Invalid link mode\n", *argv);
654 addattr8(&req->n, sizeof(*req), IFLA_LINKMODE, mode);
655 } else if (strcmp(*argv, "state") == 0) {
656 int state;
657 NEXT_ARG();
658 state = get_operstate(*argv);
659 if (state < 0)
660 invarg("Invalid operstate\n", *argv);
661
662 addattr8(&req->n, sizeof(*req), IFLA_OPERSTATE, state);
663 } else if (matches(*argv, "numtxqueues") == 0) {
664 NEXT_ARG();
665 if (numtxqueues != -1)
666 duparg("numtxqueues", *argv);
667 if (get_integer(&numtxqueues, *argv, 0))
668 invarg("Invalid \"numtxqueues\" value\n", *argv);
669 addattr_l(&req->n, sizeof(*req), IFLA_NUM_TX_QUEUES,
670 &numtxqueues, 4);
671 } else if (matches(*argv, "numrxqueues") == 0) {
672 NEXT_ARG();
673 if (numrxqueues != -1)
674 duparg("numrxqueues", *argv);
675 if (get_integer(&numrxqueues, *argv, 0))
676 invarg("Invalid \"numrxqueues\" value\n", *argv);
677 addattr_l(&req->n, sizeof(*req), IFLA_NUM_RX_QUEUES,
678 &numrxqueues, 4);
679 }
680#endif
681
486/* Return value becomes exitcode. It's okay to not return at all */ 682/* Return value becomes exitcode. It's okay to not return at all */
487int FAST_FUNC do_iplink(char **argv) 683int FAST_FUNC do_iplink(char **argv)
488{ 684{
diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c
index b9eff3da4..b28d05f51 100644
--- a/networking/nc_bloaty.c
+++ b/networking/nc_bloaty.c
@@ -175,9 +175,9 @@ enum {
175 OPT_w = (1 << 5), 175 OPT_w = (1 << 5),
176 OPT_l = (1 << 6) * ENABLE_NC_SERVER, 176 OPT_l = (1 << 6) * ENABLE_NC_SERVER,
177 OPT_k = (1 << 7) * ENABLE_NC_SERVER, 177 OPT_k = (1 << 7) * ENABLE_NC_SERVER,
178 OPT_i = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 178 OPT_i = (1 << (6+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
179 OPT_o = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 179 OPT_o = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
180 OPT_z = (1 << (9+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, 180 OPT_z = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA,
181}; 181};
182 182
183#define o_nflag (option_mask32 & OPT_n) 183#define o_nflag (option_mask32 & OPT_n)
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 03fe448ca..44592ce54 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -827,8 +827,8 @@ send_query_to_peer(peer_t *p)
827 * 827 *
828 * Save the real transmit timestamp locally. 828 * Save the real transmit timestamp locally.
829 */ 829 */
830 p->p_xmt_msg.m_xmttime.int_partl = random(); 830 p->p_xmt_msg.m_xmttime.int_partl = rand();
831 p->p_xmt_msg.m_xmttime.fractionl = random(); 831 p->p_xmt_msg.m_xmttime.fractionl = rand();
832 p->p_xmttime = gettime1900d(); 832 p->p_xmttime = gettime1900d();
833 833
834 /* Were doing it only if sendto worked, but 834 /* Were doing it only if sendto worked, but
@@ -1652,7 +1652,7 @@ retry_interval(void)
1652 /* Local problem, want to retry soon */ 1652 /* Local problem, want to retry soon */
1653 unsigned interval, r; 1653 unsigned interval, r;
1654 interval = RETRY_INTERVAL; 1654 interval = RETRY_INTERVAL;
1655 r = random(); 1655 r = rand();
1656 interval += r % (unsigned)(RETRY_INTERVAL / 4); 1656 interval += r % (unsigned)(RETRY_INTERVAL / 4);
1657 VERB4 bb_error_msg("chose retry interval:%u", interval); 1657 VERB4 bb_error_msg("chose retry interval:%u", interval);
1658 return interval; 1658 return interval;
@@ -1660,13 +1660,14 @@ retry_interval(void)
1660static unsigned 1660static unsigned
1661poll_interval(int exponent) 1661poll_interval(int exponent)
1662{ 1662{
1663 unsigned interval, r; 1663 unsigned interval, r, mask;
1664 exponent = G.poll_exp + exponent; 1664 exponent = G.poll_exp + exponent;
1665 if (exponent < 0) 1665 if (exponent < 0)
1666 exponent = 0; 1666 exponent = 0;
1667 interval = 1 << exponent; 1667 interval = 1 << exponent;
1668 r = random(); 1668 mask = ((interval-1) >> 4) | 1;
1669 interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */ 1669 r = rand();
1670 interval += r & mask; /* ~ random(0..1) * interval/16 */
1670 VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); 1671 VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent);
1671 return interval; 1672 return interval;
1672} 1673}
@@ -2066,7 +2067,7 @@ static NOINLINE void ntp_init(char **argv)
2066 unsigned opts; 2067 unsigned opts;
2067 llist_t *peers; 2068 llist_t *peers;
2068 2069
2069 srandom(getpid()); 2070 srand(getpid());
2070 2071
2071 if (getuid()) 2072 if (getuid())
2072 bb_error_msg_and_die(bb_msg_you_must_be_root); 2073 bb_error_msg_and_die(bb_msg_you_must_be_root);
diff --git a/networking/ntpd_simple.c b/networking/ntpd_simple.c
index 22e899cb6..2cfbd55d4 100644
--- a/networking/ntpd_simple.c
+++ b/networking/ntpd_simple.c
@@ -248,7 +248,7 @@ error_interval(void)
248{ 248{
249 unsigned interval, r; 249 unsigned interval, r;
250 interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN; 250 interval = INTERVAL_QUERY_PATHETIC * QSCALE_OFF_MAX / QSCALE_OFF_MIN;
251 r = (unsigned)random() % (unsigned)(interval / 10); 251 r = (unsigned)rand() % (unsigned)(interval / 10);
252 return (interval + r); 252 return (interval + r);
253} 253}
254 254
@@ -326,8 +326,8 @@ send_query_to_peer(peer_t *p)
326 * 326 *
327 * Save the real transmit timestamp locally. 327 * Save the real transmit timestamp locally.
328 */ 328 */
329 p->p_xmt_msg.m_xmttime.int_partl = random(); 329 p->p_xmt_msg.m_xmttime.int_partl = rand();
330 p->p_xmt_msg.m_xmttime.fractionl = random(); 330 p->p_xmt_msg.m_xmttime.fractionl = rand();
331 p->p_xmttime = gettime1900d(); 331 p->p_xmttime = gettime1900d();
332 332
333 if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, 333 if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len,
@@ -531,7 +531,7 @@ scale_interval(unsigned requested)
531{ 531{
532 unsigned interval, r; 532 unsigned interval, r;
533 interval = requested * G.scale; 533 interval = requested * G.scale;
534 r = (unsigned)random() % (unsigned)(MAX(5, interval / 10)); 534 r = (unsigned)rand() % (unsigned)(MAX(5, interval / 10));
535 return (interval + r); 535 return (interval + r);
536} 536}
537static void 537static void
@@ -825,7 +825,7 @@ static NOINLINE void ntp_init(char **argv)
825 unsigned opts; 825 unsigned opts;
826 llist_t *peers; 826 llist_t *peers;
827 827
828 srandom(getpid()); 828 srand(getpid());
829 829
830 if (getuid()) 830 if (getuid())
831 bb_error_msg_and_die(bb_msg_you_must_be_root); 831 bb_error_msg_and_die(bb_msg_you_must_be_root);
diff --git a/networking/ssl_helper/README b/networking/ssl_helper/README
new file mode 100644
index 000000000..4d0508fbb
--- /dev/null
+++ b/networking/ssl_helper/README
@@ -0,0 +1,16 @@
1Build instructions:
2
3* Unpack matrixssl-3-4-2-open.tgz.
4* Build it: "make"
5* Drop this directory into matrixssl-3-4-2-open/ssl_helper
6* Run ssl_helper.sh to compile and link the helper
7
8Usage: "ssl_helper -d <FILE_DESCRIPTOR>" where FILE_DESCRIPTOR is open to the peer.
9
10In bash, you can do it this way:
11$ ssl_helper -d3 3<>/dev/tcp/HOST/PORT
12
13Stdin will be SSL-encrypted and sent to FILE_DESCRIPTOR.
14Data from FILE_DESCRIPTOR will be decrypted and sent to stdout.
15
16The plan is to adapt it for wget https helper, and for ssl support in nc.
diff --git a/networking/ssl_helper/ssl_helper.c b/networking/ssl_helper/ssl_helper.c
new file mode 100644
index 000000000..d840b1b88
--- /dev/null
+++ b/networking/ssl_helper/ssl_helper.c
@@ -0,0 +1,406 @@
1/*
2 * Copyright (c) 2013 INSIDE Secure Corporation
3 * Copyright (c) PeerSec Networks, 2002-2011
4 * All Rights Reserved
5 *
6 * The latest version of this code is available at http://www.matrixssl.org
7 *
8 * This software is open source; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 * See the GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * http://www.gnu.org/copyleft/gpl.html
21 */
22#include <errno.h>
23#include <stdlib.h>
24#include <unistd.h>
25#include <stdarg.h>
26#include <fcntl.h>
27#include <stdio.h>
28#include <time.h>
29#include <poll.h>
30#include <sys/socket.h>
31
32#include "matrixssl/matrixsslApi.h"
33
34//#warning "DO NOT USE THESE DEFAULT KEYS IN PRODUCTION ENVIRONMENTS."
35
36/*
37 * If supporting client authentication, pick ONE identity to auto select a
38 * certificate and private key that support desired algorithms.
39 */
40#define ID_RSA /* RSA Certificate and Key */
41
42#define USE_HEADER_KEYS
43
44/* If the algorithm type is supported, load a CA for it */
45#ifdef USE_HEADER_KEYS
46/* CAs */
47# include "sampleCerts/RSA/ALL_RSA_CAS.h"
48/* Identity Certs and Keys for use with Client Authentication */
49# ifdef ID_RSA
50# define EXAMPLE_RSA_KEYS
51# include "sampleCerts/RSA/2048_RSA.h"
52# include "sampleCerts/RSA/2048_RSA_KEY.h"
53# endif
54#endif
55
56static ssize_t safe_write(int fd, const void *buf, size_t count)
57{
58 ssize_t n;
59
60 do {
61 n = write(fd, buf, count);
62 } while (n < 0 && errno == EINTR);
63
64 return n;
65}
66
67static ssize_t full_write(int fd, const void *buf, size_t len)
68{
69 ssize_t cc;
70 ssize_t total;
71
72 total = 0;
73
74 while (len) {
75 cc = safe_write(fd, buf, len);
76
77 if (cc < 0) {
78 if (total) {
79 /* we already wrote some! */
80 /* user can do another write to know the error code */
81 return total;
82 }
83 return cc; /* write() returns -1 on failure. */
84 }
85
86 total += cc;
87 buf = ((const char *)buf) + cc;
88 len -= cc;
89 }
90
91 return total;
92}
93
94static void say(const char *s, ...)
95{
96 char buf[256];
97 va_list p;
98 int sz;
99
100 va_start(p, s);
101 sz = vsnprintf(buf, sizeof(buf), s, p);
102 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
103 va_end(p);
104}
105
106static void die(const char *s, ...)
107{
108 char buf[256];
109 va_list p;
110 int sz;
111
112 va_start(p, s);
113 sz = vsnprintf(buf, sizeof(buf), s, p);
114 full_write(STDERR_FILENO, buf, sz >= 0 && sz < sizeof(buf) ? sz : strlen(buf));
115 exit(1);
116 va_end(p);
117}
118
119#if 0
120# define dbg(...) say(__VA_ARGS__)
121#else
122# define dbg(...) ((void)0)
123#endif
124
125static struct pollfd pfd[2] = {
126 { -1, POLLIN|POLLERR|POLLHUP, 0 },
127 { -1, POLLIN|POLLERR|POLLHUP, 0 },
128};
129#define STDIN pfd[0]
130#define NETWORK pfd[1]
131#define STDIN_READY() (pfd[0].revents & (POLLIN|POLLERR|POLLHUP))
132#define NETWORK_READY() (pfd[1].revents & (POLLIN|POLLERR|POLLHUP))
133
134static int wait_for_input(void)
135{
136 if (STDIN.fd == NETWORK.fd) /* means both are -1 */
137 exit(0);
138 dbg("polling\n");
139 STDIN.revents = NETWORK.revents = 0;
140 return poll(pfd, 2, -1);
141}
142
143static int32 certCb(ssl_t *ssl, psX509Cert_t *cert, int32 alert)
144{
145 /* Example to allow anonymous connections based on a define */
146 if (alert > 0) {
147 return SSL_ALLOW_ANON_CONNECTION; // = 254
148 }
149#if 0
150 /* Validate the 'not before' and 'not after' dates, etc */
151 return PS_FAILURE; /* if we don't like this cert */
152#endif
153 return PS_SUCCESS;
154}
155
156static void close_conn_and_exit(ssl_t *ssl, int fd)
157{
158 unsigned char *buf;
159 int len;
160
161 fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
162 /* Quick attempt to send a closure alert, don't worry about failure */
163 if (matrixSslEncodeClosureAlert(ssl) >= 0) {
164 len = matrixSslGetOutdata(ssl, &buf);
165 if (len > 0) {
166 len = safe_write(fd, buf, len);
167 //if (len > 0) {
168 // matrixSslSentData(ssl, len);
169 //}
170 }
171 }
172 //matrixSslDeleteSession(ssl);
173 shutdown(fd, SHUT_WR);
174 exit(0);
175}
176
177static int encode_data(ssl_t *ssl, const void *data, int len)
178{
179 unsigned char *buf;
180 int available;
181
182 available = matrixSslGetWritebuf(ssl, &buf, len);
183 if (available < 0)
184 die("matrixSslGetWritebuf\n");
185 if (len > available)
186 die("len > available\n");
187 memcpy(buf, data, len);
188 if (matrixSslEncodeWritebuf(ssl, len) < 0)
189 die("matrixSslEncodeWritebuf\n");
190 return len;
191}
192
193static void flush_to_net(ssl_t *ssl, int fd)
194{
195 int rc;
196 int len;
197 unsigned char *buf;
198
199 while ((len = matrixSslGetOutdata(ssl, &buf)) > 0) {
200 dbg("writing net %d bytes\n", len);
201 if (full_write(fd, buf, len) != len)
202 die("write to network\n");
203 rc = matrixSslSentData(ssl, len);
204 if (rc < 0)
205 die("matrixSslSentData\n");
206 }
207}
208
209static void do_io_until_eof_and_exit(int fd, sslKeys_t *keys)
210{
211 int rc;
212 int len;
213 uint32_t len32u;
214 sslSessionId_t *sid;
215 ssl_t *ssl;
216 unsigned char *buf;
217
218 NETWORK.fd = fd;
219 /* Note! STDIN.fd is disabled (-1) until SSL handshake is over:
220 * we do not attempt to feed any user data to MatrixSSL
221 * before it is ready.
222 */
223
224 matrixSslNewSessionId(&sid);
225 rc = matrixSslNewClientSession(&ssl, keys, sid, 0, certCb, NULL, NULL, 0);
226dbg("matrixSslNewClientSession:rc=%d\n", rc);
227 if (rc != MATRIXSSL_REQUEST_SEND)
228 die("matrixSslNewClientSession\n");
229
230 len = 0; /* only to suppress compiler warning */
231 again:
232 switch (rc) {
233 case MATRIXSSL_REQUEST_SEND:
234 dbg("MATRIXSSL_REQUEST_SEND\n");
235 flush_to_net(ssl, fd);
236 goto poll_input;
237
238 case 0:
239 dbg("rc==0\n");
240 flush_to_net(ssl, fd);
241 goto poll_input;
242
243 case MATRIXSSL_REQUEST_CLOSE:
244 /* what does this mean if we are here? */
245 dbg("MATRIXSSL_REQUEST_CLOSE\n");
246 close_conn_and_exit(ssl, fd);
247
248 case MATRIXSSL_HANDSHAKE_COMPLETE:
249 dbg("MATRIXSSL_HANDSHAKE_COMPLETE\n");
250 /* Init complete, can start reading local user's data: */
251 STDIN.fd = STDIN_FILENO;
252 poll_input:
253 wait_for_input();
254 if (STDIN_READY()) {
255 char ibuf[4 * 1024];
256 dbg("reading stdin\n");
257 len = read(STDIN_FILENO, ibuf, sizeof(ibuf));
258 if (len < 0)
259 die("read error on stdin\n");
260 if (len == 0)
261 STDIN.fd = -1;
262 else {
263 len = encode_data(ssl, ibuf, len);
264 if (len) {
265 rc = MATRIXSSL_REQUEST_SEND;
266dbg("rc=%d\n", rc);
267 goto again;
268 }
269 }
270 }
271 read_network:
272 if (NETWORK_READY()) {
273 dbg("%s%s%s\n",
274 (pfd[1].revents & POLLIN) ? "POLLIN" : "",
275 (pfd[1].revents & POLLERR) ? "|POLLERR" : "",
276 (pfd[1].revents & POLLHUP) ? "|POLLHUP" : ""
277 );
278 len = matrixSslGetReadbuf(ssl, &buf);
279 if (len <= 0)
280 die("matrixSslGetReadbuf\n");
281 dbg("reading net up to %d\n", len);
282 len = read(fd, buf, len);
283 dbg("reading net:%d\n", len);
284 if (len < 0)
285 die("read error on network\n");
286 if (len == 0) /*eof*/
287 NETWORK.fd = -1;
288 len32u = len;
289 rc = matrixSslReceivedData(ssl, len, &buf, &len32u);
290dbg("matrixSslReceivedData:rc=%d\n", rc);
291 len = len32u;
292 if (rc < 0)
293 die("matrixSslReceivedData\n");
294 }
295 goto again;
296
297 case MATRIXSSL_APP_DATA:
298 dbg("MATRIXSSL_APP_DATA: writing stdout\n");
299 do {
300 if (full_write(STDOUT_FILENO, buf, len) != len)
301 die("write to stdout\n");
302 len32u = len;
303 rc = matrixSslProcessedData(ssl, &buf, &len32u);
304//this was seen returning rc=0:
305dbg("matrixSslProcessedData:rc=%d\n", rc);
306 len = len32u;
307 } while (rc == MATRIXSSL_APP_DATA);
308 if (pfd[1].fd == -1) {
309 /* Already saw EOF on network, and we processed
310 * and wrote out all ssl data. Signal it:
311 */
312 close(STDOUT_FILENO);
313 }
314 goto again;
315
316 case MATRIXSSL_REQUEST_RECV:
317 dbg("MATRIXSSL_REQUEST_RECV\n");
318 wait_for_input();
319 goto read_network;
320
321 case MATRIXSSL_RECEIVED_ALERT:
322 dbg("MATRIXSSL_RECEIVED_ALERT\n");
323 /* The first byte of the buffer is the level */
324 /* The second byte is the description */
325 if (buf[0] == SSL_ALERT_LEVEL_FATAL)
326 die("Fatal alert\n");
327 /* Closure alert is normal (and best) way to close */
328 if (buf[1] == SSL_ALERT_CLOSE_NOTIFY)
329 close_conn_and_exit(ssl, fd);
330 die("Warning alert\n");
331 len32u = len;
332 rc = matrixSslProcessedData(ssl, &buf, &len32u);
333dbg("matrixSslProcessedData:rc=%d\n", rc);
334 len = len32u;
335 goto again;
336
337 default:
338 /* If rc < 0 it is an error */
339 die("bad rc:%d\n", rc);
340 }
341}
342
343static sslKeys_t* make_keys(void)
344{
345 int rc, CAstreamLen;
346 char *CAstream;
347 sslKeys_t *keys;
348
349 if (matrixSslNewKeys(&keys) < 0)
350 die("matrixSslNewKeys\n");
351
352#ifdef USE_HEADER_KEYS
353 /*
354 * In-memory based keys
355 * Build the CA list first for potential client auth usage
356 */
357 CAstream = NULL;
358 CAstreamLen = sizeof(RSACAS);
359 if (CAstreamLen > 0) {
360 CAstream = psMalloc(NULL, CAstreamLen);
361 memcpy(CAstream, RSACAS, sizeof(RSACAS));
362 }
363
364 #ifdef ID_RSA
365 rc = matrixSslLoadRsaKeysMem(keys, RSA2048, sizeof(RSA2048),
366 RSA2048KEY, sizeof(RSA2048KEY), (unsigned char*)CAstream,
367 CAstreamLen);
368 if (rc < 0)
369 die("matrixSslLoadRsaKeysMem\n");
370 #endif
371
372 if (CAstream)
373 psFree(CAstream);
374#endif /* USE_HEADER_KEYS */
375 return keys;
376}
377
378int main(int argc, char **argv)
379{
380 int fd;
381 char *fd_str;
382
383 if (!argv[1])
384 die("Syntax error\n");
385 if (argv[1][0] != '-')
386 die("Syntax error\n");
387 if (argv[1][1] != 'd')
388 die("Syntax error\n");
389 fd_str = argv[1] + 2;
390 if (!fd_str[0])
391 fd_str = argv[2];
392 if (!fd_str || fd_str[0] < '0' || fd_str[0] > '9')
393 die("Syntax error\n");
394
395 fd = atoi(fd_str);
396 if (fd < 3)
397 die("Syntax error\n");
398
399 if (matrixSslOpen() < 0)
400 die("matrixSslOpen\n");
401
402 do_io_until_eof_and_exit(fd, make_keys());
403 /* does not return */
404
405 return 0;
406}
diff --git a/networking/ssl_helper/ssl_helper.sh b/networking/ssl_helper/ssl_helper.sh
new file mode 100755
index 000000000..dc52de778
--- /dev/null
+++ b/networking/ssl_helper/ssl_helper.sh
@@ -0,0 +1,11 @@
1#!/bin/sh
2
3# I use this to build static uclibc based binary using Aboriginal Linux toolchain:
4PREFIX=x86_64-
5STATIC=-static
6# Standard build:
7PREFIX=""
8STATIC=""
9
10${PREFIX}gcc -Os -DPOSIX -I.. -I../sampleCerts -Wall -c ssl_helper.c -o ssl_helper.o
11${PREFIX}gcc $STATIC ssl_helper.o ../libmatrixssl.a -lc ../libmatrixssl.a -o ssl_helper
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index b0f0798e5..044f04673 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -711,7 +711,7 @@ static int d6_raw_socket(int ifindex)
711 /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */ 711 /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */
712 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), 712 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
713 /* L3: accept packet */ 713 /* L3: accept packet */
714 BPF_STMT(BPF_RET|BPF_K, 0xffffffff), 714 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
715 /* L4: discard packet */ 715 /* L4: discard packet */
716 BPF_STMT(BPF_RET|BPF_K, 0), 716 BPF_STMT(BPF_RET|BPF_K, 0),
717 }; 717 };
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index 8dee916d9..7dfc160e2 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -976,56 +976,13 @@ static int udhcp_raw_socket(int ifindex)
976 int fd; 976 int fd;
977 struct sockaddr_ll sock; 977 struct sockaddr_ll sock;
978 978
979 /*
980 * Comment:
981 *
982 * I've selected not to see LL header, so BPF doesn't see it, too.
983 * The filter may also pass non-IP and non-ARP packets, but we do
984 * a more complete check when receiving the message in userspace.
985 *
986 * and filter shamelessly stolen from:
987 *
988 * http://www.flamewarmaster.de/software/dhcpclient/
989 *
990 * There are a few other interesting ideas on that page (look under
991 * "Motivation"). Use of netlink events is most interesting. Think
992 * of various network servers listening for events and reconfiguring.
993 * That would obsolete sending HUP signals and/or make use of restarts.
994 *
995 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
996 * License: GPL v2.
997 *
998 * TODO: make conditional?
999 */
1000 static const struct sock_filter filter_instr[] = {
1001 /* load 9th byte (protocol) */
1002 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1003 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1004 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1005 /* L1: load halfword from offset 6 (flags and frag offset) */
1006 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1007 /* jump to L4 if any bits in frag offset field are set, else to L2 */
1008 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1009 /* L2: skip IP header (load index reg with header len) */
1010 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1011 /* load udp destination port from halfword[header_len + 2] */
1012 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1013 /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
1014 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1015 /* L3: accept packet */
1016 BPF_STMT(BPF_RET|BPF_K, 0xffffffff),
1017 /* L4: discard packet */
1018 BPF_STMT(BPF_RET|BPF_K, 0),
1019 };
1020 static const struct sock_fprog filter_prog = {
1021 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1022 /* casting const away: */
1023 .filter = (struct sock_filter *) filter_instr,
1024 };
1025
1026 log1("Opening raw socket on ifindex %d", ifindex); //log2? 979 log1("Opening raw socket on ifindex %d", ifindex); //log2?
1027 980
1028 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); 981 fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP));
982 /* ^^^^^
983 * SOCK_DGRAM: remove link-layer headers on input (SOCK_RAW keeps them)
984 * ETH_P_IP: want to receive only packets with IPv4 eth type
985 */
1029 log1("Got raw socket fd"); //log2? 986 log1("Got raw socket fd"); //log2?
1030 987
1031 sock.sll_family = AF_PACKET; 988 sock.sll_family = AF_PACKET;
@@ -1033,13 +990,58 @@ static int udhcp_raw_socket(int ifindex)
1033 sock.sll_ifindex = ifindex; 990 sock.sll_ifindex = ifindex;
1034 xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); 991 xbind(fd, (struct sockaddr *) &sock, sizeof(sock));
1035 992
993#if 0 /* Several users reported breakage when BPF filter is used */
1036 if (CLIENT_PORT == 68) { 994 if (CLIENT_PORT == 68) {
1037 /* Use only if standard port is in use */ 995 /* Use only if standard port is in use */
996 /*
997 * I've selected not to see LL header, so BPF doesn't see it, too.
998 * The filter may also pass non-IP and non-ARP packets, but we do
999 * a more complete check when receiving the message in userspace.
1000 *
1001 * and filter shamelessly stolen from:
1002 *
1003 * http://www.flamewarmaster.de/software/dhcpclient/
1004 *
1005 * There are a few other interesting ideas on that page (look under
1006 * "Motivation"). Use of netlink events is most interesting. Think
1007 * of various network servers listening for events and reconfiguring.
1008 * That would obsolete sending HUP signals and/or make use of restarts.
1009 *
1010 * Copyright: 2006, 2007 Stefan Rompf <sux@loplof.de>.
1011 * License: GPL v2.
1012 */
1013 static const struct sock_filter filter_instr[] = {
1014 /* load 9th byte (protocol) */
1015 BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9),
1016 /* jump to L1 if it is IPPROTO_UDP, else to L4 */
1017 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6),
1018 /* L1: load halfword from offset 6 (flags and frag offset) */
1019 BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6),
1020 /* jump to L4 if any bits in frag offset field are set, else to L2 */
1021 BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0),
1022 /* L2: skip IP header (load index reg with header len) */
1023 BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0),
1024 /* load udp destination port from halfword[header_len + 2] */
1025 BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2),
1026 /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */
1027 BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1),
1028 /* L3: accept packet ("accept 0x7fffffff bytes") */
1029 /* Accepting 0xffffffff works too but kernel 2.6.19 is buggy */
1030 BPF_STMT(BPF_RET|BPF_K, 0x7fffffff),
1031 /* L4: discard packet ("accept zero bytes") */
1032 BPF_STMT(BPF_RET|BPF_K, 0),
1033 };
1034 static const struct sock_fprog filter_prog = {
1035 .len = sizeof(filter_instr) / sizeof(filter_instr[0]),
1036 /* casting const away: */
1037 .filter = (struct sock_filter *) filter_instr,
1038 };
1038 /* Ignoring error (kernel may lack support for this) */ 1039 /* Ignoring error (kernel may lack support for this) */
1039 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, 1040 if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog,
1040 sizeof(filter_prog)) >= 0) 1041 sizeof(filter_prog)) >= 0)
1041 log1("Attached filter to raw socket fd"); // log? 1042 log1("Attached filter to raw socket fd"); // log?
1042 } 1043 }
1044#endif
1043 1045
1044 if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, 1046 if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA,
1045 &const_int_1, sizeof(int)) < 0 1047 &const_int_1, sizeof(int)) < 0
@@ -1230,7 +1232,7 @@ static void client_background(void)
1230int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 1232int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1231int udhcpc_main(int argc UNUSED_PARAM, char **argv) 1233int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1232{ 1234{
1233 uint8_t *temp, *message; 1235 uint8_t *message;
1234 const char *str_V, *str_h, *str_F, *str_r; 1236 const char *str_V, *str_h, *str_F, *str_r;
1235 IF_FEATURE_UDHCP_PORT(char *str_P;) 1237 IF_FEATURE_UDHCP_PORT(char *str_P;)
1236 void *clientid_mac_ptr; 1238 void *clientid_mac_ptr;
@@ -1638,6 +1640,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1638 case INIT_SELECTING: 1640 case INIT_SELECTING:
1639 /* Must be a DHCPOFFER */ 1641 /* Must be a DHCPOFFER */
1640 if (*message == DHCPOFFER) { 1642 if (*message == DHCPOFFER) {
1643 uint8_t *temp;
1644
1641/* What exactly is server's IP? There are several values. 1645/* What exactly is server's IP? There are several values.
1642 * Example DHCP offer captured with tchdump: 1646 * Example DHCP offer captured with tchdump:
1643 * 1647 *
@@ -1687,6 +1691,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1687 if (*message == DHCPACK) { 1691 if (*message == DHCPACK) {
1688 uint32_t lease_seconds; 1692 uint32_t lease_seconds;
1689 struct in_addr temp_addr; 1693 struct in_addr temp_addr;
1694 uint8_t *temp;
1690 1695
1691 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); 1696 temp = udhcp_get_option(&packet, DHCP_LEASE_TIME);
1692 if (!temp) { 1697 if (!temp) {
@@ -1764,6 +1769,26 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1764 continue; /* back to main loop */ 1769 continue; /* back to main loop */
1765 } 1770 }
1766 if (*message == DHCPNAK) { 1771 if (*message == DHCPNAK) {
1772 /* If network has more than one DHCP server,
1773 * "wrong" server can reply first, with a NAK.
1774 * Do not interpret it as a NAK from "our" server.
1775 */
1776 if (server_addr != 0) {
1777 uint32_t svid;
1778 uint8_t *temp;
1779
1780 temp = udhcp_get_option(&packet, DHCP_SERVER_ID);
1781 if (!temp) {
1782 non_matching_svid:
1783 log1("%s with wrong server ID, ignoring packet",
1784 "Received DHCP NAK"
1785 );
1786 continue;
1787 }
1788 move_from_unaligned32(svid, temp);
1789 if (svid != server_addr)
1790 goto non_matching_svid;
1791 }
1767 /* return to init state */ 1792 /* return to init state */
1768 bb_info_msg("Received DHCP NAK"); 1793 bb_info_msg("Received DHCP NAK");
1769 udhcp_run_script(&packet, "nak"); 1794 udhcp_run_script(&packet, "nak");
diff --git a/networking/wget.c b/networking/wget.c
index d6c509edc..62a5fcc02 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -46,11 +46,14 @@
46struct host_info { 46struct host_info {
47 char *allocated; 47 char *allocated;
48 const char *path; 48 const char *path;
49 const char *user; 49 char *user;
50 const char *protocol;
50 char *host; 51 char *host;
51 int port; 52 int port;
52 smallint is_ftp;
53}; 53};
54static const char P_FTP[] = "ftp";
55static const char P_HTTP[] = "http";
56static const char P_HTTPS[] = "https";
54 57
55 58
56/* Globals */ 59/* Globals */
@@ -219,7 +222,7 @@ static FILE *open_socket(len_and_sockaddr *lsa)
219 /* glibc 2.4 seems to try seeking on it - ??! */ 222 /* glibc 2.4 seems to try seeking on it - ??! */
220 /* hopefully it understands what ESPIPE means... */ 223 /* hopefully it understands what ESPIPE means... */
221 fp = fdopen(fd, "r+"); 224 fp = fdopen(fd, "r+");
222 if (fp == NULL) 225 if (!fp)
223 bb_perror_msg_and_die(bb_msg_memory_exhausted); 226 bb_perror_msg_and_die(bb_msg_memory_exhausted);
224 227
225 return fp; 228 return fp;
@@ -274,23 +277,31 @@ static void parse_url(const char *src_url, struct host_info *h)
274 free(h->allocated); 277 free(h->allocated);
275 h->allocated = url = xstrdup(src_url); 278 h->allocated = url = xstrdup(src_url);
276 279
277 if (strncmp(url, "ftp://", 6) == 0) { 280 h->protocol = P_FTP;
278 h->port = bb_lookup_port("ftp", "tcp", 21); 281 p = strstr(url, "://");
279 h->host = url + 6; 282 if (p) {
280 h->is_ftp = 1; 283 *p = '\0';
281 } else 284 h->host = p + 3;
282 if (strncmp(url, "http://", 7) == 0) { 285 if (strcmp(url, P_FTP) == 0) {
283 h->host = url + 7; 286 h->port = bb_lookup_port(P_FTP, "tcp", 21);
287 } else
288 if (strcmp(url, P_HTTPS) == 0) {
289 h->port = bb_lookup_port(P_HTTPS, "tcp", 443);
290 h->protocol = P_HTTPS;
291 } else
292 if (strcmp(url, P_HTTP) == 0) {
284 http: 293 http:
285 h->port = bb_lookup_port("http", "tcp", 80); 294 h->port = bb_lookup_port(P_HTTP, "tcp", 80);
286 h->is_ftp = 0; 295 h->protocol = P_HTTP;
287 } else 296 } else {
288 if (!strstr(url, "//")) { 297 *p = ':';
298 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
299 }
300 } else {
289 // GNU wget is user-friendly and falls back to http:// 301 // GNU wget is user-friendly and falls back to http://
290 h->host = url; 302 h->host = url;
291 goto http; 303 goto http;
292 } else 304 }
293 bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url));
294 305
295 // FYI: 306 // FYI:
296 // "Real" wget 'http://busybox.net?var=a/b' sends this request: 307 // "Real" wget 'http://busybox.net?var=a/b' sends this request:
@@ -322,9 +333,6 @@ static void parse_url(const char *src_url, struct host_info *h)
322 h->path = sp; 333 h->path = sp;
323 } 334 }
324 335
325 // We used to set h->user to NULL here, but this interferes
326 // with handling of code 302 ("object was moved")
327
328 sp = strrchr(h->host, '@'); 336 sp = strrchr(h->host, '@');
329 if (sp != NULL) { 337 if (sp != NULL) {
330 // URL-decode "user:password" string before base64-encoding: 338 // URL-decode "user:password" string before base64-encoding:
@@ -333,11 +341,13 @@ static void parse_url(const char *src_url, struct host_info *h)
333 // which decodes to "test:my pass". 341 // which decodes to "test:my pass".
334 // Standard wget and curl do this too. 342 // Standard wget and curl do this too.
335 *sp = '\0'; 343 *sp = '\0';
336 h->user = percent_decode_in_place(h->host, /*strict:*/ 0); 344 free(h->user);
345 h->user = xstrdup(percent_decode_in_place(h->host, /*strict:*/ 0));
337 h->host = sp + 1; 346 h->host = sp + 1;
338 } 347 }
339 348 /* else: h->user remains NULL, or as set by original request
340 sp = h->host; 349 * before redirect (if we are here after a redirect).
350 */
341} 351}
342 352
343static char *gethdr(FILE *fp) 353static char *gethdr(FILE *fp)
@@ -473,6 +483,95 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_
473 return sfp; 483 return sfp;
474} 484}
475 485
486static int spawn_https_helper(const char *host, unsigned port)
487{
488 char *allocated = NULL;
489 int sp[2];
490 int pid;
491
492 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
493 /* Kernel can have AF_UNIX support disabled */
494 bb_perror_msg_and_die("socketpair");
495
496 if (!strchr(host, ':'))
497 host = allocated = xasprintf("%s:%u", host, port);
498
499 pid = BB_MMU ? xfork() : xvfork();
500 if (pid == 0) {
501 /* Child */
502 char *argv[6];
503
504 close(sp[0]);
505 xmove_fd(sp[1], 0);
506 xdup2(0, 1);
507 /*
508 * TODO: develop a tiny ssl/tls helper (using matrixssl?),
509 * try to exec it here before falling back to big fat openssl.
510 */
511 /*
512 * openssl s_client -quiet -connect www.kernel.org:443 2>/dev/null
513 * It prints some debug stuff on stderr, don't know how to suppress it.
514 * Work around by dev-nulling stderr. We lose all error messages :(
515 */
516 xmove_fd(2, 3);
517 xopen("/dev/null", O_RDWR);
518 argv[0] = (char*)"openssl";
519 argv[1] = (char*)"s_client";
520 argv[2] = (char*)"-quiet";
521 argv[3] = (char*)"-connect";
522 argv[4] = (char*)host;
523 argv[5] = NULL;
524 BB_EXECVP(argv[0], argv);
525 xmove_fd(3, 2);
526 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
527 /* notreached */
528 }
529
530 /* Parent */
531 free(allocated);
532 close(sp[1]);
533 return sp[0];
534}
535
536/* See networking/ssl_helper/README */
537#define SSL_HELPER 0
538
539#if SSL_HELPER
540static void spawn_https_helper1(int network_fd)
541{
542 int sp[2];
543 int pid;
544
545 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sp) != 0)
546 /* Kernel can have AF_UNIX support disabled */
547 bb_perror_msg_and_die("socketpair");
548
549 pid = BB_MMU ? xfork() : xvfork();
550 if (pid == 0) {
551 /* Child */
552 char *argv[3];
553
554 close(sp[0]);
555 xmove_fd(sp[1], 0);
556 xdup2(0, 1);
557 xmove_fd(network_fd, 3);
558 /*
559 * A simple ssl/tls helper
560 */
561 argv[0] = (char*)"ssl_helper";
562 argv[1] = (char*)"-d3";
563 argv[2] = NULL;
564 BB_EXECVP(argv[0], argv);
565 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
566 /* notreached */
567 }
568
569 /* Parent */
570 close(sp[1]);
571 xmove_fd(sp[0], network_fd);
572}
573#endif
574
476static void NOINLINE retrieve_file_data(FILE *dfp) 575static void NOINLINE retrieve_file_data(FILE *dfp)
477{ 576{
478#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT 577#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT
@@ -645,7 +744,8 @@ static void download_one_url(const char *url)
645 /* Use the proxy if necessary */ 744 /* Use the proxy if necessary */
646 use_proxy = (strcmp(G.proxy_flag, "off") != 0); 745 use_proxy = (strcmp(G.proxy_flag, "off") != 0);
647 if (use_proxy) { 746 if (use_proxy) {
648 proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); 747 proxy = getenv(target.protocol == P_FTP ? "ftp_proxy" : "http_proxy");
748//FIXME: what if protocol is https? Ok to use http_proxy?
649 use_proxy = (proxy && proxy[0]); 749 use_proxy = (proxy && proxy[0]);
650 if (use_proxy) 750 if (use_proxy)
651 parse_url(proxy, &server); 751 parse_url(proxy, &server);
@@ -705,27 +805,37 @@ static void download_one_url(const char *url)
705 /*G.content_len = 0; - redundant, got_clen = 0 is enough */ 805 /*G.content_len = 0; - redundant, got_clen = 0 is enough */
706 G.got_clen = 0; 806 G.got_clen = 0;
707 G.chunked = 0; 807 G.chunked = 0;
708 if (use_proxy || !target.is_ftp) { 808 if (use_proxy || target.protocol != P_FTP) {
709 /* 809 /*
710 * HTTP session 810 * HTTP session
711 */ 811 */
712 char *str; 812 char *str;
713 int status; 813 int status;
714 814
715 815 /* Open socket to http(s) server */
716 /* Open socket to http server */ 816 if (target.protocol == P_HTTPS) {
717 sfp = open_socket(lsa); 817/* openssl-based helper
718 818 * Inconvenient API since we can't give it an open fd
819 */
820 int fd = spawn_https_helper(server.host, server.port);
821 sfp = fdopen(fd, "r+");
822 if (!sfp)
823 bb_perror_msg_and_die(bb_msg_memory_exhausted);
824 } else
825 sfp = open_socket(lsa);
826#if SSL_HELPER
827 if (target.protocol == P_HTTPS)
828 spawn_https_helper1(fileno(sfp));
829#endif
719 /* Send HTTP request */ 830 /* Send HTTP request */
720 if (use_proxy) { 831 if (use_proxy) {
721 fprintf(sfp, "GET %stp://%s/%s HTTP/1.1\r\n", 832 fprintf(sfp, "GET %s://%s/%s HTTP/1.1\r\n",
722 target.is_ftp ? "f" : "ht", target.host, 833 target.protocol, target.host,
723 target.path); 834 target.path);
724 } else { 835 } else {
725 if (option_mask32 & WGET_OPT_POST_DATA) 836 fprintf(sfp, "%s /%s HTTP/1.1\r\n",
726 fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); 837 (option_mask32 & WGET_OPT_POST_DATA) ? "POST" : "GET",
727 else 838 target.path);
728 fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path);
729 } 839 }
730 840
731 fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", 841 fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n",
@@ -880,6 +990,7 @@ However, in real world it was observed that some web servers
880 } else { 990 } else {
881 parse_url(str, &target); 991 parse_url(str, &target);
882 if (!use_proxy) { 992 if (!use_proxy) {
993 /* server.user remains untouched */
883 free(server.allocated); 994 free(server.allocated);
884 server.allocated = NULL; 995 server.allocated = NULL;
885 server.host = target.host; 996 server.host = target.host;
@@ -929,6 +1040,8 @@ However, in real world it was observed that some web servers
929 1040
930 free(server.allocated); 1041 free(server.allocated);
931 free(target.allocated); 1042 free(target.allocated);
1043 free(server.user);
1044 free(target.user);
932 free(fname_out_alloc); 1045 free(fname_out_alloc);
933 free(redirected_path); 1046 free(redirected_path);
934} 1047}
diff --git a/procps/sysctl.c b/procps/sysctl.c
index c6a1de21d..f0883f054 100644
--- a/procps/sysctl.c
+++ b/procps/sysctl.c
@@ -129,6 +129,9 @@ static int sysctl_act_on_setting(char *setting)
129 129
130 if (fd < 0) { 130 if (fd < 0) {
131 switch (errno) { 131 switch (errno) {
132 case EACCES:
133 /* Happens for write-only settings, e.g. net.ipv6.route.flush */
134 goto end;
132 case ENOENT: 135 case ENOENT:
133 if (option_mask32 & FLAG_SHOW_KEY_ERRORS) 136 if (option_mask32 & FLAG_SHOW_KEY_ERRORS)
134 bb_error_msg("error: '%s' is an unknown key", outname); 137 bb_error_msg("error: '%s' is an unknown key", outname);
diff --git a/testsuite/grep.tests b/testsuite/grep.tests
index 412efffbb..323b3849d 100755
--- a/testsuite/grep.tests
+++ b/testsuite/grep.tests
@@ -159,6 +159,18 @@ testing "grep -w ^ doesn't hang" \
159 "anything\n" \ 159 "anything\n" \
160 "" 160 ""
161 161
162testing "grep -w word doesn't match wordword" \
163 "grep -w word input" \
164 "" \
165 "wordword\n" \
166 ""
167
168testing "grep -w word match second word" \
169 "grep -w word input" \
170 "bword,word\n""wordb,word\n""bwordb,word\n" \
171 "bword,word\n""wordb,word\n""bwordb,word\n" \
172 ""
173
162# testing "test name" "commands" "expected result" "file input" "stdin" 174# testing "test name" "commands" "expected result" "file input" "stdin"
163# file input will be file called "input" 175# file input will be file called "input"
164# test can create a file "actual" instead of writing to stdout 176# test can create a file "actual" instead of writing to stdout
diff --git a/testsuite/which/which-uses-default-path b/testsuite/which/which-uses-default-path
index 349583dcc..92b6018c9 100644
--- a/testsuite/which/which-uses-default-path
+++ b/testsuite/which/which-uses-default-path
@@ -1,4 +1,4 @@
1BUSYBOX=$(command -pv busybox) 1BUSYBOX=$(command -v busybox)
2SAVED_PATH=$PATH 2SAVED_PATH=$PATH
3unset PATH 3unset PATH
4$BUSYBOX which ls 4$BUSYBOX which ls
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
index 379eeb253..3f531555b 100644
--- a/util-linux/hwclock.c
+++ b/util-linux/hwclock.c
@@ -97,7 +97,11 @@ static void to_sys_clock(const char **pp_rtcname, int utc)
97 struct timeval tv; 97 struct timeval tv;
98 struct timezone tz; 98 struct timezone tz;
99 99
100 tz.tz_minuteswest = timezone/60 - 60*daylight; 100 tz.tz_minuteswest = timezone/60;
101 /* ^^^ used to also subtract 60*daylight, but it's wrong:
102 * daylight!=0 means "this timezone has some DST
103 * during the year", not "DST is in effect now".
104 */
101 tz.tz_dsttime = 0; 105 tz.tz_dsttime = 0;
102 106
103 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc); 107 tv.tv_sec = read_rtc(pp_rtcname, NULL, utc);
@@ -248,7 +252,7 @@ static void set_system_clock_timezone(int utc)
248 gettimeofday(&tv, NULL); 252 gettimeofday(&tv, NULL);
249 broken = localtime(&tv.tv_sec); 253 broken = localtime(&tv.tv_sec);
250 tz.tz_minuteswest = timezone / 60; 254 tz.tz_minuteswest = timezone / 60;
251 if (broken->tm_isdst) 255 if (broken->tm_isdst > 0)
252 tz.tz_minuteswest -= 60; 256 tz.tz_minuteswest -= 60;
253 tz.tz_dsttime = 0; 257 tz.tz_dsttime = 0;
254 gettimeofday(&tv, NULL); 258 gettimeofday(&tv, NULL);
@@ -305,6 +309,10 @@ int hwclock_main(int argc UNUSED_PARAM, char **argv)
305 ; 309 ;
306 applet_long_options = hwclock_longopts; 310 applet_long_options = hwclock_longopts;
307#endif 311#endif
312
313 /* Initialize "timezone" (libc global variable) */
314 tzset();
315
308 opt_complementary = "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l"; 316 opt_complementary = "r--wst:w--rst:s--wrt:t--rsw:l--u:u--l";
309 opt = getopt32(argv, "lurswtf:", &rtcname); 317 opt = getopt32(argv, "lurswtf:", &rtcname);
310 318
diff --git a/util-linux/mkfs_reiser.c b/util-linux/mkfs_reiser.c
index b4efb9e9f..13abaa889 100644
--- a/util-linux/mkfs_reiser.c
+++ b/util-linux/mkfs_reiser.c
@@ -224,8 +224,8 @@ int mkfs_reiser_main(int argc UNUSED_PARAM, char **argv)
224 jp = &sb->sb_journal; 224 jp = &sb->sb_journal;
225 STORE_LE(jp->jp_journal_1st_block, REISERFS_DISK_OFFSET_IN_BYTES / blocksize + 1/*sb*/ + 1/*bmp#0*/); 225 STORE_LE(jp->jp_journal_1st_block, REISERFS_DISK_OFFSET_IN_BYTES / blocksize + 1/*sb*/ + 1/*bmp#0*/);
226 timestamp = time(NULL); 226 timestamp = time(NULL);
227 srandom(timestamp); 227 srand(timestamp);
228 STORE_LE(jp->jp_journal_magic, random()); 228 STORE_LE(jp->jp_journal_magic, rand());
229 STORE_LE(jp->jp_journal_size, journal_blocks); 229 STORE_LE(jp->jp_journal_size, journal_blocks);
230 STORE_LE(jp->jp_journal_trans_max, JOURNAL_TRANS_MAX); 230 STORE_LE(jp->jp_journal_trans_max, JOURNAL_TRANS_MAX);
231 STORE_LE(jp->jp_journal_max_batch, JOURNAL_MAX_BATCH); 231 STORE_LE(jp->jp_journal_max_batch, JOURNAL_MAX_BATCH);