diff options
57 files changed, 1537 insertions, 279 deletions
@@ -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 | ||
283 | config 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 | |||
283 | config LONG_OPTS | 290 | config 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 | */ |
123 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected) | 123 | int 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 | ||
185 | int FAST_FUNC open_zipped(const char *fname) | 185 | int 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 | ||
23 | int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
24 | int 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[ | 26 | struct 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 | ||
33 | int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
34 | int 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 | */ | ||
43 | static 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 | |||
63 | int shuf_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | ||
64 | int 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 & | |||
9 | from one of system startup scripts. (Google "man runsvdir" and "man runsv" | 9 | from one of system startup scripts. (Google "man runsvdir" and "man runsv" |
10 | for more info about these tools). | 10 | for more info about these tools). |
11 | 11 | ||
12 | You can try or debug an individual service by running its SERVICE_DIR/run script. | ||
13 | In this case, its stdout and stderr go to your terminal. | ||
14 | |||
15 | You can also run "runsv SERVICE_DIR", which runs both the service | ||
16 | and its logger service (SERVICE_DIR/log/run) if logger service exists. | ||
17 | If 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 | |||
12 | Some existing examples: | 21 | Some existing examples: |
13 | 22 | ||
14 | var_service/dhcp_if - | 23 | var_service/dhcp_if - |
@@ -47,8 +56,8 @@ This even works while fw service runs: if dhcp signals fw to (re)start | |||
47 | while fw runs, fw will not stop after its execution, but will re-execute once, | 56 | while fw runs, fw will not stop after its execution, but will re-execute once, |
48 | picking up dhcp's new configuration. | 57 | picking up dhcp's new configuration. |
49 | This is achieved very simply by having | 58 | This is achieved very simply by having |
50 | # Make ourself one-shot | 59 | # Make ourself one-shot |
51 | sv o . | 60 | sv o . |
52 | at the very beginning of fw/run script, not at the end. | 61 | at the very beginning of fw/run script, not at the end. |
53 | Therefore, any "sv u /var/run/service/fw" command by any other | 62 | Therefore, any "sv u /var/run/service/fw" command by any other |
54 | script "undoes" o(ne-shot) command if fw still runs, thus | 63 | script "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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 @@ | |||
1 | The real README file is one directory up. | ||
2 | |||
3 | This directory's run script can have useful comments. | ||
4 | If it doesn't but you feel it should, please send a patch | ||
5 | to 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 | ||
406 | static 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 | |||
417 | static 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 | ||
86 | struct globals { | 93 | struct 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 | */ | ||
101 | static int xargs_exec(void) | 111 | static 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. | ||
349 | static 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 | */ | ||
330 | static int xargs_ask_confirmation(void) | 401 | static 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 | ||
397 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 476 | int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
398 | int xargs_main(int argc, char **argv) | 477 | int 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; | |||
663 | void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; | 663 | void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; |
664 | char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; | 664 | char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; |
665 | char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; | 665 | char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; |
666 | unsigned count_strstr(const char *str, const char *sub) FAST_FUNC; | ||
667 | char *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 */ |
668 | int bb_putchar(int ch) FAST_FUNC; | 670 | int 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! */ |
752 | extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; | 754 | extern int setup_unzip_on_fd(int fd, int fail_if_not_compressed) FAST_FUNC; |
753 | /* Autodetects .gz etc */ | 755 | /* Autodetects .gz etc */ |
754 | extern int open_zipped(const char *fname) FAST_FUNC; | 756 | extern 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 |
759 | extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; | 761 | extern 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) | 611 | static 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 | ||
13 | typedef struct ino_dev_hash_bucket_struct { | 13 | typedef 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 */ |
24 | static ino_dev_hashtable_bucket_t **ino_dev_hashtable; | 33 | static 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 * | |||
72 | void FAST_FUNC reset_ino_dev_hashtable(void) | 83 | void 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 | ||
143 | char* FAST_FUNC pw_encrypt(const char *clear, const char *salt, int cleanup) | 143 | char* 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 | |||
14 | unsigned 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 | |||
26 | char* 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 | ||
226 | config 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 | |||
233 | config LOGIN_SCRIPTS | 226 | config 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; | |||
163 | int sendmail_main(int argc UNUSED_PARAM, char **argv) | 210 | int 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; | |||
150 | int man_main(int argc UNUSED_PARAM, char **argv) | 151 | int 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 | |||
294 | static const char *strstatus(int status) | 292 | static 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 | ||
688 | static int FAST_FUNC link_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) | ||
689 | { | ||
690 | return 1; | ||
691 | } | ||
692 | |||
693 | static const struct method_t link_methods[] = { | ||
694 | { "none", link_up_down, link_up_down } | ||
695 | }; | ||
696 | |||
697 | static 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 | ||
40 | struct 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 */ |
40 | static int get_ctl_fd(void) | 56 | static int get_ctl_fd(void) |
41 | { | 57 | { |
@@ -391,12 +407,13 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) | |||
391 | static int do_add_or_delete(char **argv, const unsigned rtm) | 407 | static 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 */ |
487 | int FAST_FUNC do_iplink(char **argv) | 683 | int 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) | |||
1660 | static unsigned | 1660 | static unsigned |
1661 | poll_interval(int exponent) | 1661 | poll_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 | } |
537 | static void | 537 | static 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 @@ | |||
1 | Build 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 | |||
8 | Usage: "ssl_helper -d <FILE_DESCRIPTOR>" where FILE_DESCRIPTOR is open to the peer. | ||
9 | |||
10 | In bash, you can do it this way: | ||
11 | $ ssl_helper -d3 3<>/dev/tcp/HOST/PORT | ||
12 | |||
13 | Stdin will be SSL-encrypted and sent to FILE_DESCRIPTOR. | ||
14 | Data from FILE_DESCRIPTOR will be decrypted and sent to stdout. | ||
15 | |||
16 | The 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 | |||
56 | static 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 | |||
67 | static 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 | |||
94 | static 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 | |||
106 | static 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 | |||
125 | static 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 | |||
134 | static 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 | |||
143 | static 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 | |||
156 | static 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 | |||
177 | static 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 | |||
193 | static 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 | |||
209 | static 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); | ||
226 | dbg("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; | ||
266 | dbg("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); | ||
290 | dbg("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: | ||
305 | dbg("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); | ||
333 | dbg("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 | |||
343 | static 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 | |||
378 | int 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: | ||
4 | PREFIX=x86_64- | ||
5 | STATIC=-static | ||
6 | # Standard build: | ||
7 | PREFIX="" | ||
8 | STATIC="" | ||
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) | |||
1230 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 1232 | int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
1231 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) | 1233 | int 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 @@ | |||
46 | struct host_info { | 46 | struct 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 | }; |
54 | static const char P_FTP[] = "ftp"; | ||
55 | static const char P_HTTP[] = "http"; | ||
56 | static 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 | ||
343 | static char *gethdr(FILE *fp) | 353 | static 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 | ||
486 | static 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 | ||
540 | static 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 | |||
476 | static void NOINLINE retrieve_file_data(FILE *dfp) | 575 | static 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 | ||
162 | testing "grep -w word doesn't match wordword" \ | ||
163 | "grep -w word input" \ | ||
164 | "" \ | ||
165 | "wordword\n" \ | ||
166 | "" | ||
167 | |||
168 | testing "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 @@ | |||
1 | BUSYBOX=$(command -pv busybox) | 1 | BUSYBOX=$(command -v busybox) |
2 | SAVED_PATH=$PATH | 2 | SAVED_PATH=$PATH |
3 | unset PATH | 3 | unset 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); |