aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2019-05-27 11:56:52 +0100
committerRon Yorston <rmy@pobox.com>2019-05-27 11:56:52 +0100
commita61949401890cbb33a9d6c4571b51c53460ad438 (patch)
tree64dedaddb89896d5b1670a421af123670ca2120b
parent03a7b173605a890e1db5177ecd5b8dd591081c41 (diff)
parentbcb1fc3e6ca6fe902610f507eaf9b0b58a5c583a (diff)
downloadbusybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.tar.gz
busybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.tar.bz2
busybox-w32-a61949401890cbb33a9d6c4571b51c53460ad438.zip
Merge branch 'busybox' into merge
-rw-r--r--Config.in9
-rw-r--r--archival/libarchive/decompress_bunzip2.c2
-rw-r--r--archival/libarchive/open_transformer.c44
-rw-r--r--coreutils/dd.c26
-rw-r--r--coreutils/ln.c2
-rw-r--r--coreutils/ls.c2
-rw-r--r--debianutils/start_stop_daemon.c35
-rw-r--r--editors/sed.c2
-rw-r--r--editors/vi.c16
-rwxr-xr-xexamples/shutdown-1.0/script/stop_storage2
-rw-r--r--examples/udhcp/udhcpd.conf9
-rwxr-xr-xexamples/var_service/dhcp_if/run2
-rwxr-xr-xexamples/var_service/dhcpd_if/run2
-rwxr-xr-xexamples/var_service/ifplugd_if/run2
-rwxr-xr-xexamples/var_service/supplicant_if/run2
-rwxr-xr-xexamples/var_service/zcip_if/run2
-rw-r--r--include/bb_archive.h6
-rw-r--r--include/libbb.h10
-rw-r--r--libbb/find_mount_point.c15
-rw-r--r--libbb/full_write.c3
-rw-r--r--libbb/lineedit.c13
-rw-r--r--libbb/read_printf.c12
-rw-r--r--libbb/verror_msg.c22
-rw-r--r--libbb/vfork_daemon_rexec.c17
-rw-r--r--loginutils/chpasswd.c2
-rw-r--r--loginutils/login.c2
-rw-r--r--loginutils/passwd.c2
-rw-r--r--loginutils/sulogin.c6
-rw-r--r--miscutils/crond.c6
-rw-r--r--miscutils/dc.c27
-rw-r--r--miscutils/devfsd.c2
-rw-r--r--modutils/lsmod.c5
-rw-r--r--networking/dnsd.c10
-rw-r--r--networking/ifplugd.c20
-rw-r--r--networking/ifupdown.c12
-rw-r--r--networking/libiproute/ipaddress.c8
-rw-r--r--networking/libiproute/ipneigh.c9
-rw-r--r--networking/libiproute/iproute.c5
-rw-r--r--networking/libiproute/libnetlink.c43
-rw-r--r--networking/libiproute/libnetlink.h19
-rw-r--r--networking/libiproute/ll_proto.c2
-rw-r--r--networking/ntpd.c4
-rw-r--r--networking/tc.c6
-rw-r--r--networking/tftp.c2
-rw-r--r--networking/tls.c6
-rw-r--r--networking/tls_aes.c2
-rw-r--r--networking/tls_pstm_montgomery_reduce.c12
-rw-r--r--networking/tls_pstm_mul_comba.c4
-rw-r--r--networking/tls_pstm_sqr_comba.c22
-rw-r--r--networking/udhcp/common.c2
-rw-r--r--networking/udhcp/common.h58
-rw-r--r--networking/udhcp/d6_common.h2
-rw-r--r--networking/udhcp/d6_dhcpc.c201
-rw-r--r--networking/udhcp/d6_packet.c4
-rw-r--r--networking/udhcp/dhcpc.c257
-rw-r--r--networking/udhcp/dhcpc.h12
-rw-r--r--networking/udhcp/dhcpd.c183
-rw-r--r--networking/udhcp/dhcpd.h8
-rw-r--r--networking/udhcp/packet.c6
-rw-r--r--networking/wget.c2
-rw-r--r--networking/zcip.c4
-rw-r--r--procps/ps.c2
-rw-r--r--shell/Config.src5
-rw-r--r--shell/ash_test/ash-misc/export1.right1
-rwxr-xr-xshell/ash_test/ash-misc/export1.tests2
-rw-r--r--shell/ash_test/ash-vars/param_expand_default.right2
-rwxr-xr-xshell/ash_test/ash-vars/param_expand_default.tests6
-rw-r--r--shell/hush.c241
-rw-r--r--shell/hush_test/hush-misc/export1.right1
-rwxr-xr-xshell/hush_test/hush-misc/export1.tests2
-rw-r--r--shell/hush_test/hush-vars/param_expand_default.right3
-rwxr-xr-xshell/hush_test/hush-vars/param_expand_default.tests7
-rw-r--r--shell/math.c42
-rw-r--r--shell/math.h4
-rw-r--r--shell/shell_common.c343
-rw-r--r--shell/shell_common.h2
-rwxr-xr-xtestsuite/bunzip2.tests2
-rwxr-xr-xtestsuite/sed.tests6
-rw-r--r--util-linux/losetup.c32
-rw-r--r--util-linux/mount.c5
80 files changed, 1153 insertions, 789 deletions
diff --git a/Config.in b/Config.in
index 5db86e270..f6ad627b2 100644
--- a/Config.in
+++ b/Config.in
@@ -353,6 +353,15 @@ config FEATURE_CLEAN_UP
353 Don't enable this unless you have a really good reason to clean 353 Don't enable this unless you have a really good reason to clean
354 things up manually. 354 things up manually.
355 355
356config FEATURE_SYSLOG_INFO
357 bool "Support LOG_INFO level syslog messages"
358 default y
359 depends on FEATURE_SYSLOG
360 help
361 Applets which send their output to syslog use either LOG_INFO or
362 LOG_ERR log levels, but by disabling this option all messages will
363 be logged at the LOG_ERR level, saving just under 200 bytes.
364
356# These are auto-selected by other options 365# These are auto-selected by other options
357 366
358config FEATURE_SYSLOG 367config FEATURE_SYSLOG
diff --git a/archival/libarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c
index 78366f26a..1f535b32a 100644
--- a/archival/libarchive/decompress_bunzip2.c
+++ b/archival/libarchive/decompress_bunzip2.c
@@ -235,9 +235,9 @@ static int get_next_block(bunzip_data *bd)
235 /* Get next value */ 235 /* Get next value */
236 int n = 0; 236 int n = 0;
237 while (get_bits(bd, 1)) { 237 while (get_bits(bd, 1)) {
238 n++;
238 if (n >= groupCount) 239 if (n >= groupCount)
239 return RETVAL_DATA_ERROR; 240 return RETVAL_DATA_ERROR;
240 n++;
241 } 241 }
242 /* Decode MTF to get the next selector */ 242 /* Decode MTF to get the next selector */
243 tmp_byte = mtfSymbol[n]; 243 tmp_byte = mtfSymbol[n];
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c
index 69f3ecc66..3a0fc4712 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -180,47 +180,44 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
180 */ 180 */
181static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) 181static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed)
182{ 182{
183 union {
184 uint8_t b[4];
185 uint16_t b16[2];
186 uint32_t b32[1];
187 } magic;
188 transformer_state_t *xstate; 183 transformer_state_t *xstate;
189 184
190 xstate = xzalloc(sizeof(*xstate)); 185 xstate = xzalloc(sizeof(*xstate));
191 xstate->src_fd = fd; 186 xstate->src_fd = fd;
192 xstate->signature_skipped = 2;
193 187
194 /* .gz and .bz2 both have 2-byte signature, and their 188 /* .gz and .bz2 both have 2-byte signature, and their
195 * unpack_XXX_stream wants this header skipped. */ 189 * unpack_XXX_stream wants this header skipped. */
196 xread(fd, magic.b16, sizeof(magic.b16[0])); 190 xstate->signature_skipped = 2;
191 xread(fd, xstate->magic.b16, 2);
197 if (ENABLE_FEATURE_SEAMLESS_GZ 192 if (ENABLE_FEATURE_SEAMLESS_GZ
198 && magic.b16[0] == GZIP_MAGIC 193 && xstate->magic.b16[0] == GZIP_MAGIC
199 ) { 194 ) {
200 xstate->xformer = unpack_gz_stream; 195 xstate->xformer = unpack_gz_stream;
201 USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";) 196 USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";)
202 goto found_magic; 197 goto found_magic;
203 } 198 }
204 if (ENABLE_FEATURE_SEAMLESS_Z 199 if (ENABLE_FEATURE_SEAMLESS_Z
205 && magic.b16[0] == COMPRESS_MAGIC 200 && xstate->magic.b16[0] == COMPRESS_MAGIC
206 ) { 201 ) {
207 xstate->xformer = unpack_Z_stream; 202 xstate->xformer = unpack_Z_stream;
208 USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";) 203 USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";)
209 goto found_magic; 204 goto found_magic;
210 } 205 }
211 if (ENABLE_FEATURE_SEAMLESS_BZ2 206 if (ENABLE_FEATURE_SEAMLESS_BZ2
212 && magic.b16[0] == BZIP2_MAGIC 207 && xstate->magic.b16[0] == BZIP2_MAGIC
213 ) { 208 ) {
214 xstate->xformer = unpack_bz2_stream; 209 xstate->xformer = unpack_bz2_stream;
215 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";) 210 USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";)
216 goto found_magic; 211 goto found_magic;
217 } 212 }
218 if (ENABLE_FEATURE_SEAMLESS_XZ 213 if (ENABLE_FEATURE_SEAMLESS_XZ
219 && magic.b16[0] == XZ_MAGIC1 214 && xstate->magic.b16[0] == XZ_MAGIC1
220 ) { 215 ) {
216 uint32_t v32;
221 xstate->signature_skipped = 6; 217 xstate->signature_skipped = 6;
222 xread(fd, magic.b32, sizeof(magic.b32[0])); 218 xread(fd, &xstate->magic.b16[1], 4);
223 if (magic.b32[0] == XZ_MAGIC2) { 219 move_from_unaligned32(v32, &xstate->magic.b16[1]);
220 if (v32 == XZ_MAGIC2) {
224 xstate->xformer = unpack_xz_stream; 221 xstate->xformer = unpack_xz_stream;
225 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";) 222 USE_FOR_NOMMU(xstate->xformer_prog = "unxz";)
226 goto found_magic; 223 goto found_magic;
@@ -365,11 +362,24 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
365 *maxsz_p = xstate->mem_output_size; 362 *maxsz_p = xstate->mem_output_size;
366 } 363 }
367 } else { 364 } else {
368 /* File is not compressed */ 365 /* File is not compressed.
369//FIXME: avoid seek 366 * We already read first few bytes, account for that.
370 xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR); 367 * Example where it happens:
368 * "modinfo MODULE.ko" (not compressed)
369 * open("MODULE.ko", O_RDONLY|O_LARGEFILE) = 4
370 * read(4, "\177E", 2) = 2
371 * fstat64(4, ...)
372 * mmap(...)
373 * read(4, "LF\2\1\1\0\0\0\0"...
374 * ...and we avoided seeking on the fd! :)
375 */
376 image = xmalloc_read_with_initial_buf(
377 xstate->src_fd,
378 maxsz_p,
379 xmemdup(&xstate->magic, xstate->signature_skipped),
380 xstate->signature_skipped
381 );
371 xstate->signature_skipped = 0; 382 xstate->signature_skipped = 0;
372 image = xmalloc_read(xstate->src_fd, maxsz_p);
373 } 383 }
374 384
375 if (!image) 385 if (!image)
diff --git a/coreutils/dd.c b/coreutils/dd.c
index 2d91f77ef..3054ec6ea 100644
--- a/coreutils/dd.c
+++ b/coreutils/dd.c
@@ -195,23 +195,15 @@ static void dd_output_status(int UNUSED_PARAM cur_signal)
195#endif 195#endif
196} 196}
197 197
198static ssize_t full_write_or_warn(const void *buf, size_t len,
199 const char *const filename)
200{
201 ssize_t n = full_write(ofd, buf, len);
202 if (n < 0)
203 bb_perror_msg("writing '%s'", filename);
204 return n;
205}
206
207static bool write_and_stats(const void *buf, size_t len, size_t obs, 198static bool write_and_stats(const void *buf, size_t len, size_t obs,
208 const char *filename) 199 const char *filename)
209{ 200{
210 ssize_t n = full_write_or_warn(buf, len, filename); 201 ssize_t n;
211 if (n < 0) 202
212 return 1; 203 n = full_write(ofd, buf, len);
213#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE 204#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE
214 G.total_bytes += n; 205 if (n > 0)
206 G.total_bytes += n;
215#endif 207#endif
216 if ((size_t)n == obs) { 208 if ((size_t)n == obs) {
217 G.out_full++; 209 G.out_full++;
@@ -221,6 +213,14 @@ static bool write_and_stats(const void *buf, size_t len, size_t obs,
221 G.out_part++; 213 G.out_part++;
222 return 0; 214 return 0;
223 } 215 }
216 /* n is < len (and possibly is -1).
217 * Even if n >= 0, errno is usually set correctly.
218 * For example, if writing to block device and getting ENOSPC,
219 * full_write() first sees a short write, then tries to write
220 * the remainder and gets errno set to ENOSPC.
221 * It returns n > 0 (the amount which it did write).
222 */
223 bb_perror_msg("error writing '%s'", filename);
224 return 1; 224 return 1;
225} 225}
226 226
diff --git a/coreutils/ln.c b/coreutils/ln.c
index 3fe2f3f64..afeb0d72d 100644
--- a/coreutils/ln.c
+++ b/coreutils/ln.c
@@ -29,7 +29,7 @@
29//usage: "\n -n Don't dereference symlinks - treat like normal file" 29//usage: "\n -n Don't dereference symlinks - treat like normal file"
30//usage: "\n -b Make a backup of the target (if exists) before link operation" 30//usage: "\n -b Make a backup of the target (if exists) before link operation"
31//usage: "\n -S suf Use suffix instead of ~ when making backup files" 31//usage: "\n -S suf Use suffix instead of ~ when making backup files"
32//usage: "\n -T 2nd arg must be a DIR" 32//usage: "\n -T Treat LINK as a file, not DIR"
33//usage: "\n -v Verbose" 33//usage: "\n -v Verbose"
34//usage: 34//usage:
35//usage:#define ln_example_usage 35//usage:#define ln_example_usage
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 6be3eb291..3eff5a949 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -1096,7 +1096,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
1096 static const char ls_longopts[] ALIGN1 = 1096 static const char ls_longopts[] ALIGN1 =
1097 "full-time\0" No_argument "\xff" 1097 "full-time\0" No_argument "\xff"
1098 "group-directories-first\0" No_argument "\xfe" 1098 "group-directories-first\0" No_argument "\xfe"
1099 "color\0" Optional_argument "\xfd" 1099 IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd")
1100 ; 1100 ;
1101#endif 1101#endif
1102 1102
diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c
index 3a4c1044a..72642ae74 100644
--- a/debianutils/start_stop_daemon.c
+++ b/debianutils/start_stop_daemon.c
@@ -94,7 +94,7 @@ Misc options:
94//usage: "\n -n NAME Match processes with NAME" 94//usage: "\n -n NAME Match processes with NAME"
95//usage: "\n in comm field in /proc/PID/stat" 95//usage: "\n in comm field in /proc/PID/stat"
96//usage: "\n -x EXECUTABLE Match processes with this command" 96//usage: "\n -x EXECUTABLE Match processes with this command"
97//usage: "\n command in /proc/PID/cmdline" 97//usage: "\n in /proc/PID/cmdline"
98//usage: "\n -p FILE Match a process with PID from FILE" 98//usage: "\n -p FILE Match a process with PID from FILE"
99//usage: "\n All specified conditions must match" 99//usage: "\n All specified conditions must match"
100//usage: "\n-S only:" 100//usage: "\n-S only:"
@@ -452,31 +452,34 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
452// "start-stop-daemon -S -a sleep -- 5" 452// "start-stop-daemon -S -a sleep -- 5"
453// NB: -n option does _not_ behave in this way: this will try to execute "5": 453// NB: -n option does _not_ behave in this way: this will try to execute "5":
454// "start-stop-daemon -S -n sleep -- 5" 454// "start-stop-daemon -S -n sleep -- 5"
455 if (!execname) { /* -x is not given */ 455 if (opt & CTX_START) {
456 execname = startas; 456 if (!execname) { /* -x is not given */
457 if (!execname) { /* neither -x nor -a is given */ 457 execname = startas;
458 execname = argv[0]; 458 if (!execname) { /* neither -x nor -a is given */
459 if (!execname) 459 execname = argv[0];
460 bb_show_usage(); 460 if (!execname)
461 argv++; 461 bb_show_usage();
462 argv++;
463 }
462 } 464 }
465 if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */
466 startas = execname;
467 *--argv = startas;
468 }
469 if (execname) {
470 G.execname_sizeof = strlen(execname) + 1;
471 G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
463 } 472 }
464 if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */
465 startas = execname;
466 *--argv = startas;
467 G.execname_sizeof = strlen(execname) + 1;
468 G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1);
469
470// IF_FEATURE_START_STOP_DAEMON_FANCY( 473// IF_FEATURE_START_STOP_DAEMON_FANCY(
471// if (retry_arg) 474// if (retry_arg)
472// retries = xatoi_positive(retry_arg); 475// retries = xatoi_positive(retry_arg);
473// ) 476// )
474
475 if (userspec) { 477 if (userspec) {
476 user_id = bb_strtou(userspec, NULL, 10); 478 user_id = bb_strtou(userspec, NULL, 10);
477 if (errno) 479 if (errno)
478 user_id = xuname2uid(userspec); 480 user_id = xuname2uid(userspec);
479 } 481 }
482
480 /* Both start and stop need to know current processes */ 483 /* Both start and stop need to know current processes */
481 do_procinit(); 484 do_procinit();
482 485
@@ -485,6 +488,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv)
485 return (opt & OPT_OKNODO) ? 0 : (i <= 0); 488 return (opt & OPT_OKNODO) ? 0 : (i <= 0);
486 } 489 }
487 490
491 /* else: CTX_START (-S). execname can't be NULL. */
492
488 if (G.found_procs) { 493 if (G.found_procs) {
489 if (!QUIET) 494 if (!QUIET)
490 printf("%s is already running\n", execname); 495 printf("%s is already running\n", execname);
diff --git a/editors/sed.c b/editors/sed.c
index a5cedbd8d..a93e5494a 100644
--- a/editors/sed.c
+++ b/editors/sed.c
@@ -1108,6 +1108,8 @@ static void process_files(void)
1108 int old_matched, matched; 1108 int old_matched, matched;
1109 1109
1110 old_matched = sed_cmd->in_match; 1110 old_matched = sed_cmd->in_match;
1111 if (!old_matched)
1112 sed_cmd->end_line = sed_cmd->end_line_orig;
1111 1113
1112 /* Determine if this command matches this line: */ 1114 /* Determine if this command matches this line: */
1113 1115
diff --git a/editors/vi.c b/editors/vi.c
index a8b4dc5a4..70c8f3daf 100644
--- a/editors/vi.c
+++ b/editors/vi.c
@@ -3067,11 +3067,14 @@ static void do_cmd(int c);
3067static int find_range(char **start, char **stop, char c) 3067static int find_range(char **start, char **stop, char c)
3068{ 3068{
3069 char *save_dot, *p, *q, *t; 3069 char *save_dot, *p, *q, *t;
3070 int cnt, multiline = 0; 3070 int cnt, multiline = 0, forward;
3071 3071
3072 save_dot = dot; 3072 save_dot = dot;
3073 p = q = dot; 3073 p = q = dot;
3074 3074
3075 // will a 'G' command move forwards or backwards?
3076 forward = cmdcnt == 0 || cmdcnt > count_lines(text, dot);
3077
3075 if (strchr("cdy><", c)) { 3078 if (strchr("cdy><", c)) {
3076 // these cmds operate on whole lines 3079 // these cmds operate on whole lines
3077 p = q = begin_line(p); 3080 p = q = begin_line(p);
@@ -3095,13 +3098,13 @@ static int find_range(char **start, char **stop, char c)
3095 if (dot > text && *dot == '\n') 3098 if (dot > text && *dot == '\n')
3096 dot--; // stay off NL 3099 dot--; // stay off NL
3097 q = dot; 3100 q = dot;
3098 } else if (strchr("H-k{", c)) { 3101 } else if (strchr("H-k{", c) || (c == 'G' && !forward)) {
3099 // these operate on multi-lines backwards 3102 // these operate on multi-lines backwards
3100 q = end_line(dot); // find NL 3103 q = end_line(dot); // find NL
3101 do_cmd(c); // execute movement cmd 3104 do_cmd(c); // execute movement cmd
3102 dot_begin(); 3105 dot_begin();
3103 p = dot; 3106 p = dot;
3104 } else if (strchr("L+j}\r\n", c)) { 3107 } else if (strchr("L+j}\r\n", c) || (c == 'G' && forward)) {
3105 // these operate on multi-lines forwards 3108 // these operate on multi-lines forwards
3106 p = begin_line(dot); 3109 p = begin_line(dot);
3107 do_cmd(c); // execute movement cmd 3110 do_cmd(c); // execute movement cmd
@@ -3836,11 +3839,10 @@ static void do_cmd(int c)
3836 if (c1 == 27) { // ESC- user changed mind and wants out 3839 if (c1 == 27) { // ESC- user changed mind and wants out
3837 c = c1 = 27; // Escape- do nothing 3840 c = c1 = 27; // Escape- do nothing
3838 } else if (strchr("wW", c1)) { 3841 } else if (strchr("wW", c1)) {
3842 ml = 0; // multi-line ranges aren't allowed for words
3839 if (c == 'c') { 3843 if (c == 'c') {
3840 // don't include trailing WS as part of word 3844 // don't include trailing WS as part of word
3841 while (isblank(*q)) { 3845 while (isspace(*q) && q > p) {
3842 if (q <= text || q[-1] == '\n')
3843 break;
3844 q--; 3846 q--;
3845 } 3847 }
3846 } 3848 }
@@ -3848,7 +3850,7 @@ static void do_cmd(int c)
3848 } else if (strchr("^0bBeEft%$ lh\b\177", c1)) { 3850 } else if (strchr("^0bBeEft%$ lh\b\177", c1)) {
3849 // partial line copy text into a register and delete 3851 // partial line copy text into a register and delete
3850 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word 3852 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete word
3851 } else if (strchr("cdykjHL+-{}\r\n", c1)) { 3853 } else if (strchr("cdykjGHL+-{}\r\n", c1)) {
3852 // whole line copy text into a register and delete 3854 // whole line copy text into a register and delete
3853 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete lines 3855 dot = yank_delete(p, q, ml, yf, ALLOW_UNDO); // delete lines
3854 whole = 1; 3856 whole = 1;
diff --git a/examples/shutdown-1.0/script/stop_storage b/examples/shutdown-1.0/script/stop_storage
index 1be5f735b..50f3b4dd2 100755
--- a/examples/shutdown-1.0/script/stop_storage
+++ b/examples/shutdown-1.0/script/stop_storage
@@ -4,7 +4,7 @@
4# Repeat. 4# Repeat.
5 5
6umountcnt=2 6umountcnt=2
7writeout=0 # increase if your kernel doesn ot guarantee writes to complete 7writeout=0 # increase if your kernel does not guarantee writes to complete
8 8
9# No /usr - we are expecting all binaries to be accessible 9# No /usr - we are expecting all binaries to be accessible
10# from root fs alone 10# from root fs alone
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf
index bb8774e08..df1258aaf 100644
--- a/examples/udhcp/udhcpd.conf
+++ b/examples/udhcp/udhcpd.conf
@@ -44,7 +44,7 @@ interface eth0
44#notify_file # default: no script 44#notify_file # default: no script
45#notify_file dumpleases # useful for debugging 45#notify_file dumpleases # useful for debugging
46 46
47# The following are bootp specific options 47# The following are BOOTP specific options
48# next server to use in bootstrap 48# next server to use in bootstrap
49#siaddr 192.168.0.22 # default: 0.0.0.0 (none) 49#siaddr 192.168.0.22 # default: 0.0.0.0 (none)
50# tftp server name 50# tftp server name
@@ -52,9 +52,14 @@ interface eth0
52# tftp file to download (e.g. kernel image) 52# tftp file to download (e.g. kernel image)
53#boot_file /var/nfs_root # default: none 53#boot_file /var/nfs_root # default: none
54 54
55# NOTE: "boot_file FILE" and "opt bootfile FILE" are conceptually the same,
56# but "boot_file" goes into BOOTP-defined fixed-size field in the packet,
57# whereas "opt bootfile" goes into DHCP option 0x43.
58# Same for "sname HOST" and "opt tftp HOST".
59
55# Static leases map 60# Static leases map
56#static_lease 00:60:08:11:CE:4E 192.168.0.54 61#static_lease 00:60:08:11:CE:4E 192.168.0.54
57#static_lease 00:60:08:11:CE:3E 192.168.0.44 62#static_lease 00:60:08:11:CE:3E 192.168.0.44 optional_hostname
58 63
59# The remainder of options are DHCP options and can be specified with the 64# The remainder of options are DHCP options and can be specified with the
60# keyword 'opt' or 'option'. If an option can take multiple items, such 65# keyword 'opt' or 'option'. If an option can take multiple items, such
diff --git a/examples/var_service/dhcp_if/run b/examples/var_service/dhcp_if/run
index d8f343586..882f008d6 100755
--- a/examples/var_service/dhcp_if/run
+++ b/examples/var_service/dhcp_if/run
@@ -8,7 +8,7 @@ pwd="$PWD"
8if="${PWD##*/dhcp_}" 8if="${PWD##*/dhcp_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev "$if" up || { sleep 5; exit; } 11ip link set dev "$if" up || exec sleep 5
12 12
13echo "* Starting udhcpc on $if [$$]" 13echo "* Starting udhcpc on $if [$$]"
14exec \ 14exec \
diff --git a/examples/var_service/dhcpd_if/run b/examples/var_service/dhcpd_if/run
index e3d1b00f4..82ac08aa4 100755
--- a/examples/var_service/dhcpd_if/run
+++ b/examples/var_service/dhcpd_if/run
@@ -8,7 +8,7 @@ pwd="$PWD"
8if="${PWD##*/dhcpd_}" 8if="${PWD##*/dhcpd_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev $if up || { sleep 5; exit; } 11ip link set dev $if up || exec sleep 5
12 12
13>>udhcpd.leases 13>>udhcpd.leases
14sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf 14sed 's/^interface.*$/interface '"$if/" -i udhcpd.conf
diff --git a/examples/var_service/ifplugd_if/run b/examples/var_service/ifplugd_if/run
index e7816619d..cfddfec06 100755
--- a/examples/var_service/ifplugd_if/run
+++ b/examples/var_service/ifplugd_if/run
@@ -9,7 +9,7 @@ pwd="$PWD"
9if="${PWD##*/ifplugd_}" 9if="${PWD##*/ifplugd_}"
10 10
11echo "* Upping iface $if" 11echo "* Upping iface $if"
12ip link set dev "$if" up || { sleep 5; exit; } 12ip link set dev "$if" up || exec sleep 5
13 13
14echo "* Starting ifplugd on $if [$$]" 14echo "* Starting ifplugd on $if [$$]"
15exec \ 15exec \
diff --git a/examples/var_service/supplicant_if/run b/examples/var_service/supplicant_if/run
index bc16fb606..5c813b07f 100755
--- a/examples/var_service/supplicant_if/run
+++ b/examples/var_service/supplicant_if/run
@@ -9,7 +9,7 @@ if="${PWD##*/dhcp_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11# "or sleep" idiom prevents rapid respawning if iface does not exist 11# "or sleep" idiom prevents rapid respawning if iface does not exist
12ip link set dev "$if" up || { sleep 5; exit; } 12ip link set dev "$if" up || exec sleep 5
13 13
14##echo "* Powersave disable on $if" 14##echo "* Powersave disable on $if"
15##iw dev "$if" set power_save off 15##iw dev "$if" set power_save off
diff --git a/examples/var_service/zcip_if/run b/examples/var_service/zcip_if/run
index 699823246..69f8b9bae 100755
--- a/examples/var_service/zcip_if/run
+++ b/examples/var_service/zcip_if/run
@@ -8,7 +8,7 @@ pwd="$PWD"
8if="${PWD##*/zcip_}" 8if="${PWD##*/zcip_}"
9 9
10echo "* Upping iface $if" 10echo "* Upping iface $if"
11ip link set dev "$if" up || { sleep 5; exit; } 11ip link set dev "$if" up || exec sleep 5
12 12
13echo "* Starting zcip on $if [$$]" 13echo "* Starting zcip on $if [$$]"
14exec \ 14exec \
diff --git a/include/bb_archive.h b/include/bb_archive.h
index b2cb7b347..58e4c21bb 100644
--- a/include/bb_archive.h
+++ b/include/bb_archive.h
@@ -252,6 +252,12 @@ typedef struct transformer_state_t {
252 off_t bytes_in; /* used in unzip code only: needs to know packed size */ 252 off_t bytes_in; /* used in unzip code only: needs to know packed size */
253 uint32_t crc32; 253 uint32_t crc32;
254 time_t mtime; /* gunzip code may set this on exit */ 254 time_t mtime; /* gunzip code may set this on exit */
255
256 union { /* if we read magic, it's saved here */
257 uint8_t b[8];
258 uint16_t b16[4];
259 uint32_t b32[2];
260 } magic;
255} transformer_state_t; 261} transformer_state_t;
256 262
257void init_transformer_state(transformer_state_t *xstate) FAST_FUNC; 263void init_transformer_state(transformer_state_t *xstate) FAST_FUNC;
diff --git a/include/libbb.h b/include/libbb.h
index 05a0c575c..9da94638b 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -920,6 +920,7 @@ extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FA
920extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC; 920extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC;
921/* Reads block up to *maxsz_p (default: INT_MAX - 4095) */ 921/* Reads block up to *maxsz_p (default: INT_MAX - 4095) */
922extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 922extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
923extern void *xmalloc_read_with_initial_buf(int fd, size_t *maxsz_p, char *buf, size_t total) FAST_FUNC;
923/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ 924/* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */
924extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; 925extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC;
925/* Never returns NULL */ 926/* Never returns NULL */
@@ -1359,7 +1360,6 @@ enum {
1359 LOGMODE_BOTH = LOGMODE_SYSLOG + LOGMODE_STDIO, 1360 LOGMODE_BOTH = LOGMODE_SYSLOG + LOGMODE_STDIO,
1360}; 1361};
1361extern const char *msg_eol; 1362extern const char *msg_eol;
1362extern smallint syslog_level;
1363extern smallint logmode; 1363extern smallint logmode;
1364extern uint8_t xfunc_error_retval; 1364extern uint8_t xfunc_error_retval;
1365extern void (*die_func)(void); 1365extern void (*die_func)(void);
@@ -1379,6 +1379,14 @@ void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC;
1379void bb_die_memory_exhausted(void) NORETURN FAST_FUNC; 1379void bb_die_memory_exhausted(void) NORETURN FAST_FUNC;
1380void bb_logenv_override(void) FAST_FUNC; 1380void bb_logenv_override(void) FAST_FUNC;
1381 1381
1382#if ENABLE_FEATURE_SYSLOG_INFO
1383void bb_info_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC;
1384void bb_vinfo_msg(const char *s, va_list p) FAST_FUNC;
1385#else
1386#define bb_info_msg bb_error_msg
1387#define bb_vinfo_msg(s,p) bb_verror_msg(s,p,NULL)
1388#endif
1389
1382/* We need to export XXX_main from libbusybox 1390/* We need to export XXX_main from libbusybox
1383 * only if we build "individual" binaries 1391 * only if we build "individual" binaries
1384 */ 1392 */
diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c
index 341c30102..edf734614 100644
--- a/libbb/find_mount_point.c
+++ b/libbb/find_mount_point.c
@@ -70,11 +70,22 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too)
70 continue; 70 continue;
71 71
72 /* Is device's dev_t == name's dev_t? */ 72 /* Is device's dev_t == name's dev_t? */
73 if (stat(mountEntry->mnt_fsname, &s) == 0 && s.st_rdev == devno_of_name) 73 if (mountEntry->mnt_fsname[0] == '/'
74 /* ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
75 * avoid stat'ing "sysfs", "proc", "none" and such,
76 * useless at best, can stat unrelated files at worst.
77 */
78 && stat(mountEntry->mnt_fsname, &s) == 0
79 && s.st_rdev == devno_of_name
80 ) {
74 break; 81 break;
82 }
75 /* Match the directory's mount point. */ 83 /* Match the directory's mount point. */
76 if (stat(mountEntry->mnt_dir, &s) == 0 && s.st_dev == devno_of_name) 84 if (stat(mountEntry->mnt_dir, &s) == 0
85 && s.st_dev == devno_of_name
86 ) {
77 break; 87 break;
88 }
78 } 89 }
79 endmntent(mtab_fp); 90 endmntent(mtab_fp);
80#else 91#else
diff --git a/libbb/full_write.c b/libbb/full_write.c
index 2b7983f4c..15766fc6c 100644
--- a/libbb/full_write.c
+++ b/libbb/full_write.c
@@ -11,7 +11,8 @@
11/* 11/*
12 * Write all of the supplied buffer out to a file. 12 * Write all of the supplied buffer out to a file.
13 * This does multiple writes as necessary. 13 * This does multiple writes as necessary.
14 * Returns the amount written, or -1 on an error. 14 * Returns the amount written, or -1 if error was seen
15 * on the very first write.
15 */ 16 */
16ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len) 17ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len)
17{ 18{
diff --git a/libbb/lineedit.c b/libbb/lineedit.c
index 191bc0598..9781b4a08 100644
--- a/libbb/lineedit.c
+++ b/libbb/lineedit.c
@@ -70,13 +70,20 @@
70#if ENABLE_UNICODE_SUPPORT 70#if ENABLE_UNICODE_SUPPORT
71# define BB_NUL ((wchar_t)0) 71# define BB_NUL ((wchar_t)0)
72# define CHAR_T wchar_t 72# define CHAR_T wchar_t
73static bool BB_isspace(CHAR_T c) { return ((unsigned)c < 256 && isspace(c)); } 73static bool BB_isspace(CHAR_T c)
74{
75 return ((unsigned)c < 256 && isspace(c));
76}
74# if ENABLE_FEATURE_EDITING_VI 77# if ENABLE_FEATURE_EDITING_VI
75static bool BB_isalnum_or_underscore(CHAR_T c) { 78static bool BB_isalnum_or_underscore(CHAR_T c)
79{
76 return ((unsigned)c < 256 && isalnum(c)) || c == '_'; 80 return ((unsigned)c < 256 && isalnum(c)) || c == '_';
77} 81}
78# endif 82# endif
79static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } 83static bool BB_ispunct(CHAR_T c)
84{
85 return ((unsigned)c < 256 && ispunct(c));
86}
80# undef isspace 87# undef isspace
81# undef isalnum 88# undef isalnum
82# undef ispunct 89# undef ispunct
diff --git a/libbb/read_printf.c b/libbb/read_printf.c
index e47ac7afe..1e67d6542 100644
--- a/libbb/read_printf.c
+++ b/libbb/read_printf.c
@@ -107,10 +107,9 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p)
107 107
108// Read (potentially big) files in one go. File size is estimated 108// Read (potentially big) files in one go. File size is estimated
109// by stat. Extra '\0' byte is appended. 109// by stat. Extra '\0' byte is appended.
110void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p) 110void* FAST_FUNC xmalloc_read_with_initial_buf(int fd, size_t *maxsz_p, char *buf, size_t total)
111{ 111{
112 char *buf; 112 size_t size, rd_size;
113 size_t size, rd_size, total;
114 size_t to_read; 113 size_t to_read;
115 struct stat st; 114 struct stat st;
116 115
@@ -123,8 +122,6 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
123 /* In order to make such files readable, we add small const */ 122 /* In order to make such files readable, we add small const */
124 size = (st.st_size | 0x3ff) + 1; 123 size = (st.st_size | 0x3ff) + 1;
125 124
126 total = 0;
127 buf = NULL;
128 while (1) { 125 while (1) {
129 if (to_read < size) 126 if (to_read < size)
130 size = to_read; 127 size = to_read;
@@ -153,6 +150,11 @@ void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
153 return buf; 150 return buf;
154} 151}
155 152
153void* FAST_FUNC xmalloc_read(int fd, size_t *maxsz_p)
154{
155 return xmalloc_read_with_initial_buf(fd, maxsz_p, NULL, 0);
156}
157
156#ifdef USING_LSEEK_TO_GET_SIZE 158#ifdef USING_LSEEK_TO_GET_SIZE
157/* Alternatively, file size can be obtained by lseek to the end. 159/* Alternatively, file size can be obtained by lseek to the end.
158 * The code is slightly bigger. Retained in case fstat approach 160 * The code is slightly bigger. Retained in case fstat approach
diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c
index 22c30357b..6d3459905 100644
--- a/libbb/verror_msg.c
+++ b/libbb/verror_msg.c
@@ -12,7 +12,7 @@
12#endif 12#endif
13 13
14#if ENABLE_FEATURE_SYSLOG 14#if ENABLE_FEATURE_SYSLOG
15smallint syslog_level = LOG_ERR; 15static smallint syslog_level = LOG_ERR;
16#endif 16#endif
17smallint logmode = LOGMODE_STDIO; 17smallint logmode = LOGMODE_STDIO;
18const char *msg_eol = "\n"; 18const char *msg_eol = "\n";
@@ -154,7 +154,7 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr)
154 } 154 }
155# if ENABLE_FEATURE_SYSLOG 155# if ENABLE_FEATURE_SYSLOG
156 if (logmode & LOGMODE_SYSLOG) { 156 if (logmode & LOGMODE_SYSLOG) {
157 syslog(LOG_ERR, "%s", msgc); 157 syslog(syslog_level, "%s", msgc);
158 } 158 }
159# endif 159# endif
160 free(msgc); 160 free(msgc);
@@ -180,3 +180,21 @@ void FAST_FUNC bb_error_msg(const char *s, ...)
180 bb_verror_msg(s, p, NULL); 180 bb_verror_msg(s, p, NULL);
181 va_end(p); 181 va_end(p);
182} 182}
183
184#if ENABLE_FEATURE_SYSLOG_INFO
185void FAST_FUNC bb_vinfo_msg(const char *s, va_list p)
186{
187 syslog_level = LOG_INFO;
188 bb_verror_msg(s, p, NULL);
189 syslog_level = LOG_ERR;
190}
191
192void FAST_FUNC bb_info_msg(const char *s, ...)
193{
194 va_list p;
195
196 va_start(p, s);
197 bb_vinfo_msg(s, p);
198 va_end(p);
199}
200#endif
diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c
index 2d497d754..26e1776a4 100644
--- a/libbb/vfork_daemon_rexec.c
+++ b/libbb/vfork_daemon_rexec.c
@@ -268,12 +268,6 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
268 if (flags & DAEMON_CHDIR_ROOT) 268 if (flags & DAEMON_CHDIR_ROOT)
269 xchdir("/"); 269 xchdir("/");
270 270
271 if (flags & DAEMON_DEVNULL_STDIO) {
272 close(0);
273 close(1);
274 close(2);
275 }
276
277 fd = open(bb_dev_null, O_RDWR); 271 fd = open(bb_dev_null, O_RDWR);
278 if (fd < 0) { 272 if (fd < 0) {
279 /* NB: we can be called as bb_sanitize_stdio() from init 273 /* NB: we can be called as bb_sanitize_stdio() from init
@@ -283,8 +277,15 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
283 fd = xopen("/", O_RDONLY); /* don't believe this can fail */ 277 fd = xopen("/", O_RDONLY); /* don't believe this can fail */
284 } 278 }
285 279
286 while ((unsigned)fd < 2) 280 if (flags & DAEMON_DEVNULL_STDIO) {
287 fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ 281 xdup2(fd, 0);
282 xdup2(fd, 1);
283 xdup2(fd, 2);
284 } else {
285 /* have 0,1,2 open at least to /dev/null */
286 while ((unsigned)fd < 2)
287 fd = dup(fd);
288 }
288 289
289 if (!(flags & DAEMON_ONLY_SANITIZE)) { 290 if (!(flags & DAEMON_ONLY_SANITIZE)) {
290 291
diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c
index 4b3602e7a..dd0532c66 100644
--- a/loginutils/chpasswd.c
+++ b/loginutils/chpasswd.c
@@ -114,7 +114,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv)
114 if (rc < 0) 114 if (rc < 0)
115 bb_error_msg_and_die("an error occurred updating password for %s", name); 115 bb_error_msg_and_die("an error occurred updating password for %s", name);
116 if (rc) 116 if (rc)
117 bb_error_msg("password for '%s' changed", name); 117 bb_info_msg("password for '%s' changed", name);
118 logmode = LOGMODE_STDIO; 118 logmode = LOGMODE_STDIO;
119 free(name); 119 free(name);
120 free(free_me); 120 free(free_me);
diff --git a/loginutils/login.c b/loginutils/login.c
index 4df651cc6..a08642a34 100644
--- a/loginutils/login.c
+++ b/loginutils/login.c
@@ -534,7 +534,7 @@ int login_main(int argc UNUSED_PARAM, char **argv)
534 wait_for_exitstatus(child_pid); 534 wait_for_exitstatus(child_pid);
535 update_utmp_DEAD_PROCESS(child_pid); 535 update_utmp_DEAD_PROCESS(child_pid);
536 } 536 }
537 IF_PAM(login_pam_end(pamh);) 537 login_pam_end(pamh);
538 return 0; 538 return 0;
539 } 539 }
540#endif 540#endif
diff --git a/loginutils/passwd.c b/loginutils/passwd.c
index 30e096460..6c643d3d0 100644
--- a/loginutils/passwd.c
+++ b/loginutils/passwd.c
@@ -228,7 +228,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv)
228 /* LOGMODE_BOTH */ 228 /* LOGMODE_BOTH */
229 if (rc < 0) 229 if (rc < 0)
230 bb_error_msg_and_die("can't update password file %s", filename); 230 bb_error_msg_and_die("can't update password file %s", filename);
231 bb_error_msg("password for %s changed by %s", name, myname); 231 bb_info_msg("password for %s changed by %s", name, myname);
232 232
233 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */ 233 /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */
234 skip: 234 skip:
diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c
index 27ea5dff0..9bb4d3613 100644
--- a/loginutils/sulogin.c
+++ b/loginutils/sulogin.c
@@ -68,17 +68,17 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv)
68 ); 68 );
69 if (r < 0) { 69 if (r < 0) {
70 /* ^D, ^C, timeout, or read error */ 70 /* ^D, ^C, timeout, or read error */
71 bb_error_msg("normal startup"); 71 bb_info_msg("normal startup");
72 return 0; 72 return 0;
73 } 73 }
74 if (r > 0) { 74 if (r > 0) {
75 break; 75 break;
76 } 76 }
77 bb_do_delay(LOGIN_FAIL_DELAY); 77 bb_do_delay(LOGIN_FAIL_DELAY);
78 bb_error_msg("Login incorrect"); 78 bb_info_msg("Login incorrect");
79 } 79 }
80 80
81 bb_error_msg("starting shell for system maintenance"); 81 bb_info_msg("starting shell for system maintenance");
82 82
83 IF_SELINUX(renew_current_security_context()); 83 IF_SELINUX(renew_current_security_context());
84 84
diff --git a/miscutils/crond.c b/miscutils/crond.c
index 25e5503c7..b533a3991 100644
--- a/miscutils/crond.c
+++ b/miscutils/crond.c
@@ -181,9 +181,7 @@ static void crondlog(unsigned level, const char *msg, va_list va)
181 * need not touch syslog_level 181 * need not touch syslog_level
182 * (they are ok with LOG_ERR default). 182 * (they are ok with LOG_ERR default).
183 */ 183 */
184 syslog_level = LOG_INFO; 184 bb_vinfo_msg(msg, va);
185 bb_verror_msg(msg, va, /* strerr: */ NULL);
186 syslog_level = LOG_ERR;
187 } 185 }
188} 186}
189 187
@@ -1108,7 +1106,7 @@ int crond_main(int argc UNUSED_PARAM, char **argv)
1108 process_cron_update_file(); 1106 process_cron_update_file();
1109 log5("wakeup dt=%ld", dt); 1107 log5("wakeup dt=%ld", dt);
1110 if (dt < -60 * 60 || dt > 60 * 60) { 1108 if (dt < -60 * 60 || dt > 60 * 60) {
1111 bb_error_msg("time disparity of %ld minutes detected", dt / 60); 1109 bb_info_msg("time disparity of %ld minutes detected", dt / 60);
1112 /* and we do not run any jobs in this case */ 1110 /* and we do not run any jobs in this case */
1113 } else if (dt > 0) { 1111 } else if (dt > 0) {
1114 /* Usual case: time advances forward, as expected */ 1112 /* Usual case: time advances forward, as expected */
diff --git a/miscutils/dc.c b/miscutils/dc.c
index 0d09f5e2b..c7ce2be0b 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -35,10 +35,12 @@ enum { STACK_SIZE = (COMMON_BUFSIZE - offsetof(struct globals, stack)) / sizeof(
35 base = 10; \ 35 base = 10; \
36} while (0) 36} while (0)
37 37
38static void check_under(void) 38static unsigned check_under(void)
39{ 39{
40 if (pointer == 0) 40 unsigned p = pointer;
41 if (p == 0)
41 bb_error_msg_and_die("stack underflow"); 42 bb_error_msg_and_die("stack underflow");
43 return p - 1;
42} 44}
43 45
44static void push(double a) 46static void push(double a)
@@ -50,8 +52,9 @@ static void push(double a)
50 52
51static double pop(void) 53static double pop(void)
52{ 54{
53 check_under(); 55 unsigned p = check_under();
54 return stack[--pointer]; 56 pointer = p;
57 return stack[p];
55} 58}
56 59
57static void add(void) 60static void add(void)
@@ -91,6 +94,19 @@ static void mod(void)
91{ 94{
92 data_t d = pop(); 95 data_t d = pop();
93 96
97 /* compat with dc (GNU bc 1.07.1) 1.4.1:
98 * $ dc -e '4 0 % p'
99 * dc: remainder by zero
100 * 0
101 */
102 if (d == 0) {
103 bb_error_msg("remainder by zero");
104 pop();
105 push(0);
106 return;
107 }
108 /* ^^^^ without this, we simply get SIGFPE and die */
109
94 push((data_t) pop() % d); 110 push((data_t) pop() % d);
95} 111}
96 112
@@ -171,8 +187,7 @@ static void print_stack_no_pop(void)
171 187
172static void print_no_pop(void) 188static void print_no_pop(void)
173{ 189{
174 check_under(); 190 print_base(stack[check_under()]);
175 print_base(stack[pointer-1]);
176} 191}
177 192
178struct op { 193struct op {
diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c
index 3bf06b965..e4d104d0c 100644
--- a/miscutils/devfsd.c
+++ b/miscutils/devfsd.c
@@ -343,7 +343,7 @@ static const char bb_msg_variable_not_found[] ALIGN1 = "variable: %s not found";
343 343
344/* Busybox stuff */ 344/* Busybox stuff */
345#if ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG 345#if ENABLE_DEVFSD_VERBOSE || ENABLE_DEBUG
346#define info_logger(p, fmt, args...) bb_error_msg(fmt, ## args) 346#define info_logger(p, fmt, args...) bb_info_msg(fmt, ## args)
347#define msg_logger(p, fmt, args...) bb_error_msg(fmt, ## args) 347#define msg_logger(p, fmt, args...) bb_error_msg(fmt, ## args)
348#define msg_logger_and_die(p, fmt, args...) bb_error_msg_and_die(fmt, ## args) 348#define msg_logger_and_die(p, fmt, args...) bb_error_msg_and_die(fmt, ## args)
349#define error_logger(p, fmt, args...) bb_perror_msg(fmt, ## args) 349#define error_logger(p, fmt, args...) bb_perror_msg(fmt, ## args)
diff --git a/modutils/lsmod.c b/modutils/lsmod.c
index 694205fda..39dc8e6b7 100644
--- a/modutils/lsmod.c
+++ b/modutils/lsmod.c
@@ -66,7 +66,10 @@ static void check_tainted(void)
66 } 66 }
67} 67}
68#else 68#else
69static void check_tainted(void) { putchar('\n'); } 69static ALWAYS_INLINE void check_tainted(void)
70{
71 putchar('\n');
72}
70#endif 73#endif
71 74
72int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 75int lsmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
diff --git a/networking/dnsd.c b/networking/dnsd.c
index 37a80309d..f2c6bddc6 100644
--- a/networking/dnsd.c
+++ b/networking/dnsd.c
@@ -133,7 +133,7 @@ static struct dns_entry *parse_conf_file(const char *fileconf)
133 } 133 }
134 134
135 if (OPT_verbose) 135 if (OPT_verbose)
136 bb_error_msg("name:%s, ip:%s", token[0], token[1]); 136 bb_info_msg("name:%s, ip:%s", token[0], token[1]);
137 137
138 /* sizeof(*m) includes 1 byte for m->name[0] */ 138 /* sizeof(*m) includes 1 byte for m->name[0] */
139 m = xzalloc(sizeof(*m) + strlen(token[0]) + 1); 139 m = xzalloc(sizeof(*m) + strlen(token[0]) + 1);
@@ -438,7 +438,7 @@ static int process_packet(struct dns_entry *conf_data,
438 answstr = table_lookup(conf_data, type, query_string); 438 answstr = table_lookup(conf_data, type, query_string);
439#if DEBUG 439#if DEBUG
440 /* Shows lengths instead of dots, unusable for !DEBUG */ 440 /* Shows lengths instead of dots, unusable for !DEBUG */
441 bb_error_msg("'%s'->'%s'", query_string, answstr); 441 bb_info_msg("'%s'->'%s'", query_string, answstr);
442#endif 442#endif
443 outr_rlen = 4; 443 outr_rlen = 4;
444 if (answstr && type == htons(REQ_PTR)) { 444 if (answstr && type == htons(REQ_PTR)) {
@@ -474,7 +474,7 @@ static int process_packet(struct dns_entry *conf_data,
474 * RCODE = 0 "success" 474 * RCODE = 0 "success"
475 */ 475 */
476 if (OPT_verbose) 476 if (OPT_verbose)
477 bb_error_msg("returning positive reply"); 477 bb_info_msg("returning positive reply");
478 outr_flags = htons(0x8000 | 0x0400 | 0); 478 outr_flags = htons(0x8000 | 0x0400 | 0);
479 /* we have one answer */ 479 /* we have one answer */
480 head->nansw = htons(1); 480 head->nansw = htons(1);
@@ -539,7 +539,7 @@ int dnsd_main(int argc UNUSED_PARAM, char **argv)
539 539
540 { 540 {
541 char *p = xmalloc_sockaddr2dotted(&lsa->u.sa); 541 char *p = xmalloc_sockaddr2dotted(&lsa->u.sa);
542 bb_error_msg("accepting UDP packets on %s", p); 542 bb_info_msg("accepting UDP packets on %s", p);
543 free(p); 543 free(p);
544 } 544 }
545 545
@@ -557,7 +557,7 @@ int dnsd_main(int argc UNUSED_PARAM, char **argv)
557 continue; 557 continue;
558 } 558 }
559 if (OPT_verbose) 559 if (OPT_verbose)
560 bb_error_msg("got UDP packet"); 560 bb_info_msg("got UDP packet");
561 buf[r] = '\0'; /* paranoia */ 561 buf[r] = '\0'; /* paranoia */
562 r = process_packet(conf_data, conf_ttl, buf); 562 r = process_packet(conf_data, conf_ttl, buf);
563 if (r <= 0) 563 if (r <= 0)
diff --git a/networking/ifplugd.c b/networking/ifplugd.c
index 026ff1cc8..1426709cb 100644
--- a/networking/ifplugd.c
+++ b/networking/ifplugd.c
@@ -326,7 +326,7 @@ static int run_script(const char *action)
326 char *argv[5]; 326 char *argv[5];
327 int r; 327 int r;
328 328
329 bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action); 329 bb_info_msg("executing '%s %s %s'", G.script_name, G.iface, action);
330 330
331 argv[0] = (char*) G.script_name; 331 argv[0] = (char*) G.script_name;
332 argv[1] = (char*) G.iface; 332 argv[1] = (char*) G.iface;
@@ -345,7 +345,7 @@ static int run_script(const char *action)
345 bb_unsetenv_and_free(env_PREVIOUS); 345 bb_unsetenv_and_free(env_PREVIOUS);
346 bb_unsetenv_and_free(env_CURRENT); 346 bb_unsetenv_and_free(env_CURRENT);
347 347
348 bb_error_msg("exit code: %d", r & 0xff); 348 bb_info_msg("exit code: %d", r & 0xff);
349 return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r; 349 return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r;
350} 350}
351 351
@@ -365,7 +365,7 @@ static void up_iface(void)
365 if (!(ifrequest.ifr_flags & IFF_UP)) { 365 if (!(ifrequest.ifr_flags & IFF_UP)) {
366 ifrequest.ifr_flags |= IFF_UP; 366 ifrequest.ifr_flags |= IFF_UP;
367 /* Let user know we mess up with interface */ 367 /* Let user know we mess up with interface */
368 bb_error_msg("upping interface"); 368 bb_info_msg("upping interface");
369 if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) { 369 if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) {
370 if (errno != ENODEV && errno != EADDRNOTAVAIL) 370 if (errno != ENODEV && errno != EADDRNOTAVAIL)
371 xfunc_die(); 371 xfunc_die();
@@ -414,7 +414,7 @@ static void maybe_up_new_iface(void)
414 (uint8_t)(ifrequest.ifr_hwaddr.sa_data[5])); 414 (uint8_t)(ifrequest.ifr_hwaddr.sa_data[5]));
415 } 415 }
416 416
417 bb_error_msg("using interface %s%s with driver<%s> (version: %s)", 417 bb_info_msg("using interface %s%s with driver<%s> (version: %s)",
418 G.iface, buf, driver_info.driver, driver_info.version); 418 G.iface, buf, driver_info.driver, driver_info.version);
419 } 419 }
420#endif 420#endif
@@ -447,7 +447,7 @@ static smallint detect_link(void)
447 logmode = sv_logmode; 447 logmode = sv_logmode;
448 if (status != IFSTATUS_ERR) { 448 if (status != IFSTATUS_ERR) {
449 G.api_method_num = i; 449 G.api_method_num = i;
450 bb_error_msg("using %s detection mode", method_table[i].name); 450 bb_info_msg("using %s detection mode", method_table[i].name);
451 break; 451 break;
452 } 452 }
453 } 453 }
@@ -632,7 +632,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
632 /* | (1 << SIGCHLD) - run_script does not use it anymore */ 632 /* | (1 << SIGCHLD) - run_script does not use it anymore */
633 , record_signo); 633 , record_signo);
634 634
635 bb_error_msg("started: %s", bb_banner); 635 bb_info_msg("started: %s", bb_banner);
636 636
637 if (opts & FLAG_MONITOR) { 637 if (opts & FLAG_MONITOR) {
638 struct ifreq ifrequest; 638 struct ifreq ifrequest;
@@ -649,7 +649,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
649 iface_status_str = strstatus(iface_status); 649 iface_status_str = strstatus(iface_status);
650 650
651 if (opts & FLAG_MONITOR) { 651 if (opts & FLAG_MONITOR) {
652 bb_error_msg("interface %s", 652 bb_info_msg("interface %s",
653 G.iface_exists ? "exists" 653 G.iface_exists ? "exists"
654 : "doesn't exist, waiting"); 654 : "doesn't exist, waiting");
655 } 655 }
@@ -657,7 +657,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
657 * by potentially lying that it really exists */ 657 * by potentially lying that it really exists */
658 658
659 if (G.iface_exists) { 659 if (G.iface_exists) {
660 bb_error_msg("link is %s", iface_status_str); 660 bb_info_msg("link is %s", iface_status_str);
661 } 661 }
662 662
663 if ((!(opts & FLAG_NO_STARTUP) 663 if ((!(opts & FLAG_NO_STARTUP)
@@ -712,7 +712,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
712 if (G.iface_exists < 0) /* error */ 712 if (G.iface_exists < 0) /* error */
713 goto exiting; 713 goto exiting;
714 if (iface_exists_old != G.iface_exists) { 714 if (iface_exists_old != G.iface_exists) {
715 bb_error_msg("interface %sappeared", 715 bb_info_msg("interface %sappeared",
716 G.iface_exists ? "" : "dis"); 716 G.iface_exists ? "" : "dis");
717 if (G.iface_exists) 717 if (G.iface_exists)
718 maybe_up_new_iface(); 718 maybe_up_new_iface();
@@ -730,7 +730,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv)
730 iface_status_str = strstatus(iface_status); 730 iface_status_str = strstatus(iface_status);
731 731
732 if (iface_status_old != iface_status) { 732 if (iface_status_old != iface_status) {
733 bb_error_msg("link is %s", iface_status_str); 733 bb_info_msg("link is %s", iface_status_str);
734 734
735 if (delay_time) { 735 if (delay_time) {
736 /* link restored its old status before 736 /* link restored its old status before
diff --git a/networking/ifupdown.c b/networking/ifupdown.c
index 8a6efc976..5327b0979 100644
--- a/networking/ifupdown.c
+++ b/networking/ifupdown.c
@@ -1177,8 +1177,15 @@ static int doit(char *str)
1177 1177
1178static int execute_all(struct interface_defn_t *ifd, const char *opt) 1178static int execute_all(struct interface_defn_t *ifd, const char *opt)
1179{ 1179{
1180 /* 'opt' is always short, the longest value is "post-down".
1181 * Can use on-stack buffer instead of xasprintf'ed one.
1182 */
1183 char buf[sizeof("run-parts /etc/network/if-%s.d")
1184 + sizeof("post-down")
1185 /*paranoia:*/ + 8
1186 ];
1180 int i; 1187 int i;
1181 char *buf; 1188
1182 for (i = 0; i < ifd->n_options; i++) { 1189 for (i = 0; i < ifd->n_options; i++) {
1183 if (strcmp(ifd->option[i].name, opt) == 0) { 1190 if (strcmp(ifd->option[i].name, opt) == 0) {
1184 if (!doit(ifd->option[i].value)) { 1191 if (!doit(ifd->option[i].value)) {
@@ -1192,8 +1199,7 @@ static int execute_all(struct interface_defn_t *ifd, const char *opt)
1192 * complains, and this message _is_ annoyingly visible. 1199 * complains, and this message _is_ annoyingly visible.
1193 * Don't "fix" this (unless newer Debian does). 1200 * Don't "fix" this (unless newer Debian does).
1194 */ 1201 */
1195 buf = xasprintf("run-parts /etc/network/if-%s.d", opt); 1202 sprintf(buf, "run-parts /etc/network/if-%s.d", opt);
1196 /* heh, we don't bother free'ing it */
1197 return doit(buf); 1203 return doit(buf);
1198} 1204}
1199 1205
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index 8364f6a3e..7b7e0154b 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -23,6 +23,7 @@
23 23
24struct filter_t { 24struct filter_t {
25 char *label; 25 char *label;
26 /* Flush cmd buf. If !NULL, print_addrinfo() constructs flush commands in it */
26 char *flushb; 27 char *flushb;
27 struct rtnl_handle *rth; 28 struct rtnl_handle *rth;
28 int scope, scopemask; 29 int scope, scopemask;
@@ -34,6 +35,8 @@ struct filter_t {
34 smallint showqueue; 35 smallint showqueue;
35 smallint oneline; 36 smallint oneline;
36 smallint up; 37 smallint up;
38 /* Misnomer. Does not mean "flushed something" */
39 /* More like "flush commands were constructed by print_addrinfo()" */
37 smallint flushed; 40 smallint flushed;
38 inet_prefix pfx; 41 inet_prefix pfx;
39} FIX_ALIASING; 42} FIX_ALIASING;
@@ -201,7 +204,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n)
201 204
202static int flush_update(void) 205static int flush_update(void)
203{ 206{
204 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) { 207 if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
205 bb_perror_msg("can't send flush request"); 208 bb_perror_msg("can't send flush request");
206 return -1; 209 return -1;
207 } 210 }
@@ -510,7 +513,6 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
510 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo); 513 xrtnl_dump_filter(&rth, store_nlmsg, &ainfo);
511 } 514 }
512 515
513
514 if (G_filter.family && G_filter.family != AF_PACKET) { 516 if (G_filter.family && G_filter.family != AF_PACKET) {
515 struct nlmsg_list **lp; 517 struct nlmsg_list **lp;
516 lp = &linfo; 518 lp = &linfo;
@@ -571,8 +573,8 @@ int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush)
571 573
572 for (l = linfo; l; l = l->next) { 574 for (l = linfo; l; l = l->next) {
573 if ((oneline && G_filter.family != AF_PACKET) 575 if ((oneline && G_filter.family != AF_PACKET)
574 || (print_linkinfo(&l->h) == 0)
575 /* ^^^^^^^^^ "ip -oneline a" does not print link info */ 576 /* ^^^^^^^^^ "ip -oneline a" does not print link info */
577 || (print_linkinfo(&l->h) == 0)
576 ) { 578 ) {
577 struct ifinfomsg *ifi = NLMSG_DATA(&l->h); 579 struct ifinfomsg *ifi = NLMSG_DATA(&l->h);
578 if (G_filter.family != AF_PACKET) 580 if (G_filter.family != AF_PACKET)
diff --git a/networking/libiproute/ipneigh.c b/networking/libiproute/ipneigh.c
index f572414e9..984dd4bdd 100644
--- a/networking/libiproute/ipneigh.c
+++ b/networking/libiproute/ipneigh.c
@@ -32,7 +32,10 @@ struct filter_t {
32 int state; 32 int state;
33 int unused_only; 33 int unused_only;
34 inet_prefix pfx; 34 inet_prefix pfx;
35 /* Misnomer. Does not mean "flushed N something" */
36 /* More like "no_of_flush_commands_constructed_by_print_neigh()" */
35 int flushed; 37 int flushed;
38 /* Flush cmd buf. If !NULL, print_neigh() constructs flush commands in it */
36 char *flushb; 39 char *flushb;
37 int flushp; 40 int flushp;
38 int flushe; 41 int flushe;
@@ -45,7 +48,7 @@ typedef struct filter_t filter_t;
45 48
46static int flush_update(void) 49static int flush_update(void)
47{ 50{
48 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) { 51 if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
49 bb_perror_msg("can't send flush request"); 52 bb_perror_msg("can't send flush request");
50 return -1; 53 return -1;
51 } 54 }
@@ -299,9 +302,7 @@ static int FAST_FUNC ipneigh_list_or_flush(char **argv, int flush)
299 G_filter.rth = &rth; 302 G_filter.rth = &rth;
300 303
301 while (round < MAX_ROUNDS) { 304 while (round < MAX_ROUNDS) {
302 if (xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH) < 0) { 305 xrtnl_wilddump_request(&rth, G_filter.family, RTM_GETNEIGH);
303 bb_perror_msg_and_die("can't send dump request");
304 }
305 G_filter.flushed = 0; 306 G_filter.flushed = 0;
306 if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) { 307 if (xrtnl_dump_filter(&rth, print_neigh, NULL) < 0) {
307 bb_perror_msg_and_die("flush terminated"); 308 bb_perror_msg_and_die("flush terminated");
diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c
index 2a8610ea6..b11078ed5 100644
--- a/networking/libiproute/iproute.c
+++ b/networking/libiproute/iproute.c
@@ -26,7 +26,10 @@
26 26
27struct filter_t { 27struct filter_t {
28 int tb; 28 int tb;
29 /* Misnomer. Does not mean "flushed something" */
30 /* More like "flush commands were constructed by print_route()" */
29 smallint flushed; 31 smallint flushed;
32 /* Flush cmd buf. If !NULL, print_route() constructs flush commands in it */
30 char *flushb; 33 char *flushb;
31 int flushp; 34 int flushp;
32 int flushe; 35 int flushe;
@@ -53,7 +56,7 @@ typedef struct filter_t filter_t;
53 56
54static int flush_update(void) 57static int flush_update(void)
55{ 58{
56 if (rtnl_send(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) { 59 if (rtnl_send_check(G_filter.rth, G_filter.flushb, G_filter.flushp) < 0) {
57 bb_perror_msg("can't send flush request"); 60 bb_perror_msg("can't send flush request");
58 return -1; 61 return -1;
59 } 62 }
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index 40955fcae..b0d4166ac 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -34,7 +34,7 @@ void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/)
34 rth->seq = time(NULL); 34 rth->seq = time(NULL);
35} 35}
36 36
37int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) 37void FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
38{ 38{
39 struct { 39 struct {
40 struct nlmsghdr nlh; 40 struct nlmsghdr nlh;
@@ -48,18 +48,45 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty
48 req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 48 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
49 req.g.rtgen_family = family; 49 req.g.rtgen_family = family;
50 50
51 return rtnl_send(rth, (void*)&req, sizeof(req)); 51 rtnl_send(rth, (void*)&req, sizeof(req));
52} 52}
53 53
54//TODO: pass rth->fd instead of full rth? 54/* A version which checks for e.g. EPERM errors.
55int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) 55 * Try: setuidgid 1:1 ip addr flush dev eth0
56 */
57int FAST_FUNC rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len)
56{ 58{
57 struct sockaddr_nl nladdr; 59 struct nlmsghdr *h;
60 int status;
61 char resp[1024];
58 62
59 memset(&nladdr, 0, sizeof(nladdr)); 63 status = write(rth->fd, buf, len);
60 nladdr.nl_family = AF_NETLINK; 64 if (status < 0)
65 return status;
66
67 /* Check for immediate errors */
68 status = recv(rth->fd, resp, sizeof(resp), MSG_DONTWAIT|MSG_PEEK);
69 if (status < 0) {
70 if (errno == EAGAIN) /* if no error, this happens */
71 return 0;
72 return -1;
73 }
61 74
62 return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr)); 75 for (h = (struct nlmsghdr *)resp;
76 NLMSG_OK(h, status);
77 h = NLMSG_NEXT(h, status)
78 ) {
79 if (h->nlmsg_type == NLMSG_ERROR) {
80 struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
81 if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr)))
82 bb_error_msg("ERROR truncated");
83 else
84 errno = -err->error;
85 return -1;
86 }
87 }
88
89 return 0;
63} 90}
64 91
65int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) 92int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h
index 51bee2d67..1b082e019 100644
--- a/networking/libiproute/libnetlink.h
+++ b/networking/libiproute/libnetlink.h
@@ -20,7 +20,7 @@ struct rtnl_handle {
20 20
21extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; 21extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC;
22#define rtnl_close(rth) (close((rth)->fd)) 22#define rtnl_close(rth) (close((rth)->fd))
23extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC; 23extern void xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC;
24extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC; 24extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC;
25extern int xrtnl_dump_filter(struct rtnl_handle *rth, 25extern int xrtnl_dump_filter(struct rtnl_handle *rth,
26 int (*filter)(const struct sockaddr_nl*, struct nlmsghdr *n, void*) FAST_FUNC, 26 int (*filter)(const struct sockaddr_nl*, struct nlmsghdr *n, void*) FAST_FUNC,
@@ -34,8 +34,23 @@ extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
34 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 34 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
35 void *jarg) FAST_FUNC; 35 void *jarg) FAST_FUNC;
36 36
37extern int rtnl_send(struct rtnl_handle *rth, char *buf, int) FAST_FUNC; 37int rtnl_send_check(struct rtnl_handle *rth, const void *buf, int len) FAST_FUNC;
38//TODO: pass rth->fd instead of full rth?
39static ALWAYS_INLINE void rtnl_send(struct rtnl_handle *rth, const void *buf, int len)
40{
41 // Used to be:
42 //struct sockaddr_nl nladdr;
43 //memset(&nladdr, 0, sizeof(nladdr));
44 //nladdr.nl_family = AF_NETLINK;
45 //return xsendto(rth->fd, buf, len, (struct sockaddr*)&nladdr, sizeof(nladdr));
38 46
47 // iproute2-4.2.0 simplified the above to:
48 //return send(rth->fd, buf, len, 0);
49
50 // We are using even shorter:
51 xwrite(rth->fd, buf, len);
52 // and convert to void, inline.
53}
39 54
40extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC; 55extern int addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) FAST_FUNC;
41extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC; 56extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) FAST_FUNC;
diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c
index 7d46221ac..611e0a2c9 100644
--- a/networking/libiproute/ll_proto.c
+++ b/networking/libiproute/ll_proto.c
@@ -15,7 +15,7 @@
15 15
16/* Please conditionalize exotic protocols on CONFIG_something */ 16/* Please conditionalize exotic protocols on CONFIG_something */
17 17
18static const uint16_t llproto_ids[] = { 18static const uint16_t llproto_ids[] ALIGN2 = {
19#define __PF(f,n) ETH_P_##f, 19#define __PF(f,n) ETH_P_##f,
20__PF(LOOP,loop) 20__PF(LOOP,loop)
21__PF(PUP,pup) 21__PF(PUP,pup)
diff --git a/networking/ntpd.c b/networking/ntpd.c
index 027cfe783..cd6da2b38 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -1130,7 +1130,7 @@ step_time(double offset)
1130 } 1130 }
1131 tval = tvn.tv_sec; 1131 tval = tvn.tv_sec;
1132 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); 1132 strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval);
1133 bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); 1133 bb_info_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset);
1134 //maybe? G.FREQHOLD_cnt = 0; 1134 //maybe? G.FREQHOLD_cnt = 0;
1135 1135
1136 /* Correct various fields which contain time-relative values: */ 1136 /* Correct various fields which contain time-relative values: */
@@ -2132,7 +2132,7 @@ recv_and_process_peer_pkt(peer_t *p)
2132 2132
2133 p->reachable_bits |= 1; 2133 p->reachable_bits |= 1;
2134 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { 2134 if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) {
2135 bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", 2135 bb_info_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x",
2136 p->p_dotted, 2136 p->p_dotted,
2137 offset, 2137 offset,
2138 p->p_raw_delay, 2138 p->p_raw_delay,
diff --git a/networking/tc.c b/networking/tc.c
index 3e9808328..2e1078d31 100644
--- a/networking/tc.c
+++ b/networking/tc.c
@@ -124,7 +124,8 @@ static char* print_tc_classid(uint32_t cid)
124} 124}
125 125
126/* Get a qdisc handle. Return 0 on success, !0 otherwise. */ 126/* Get a qdisc handle. Return 0 on success, !0 otherwise. */
127static int get_qdisc_handle(uint32_t *h, const char *str) { 127static int get_qdisc_handle(uint32_t *h, const char *str)
128{
128 uint32_t maj; 129 uint32_t maj;
129 char *p; 130 char *p;
130 131
@@ -143,7 +144,8 @@ static int get_qdisc_handle(uint32_t *h, const char *str) {
143} 144}
144 145
145/* Get class ID. Return 0 on success, !0 otherwise. */ 146/* Get class ID. Return 0 on success, !0 otherwise. */
146static int get_tc_classid(uint32_t *h, const char *str) { 147static int get_tc_classid(uint32_t *h, const char *str)
148{
147 uint32_t maj, min; 149 uint32_t maj, min;
148 char *p; 150 char *p;
149 151
diff --git a/networking/tftp.c b/networking/tftp.c
index d20d4ca4b..5ebd22105 100644
--- a/networking/tftp.c
+++ b/networking/tftp.c
@@ -245,7 +245,7 @@ static int tftp_blksize_check(const char *blksize_str, int maxsize)
245 return -1; 245 return -1;
246 } 246 }
247# if ENABLE_TFTP_DEBUG 247# if ENABLE_TFTP_DEBUG
248 bb_error_msg("using blksize %u", blksize); 248 bb_info_msg("using blksize %u", blksize);
249# endif 249# endif
250 return blksize; 250 return blksize;
251} 251}
diff --git a/networking/tls.c b/networking/tls.c
index d2385efe8..d1a0204ed 100644
--- a/networking/tls.c
+++ b/networking/tls.c
@@ -1393,12 +1393,12 @@ static void find_key_in_der_cert(tls_state_t *tls, uint8_t *der, int len)
1393 /* enter subjectPublicKeyInfo */ 1393 /* enter subjectPublicKeyInfo */
1394 der = enter_der_item(der, &end); 1394 der = enter_der_item(der, &end);
1395 { /* check subjectPublicKeyInfo.algorithm */ 1395 { /* check subjectPublicKeyInfo.algorithm */
1396 static const uint8_t OID_RSA_KEY_ALG[] = { 1396 static const uint8_t OID_RSA_KEY_ALG[] ALIGN1 = {
1397 0x30,0x0d, // SEQ 13 bytes 1397 0x30,0x0d, // SEQ 13 bytes
1398 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, //OID_RSA_KEY_ALG 42.134.72.134.247.13.1.1.1 1398 0x06,0x09, 0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,0x01,0x01, //OID_RSA_KEY_ALG 42.134.72.134.247.13.1.1.1
1399 //0x05,0x00, // NULL 1399 //0x05,0x00, // NULL
1400 }; 1400 };
1401 static const uint8_t OID_ECDSA_KEY_ALG[] = { 1401 static const uint8_t OID_ECDSA_KEY_ALG[] ALIGN1 = {
1402 0x30,0x13, // SEQ 0x13 bytes 1402 0x30,0x13, // SEQ 0x13 bytes
1403 0x06,0x07, 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01, //OID_ECDSA_KEY_ALG 42.134.72.206.61.2.1 1403 0x06,0x07, 0x2a,0x86,0x48,0xce,0x3d,0x02,0x01, //OID_ECDSA_KEY_ALG 42.134.72.206.61.2.1
1404 //allow any curve code for now... 1404 //allow any curve code for now...
@@ -2089,7 +2089,7 @@ static void send_client_key_exchange(tls_state_t *tls)
2089 } 2089 }
2090} 2090}
2091 2091
2092static const uint8_t rec_CHANGE_CIPHER_SPEC[] = { 2092static const uint8_t rec_CHANGE_CIPHER_SPEC[] ALIGN1 = {
2093 RECORD_TYPE_CHANGE_CIPHER_SPEC, TLS_MAJ, TLS_MIN, 00, 01, 2093 RECORD_TYPE_CHANGE_CIPHER_SPEC, TLS_MAJ, TLS_MIN, 00, 01,
2094 01 2094 01
2095}; 2095};
diff --git a/networking/tls_aes.c b/networking/tls_aes.c
index cf6b5fe3d..5400ad9b5 100644
--- a/networking/tls_aes.c
+++ b/networking/tls_aes.c
@@ -130,7 +130,7 @@ static int KeyExpansion(uint32_t *RoundKey, const void *key, unsigned key_len)
130 // The round constant word array, Rcon[i], contains the values given by 130 // The round constant word array, Rcon[i], contains the values given by
131 // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8). 131 // x to th e power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8).
132 // Note that i starts at 2, not 0. 132 // Note that i starts at 2, not 0.
133 static const uint8_t Rcon[] = { 133 static const uint8_t Rcon[] ALIGN1 = {
134 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 134 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
135 //..... 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,... 135 //..... 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6,...
136 // but aes256 only uses values up to 0x36 136 // but aes256 only uses values up to 0x36
diff --git a/networking/tls_pstm_montgomery_reduce.c b/networking/tls_pstm_montgomery_reduce.c
index d46e2aa2b..20f9c26d5 100644
--- a/networking/tls_pstm_montgomery_reduce.c
+++ b/networking/tls_pstm_montgomery_reduce.c
@@ -73,7 +73,7 @@ asm( \
73 "movl %%edx,%1 \n\t" \ 73 "movl %%edx,%1 \n\t" \
74:"=g"(_c[LO]), "=r"(cy) \ 74:"=g"(_c[LO]), "=r"(cy) \
75:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ 75:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \
76: "%eax", "%edx", "%cc") 76: "%eax", "%edx", "cc")
77 77
78#define PROPCARRY \ 78#define PROPCARRY \
79asm( \ 79asm( \
@@ -82,7 +82,7 @@ asm( \
82 "movzbl %%al,%1 \n\t" \ 82 "movzbl %%al,%1 \n\t" \
83:"=g"(_c[LO]), "=r"(cy) \ 83:"=g"(_c[LO]), "=r"(cy) \
84:"0"(_c[LO]), "1"(cy) \ 84:"0"(_c[LO]), "1"(cy) \
85: "%eax", "%cc") 85: "%eax", "cc")
86 86
87/******************************************************************************/ 87/******************************************************************************/
88#elif defined(PSTM_X86_64) 88#elif defined(PSTM_X86_64)
@@ -235,7 +235,7 @@ asm( \
235 " STR r0,%1 \n\t" \ 235 " STR r0,%1 \n\t" \
236 :"=r"(cy),"=m"(_c[0])\ 236 :"=r"(cy),"=m"(_c[0])\
237 :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\ 237 :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\
238 :"r0","%cc"); 238 :"r0","cc");
239#define PROPCARRY \ 239#define PROPCARRY \
240asm( \ 240asm( \
241 " LDR r0,%1 \n\t" \ 241 " LDR r0,%1 \n\t" \
@@ -246,7 +246,7 @@ asm( \
246 " MOVCC %0,#0 \n\t" \ 246 " MOVCC %0,#0 \n\t" \
247 :"=r"(cy),"=m"(_c[0])\ 247 :"=r"(cy),"=m"(_c[0])\
248 :"0"(cy),"m"(_c[0])\ 248 :"0"(cy),"m"(_c[0])\
249 :"r0","%cc"); 249 :"r0","cc");
250#else /* Non-Thumb2 code */ 250#else /* Non-Thumb2 code */
251//#pragma message ("Using 32 bit ARM Assembly Optimizations") 251//#pragma message ("Using 32 bit ARM Assembly Optimizations")
252#define INNERMUL \ 252#define INNERMUL \
@@ -259,7 +259,7 @@ asm( \
259 " STR r0,%1 \n\t" \ 259 " STR r0,%1 \n\t" \
260 :"=r"(cy),"=m"(_c[0])\ 260 :"=r"(cy),"=m"(_c[0])\
261 :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\ 261 :"0"(cy),"r"(mu),"r"(*tmpm++),"m"(_c[0])\
262 :"r0","%cc"); 262 :"r0","cc");
263#define PROPCARRY \ 263#define PROPCARRY \
264asm( \ 264asm( \
265 " LDR r0,%1 \n\t" \ 265 " LDR r0,%1 \n\t" \
@@ -269,7 +269,7 @@ asm( \
269 " MOVCC %0,#0 \n\t" \ 269 " MOVCC %0,#0 \n\t" \
270 :"=r"(cy),"=m"(_c[0])\ 270 :"=r"(cy),"=m"(_c[0])\
271 :"0"(cy),"m"(_c[0])\ 271 :"0"(cy),"m"(_c[0])\
272 :"r0","%cc"); 272 :"r0","cc");
273#endif /* __thumb2__ */ 273#endif /* __thumb2__ */
274 274
275 275
diff --git a/networking/tls_pstm_mul_comba.c b/networking/tls_pstm_mul_comba.c
index ac4fcc3ef..af50358e5 100644
--- a/networking/tls_pstm_mul_comba.c
+++ b/networking/tls_pstm_mul_comba.c
@@ -85,7 +85,7 @@ asm( \
85 "addl %%eax,%0 \n\t" \ 85 "addl %%eax,%0 \n\t" \
86 "adcl %%edx,%1 \n\t" \ 86 "adcl %%edx,%1 \n\t" \
87 "adcl $0,%2 \n\t" \ 87 "adcl $0,%2 \n\t" \
88 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","%cc"); 88 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","cc");
89 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build 89 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build
90 90
91/******************************************************************************/ 91/******************************************************************************/
@@ -155,7 +155,7 @@ asm( \
155 " ADDS %0,%0,r0 \n\t" \ 155 " ADDS %0,%0,r0 \n\t" \
156 " ADCS %1,%1,r1 \n\t" \ 156 " ADCS %1,%1,r1 \n\t" \
157 " ADC %2,%2,#0 \n\t" \ 157 " ADC %2,%2,#0 \n\t" \
158 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc"); 158 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
159 159
160/******************************************************************************/ 160/******************************************************************************/
161#elif defined(PSTM_MIPS) 161#elif defined(PSTM_MIPS)
diff --git a/networking/tls_pstm_sqr_comba.c b/networking/tls_pstm_sqr_comba.c
index 8604132d6..a4d421b89 100644
--- a/networking/tls_pstm_sqr_comba.c
+++ b/networking/tls_pstm_sqr_comba.c
@@ -78,7 +78,7 @@ asm( \
78 "addl %%eax,%0 \n\t" \ 78 "addl %%eax,%0 \n\t" \
79 "adcl %%edx,%1 \n\t" \ 79 "adcl %%edx,%1 \n\t" \
80 "adcl $0,%2 \n\t" \ 80 "adcl $0,%2 \n\t" \
81 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","%cc"); 81 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","cc");
82 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build 82 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build
83 83
84#define SQRADD2(i, j) \ 84#define SQRADD2(i, j) \
@@ -91,7 +91,7 @@ asm( \
91 "addl %%eax,%0 \n\t" \ 91 "addl %%eax,%0 \n\t" \
92 "adcl %%edx,%1 \n\t" \ 92 "adcl %%edx,%1 \n\t" \
93 "adcl $0,%2 \n\t" \ 93 "adcl $0,%2 \n\t" \
94 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","%cc"); 94 :"=rm"(c0), "=rm"(c1), "=rm"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%edx","cc");
95 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build 95 //bbox: ^^^ replaced "=r" with "=rm": %ebx is not available on shared build
96 96
97#define SQRADDSC(i, j) \ 97#define SQRADDSC(i, j) \
@@ -101,7 +101,7 @@ asm( \
101 "movl %%eax,%0 \n\t" \ 101 "movl %%eax,%0 \n\t" \
102 "movl %%edx,%1 \n\t" \ 102 "movl %%edx,%1 \n\t" \
103 "xorl %2,%2 \n\t" \ 103 "xorl %2,%2 \n\t" \
104 :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); 104 :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc");
105 105
106#define SQRADDAC(i, j) \ 106#define SQRADDAC(i, j) \
107asm( \ 107asm( \
@@ -110,7 +110,7 @@ asm( \
110 "addl %%eax,%0 \n\t" \ 110 "addl %%eax,%0 \n\t" \
111 "adcl %%edx,%1 \n\t" \ 111 "adcl %%edx,%1 \n\t" \
112 "adcl $0,%2 \n\t" \ 112 "adcl $0,%2 \n\t" \
113 :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc"); 113 :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","cc");
114 114
115#define SQRADDDB \ 115#define SQRADDDB \
116asm( \ 116asm( \
@@ -120,7 +120,7 @@ asm( \
120 "addl %6,%0 \n\t" \ 120 "addl %6,%0 \n\t" \
121 "adcl %7,%1 \n\t" \ 121 "adcl %7,%1 \n\t" \
122 "adcl %8,%2 \n\t" \ 122 "adcl %8,%2 \n\t" \
123 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "%cc"); 123 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(sc0), "r"(sc1), "r"(sc2) : "cc");
124 124
125/******************************************************************************/ 125/******************************************************************************/
126#elif defined(PSTM_X86_64) 126#elif defined(PSTM_X86_64)
@@ -223,7 +223,7 @@ asm( \
223" ADDS %0,%0,r0 \n\t" \ 223" ADDS %0,%0,r0 \n\t" \
224" ADCS %1,%1,r1 \n\t" \ 224" ADCS %1,%1,r1 \n\t" \
225" ADC %2,%2,#0 \n\t" \ 225" ADC %2,%2,#0 \n\t" \
226:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "%cc"); 226:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "cc");
227 227
228/* for squaring some of the terms are doubled... */ 228/* for squaring some of the terms are doubled... */
229#define SQRADD2(i, j) \ 229#define SQRADD2(i, j) \
@@ -235,13 +235,13 @@ asm( \
235" ADDS %0,%0,r0 \n\t" \ 235" ADDS %0,%0,r0 \n\t" \
236" ADCS %1,%1,r1 \n\t" \ 236" ADCS %1,%1,r1 \n\t" \
237" ADC %2,%2,#0 \n\t" \ 237" ADC %2,%2,#0 \n\t" \
238:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc"); 238:"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "cc");
239 239
240#define SQRADDSC(i, j) \ 240#define SQRADDSC(i, j) \
241asm( \ 241asm( \
242" UMULL %0,%1,%6,%7 \n\t" \ 242" UMULL %0,%1,%6,%7 \n\t" \
243" SUB %2,%2,%2 \n\t" \ 243" SUB %2,%2,%2 \n\t" \
244:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "%cc"); 244:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "cc");
245 245
246#define SQRADDAC(i, j) \ 246#define SQRADDAC(i, j) \
247asm( \ 247asm( \
@@ -249,7 +249,7 @@ asm( \
249" ADDS %0,%0,r0 \n\t" \ 249" ADDS %0,%0,r0 \n\t" \
250" ADCS %1,%1,r1 \n\t" \ 250" ADCS %1,%1,r1 \n\t" \
251" ADC %2,%2,#0 \n\t" \ 251" ADC %2,%2,#0 \n\t" \
252:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "%cc"); 252:"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "cc");
253 253
254#define SQRADDDB \ 254#define SQRADDDB \
255asm( \ 255asm( \
@@ -259,7 +259,7 @@ asm( \
259" ADDS %0,%0,%3 \n\t" \ 259" ADDS %0,%0,%3 \n\t" \
260" ADCS %1,%1,%4 \n\t" \ 260" ADCS %1,%1,%4 \n\t" \
261" ADC %2,%2,%5 \n\t" \ 261" ADC %2,%2,%5 \n\t" \
262:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "%cc"); 262:"=r"(c0), "=r"(c1), "=r"(c2) : "r"(sc0), "r"(sc1), "r"(sc2), "0"(c0), "1"(c1), "2"(c2) : "cc");
263 263
264/******************************************************************************/ 264/******************************************************************************/
265#elif defined(PSTM_MIPS) 265#elif defined(PSTM_MIPS)
@@ -330,7 +330,7 @@ asm( \
330 " mflo %0 \n\t" \ 330 " mflo %0 \n\t" \
331 " mfhi %1 \n\t" \ 331 " mfhi %1 \n\t" \
332 " xor %2,%2,%2 \n\t" \ 332 " xor %2,%2,%2 \n\t" \
333 :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "%cc"); 333 :"=r"(sc0), "=r"(sc1), "=r"(sc2):"0"(sc0), "1"(sc1), "2"(sc2), "r"(i),"r"(j) : "cc");
334 334
335#define SQRADDAC(i, j) \ 335#define SQRADDAC(i, j) \
336asm( \ 336asm( \
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 59cf723ee..62ad248ce 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -191,7 +191,7 @@ static void log_option(const char *pfx, const uint8_t *opt)
191 if (dhcp_verbose >= 2) { 191 if (dhcp_verbose >= 2) {
192 char buf[256 * 2 + 2]; 192 char buf[256 * 2 + 2];
193 *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0'; 193 *bin2hex(buf, (void*) (opt + OPT_DATA), opt[OPT_LEN]) = '\0';
194 bb_error_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf); 194 bb_info_msg("%s: 0x%02x %s", pfx, opt[OPT_CODE], buf);
195 } 195 }
196} 196}
197#else 197#else
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 9d1f71aae..bba3d6037 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -40,7 +40,7 @@ struct dhcp_packet {
40 uint32_t yiaddr; /* 'your' (client) IP address */ 40 uint32_t yiaddr; /* 'your' (client) IP address */
41 /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */ 41 /* IP address of next server to use in bootstrap, returned in DHCPOFFER, DHCPACK by server */
42 uint32_t siaddr_nip; 42 uint32_t siaddr_nip;
43 uint32_t gateway_nip; /* relay agent IP address */ 43 uint32_t gateway_nip; /* aka 'giaddr': relay agent IP address */
44 uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */ 44 uint8_t chaddr[16]; /* link-layer client hardware address (MAC) */
45 uint8_t sname[64]; /* server host name (ASCIZ) */ 45 uint8_t sname[64]; /* server host name (ASCIZ) */
46 uint8_t file[128]; /* boot file name (ASCIZ) */ 46 uint8_t file[128]; /* boot file name (ASCIZ) */
@@ -222,10 +222,9 @@ uint8_t *dname_enc(const uint8_t *cstr, int clen, const char *src, int *retlen)
222#endif 222#endif
223struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC; 223struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) FAST_FUNC;
224 224
225
226// RFC 2131 Table 5: Fields and options used by DHCP clients 225// RFC 2131 Table 5: Fields and options used by DHCP clients
227// 226//
228// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero 227// Fields 'hops', 'yiaddr', 'siaddr', 'giaddr' are always zero, 'chaddr' is always client's MAC
229// 228//
230// Field DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE 229// Field DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
231// ----- ------------ ------------ ----------- ----------- ----------- 230// ----- ------------ ------------ ----------- ----------- -----------
@@ -234,56 +233,49 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code)
234// 'secs' 0 or seconds since 0 or seconds since 0 or seconds since 0 0 233// 'secs' 0 or seconds since 0 or seconds since 0 or seconds since 0 0
235// DHCP process started DHCP process started DHCP process started 234// DHCP process started DHCP process started DHCP process started
236// 'flags' Set 'BROADCAST' Set 'BROADCAST' Set 'BROADCAST' 0 0 235// 'flags' Set 'BROADCAST' Set 'BROADCAST' Set 'BROADCAST' 0 0
237// flag if client flag if client flag if client 236// flag if client needs flag if client needs flag if client needs
238// requires broadcast requires broadcast requires broadcast 237// broadcast reply broadcast reply broadcast reply
239// reply reply reply
240// 'ciaddr' 0 client's IP 0 or client's IP 0 client's IP 238// 'ciaddr' 0 client's IP 0 or client's IP 0 client's IP
241// (BOUND/RENEW/REBIND) 239// (BOUND/RENEW/REBIND)
242// 'chaddr' client's MAC client's MAC client's MAC client's MAC client's MAC
243// 'sname' options or sname options or sname options or sname (unused) (unused) 240// 'sname' options or sname options or sname options or sname (unused) (unused)
244// 'file' options or file options or file options or file (unused) (unused) 241// 'file' options or file options or file options or file (unused) (unused)
245// 'options' options options options message type opt message type opt 242// 'options' options options options message type opt message type opt
246// 243//
247// Option DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE 244// Option DHCPDISCOVER DHCPINFORM DHCPREQUEST DHCPDECLINE DHCPRELEASE
248// ------ ------------ ---------- ----------- ----------- ----------- 245// ------ ------------ ---------- ----------- ----------- -----------
249// Requested IP address MAY MUST NOT MUST (in MUST MUST NOT 246// Requested IP address MAY MUST NOT MUST (in SELECTING MUST MUST NOT
250// SELECTING or 247// or INIT-REBOOT)
251// INIT-REBOOT) 248// MUST NOT (in BOUND
252// MUST NOT (in 249// or RENEWING)
253// BOUND or 250// IP address lease time MAY MUST NOT MAY MUST NOT MUST NOT
254// RENEWING) 251// Use 'file'/'sname' fields MAY MAY MAY MAY MAY
255// IP address lease time MAY MUST NOT MAY MUST NOT MUST NOT 252// Client identifier MAY MAY MAY MAY MAY
256// Use 'file'/'sname' fields MAY MAY MAY MAY MAY 253// Vendor class identifier MAY MAY MAY MUST NOT MUST NOT
257// Client identifier MAY MAY MAY MAY MAY 254// Server identifier MUST NOT MUST NOT MUST (after SELECTING) MUST MUST
258// Vendor class identifier MAY MAY MAY MUST NOT MUST NOT
259// Server identifier MUST NOT MUST NOT MUST (after MUST MUST
260// SELECTING)
261// MUST NOT (after 255// MUST NOT (after
262// INIT-REBOOT, 256// INIT-REBOOT, BOUND,
263// BOUND, RENEWING 257// RENEWING or REBINDING)
264// or REBINDING) 258// Parameter request list MAY MAY MAY MUST NOT MUST NOT
265// Parameter request list MAY MAY MAY MUST NOT MUST NOT 259// Maximum message size MAY MAY MAY MUST NOT MUST NOT
266// Maximum message size MAY MAY MAY MUST NOT MUST NOT 260// Message SHOULD NOT SHOULD NOT SHOULD NOT SHOULD SHOULD
267// Message SHOULD NOT SHOULD NOT SHOULD NOT SHOULD SHOULD 261// Site-specific MAY MAY MAY MUST NOT MUST NOT
268// Site-specific MAY MAY MAY MUST NOT MUST NOT 262// All others MAY MAY MAY MUST NOT MUST NOT
269// All others MAY MAY MAY MUST NOT MUST NOT
270
271 263
272/*** Logging ***/ 264/*** Logging ***/
273 265
274#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 266#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1
275# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ 267# define IF_UDHCP_VERBOSE(...) __VA_ARGS__
276extern unsigned dhcp_verbose; 268extern unsigned dhcp_verbose;
277# define log1(...) do { if (dhcp_verbose >= 1) bb_error_msg(__VA_ARGS__); } while (0) 269# define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0)
278# if CONFIG_UDHCP_DEBUG >= 2 270# if CONFIG_UDHCP_DEBUG >= 2
279void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; 271void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC;
280# define log2(...) do { if (dhcp_verbose >= 2) bb_error_msg(__VA_ARGS__); } while (0) 272# define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0)
281# else 273# else
282# define udhcp_dump_packet(...) ((void)0) 274# define udhcp_dump_packet(...) ((void)0)
283# define log2(...) ((void)0) 275# define log2(...) ((void)0)
284# endif 276# endif
285# if CONFIG_UDHCP_DEBUG >= 3 277# if CONFIG_UDHCP_DEBUG >= 3
286# define log3(...) do { if (dhcp_verbose >= 3) bb_error_msg(__VA_ARGS__); } while (0) 278# define log3(...) do { if (dhcp_verbose >= 3) bb_info_msg(__VA_ARGS__); } while (0)
287# else 279# else
288# define log3(...) ((void)0) 280# define log3(...) ((void)0)
289# endif 281# endif
diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h
index 2178cb9d6..dee2558e2 100644
--- a/networking/udhcp/d6_common.h
+++ b/networking/udhcp/d6_common.h
@@ -141,7 +141,7 @@ struct client6_data_t {
141 unsigned env_idx; 141 unsigned env_idx;
142 /* link-local IPv6 address */ 142 /* link-local IPv6 address */
143 struct in6_addr ll_ip6; 143 struct in6_addr ll_ip6;
144}; 144} FIX_ALIASING;
145 145
146#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) 146#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)]))
147 147
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index 3562988fd..15e9f3924 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -63,7 +63,7 @@
63#include <netpacket/packet.h> 63#include <netpacket/packet.h>
64#include <linux/filter.h> 64#include <linux/filter.h>
65 65
66/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ 66/* "struct client_data_t client_data" is in bb_common_bufsiz1 */
67 67
68static const struct dhcp_optflag d6_optflags[] = { 68static const struct dhcp_optflag d6_optflags[] = {
69#if ENABLE_FEATURE_UDHCPC6_RFC3646 69#if ENABLE_FEATURE_UDHCPC6_RFC3646
@@ -427,7 +427,7 @@ static char **fill_envp(const uint8_t *option, const uint8_t *option_end)
427 client6_data.env_ptr = NULL; 427 client6_data.env_ptr = NULL;
428 client6_data.env_idx = 0; 428 client6_data.env_idx = 0;
429 429
430 *new_env() = xasprintf("interface=%s", client_config.interface); 430 *new_env() = xasprintf("interface=%s", client_data.interface);
431 431
432 if (option) 432 if (option)
433 option_to_env(option, option_end); 433 option_to_env(option, option_end);
@@ -449,8 +449,8 @@ static void d6_run_script(const uint8_t *option, const uint8_t *option_end,
449 envp = fill_envp(option, option_end); 449 envp = fill_envp(option, option_end);
450 450
451 /* call script */ 451 /* call script */
452 log1("executing %s %s", client_config.script, name); 452 log1("executing %s %s", client_data.script, name);
453 argv[0] = (char*) client_config.script; 453 argv[0] = (char*) client_data.script;
454 argv[1] = (char*) name; 454 argv[1] = (char*) name;
455 argv[2] = NULL; 455 argv[2] = NULL;
456 spawn_and_wait(argv); 456 spawn_and_wait(argv);
@@ -486,7 +486,7 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid
486 packet->d6_xid32 = xid; 486 packet->d6_xid32 = xid;
487 packet->d6_msg_type = type; 487 packet->d6_msg_type = type;
488 488
489 clientid = (void*)client_config.clientid; 489 clientid = (void*)client_data.clientid;
490 return mempcpy(packet->d6_options, clientid, clientid->len + 2+2); 490 return mempcpy(packet->d6_options, clientid, clientid->len + 2+2);
491} 491}
492 492
@@ -499,7 +499,7 @@ static uint8_t *add_d6_client_options(uint8_t *ptr)
499 499
500 ptr += 4; 500 ptr += 4;
501 for (option = 1; option < 256; option++) { 501 for (option = 1; option < 256; option++) {
502 if (client_config.opt_mask[option >> 3] & (1 << (option & 7))) { 502 if (client_data.opt_mask[option >> 3] & (1 << (option & 7))) {
503 ptr[0] = (option >> 8); 503 ptr[0] = (option >> 8);
504 ptr[1] = option; 504 ptr[1] = option;
505 ptr += 2; 505 ptr += 2;
@@ -518,7 +518,7 @@ static uint8_t *add_d6_client_options(uint8_t *ptr)
518 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req)); 518 ptr = mempcpy(ptr, &opt_fqdn_req, sizeof(opt_fqdn_req));
519#endif 519#endif
520 /* Add -x options if any */ 520 /* Add -x options if any */
521 curr = client_config.options; 521 curr = client_data.options;
522 while (curr) { 522 while (curr) {
523 len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1]; 523 len = (curr->data[D6_OPT_LEN] << 8) | curr->data[D6_OPT_LEN + 1];
524 ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len); 524 ptr = mempcpy(ptr, curr->data, D6_OPT_DATA + len);
@@ -528,7 +528,7 @@ static uint8_t *add_d6_client_options(uint8_t *ptr)
528 return ptr; 528 return ptr;
529} 529}
530 530
531static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) 531static int d6_mcast_from_client_data_ifindex(struct d6_packet *packet, uint8_t *end)
532{ 532{
533 /* FF02::1:2 is "All_DHCP_Relay_Agents_and_Servers" address */ 533 /* FF02::1:2 is "All_DHCP_Relay_Agents_and_Servers" address */
534 static const uint8_t FF02__1_2[16] = { 534 static const uint8_t FF02__1_2[16] = {
@@ -540,7 +540,7 @@ static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t
540 packet, (end - (uint8_t*) packet), 540 packet, (end - (uint8_t*) packet),
541 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6, 541 /*src*/ &client6_data.ll_ip6, CLIENT_PORT6,
542 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR, 542 /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR,
543 client_config.ifindex 543 client_data.ifindex
544 ); 544 );
545} 545}
546 546
@@ -670,8 +670,8 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip
670 */ 670 */
671 opt_ptr = add_d6_client_options(opt_ptr); 671 opt_ptr = add_d6_client_options(opt_ptr);
672 672
673 bb_error_msg("sending %s", "discover"); 673 bb_info_msg("sending %s", "discover");
674 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 674 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
675} 675}
676 676
677/* Multicast a DHCPv6 request message 677/* Multicast a DHCPv6 request message
@@ -727,8 +727,8 @@ static NOINLINE int send_d6_select(uint32_t xid)
727 */ 727 */
728 opt_ptr = add_d6_client_options(opt_ptr); 728 opt_ptr = add_d6_client_options(opt_ptr);
729 729
730 bb_error_msg("sending %s", "select"); 730 bb_info_msg("sending %s", "select");
731 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 731 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
732} 732}
733 733
734/* Unicast or broadcast a DHCP renew message 734/* Unicast or broadcast a DHCP renew message
@@ -800,15 +800,15 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st
800 */ 800 */
801 opt_ptr = add_d6_client_options(opt_ptr); 801 opt_ptr = add_d6_client_options(opt_ptr);
802 802
803 bb_error_msg("sending %s", "renew"); 803 bb_info_msg("sending %s", "renew");
804 if (server_ipv6) 804 if (server_ipv6)
805 return d6_send_kernel_packet( 805 return d6_send_kernel_packet(
806 &packet, (opt_ptr - (uint8_t*) &packet), 806 &packet, (opt_ptr - (uint8_t*) &packet),
807 our_cur_ipv6, CLIENT_PORT6, 807 our_cur_ipv6, CLIENT_PORT6,
808 server_ipv6, SERVER_PORT6, 808 server_ipv6, SERVER_PORT6,
809 client_config.ifindex 809 client_data.ifindex
810 ); 810 );
811 return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); 811 return d6_mcast_from_client_data_ifindex(&packet, opt_ptr);
812} 812}
813 813
814/* Unicast a DHCP release message */ 814/* Unicast a DHCP release message */
@@ -830,12 +830,12 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
830 if (client6_data.ia_pd) 830 if (client6_data.ia_pd)
831 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); 831 opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2);
832 832
833 bb_error_msg("sending %s", "release"); 833 bb_info_msg("sending %s", "release");
834 return d6_send_kernel_packet( 834 return d6_send_kernel_packet(
835 &packet, (opt_ptr - (uint8_t*) &packet), 835 &packet, (opt_ptr - (uint8_t*) &packet),
836 our_cur_ipv6, CLIENT_PORT6, 836 our_cur_ipv6, CLIENT_PORT6,
837 server_ipv6, SERVER_PORT6, 837 server_ipv6, SERVER_PORT6,
838 client_config.ifindex 838 client_data.ifindex
839 ); 839 );
840} 840}
841 841
@@ -903,13 +903,12 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac
903 903
904/*** Main ***/ 904/*** Main ***/
905 905
906static int sockfd = -1; 906/* Values for client_data.listen_mode */
907
908#define LISTEN_NONE 0 907#define LISTEN_NONE 0
909#define LISTEN_KERNEL 1 908#define LISTEN_KERNEL 1
910#define LISTEN_RAW 2 909#define LISTEN_RAW 2
911static smallint listen_mode;
912 910
911/* Values for client_data.state */
913/* initial state: (re)start DHCP negotiation */ 912/* initial state: (re)start DHCP negotiation */
914#define INIT_SELECTING 0 913#define INIT_SELECTING 0
915/* discover was sent, DHCPOFFER reply received */ 914/* discover was sent, DHCPOFFER reply received */
@@ -924,7 +923,6 @@ static smallint listen_mode;
924#define RENEW_REQUESTED 5 923#define RENEW_REQUESTED 5
925/* release, possibly manually requested (SIGUSR2) */ 924/* release, possibly manually requested (SIGUSR2) */
926#define RELEASED 6 925#define RELEASED 6
927static smallint state;
928 926
929static int d6_raw_socket(int ifindex) 927static int d6_raw_socket(int ifindex)
930{ 928{
@@ -1018,35 +1016,35 @@ static void change_listen_mode(int new_mode)
1018 : "none" 1016 : "none"
1019 ); 1017 );
1020 1018
1021 listen_mode = new_mode; 1019 client_data.listen_mode = new_mode;
1022 if (sockfd >= 0) { 1020 if (client_data.sockfd >= 0) {
1023 close(sockfd); 1021 close(client_data.sockfd);
1024 sockfd = -1; 1022 client_data.sockfd = -1;
1025 } 1023 }
1026 if (new_mode == LISTEN_KERNEL) 1024 if (new_mode == LISTEN_KERNEL)
1027 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_config.interface); 1025 client_data.sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_data.interface);
1028 else if (new_mode != LISTEN_NONE) 1026 else if (new_mode != LISTEN_NONE)
1029 sockfd = d6_raw_socket(client_config.ifindex); 1027 client_data.sockfd = d6_raw_socket(client_data.ifindex);
1030 /* else LISTEN_NONE: sockfd stays closed */ 1028 /* else LISTEN_NONE: client_data.sockfd stays closed */
1031} 1029}
1032 1030
1033/* Called only on SIGUSR1 */ 1031/* Called only on SIGUSR1 */
1034static void perform_renew(void) 1032static void perform_renew(void)
1035{ 1033{
1036 bb_error_msg("performing DHCP renew"); 1034 bb_info_msg("performing DHCP renew");
1037 switch (state) { 1035 switch (client_data.state) {
1038 case BOUND: 1036 case BOUND:
1039 change_listen_mode(LISTEN_KERNEL); 1037 change_listen_mode(LISTEN_KERNEL);
1040 case RENEWING: 1038 case RENEWING:
1041 case REBINDING: 1039 case REBINDING:
1042 state = RENEW_REQUESTED; 1040 client_data.state = RENEW_REQUESTED;
1043 break; 1041 break;
1044 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ 1042 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
1045 d6_run_script_no_option("deconfig"); 1043 d6_run_script_no_option("deconfig");
1046 case REQUESTING: 1044 case REQUESTING:
1047 case RELEASED: 1045 case RELEASED:
1048 change_listen_mode(LISTEN_RAW); 1046 change_listen_mode(LISTEN_RAW);
1049 state = INIT_SELECTING; 1047 client_data.state = INIT_SELECTING;
1050 break; 1048 break;
1051 case INIT_SELECTING: 1049 case INIT_SELECTING:
1052 break; 1050 break;
@@ -1056,15 +1054,15 @@ static void perform_renew(void)
1056static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) 1054static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6)
1057{ 1055{
1058 /* send release packet */ 1056 /* send release packet */
1059 if (state == BOUND 1057 if (client_data.state == BOUND
1060 || state == RENEWING 1058 || client_data.state == RENEWING
1061 || state == REBINDING 1059 || client_data.state == REBINDING
1062 || state == RENEW_REQUESTED 1060 || client_data.state == RENEW_REQUESTED
1063 ) { 1061 ) {
1064 bb_error_msg("unicasting a release"); 1062 bb_info_msg("unicasting a release");
1065 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ 1063 send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */
1066 } 1064 }
1067 bb_error_msg("entering released state"); 1065 bb_info_msg("entering released state");
1068/* 1066/*
1069 * We can be here on: SIGUSR2, 1067 * We can be here on: SIGUSR2,
1070 * or on exit (SIGTERM) and -R "release on quit" is specified. 1068 * or on exit (SIGTERM) and -R "release on quit" is specified.
@@ -1073,7 +1071,7 @@ static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *ou
1073 */ 1071 */
1074 d6_run_script_no_option("deconfig"); 1072 d6_run_script_no_option("deconfig");
1075 change_listen_mode(LISTEN_NONE); 1073 change_listen_mode(LISTEN_NONE);
1076 state = RELEASED; 1074 client_data.state = RELEASED;
1077} 1075}
1078 1076
1079///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 1077///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
@@ -1093,7 +1091,7 @@ static void client_background(void)
1093 bb_daemonize(0); 1091 bb_daemonize(0);
1094 logmode &= ~LOGMODE_STDIO; 1092 logmode &= ~LOGMODE_STDIO;
1095 /* rewrite pidfile, as our pid is different now */ 1093 /* rewrite pidfile, as our pid is different now */
1096 write_pidfile(client_config.pidfile); 1094 write_pidfile(client_data.pidfile);
1097} 1095}
1098#endif 1096#endif
1099 1097
@@ -1172,8 +1170,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1172 /* Default options */ 1170 /* Default options */
1173 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) 1171 IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;)
1174 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;) 1172 IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;)
1175 client_config.interface = "eth0"; 1173 client_data.interface = "eth0";
1176 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 1174 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1175 client_data.sockfd = -1;
1177 1176
1178 /* Parse command line */ 1177 /* Parse command line */
1179 opt = getopt32long(argv, "^" 1178 opt = getopt32long(argv, "^"
@@ -1185,8 +1184,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1185 "v" 1184 "v"
1186 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ 1185 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
1187 , udhcpc6_longopts 1186 , udhcpc6_longopts
1188 , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ 1187 , &client_data.interface, &client_data.pidfile, &str_r /* i,p */
1189 , &client_config.script /* s */ 1188 , &client_data.script /* s */
1190 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ 1189 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1191 , &list_O 1190 , &list_O
1192 , &list_x 1191 , &list_x
@@ -1217,29 +1216,29 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1217 n = udhcp_option_idx(optstr, d6_option_strings); 1216 n = udhcp_option_idx(optstr, d6_option_strings);
1218 n = d6_optflags[n].code; 1217 n = d6_optflags[n].code;
1219 } 1218 }
1220 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1219 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1221 } 1220 }
1222 if (!(opt & OPT_o)) { 1221 if (!(opt & OPT_o)) {
1223 unsigned i, n; 1222 unsigned i, n;
1224 for (i = 0; (n = d6_optflags[i].code) != 0; i++) { 1223 for (i = 0; (n = d6_optflags[i].code) != 0; i++) {
1225 if (d6_optflags[i].flags & OPTION_REQ) { 1224 if (d6_optflags[i].flags & OPTION_REQ) {
1226 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1225 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1227 } 1226 }
1228 } 1227 }
1229 } 1228 }
1230 while (list_x) { 1229 while (list_x) {
1231 char *optstr = xstrdup(llist_pop(&list_x)); 1230 char *optstr = xstrdup(llist_pop(&list_x));
1232 udhcp_str2optset(optstr, &client_config.options, 1231 udhcp_str2optset(optstr, &client_data.options,
1233 d6_optflags, d6_option_strings, 1232 d6_optflags, d6_option_strings,
1234 /*dhcpv6:*/ 1 1233 /*dhcpv6:*/ 1
1235 ); 1234 );
1236 free(optstr); 1235 free(optstr);
1237 } 1236 }
1238 1237
1239 if (d6_read_interface(client_config.interface, 1238 if (d6_read_interface(client_data.interface,
1240 &client_config.ifindex, 1239 &client_data.ifindex,
1241 &client6_data.ll_ip6, 1240 &client6_data.ll_ip6,
1242 client_config.client_mac) 1241 client_data.client_mac)
1243 ) { 1242 ) {
1244 return 1; 1243 return 1;
1245 } 1244 }
@@ -1253,8 +1252,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1253 clientid->data[1] = 3; /* DUID-LL */ 1252 clientid->data[1] = 3; /* DUID-LL */
1254 clientid->data[3] = 1; /* ethernet */ 1253 clientid->data[3] = 1; /* ethernet */
1255 clientid_mac_ptr = clientid->data + 2+2; 1254 clientid_mac_ptr = clientid->data + 2+2;
1256 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1255 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1257 client_config.clientid = (void*)clientid; 1256 client_data.clientid = (void*)clientid;
1258 } 1257 }
1259 1258
1260#if !BB_MMU 1259#if !BB_MMU
@@ -1272,13 +1271,13 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1272 /* Make sure fd 0,1,2 are open */ 1271 /* Make sure fd 0,1,2 are open */
1273 bb_sanitize_stdio(); 1272 bb_sanitize_stdio();
1274 /* Create pidfile */ 1273 /* Create pidfile */
1275 write_pidfile(client_config.pidfile); 1274 write_pidfile(client_data.pidfile);
1276 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1275 /* Goes to stdout (unless NOMMU) and possibly syslog */
1277 bb_error_msg("started, v"BB_VER); 1276 bb_info_msg("started, v"BB_VER);
1278 /* Set up the signal pipe */ 1277 /* Set up the signal pipe */
1279 udhcp_sp_setup(); 1278 udhcp_sp_setup();
1280 1279
1281 state = INIT_SELECTING; 1280 client_data.state = INIT_SELECTING;
1282 d6_run_script_no_option("deconfig"); 1281 d6_run_script_no_option("deconfig");
1283 change_listen_mode(LISTEN_RAW); 1282 change_listen_mode(LISTEN_RAW);
1284 packet_num = 0; 1283 packet_num = 0;
@@ -1297,16 +1296,16 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1297 /* silence "uninitialized!" warning */ 1296 /* silence "uninitialized!" warning */
1298 unsigned timestamp_before_wait = timestamp_before_wait; 1297 unsigned timestamp_before_wait = timestamp_before_wait;
1299 1298
1300 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); 1299 //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode);
1301 1300
1302 /* Was opening raw or udp socket here 1301 /* Was opening raw or udp socket here
1303 * if (listen_mode != LISTEN_NONE && sockfd < 0), 1302 * if (client_data.listen_mode != LISTEN_NONE && client_data.sockfd < 0),
1304 * but on fast network renew responses return faster 1303 * but on fast network renew responses return faster
1305 * than we open sockets. Thus this code is moved 1304 * than we open sockets. Thus this code is moved
1306 * to change_listen_mode(). Thus we open listen socket 1305 * to change_listen_mode(). Thus we open listen socket
1307 * BEFORE we send renew request (see "case BOUND:"). */ 1306 * BEFORE we send renew request (see "case BOUND:"). */
1308 1307
1309 udhcp_sp_fd_set(pfds, sockfd); 1308 udhcp_sp_fd_set(pfds, client_data.sockfd);
1310 1309
1311 tv = timeout - already_waited_sec; 1310 tv = timeout - already_waited_sec;
1312 retval = 0; 1311 retval = 0;
@@ -1335,20 +1334,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1335 * or if the status of the bridge changed). 1334 * or if the status of the bridge changed).
1336 * Refresh ifindex and client_mac: 1335 * Refresh ifindex and client_mac:
1337 */ 1336 */
1338 if (d6_read_interface(client_config.interface, 1337 if (d6_read_interface(client_data.interface,
1339 &client_config.ifindex, 1338 &client_data.ifindex,
1340 &client6_data.ll_ip6, 1339 &client6_data.ll_ip6,
1341 client_config.client_mac) 1340 client_data.client_mac)
1342 ) { 1341 ) {
1343 goto ret0; /* iface is gone? */ 1342 goto ret0; /* iface is gone? */
1344 } 1343 }
1345 1344
1346 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1345 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1347 1346
1348 /* We will restart the wait in any case */ 1347 /* We will restart the wait in any case */
1349 already_waited_sec = 0; 1348 already_waited_sec = 0;
1350 1349
1351 switch (state) { 1350 switch (client_data.state) {
1352 case INIT_SELECTING: 1351 case INIT_SELECTING:
1353 if (!discover_retries || packet_num < discover_retries) { 1352 if (!discover_retries || packet_num < discover_retries) {
1354 if (packet_num == 0) 1353 if (packet_num == 0)
@@ -1363,7 +1362,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1363 d6_run_script_no_option("leasefail"); 1362 d6_run_script_no_option("leasefail");
1364#if BB_MMU /* -b is not supported on NOMMU */ 1363#if BB_MMU /* -b is not supported on NOMMU */
1365 if (opt & OPT_b) { /* background if no lease */ 1364 if (opt & OPT_b) { /* background if no lease */
1366 bb_error_msg("no lease, forking to background"); 1365 bb_info_msg("no lease, forking to background");
1367 client_background(); 1366 client_background();
1368 /* do not background again! */ 1367 /* do not background again! */
1369 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f); 1368 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f);
@@ -1376,7 +1375,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1376 } else 1375 } else
1377#endif 1376#endif
1378 if (opt & OPT_n) { /* abort if no lease */ 1377 if (opt & OPT_n) { /* abort if no lease */
1379 bb_error_msg("no lease, failing"); 1378 bb_info_msg("no lease, failing");
1380 retval = 1; 1379 retval = 1;
1381 goto ret; 1380 goto ret;
1382 } 1381 }
@@ -1397,12 +1396,12 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1397 * were seen in the wild. Treat them similarly 1396 * were seen in the wild. Treat them similarly
1398 * to "no response to discover" case */ 1397 * to "no response to discover" case */
1399 change_listen_mode(LISTEN_RAW); 1398 change_listen_mode(LISTEN_RAW);
1400 state = INIT_SELECTING; 1399 client_data.state = INIT_SELECTING;
1401 goto leasefail; 1400 goto leasefail;
1402 case BOUND: 1401 case BOUND:
1403 /* 1/2 lease passed, enter renewing state */ 1402 /* 1/2 lease passed, enter renewing state */
1404 state = RENEWING; 1403 client_data.state = RENEWING;
1405 client_config.first_secs = 0; /* make secs field count from 0 */ 1404 client_data.first_secs = 0; /* make secs field count from 0 */
1406 change_listen_mode(LISTEN_KERNEL); 1405 change_listen_mode(LISTEN_KERNEL);
1407 log1("entering renew state"); 1406 log1("entering renew state");
1408 /* fall right through */ 1407 /* fall right through */
@@ -1425,7 +1424,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1425 } 1424 }
1426 /* Timed out, enter rebinding state */ 1425 /* Timed out, enter rebinding state */
1427 log1("entering rebinding state"); 1426 log1("entering rebinding state");
1428 state = REBINDING; 1427 client_data.state = REBINDING;
1429 /* fall right through */ 1428 /* fall right through */
1430 case REBINDING: 1429 case REBINDING:
1431 /* Switch to bcast receive */ 1430 /* Switch to bcast receive */
@@ -1439,10 +1438,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1439 continue; 1438 continue;
1440 } 1439 }
1441 /* Timed out, enter init state */ 1440 /* Timed out, enter init state */
1442 bb_error_msg("lease lost, entering init state"); 1441 bb_info_msg("lease lost, entering init state");
1443 d6_run_script_no_option("deconfig"); 1442 d6_run_script_no_option("deconfig");
1444 state = INIT_SELECTING; 1443 client_data.state = INIT_SELECTING;
1445 client_config.first_secs = 0; /* make secs field count from 0 */ 1444 client_data.first_secs = 0; /* make secs field count from 0 */
1446 /*timeout = 0; - already is */ 1445 /*timeout = 0; - already is */
1447 packet_num = 0; 1446 packet_num = 0;
1448 continue; 1447 continue;
@@ -1458,10 +1457,10 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1458 /* Is it a signal? */ 1457 /* Is it a signal? */
1459 switch (udhcp_sp_read()) { 1458 switch (udhcp_sp_read()) {
1460 case SIGUSR1: 1459 case SIGUSR1:
1461 client_config.first_secs = 0; /* make secs field count from 0 */ 1460 client_data.first_secs = 0; /* make secs field count from 0 */
1462 already_waited_sec = 0; 1461 already_waited_sec = 0;
1463 perform_renew(); 1462 perform_renew();
1464 if (state == RENEW_REQUESTED) { 1463 if (client_data.state == RENEW_REQUESTED) {
1465 /* We might be either on the same network 1464 /* We might be either on the same network
1466 * (in which case renew might work), 1465 * (in which case renew might work),
1467 * or we might be on a completely different one 1466 * or we might be on a completely different one
@@ -1484,7 +1483,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1484 timeout = INT_MAX; 1483 timeout = INT_MAX;
1485 continue; 1484 continue;
1486 case SIGTERM: 1485 case SIGTERM:
1487 bb_error_msg("received %s", "SIGTERM"); 1486 bb_info_msg("received %s", "SIGTERM");
1488 goto ret0; 1487 goto ret0;
1489 } 1488 }
1490 1489
@@ -1496,15 +1495,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1496 int len; 1495 int len;
1497 1496
1498 /* A packet is ready, read it */ 1497 /* A packet is ready, read it */
1499 if (listen_mode == LISTEN_KERNEL) 1498 if (client_data.listen_mode == LISTEN_KERNEL)
1500 len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd); 1499 len = d6_recv_kernel_packet(&srv6_buf, &packet, client_data.sockfd);
1501 else 1500 else
1502 len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd); 1501 len = d6_recv_raw_packet(&srv6_buf, &packet, client_data.sockfd);
1503 if (len == -1) { 1502 if (len == -1) {
1504 /* Error is severe, reopen socket */ 1503 /* Error is severe, reopen socket */
1505 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO); 1504 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1506 sleep(discover_timeout); /* 3 seconds by default */ 1505 sleep(discover_timeout); /* 3 seconds by default */
1507 change_listen_mode(listen_mode); /* just close and reopen */ 1506 change_listen_mode(client_data.listen_mode); /* just close and reopen */
1508 } 1507 }
1509 /* If this packet will turn out to be unrelated/bogus, 1508 /* If this packet will turn out to be unrelated/bogus,
1510 * we will go back and wait for next one. 1509 * we will go back and wait for next one.
@@ -1521,7 +1520,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1521 continue; 1520 continue;
1522 } 1521 }
1523 1522
1524 switch (state) { 1523 switch (client_data.state) {
1525 case INIT_SELECTING: 1524 case INIT_SELECTING:
1526 if (packet.d6_msg_type == D6_MSG_ADVERTISE) 1525 if (packet.d6_msg_type == D6_MSG_ADVERTISE)
1527 goto type_is_ok; 1526 goto type_is_ok;
@@ -1544,15 +1543,15 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1544 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); 1543 option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE);
1545 if (option && (option->data[0] | option->data[1]) != 0) { 1544 if (option && (option->data[0] | option->data[1]) != 0) {
1546 /* return to init state */ 1545 /* return to init state */
1547 bb_error_msg("received DHCP NAK (%u)", option->data[4]); 1546 bb_info_msg("received DHCP NAK (%u)", option->data[4]);
1548 d6_run_script(packet.d6_options, 1547 d6_run_script(packet.d6_options,
1549 packet_end, "nak"); 1548 packet_end, "nak");
1550 if (state != REQUESTING) 1549 if (client_data.state != REQUESTING)
1551 d6_run_script_no_option("deconfig"); 1550 d6_run_script_no_option("deconfig");
1552 change_listen_mode(LISTEN_RAW); 1551 change_listen_mode(LISTEN_RAW);
1553 sleep(3); /* avoid excessive network traffic */ 1552 sleep(3); /* avoid excessive network traffic */
1554 state = INIT_SELECTING; 1553 client_data.state = INIT_SELECTING;
1555 client_config.first_secs = 0; /* make secs field count from 0 */ 1554 client_data.first_secs = 0; /* make secs field count from 0 */
1556 requested_ipv6 = NULL; 1555 requested_ipv6 = NULL;
1557 timeout = 0; 1556 timeout = 0;
1558 packet_num = 0; 1557 packet_num = 0;
@@ -1561,7 +1560,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1561 } 1560 }
1562 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); 1561 option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID);
1563 if (!option) { 1562 if (!option) {
1564 bb_error_msg("no server ID, ignoring packet"); 1563 bb_info_msg("no server ID, ignoring packet");
1565 continue; 1564 continue;
1566 /* still selecting - this server looks bad */ 1565 /* still selecting - this server looks bad */
1567 } 1566 }
@@ -1572,7 +1571,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1572 client6_data.server_id = option; 1571 client6_data.server_id = option;
1573 if (packet.d6_msg_type == D6_MSG_ADVERTISE) { 1572 if (packet.d6_msg_type == D6_MSG_ADVERTISE) {
1574 /* enter requesting state */ 1573 /* enter requesting state */
1575 state = REQUESTING; 1574 client_data.state = REQUESTING;
1576 timeout = 0; 1575 timeout = 0;
1577 packet_num = 0; 1576 packet_num = 0;
1578 already_waited_sec = 0; 1577 already_waited_sec = 0;
@@ -1670,11 +1669,11 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1670 free(client6_data.ia_na); 1669 free(client6_data.ia_na);
1671 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); 1670 client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA);
1672 if (!client6_data.ia_na) { 1671 if (!client6_data.ia_na) {
1673 bb_error_msg("no %s option, ignoring packet", "IA_NA"); 1672 bb_info_msg("no %s option, ignoring packet", "IA_NA");
1674 continue; 1673 continue;
1675 } 1674 }
1676 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { 1675 if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) {
1677 bb_error_msg("%s option is too short:%d bytes", 1676 bb_info_msg("%s option is too short:%d bytes",
1678 "IA_NA", client6_data.ia_na->len); 1677 "IA_NA", client6_data.ia_na->len);
1679 continue; 1678 continue;
1680 } 1679 }
@@ -1683,11 +1682,11 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1683 D6_OPT_IAADDR 1682 D6_OPT_IAADDR
1684 ); 1683 );
1685 if (!iaaddr) { 1684 if (!iaaddr) {
1686 bb_error_msg("no %s option, ignoring packet", "IAADDR"); 1685 bb_info_msg("no %s option, ignoring packet", "IAADDR");
1687 continue; 1686 continue;
1688 } 1687 }
1689 if (iaaddr->len < (16 + 4 + 4)) { 1688 if (iaaddr->len < (16 + 4 + 4)) {
1690 bb_error_msg("%s option is too short:%d bytes", 1689 bb_info_msg("%s option is too short:%d bytes",
1691 "IAADDR", iaaddr->len); 1690 "IAADDR", iaaddr->len);
1692 continue; 1691 continue;
1693 } 1692 }
@@ -1698,7 +1697,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1698 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); 1697 move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4);
1699 lease_seconds = ntohl(lease_seconds); 1698 lease_seconds = ntohl(lease_seconds);
1700/// TODO: check for 0 lease time? 1699/// TODO: check for 0 lease time?
1701 bb_error_msg("%s obtained, lease time %u", 1700 bb_info_msg("%s obtained, lease time %u",
1702 "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); 1701 "IPv6", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1703 address_timeout = lease_seconds; 1702 address_timeout = lease_seconds;
1704 } 1703 }
@@ -1708,11 +1707,11 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1708 free(client6_data.ia_pd); 1707 free(client6_data.ia_pd);
1709 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD); 1708 client6_data.ia_pd = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_PD);
1710 if (!client6_data.ia_pd) { 1709 if (!client6_data.ia_pd) {
1711 bb_error_msg("no %s option, ignoring packet", "IA_PD"); 1710 bb_info_msg("no %s option, ignoring packet", "IA_PD");
1712 continue; 1711 continue;
1713 } 1712 }
1714 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) { 1713 if (client6_data.ia_pd->len < (4 + 4 + 4) + (2 + 2 + 4 + 4 + 1 + 16)) {
1715 bb_error_msg("%s option is too short:%d bytes", 1714 bb_info_msg("%s option is too short:%d bytes",
1716 "IA_PD", client6_data.ia_pd->len); 1715 "IA_PD", client6_data.ia_pd->len);
1717 continue; 1716 continue;
1718 } 1717 }
@@ -1721,17 +1720,17 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1721 D6_OPT_IAPREFIX 1720 D6_OPT_IAPREFIX
1722 ); 1721 );
1723 if (!iaprefix) { 1722 if (!iaprefix) {
1724 bb_error_msg("no %s option, ignoring packet", "IAPREFIX"); 1723 bb_info_msg("no %s option, ignoring packet", "IAPREFIX");
1725 continue; 1724 continue;
1726 } 1725 }
1727 if (iaprefix->len < (4 + 4 + 1 + 16)) { 1726 if (iaprefix->len < (4 + 4 + 1 + 16)) {
1728 bb_error_msg("%s option is too short:%d bytes", 1727 bb_info_msg("%s option is too short:%d bytes",
1729 "IAPREFIX", iaprefix->len); 1728 "IAPREFIX", iaprefix->len);
1730 continue; 1729 continue;
1731 } 1730 }
1732 move_from_unaligned32(lease_seconds, iaprefix->data + 4); 1731 move_from_unaligned32(lease_seconds, iaprefix->data + 4);
1733 lease_seconds = ntohl(lease_seconds); 1732 lease_seconds = ntohl(lease_seconds);
1734 bb_error_msg("%s obtained, lease time %u", 1733 bb_info_msg("%s obtained, lease time %u",
1735 "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); 1734 "prefix", /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds);
1736 prefix_timeout = lease_seconds; 1735 prefix_timeout = lease_seconds;
1737 } 1736 }
@@ -1747,9 +1746,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1747 timeout = 61; 1746 timeout = 61;
1748 /* enter bound state */ 1747 /* enter bound state */
1749 d6_run_script(packet.d6_options, packet_end, 1748 d6_run_script(packet.d6_options, packet_end,
1750 (state == REQUESTING ? "bound" : "renew")); 1749 (client_data.state == REQUESTING ? "bound" : "renew"));
1751 1750
1752 state = BOUND; 1751 client_data.state = BOUND;
1753 change_listen_mode(LISTEN_NONE); 1752 change_listen_mode(LISTEN_NONE);
1754 if (opt & OPT_q) { /* quit after lease */ 1753 if (opt & OPT_q) { /* quit after lease */
1755 goto ret0; 1754 goto ret0;
@@ -1778,7 +1777,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv)
1778 perform_d6_release(&srv6_buf, requested_ipv6); 1777 perform_d6_release(&srv6_buf, requested_ipv6);
1779 retval = 0; 1778 retval = 0;
1780 ret: 1779 ret:
1781 /*if (client_config.pidfile) - remove_pidfile has its own check */ 1780 /*if (client_data.pidfile) - remove_pidfile has its own check */
1782 remove_pidfile(client_config.pidfile); 1781 remove_pidfile(client_data.pidfile);
1783 return retval; 1782 return retval;
1784} 1783}
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
index 493943d72..01d1c930b 100644
--- a/networking/udhcp/d6_packet.c
+++ b/networking/udhcp/d6_packet.c
@@ -17,7 +17,7 @@ void FAST_FUNC d6_dump_packet(struct d6_packet *packet)
17 if (dhcp_verbose < 2) 17 if (dhcp_verbose < 2)
18 return; 18 return;
19 19
20 bb_error_msg( 20 bb_info_msg(
21 " xid %x" 21 " xid %x"
22 , packet->d6_xid32 22 , packet->d6_xid32
23 ); 23 );
@@ -40,7 +40,7 @@ int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6
40 } 40 }
41 41
42 if (bytes < offsetof(struct d6_packet, d6_options)) { 42 if (bytes < offsetof(struct d6_packet, d6_options)) {
43 bb_error_msg("packet with bad magic, ignoring"); 43 bb_info_msg("packet with bad magic, ignoring");
44 return -2; 44 return -2;
45 } 45 }
46 log1("received %s", "a packet"); 46 log1("received %s", "a packet");
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index e2fb18aba..cb85fa9e3 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -49,7 +49,7 @@ struct tpacket_auxdata {
49#endif 49#endif
50 50
51 51
52/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ 52/* "struct client_data_t client_data" is in bb_common_bufsiz1 */
53 53
54 54
55#if ENABLE_LONG_OPTS 55#if ENABLE_LONG_OPTS
@@ -477,7 +477,7 @@ static char **fill_envp(struct dhcp_packet *packet)
477 } 477 }
478 curr = envp = xzalloc(sizeof(envp[0]) * envc); 478 curr = envp = xzalloc(sizeof(envp[0]) * envc);
479 479
480 *curr = xasprintf("interface=%s", client_config.interface); 480 *curr = xasprintf("interface=%s", client_data.interface);
481 putenv(*curr++); 481 putenv(*curr++);
482 482
483 if (!packet) 483 if (!packet)
@@ -577,8 +577,8 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name)
577 envp = fill_envp(packet); 577 envp = fill_envp(packet);
578 578
579 /* call script */ 579 /* call script */
580 log1("executing %s %s", client_config.script, name); 580 log1("executing %s %s", client_data.script, name);
581 argv[0] = (char*) client_config.script; 581 argv[0] = (char*) client_data.script;
582 argv[1] = (char*) name; 582 argv[1] = (char*) name;
583 argv[2] = NULL; 583 argv[2] = NULL;
584 spawn_and_wait(argv); 584 spawn_and_wait(argv);
@@ -608,15 +608,15 @@ static void init_packet(struct dhcp_packet *packet, char type)
608 608
609 packet->xid = random_xid(); 609 packet->xid = random_xid();
610 610
611 client_config.last_secs = monotonic_sec(); 611 client_data.last_secs = monotonic_sec();
612 if (client_config.first_secs == 0) 612 if (client_data.first_secs == 0)
613 client_config.first_secs = client_config.last_secs; 613 client_data.first_secs = client_data.last_secs;
614 secs = client_config.last_secs - client_config.first_secs; 614 secs = client_data.last_secs - client_data.first_secs;
615 packet->secs = htons(secs); 615 packet->secs = htons(secs);
616 616
617 memcpy(packet->chaddr, client_config.client_mac, 6); 617 memcpy(packet->chaddr, client_data.client_mac, 6);
618 if (client_config.clientid) 618 if (client_data.clientid)
619 udhcp_add_binary_option(packet, client_config.clientid); 619 udhcp_add_binary_option(packet, client_data.clientid);
620} 620}
621 621
622static void add_client_options(struct dhcp_packet *packet) 622static void add_client_options(struct dhcp_packet *packet)
@@ -631,7 +631,7 @@ static void add_client_options(struct dhcp_packet *packet)
631 end = udhcp_end_option(packet->options); 631 end = udhcp_end_option(packet->options);
632 len = 0; 632 len = 0;
633 for (i = 1; i < DHCP_END; i++) { 633 for (i = 1; i < DHCP_END; i++) {
634 if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) { 634 if (client_data.opt_mask[i >> 3] & (1 << (i & 7))) {
635 packet->options[end + OPT_DATA + len] = i; 635 packet->options[end + OPT_DATA + len] = i;
636 len++; 636 len++;
637 } 637 }
@@ -642,12 +642,12 @@ static void add_client_options(struct dhcp_packet *packet)
642 packet->options[end + OPT_DATA + len] = DHCP_END; 642 packet->options[end + OPT_DATA + len] = DHCP_END;
643 } 643 }
644 644
645 if (client_config.vendorclass) 645 if (client_data.vendorclass)
646 udhcp_add_binary_option(packet, client_config.vendorclass); 646 udhcp_add_binary_option(packet, client_data.vendorclass);
647 if (client_config.hostname) 647 if (client_data.hostname)
648 udhcp_add_binary_option(packet, client_config.hostname); 648 udhcp_add_binary_option(packet, client_data.hostname);
649 if (client_config.fqdn) 649 if (client_data.fqdn)
650 udhcp_add_binary_option(packet, client_config.fqdn); 650 udhcp_add_binary_option(packet, client_data.fqdn);
651 651
652 /* Request broadcast replies if we have no IP addr */ 652 /* Request broadcast replies if we have no IP addr */
653 if ((option_mask32 & OPT_B) && packet->ciaddr == 0) 653 if ((option_mask32 & OPT_B) && packet->ciaddr == 0)
@@ -655,15 +655,15 @@ static void add_client_options(struct dhcp_packet *packet)
655 655
656 /* Add -x options if any */ 656 /* Add -x options if any */
657 { 657 {
658 struct option_set *curr = client_config.options; 658 struct option_set *curr = client_data.options;
659 while (curr) { 659 while (curr) {
660 udhcp_add_binary_option(packet, curr->data); 660 udhcp_add_binary_option(packet, curr->data);
661 curr = curr->next; 661 curr = curr->next;
662 } 662 }
663// if (client_config.sname) 663// if (client_data.sname)
664// strncpy((char*)packet->sname, client_config.sname, sizeof(packet->sname) - 1); 664// strncpy((char*)packet->sname, client_data.sname, sizeof(packet->sname) - 1);
665// if (client_config.boot_file) 665// if (client_data.boot_file)
666// strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); 666// strncpy((char*)packet->file, client_data.boot_file, sizeof(packet->file) - 1);
667 } 667 }
668 668
669 // This will be needed if we remove -V VENDOR_STR in favor of 669 // This will be needed if we remove -V VENDOR_STR in favor of
@@ -691,12 +691,12 @@ static void add_client_options(struct dhcp_packet *packet)
691 * client reverts to using the IP broadcast address. 691 * client reverts to using the IP broadcast address.
692 */ 692 */
693 693
694static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet, uint32_t src_nip) 694static int raw_bcast_from_client_data_ifindex(struct dhcp_packet *packet, uint32_t src_nip)
695{ 695{
696 return udhcp_send_raw_packet(packet, 696 return udhcp_send_raw_packet(packet,
697 /*src*/ src_nip, CLIENT_PORT, 697 /*src*/ src_nip, CLIENT_PORT,
698 /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR, 698 /*dst*/ INADDR_BROADCAST, SERVER_PORT, MAC_BCAST_ADDR,
699 client_config.ifindex); 699 client_data.ifindex);
700} 700}
701 701
702static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server) 702static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server)
@@ -705,7 +705,7 @@ static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t
705 return udhcp_send_kernel_packet(packet, 705 return udhcp_send_kernel_packet(packet,
706 ciaddr, CLIENT_PORT, 706 ciaddr, CLIENT_PORT,
707 server, SERVER_PORT); 707 server, SERVER_PORT);
708 return raw_bcast_from_client_config_ifindex(packet, ciaddr); 708 return raw_bcast_from_client_data_ifindex(packet, ciaddr);
709} 709}
710 710
711/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ 711/* Broadcast a DHCP discover packet to the network, with an optionally requested IP */
@@ -730,8 +730,8 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested)
730 */ 730 */
731 add_client_options(&packet); 731 add_client_options(&packet);
732 732
733 bb_error_msg("sending %s", "discover"); 733 bb_info_msg("sending %s", "discover");
734 return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY); 734 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
735} 735}
736 736
737/* Broadcast a DHCP request message */ 737/* Broadcast a DHCP request message */
@@ -774,8 +774,8 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste
774 add_client_options(&packet); 774 add_client_options(&packet);
775 775
776 temp_addr.s_addr = requested; 776 temp_addr.s_addr = requested;
777 bb_error_msg("sending select for %s", inet_ntoa(temp_addr)); 777 bb_info_msg("sending select for %s", inet_ntoa(temp_addr));
778 return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY); 778 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
779} 779}
780 780
781/* Unicast or broadcast a DHCP renew message */ 781/* Unicast or broadcast a DHCP renew message */
@@ -815,7 +815,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr)
815 add_client_options(&packet); 815 add_client_options(&packet);
816 816
817 temp_addr.s_addr = server; 817 temp_addr.s_addr = server;
818 bb_error_msg("sending renew to %s", inet_ntoa(temp_addr)); 818 bb_info_msg("sending renew to %s", inet_ntoa(temp_addr));
819 return bcast_or_ucast(&packet, ciaddr, server); 819 return bcast_or_ucast(&packet, ciaddr, server);
820} 820}
821 821
@@ -844,8 +844,8 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req
844 844
845 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 845 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
846 846
847 bb_error_msg("sending %s", "decline"); 847 bb_info_msg("sending %s", "decline");
848 return raw_bcast_from_client_config_ifindex(&packet, INADDR_ANY); 848 return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY);
849} 849}
850#endif 850#endif
851 851
@@ -866,7 +866,7 @@ int send_release(uint32_t server, uint32_t ciaddr)
866 866
867 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); 867 udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server);
868 868
869 bb_error_msg("sending %s", "release"); 869 bb_info_msg("sending %s", "release");
870 /* Note: normally we unicast here since "server" is not zero. 870 /* Note: normally we unicast here since "server" is not zero.
871 * However, there _are_ people who run "address-less" DHCP servers, 871 * However, there _are_ people who run "address-less" DHCP servers,
872 * and reportedly ISC dhcp client and Windows allow that. 872 * and reportedly ISC dhcp client and Windows allow that.
@@ -969,7 +969,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
969 skip_udp_sum_check: 969 skip_udp_sum_check:
970 970
971 if (packet.data.cookie != htonl(DHCP_MAGIC)) { 971 if (packet.data.cookie != htonl(DHCP_MAGIC)) {
972 bb_error_msg("packet with bad magic, ignoring"); 972 bb_info_msg("packet with bad magic, ignoring");
973 return -2; 973 return -2;
974 } 974 }
975 975
@@ -984,13 +984,12 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
984 984
985/*** Main ***/ 985/*** Main ***/
986 986
987static int sockfd = -1; 987/* Values for client_data.listen_mode */
988
989#define LISTEN_NONE 0 988#define LISTEN_NONE 0
990#define LISTEN_KERNEL 1 989#define LISTEN_KERNEL 1
991#define LISTEN_RAW 2 990#define LISTEN_RAW 2
992static smallint listen_mode;
993 991
992/* Values for client_data.state */
994/* initial state: (re)start DHCP negotiation */ 993/* initial state: (re)start DHCP negotiation */
995#define INIT_SELECTING 0 994#define INIT_SELECTING 0
996/* discover was sent, DHCPOFFER reply received */ 995/* discover was sent, DHCPOFFER reply received */
@@ -1005,7 +1004,6 @@ static smallint listen_mode;
1005#define RENEW_REQUESTED 5 1004#define RENEW_REQUESTED 5
1006/* release, possibly manually requested (SIGUSR2) */ 1005/* release, possibly manually requested (SIGUSR2) */
1007#define RELEASED 6 1006#define RELEASED 6
1008static smallint state;
1009 1007
1010static int udhcp_raw_socket(int ifindex) 1008static int udhcp_raw_socket(int ifindex)
1011{ 1009{
@@ -1102,35 +1100,35 @@ static void change_listen_mode(int new_mode)
1102 : "none" 1100 : "none"
1103 ); 1101 );
1104 1102
1105 listen_mode = new_mode; 1103 client_data.listen_mode = new_mode;
1106 if (sockfd >= 0) { 1104 if (client_data.sockfd >= 0) {
1107 close(sockfd); 1105 close(client_data.sockfd);
1108 sockfd = -1; 1106 client_data.sockfd = -1;
1109 } 1107 }
1110 if (new_mode == LISTEN_KERNEL) 1108 if (new_mode == LISTEN_KERNEL)
1111 sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_config.interface); 1109 client_data.sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT, client_data.interface);
1112 else if (new_mode != LISTEN_NONE) 1110 else if (new_mode != LISTEN_NONE)
1113 sockfd = udhcp_raw_socket(client_config.ifindex); 1111 client_data.sockfd = udhcp_raw_socket(client_data.ifindex);
1114 /* else LISTEN_NONE: sockfd stays closed */ 1112 /* else LISTEN_NONE: client_data.sockfd stays closed */
1115} 1113}
1116 1114
1117/* Called only on SIGUSR1 */ 1115/* Called only on SIGUSR1 */
1118static void perform_renew(void) 1116static void perform_renew(void)
1119{ 1117{
1120 bb_error_msg("performing DHCP renew"); 1118 bb_info_msg("performing DHCP renew");
1121 switch (state) { 1119 switch (client_data.state) {
1122 case BOUND: 1120 case BOUND:
1123 change_listen_mode(LISTEN_KERNEL); 1121 change_listen_mode(LISTEN_KERNEL);
1124 case RENEWING: 1122 case RENEWING:
1125 case REBINDING: 1123 case REBINDING:
1126 state = RENEW_REQUESTED; 1124 client_data.state = RENEW_REQUESTED;
1127 break; 1125 break;
1128 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ 1126 case RENEW_REQUESTED: /* impatient are we? fine, square 1 */
1129 udhcp_run_script(NULL, "deconfig"); 1127 udhcp_run_script(NULL, "deconfig");
1130 case REQUESTING: 1128 case REQUESTING:
1131 case RELEASED: 1129 case RELEASED:
1132 change_listen_mode(LISTEN_RAW); 1130 change_listen_mode(LISTEN_RAW);
1133 state = INIT_SELECTING; 1131 client_data.state = INIT_SELECTING;
1134 break; 1132 break;
1135 case INIT_SELECTING: 1133 case INIT_SELECTING:
1136 break; 1134 break;
@@ -1143,19 +1141,19 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1143 struct in_addr temp_addr; 1141 struct in_addr temp_addr;
1144 1142
1145 /* send release packet */ 1143 /* send release packet */
1146 if (state == BOUND 1144 if (client_data.state == BOUND
1147 || state == RENEWING 1145 || client_data.state == RENEWING
1148 || state == REBINDING 1146 || client_data.state == REBINDING
1149 || state == RENEW_REQUESTED 1147 || client_data.state == RENEW_REQUESTED
1150 ) { 1148 ) {
1151 temp_addr.s_addr = server_addr; 1149 temp_addr.s_addr = server_addr;
1152 strcpy(buffer, inet_ntoa(temp_addr)); 1150 strcpy(buffer, inet_ntoa(temp_addr));
1153 temp_addr.s_addr = requested_ip; 1151 temp_addr.s_addr = requested_ip;
1154 bb_error_msg("unicasting a release of %s to %s", 1152 bb_info_msg("unicasting a release of %s to %s",
1155 inet_ntoa(temp_addr), buffer); 1153 inet_ntoa(temp_addr), buffer);
1156 send_release(server_addr, requested_ip); /* unicast */ 1154 send_release(server_addr, requested_ip); /* unicast */
1157 } 1155 }
1158 bb_error_msg("entering released state"); 1156 bb_info_msg("entering released state");
1159/* 1157/*
1160 * We can be here on: SIGUSR2, 1158 * We can be here on: SIGUSR2,
1161 * or on exit (SIGTERM) and -R "release on quit" is specified. 1159 * or on exit (SIGTERM) and -R "release on quit" is specified.
@@ -1165,7 +1163,7 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip)
1165 udhcp_run_script(NULL, "deconfig"); 1163 udhcp_run_script(NULL, "deconfig");
1166 1164
1167 change_listen_mode(LISTEN_NONE); 1165 change_listen_mode(LISTEN_NONE);
1168 state = RELEASED; 1166 client_data.state = RELEASED;
1169} 1167}
1170 1168
1171static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) 1169static uint8_t* alloc_dhcp_option(int code, const char *str, int extra)
@@ -1185,7 +1183,7 @@ static void client_background(void)
1185 bb_daemonize(0); 1183 bb_daemonize(0);
1186 logmode &= ~LOGMODE_STDIO; 1184 logmode &= ~LOGMODE_STDIO;
1187 /* rewrite pidfile, as our pid is different now */ 1185 /* rewrite pidfile, as our pid is different now */
1188 write_pidfile(client_config.pidfile); 1186 write_pidfile(client_data.pidfile);
1189} 1187}
1190#endif 1188#endif
1191 1189
@@ -1268,8 +1266,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1268 /* Default options */ 1266 /* Default options */
1269 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) 1267 IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
1270 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) 1268 IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
1271 client_config.interface = "eth0"; 1269 client_data.interface = "eth0";
1272 client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; 1270 client_data.script = CONFIG_UDHCPC_DEFAULT_SCRIPT;
1271 client_data.sockfd = -1;
1273 str_V = "udhcp "BB_VER; 1272 str_V = "udhcp "BB_VER;
1274 1273
1275 /* Parse command line */ 1274 /* Parse command line */
@@ -1283,9 +1282,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1283 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ 1282 "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */
1284 , udhcpc_longopts 1283 , udhcpc_longopts
1285 , &str_V, &str_h, &str_h, &str_F 1284 , &str_V, &str_h, &str_h, &str_F
1286 , &client_config.interface, &client_config.pidfile /* i,p */ 1285 , &client_data.interface, &client_data.pidfile /* i,p */
1287 , &str_r /* r */ 1286 , &str_r /* r */
1288 , &client_config.script /* s */ 1287 , &client_data.script /* s */
1289 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ 1288 , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */
1290 , &list_O 1289 , &list_O
1291 , &list_x 1290 , &list_x
@@ -1296,11 +1295,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1296 if (opt & (OPT_h|OPT_H)) { 1295 if (opt & (OPT_h|OPT_H)) {
1297 //msg added 2011-11 1296 //msg added 2011-11
1298 bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); 1297 bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME");
1299 client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); 1298 client_data.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0);
1300 } 1299 }
1301 if (opt & OPT_F) { 1300 if (opt & OPT_F) {
1302 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ 1301 /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */
1303 client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); 1302 client_data.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3);
1304 /* Flag bits: 0000NEOS 1303 /* Flag bits: 0000NEOS
1305 * S: 1 = Client requests server to update A RR in DNS as well as PTR 1304 * S: 1 = Client requests server to update A RR in DNS as well as PTR
1306 * O: 1 = Server indicates to client that DNS has been updated regardless 1305 * O: 1 = Server indicates to client that DNS has been updated regardless
@@ -1309,9 +1308,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1309 * N: 1 = Client requests server to not update DNS (S must be 0 then) 1308 * N: 1 = Client requests server to not update DNS (S must be 0 then)
1310 * Two [0] bytes which follow are deprecated and must be 0. 1309 * Two [0] bytes which follow are deprecated and must be 0.
1311 */ 1310 */
1312 client_config.fqdn[OPT_DATA + 0] = 0x1; 1311 client_data.fqdn[OPT_DATA + 0] = 0x1;
1313 /*client_config.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */ 1312 /*client_data.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */
1314 /*client_config.fqdn[OPT_DATA + 2] = 0; */ 1313 /*client_data.fqdn[OPT_DATA + 2] = 0; */
1315 } 1314 }
1316 if (opt & OPT_r) 1315 if (opt & OPT_r)
1317 requested_ip = inet_addr(str_r); 1316 requested_ip = inet_addr(str_r);
@@ -1329,49 +1328,49 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1329 n = udhcp_option_idx(optstr, dhcp_option_strings); 1328 n = udhcp_option_idx(optstr, dhcp_option_strings);
1330 n = dhcp_optflags[n].code; 1329 n = dhcp_optflags[n].code;
1331 } 1330 }
1332 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1331 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1333 } 1332 }
1334 if (!(opt & OPT_o)) { 1333 if (!(opt & OPT_o)) {
1335 unsigned i, n; 1334 unsigned i, n;
1336 for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) { 1335 for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) {
1337 if (dhcp_optflags[i].flags & OPTION_REQ) { 1336 if (dhcp_optflags[i].flags & OPTION_REQ) {
1338 client_config.opt_mask[n >> 3] |= 1 << (n & 7); 1337 client_data.opt_mask[n >> 3] |= 1 << (n & 7);
1339 } 1338 }
1340 } 1339 }
1341 } 1340 }
1342 while (list_x) { 1341 while (list_x) {
1343 char *optstr = xstrdup(llist_pop(&list_x)); 1342 char *optstr = xstrdup(llist_pop(&list_x));
1344 udhcp_str2optset(optstr, &client_config.options, 1343 udhcp_str2optset(optstr, &client_data.options,
1345 dhcp_optflags, dhcp_option_strings, 1344 dhcp_optflags, dhcp_option_strings,
1346 /*dhcpv6:*/ 0 1345 /*dhcpv6:*/ 0
1347 ); 1346 );
1348 free(optstr); 1347 free(optstr);
1349 } 1348 }
1350 1349
1351 if (udhcp_read_interface(client_config.interface, 1350 if (udhcp_read_interface(client_data.interface,
1352 &client_config.ifindex, 1351 &client_data.ifindex,
1353 NULL, 1352 NULL,
1354 client_config.client_mac) 1353 client_data.client_mac)
1355 ) { 1354 ) {
1356 return 1; 1355 return 1;
1357 } 1356 }
1358 1357
1359 clientid_mac_ptr = NULL; 1358 clientid_mac_ptr = NULL;
1360 if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) { 1359 if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) {
1361 /* not suppressed and not set, set the default client ID */ 1360 /* not suppressed and not set, set the default client ID */
1362 client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); 1361 client_data.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7);
1363 client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ 1362 client_data.clientid[OPT_DATA] = 1; /* type: ethernet */
1364 clientid_mac_ptr = client_config.clientid + OPT_DATA+1; 1363 clientid_mac_ptr = client_data.clientid + OPT_DATA+1;
1365 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1364 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1366 } 1365 }
1367 if (str_V[0] != '\0') { 1366 if (str_V[0] != '\0') {
1368 // can drop -V, str_V, client_config.vendorclass, 1367 // can drop -V, str_V, client_data.vendorclass,
1369 // but need to add "vendor" to the list of recognized 1368 // but need to add "vendor" to the list of recognized
1370 // string opts for this to work; 1369 // string opts for this to work;
1371 // and need to tweak add_client_options() too... 1370 // and need to tweak add_client_options() too...
1372 // ...so the question is, should we? 1371 // ...so the question is, should we?
1373 //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); 1372 //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR");
1374 client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); 1373 client_data.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0);
1375 } 1374 }
1376 1375
1377#if !BB_MMU 1376#if !BB_MMU
@@ -1389,15 +1388,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1389 /* Make sure fd 0,1,2 are open */ 1388 /* Make sure fd 0,1,2 are open */
1390 bb_sanitize_stdio(); 1389 bb_sanitize_stdio();
1391 /* Create pidfile */ 1390 /* Create pidfile */
1392 write_pidfile(client_config.pidfile); 1391 write_pidfile(client_data.pidfile);
1393 /* Goes to stdout (unless NOMMU) and possibly syslog */ 1392 /* Goes to stdout (unless NOMMU) and possibly syslog */
1394 bb_error_msg("started, v"BB_VER); 1393 bb_info_msg("started, v"BB_VER);
1395 /* Set up the signal pipe */ 1394 /* Set up the signal pipe */
1396 udhcp_sp_setup(); 1395 udhcp_sp_setup();
1397 /* We want random_xid to be random... */ 1396 /* We want random_xid to be random... */
1398 srand(monotonic_us()); 1397 srand(monotonic_us());
1399 1398
1400 state = INIT_SELECTING; 1399 client_data.state = INIT_SELECTING;
1401 udhcp_run_script(NULL, "deconfig"); 1400 udhcp_run_script(NULL, "deconfig");
1402 change_listen_mode(LISTEN_RAW); 1401 change_listen_mode(LISTEN_RAW);
1403 packet_num = 0; 1402 packet_num = 0;
@@ -1415,16 +1414,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1415 /* silence "uninitialized!" warning */ 1414 /* silence "uninitialized!" warning */
1416 unsigned timestamp_before_wait = timestamp_before_wait; 1415 unsigned timestamp_before_wait = timestamp_before_wait;
1417 1416
1418 //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); 1417 //bb_error_msg("sockfd:%d, listen_mode:%d", client_data.sockfd, client_data.listen_mode);
1419 1418
1420 /* Was opening raw or udp socket here 1419 /* Was opening raw or udp socket here
1421 * if (listen_mode != LISTEN_NONE && sockfd < 0), 1420 * if (client_data.listen_mode != LISTEN_NONE && client_data.sockfd < 0),
1422 * but on fast network renew responses return faster 1421 * but on fast network renew responses return faster
1423 * than we open sockets. Thus this code is moved 1422 * than we open sockets. Thus this code is moved
1424 * to change_listen_mode(). Thus we open listen socket 1423 * to change_listen_mode(). Thus we open listen socket
1425 * BEFORE we send renew request (see "case BOUND:"). */ 1424 * BEFORE we send renew request (see "case BOUND:"). */
1426 1425
1427 udhcp_sp_fd_set(pfds, sockfd); 1426 udhcp_sp_fd_set(pfds, client_data.sockfd);
1428 1427
1429 tv = timeout - already_waited_sec; 1428 tv = timeout - already_waited_sec;
1430 retval = 0; 1429 retval = 0;
@@ -1453,20 +1452,20 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1453 * or if the status of the bridge changed). 1452 * or if the status of the bridge changed).
1454 * Refresh ifindex and client_mac: 1453 * Refresh ifindex and client_mac:
1455 */ 1454 */
1456 if (udhcp_read_interface(client_config.interface, 1455 if (udhcp_read_interface(client_data.interface,
1457 &client_config.ifindex, 1456 &client_data.ifindex,
1458 NULL, 1457 NULL,
1459 client_config.client_mac) 1458 client_data.client_mac)
1460 ) { 1459 ) {
1461 goto ret0; /* iface is gone? */ 1460 goto ret0; /* iface is gone? */
1462 } 1461 }
1463 if (clientid_mac_ptr) 1462 if (clientid_mac_ptr)
1464 memcpy(clientid_mac_ptr, client_config.client_mac, 6); 1463 memcpy(clientid_mac_ptr, client_data.client_mac, 6);
1465 1464
1466 /* We will restart the wait in any case */ 1465 /* We will restart the wait in any case */
1467 already_waited_sec = 0; 1466 already_waited_sec = 0;
1468 1467
1469 switch (state) { 1468 switch (client_data.state) {
1470 case INIT_SELECTING: 1469 case INIT_SELECTING:
1471 if (!discover_retries || packet_num < discover_retries) { 1470 if (!discover_retries || packet_num < discover_retries) {
1472 if (packet_num == 0) 1471 if (packet_num == 0)
@@ -1481,7 +1480,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1481 udhcp_run_script(NULL, "leasefail"); 1480 udhcp_run_script(NULL, "leasefail");
1482#if BB_MMU /* -b is not supported on NOMMU */ 1481#if BB_MMU /* -b is not supported on NOMMU */
1483 if (opt & OPT_b) { /* background if no lease */ 1482 if (opt & OPT_b) { /* background if no lease */
1484 bb_error_msg("no lease, forking to background"); 1483 bb_info_msg("no lease, forking to background");
1485 client_background(); 1484 client_background();
1486 /* do not background again! */ 1485 /* do not background again! */
1487 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f); 1486 opt = ((opt & ~(OPT_b|OPT_n)) | OPT_f);
@@ -1494,7 +1493,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1494 } else 1493 } else
1495#endif 1494#endif
1496 if (opt & OPT_n) { /* abort if no lease */ 1495 if (opt & OPT_n) { /* abort if no lease */
1497 bb_error_msg("no lease, failing"); 1496 bb_info_msg("no lease, failing");
1498 retval = 1; 1497 retval = 1;
1499 goto ret; 1498 goto ret;
1500 } 1499 }
@@ -1515,12 +1514,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1515 * were seen in the wild. Treat them similarly 1514 * were seen in the wild. Treat them similarly
1516 * to "no response to discover" case */ 1515 * to "no response to discover" case */
1517 change_listen_mode(LISTEN_RAW); 1516 change_listen_mode(LISTEN_RAW);
1518 state = INIT_SELECTING; 1517 client_data.state = INIT_SELECTING;
1519 goto leasefail; 1518 goto leasefail;
1520 case BOUND: 1519 case BOUND:
1521 /* 1/2 lease passed, enter renewing state */ 1520 /* 1/2 lease passed, enter renewing state */
1522 state = RENEWING; 1521 client_data.state = RENEWING;
1523 client_config.first_secs = 0; /* make secs field count from 0 */ 1522 client_data.first_secs = 0; /* make secs field count from 0 */
1524 change_listen_mode(LISTEN_KERNEL); 1523 change_listen_mode(LISTEN_KERNEL);
1525 log1("entering renew state"); 1524 log1("entering renew state");
1526 /* fall right through */ 1525 /* fall right through */
@@ -1556,7 +1555,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1556 } 1555 }
1557 /* Timed out or error, enter rebinding state */ 1556 /* Timed out or error, enter rebinding state */
1558 log1("entering rebinding state"); 1557 log1("entering rebinding state");
1559 state = REBINDING; 1558 client_data.state = REBINDING;
1560 /* fall right through */ 1559 /* fall right through */
1561 case REBINDING: 1560 case REBINDING:
1562 /* Switch to bcast receive */ 1561 /* Switch to bcast receive */
@@ -1570,10 +1569,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1570 continue; 1569 continue;
1571 } 1570 }
1572 /* Timed out, enter init state */ 1571 /* Timed out, enter init state */
1573 bb_error_msg("lease lost, entering init state"); 1572 bb_info_msg("lease lost, entering init state");
1574 udhcp_run_script(NULL, "deconfig"); 1573 udhcp_run_script(NULL, "deconfig");
1575 state = INIT_SELECTING; 1574 client_data.state = INIT_SELECTING;
1576 client_config.first_secs = 0; /* make secs field count from 0 */ 1575 client_data.first_secs = 0; /* make secs field count from 0 */
1577 /*timeout = 0; - already is */ 1576 /*timeout = 0; - already is */
1578 packet_num = 0; 1577 packet_num = 0;
1579 continue; 1578 continue;
@@ -1589,10 +1588,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1589 /* Is it a signal? */ 1588 /* Is it a signal? */
1590 switch (udhcp_sp_read()) { 1589 switch (udhcp_sp_read()) {
1591 case SIGUSR1: 1590 case SIGUSR1:
1592 client_config.first_secs = 0; /* make secs field count from 0 */ 1591 client_data.first_secs = 0; /* make secs field count from 0 */
1593 already_waited_sec = 0; 1592 already_waited_sec = 0;
1594 perform_renew(); 1593 perform_renew();
1595 if (state == RENEW_REQUESTED) { 1594 if (client_data.state == RENEW_REQUESTED) {
1596 /* We might be either on the same network 1595 /* We might be either on the same network
1597 * (in which case renew might work), 1596 * (in which case renew might work),
1598 * or we might be on a completely different one 1597 * or we might be on a completely different one
@@ -1615,7 +1614,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1615 timeout = INT_MAX; 1614 timeout = INT_MAX;
1616 continue; 1615 continue;
1617 case SIGTERM: 1616 case SIGTERM:
1618 bb_error_msg("received %s", "SIGTERM"); 1617 bb_info_msg("received %s", "SIGTERM");
1619 goto ret0; 1618 goto ret0;
1620 } 1619 }
1621 1620
@@ -1627,15 +1626,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1627 int len; 1626 int len;
1628 1627
1629 /* A packet is ready, read it */ 1628 /* A packet is ready, read it */
1630 if (listen_mode == LISTEN_KERNEL) 1629 if (client_data.listen_mode == LISTEN_KERNEL)
1631 len = udhcp_recv_kernel_packet(&packet, sockfd); 1630 len = udhcp_recv_kernel_packet(&packet, client_data.sockfd);
1632 else 1631 else
1633 len = udhcp_recv_raw_packet(&packet, sockfd); 1632 len = udhcp_recv_raw_packet(&packet, client_data.sockfd);
1634 if (len == -1) { 1633 if (len == -1) {
1635 /* Error is severe, reopen socket */ 1634 /* Error is severe, reopen socket */
1636 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO); 1635 bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO);
1637 sleep(discover_timeout); /* 3 seconds by default */ 1636 sleep(discover_timeout); /* 3 seconds by default */
1638 change_listen_mode(listen_mode); /* just close and reopen */ 1637 change_listen_mode(client_data.listen_mode); /* just close and reopen */
1639 } 1638 }
1640 /* If this packet will turn out to be unrelated/bogus, 1639 /* If this packet will turn out to be unrelated/bogus,
1641 * we will go back and wait for next one. 1640 * we will go back and wait for next one.
@@ -1653,7 +1652,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1653 1652
1654 /* Ignore packets that aren't for us */ 1653 /* Ignore packets that aren't for us */
1655 if (packet.hlen != 6 1654 if (packet.hlen != 6
1656 || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 1655 || memcmp(packet.chaddr, client_data.client_mac, 6) != 0
1657 ) { 1656 ) {
1658//FIXME: need to also check that last 10 bytes are zero 1657//FIXME: need to also check that last 10 bytes are zero
1659 log1("chaddr does not match, ignoring packet"); // log2? 1658 log1("chaddr does not match, ignoring packet"); // log2?
@@ -1662,11 +1661,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1662 1661
1663 message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 1662 message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
1664 if (message == NULL) { 1663 if (message == NULL) {
1665 bb_error_msg("no message type option, ignoring packet"); 1664 bb_info_msg("no message type option, ignoring packet");
1666 continue; 1665 continue;
1667 } 1666 }
1668 1667
1669 switch (state) { 1668 switch (client_data.state) {
1670 case INIT_SELECTING: 1669 case INIT_SELECTING:
1671 /* Must be a DHCPOFFER */ 1670 /* Must be a DHCPOFFER */
1672 if (*message == DHCPOFFER) { 1671 if (*message == DHCPOFFER) {
@@ -1691,7 +1690,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1691 * might work too. 1690 * might work too.
1692 * "Next server" and router are definitely wrong ones to use, though... 1691 * "Next server" and router are definitely wrong ones to use, though...
1693 */ 1692 */
1694/* We used to ignore pcakets without DHCP_SERVER_ID. 1693/* We used to ignore packets without DHCP_SERVER_ID.
1695 * I've got user reports from people who run "address-less" servers. 1694 * I've got user reports from people who run "address-less" servers.
1696 * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. 1695 * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all.
1697 * They say ISC DHCP client supports this case. 1696 * They say ISC DHCP client supports this case.
@@ -1699,7 +1698,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1699 server_addr = 0; 1698 server_addr = 0;
1700 temp = udhcp_get_option32(&packet, DHCP_SERVER_ID); 1699 temp = udhcp_get_option32(&packet, DHCP_SERVER_ID);
1701 if (!temp) { 1700 if (!temp) {
1702 bb_error_msg("no server ID, using 0.0.0.0"); 1701 bb_info_msg("no server ID, using 0.0.0.0");
1703 } else { 1702 } else {
1704 /* it IS unaligned sometimes, don't "optimize" */ 1703 /* it IS unaligned sometimes, don't "optimize" */
1705 move_from_unaligned32(server_addr, temp); 1704 move_from_unaligned32(server_addr, temp);
@@ -1708,7 +1707,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1708 requested_ip = packet.yiaddr; 1707 requested_ip = packet.yiaddr;
1709 1708
1710 /* enter requesting state */ 1709 /* enter requesting state */
1711 state = REQUESTING; 1710 client_data.state = REQUESTING;
1712 timeout = 0; 1711 timeout = 0;
1713 packet_num = 0; 1712 packet_num = 0;
1714 already_waited_sec = 0; 1713 already_waited_sec = 0;
@@ -1726,7 +1725,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1726 1725
1727 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); 1726 temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME);
1728 if (!temp) { 1727 if (!temp) {
1729 bb_error_msg("no lease time with ACK, using 1 hour lease"); 1728 bb_info_msg("no lease time with ACK, using 1 hour lease");
1730 lease_seconds = 60 * 60; 1729 lease_seconds = 60 * 60;
1731 } else { 1730 } else {
1732 /* it IS unaligned sometimes, don't "optimize" */ 1731 /* it IS unaligned sometimes, don't "optimize" */
@@ -1755,19 +1754,19 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1755 if (!arpping(packet.yiaddr, 1754 if (!arpping(packet.yiaddr,
1756 NULL, 1755 NULL,
1757 (uint32_t) 0, 1756 (uint32_t) 0,
1758 client_config.client_mac, 1757 client_data.client_mac,
1759 client_config.interface, 1758 client_data.interface,
1760 arpping_ms) 1759 arpping_ms)
1761 ) { 1760 ) {
1762 bb_error_msg("offered address is in use " 1761 bb_info_msg("offered address is in use "
1763 "(got ARP reply), declining"); 1762 "(got ARP reply), declining");
1764 send_decline(/*xid,*/ server_addr, packet.yiaddr); 1763 send_decline(/*xid,*/ server_addr, packet.yiaddr);
1765 1764
1766 if (state != REQUESTING) 1765 if (client_data.state != REQUESTING)
1767 udhcp_run_script(NULL, "deconfig"); 1766 udhcp_run_script(NULL, "deconfig");
1768 change_listen_mode(LISTEN_RAW); 1767 change_listen_mode(LISTEN_RAW);
1769 state = INIT_SELECTING; 1768 client_data.state = INIT_SELECTING;
1770 client_config.first_secs = 0; /* make secs field count from 0 */ 1769 client_data.first_secs = 0; /* make secs field count from 0 */
1771 requested_ip = 0; 1770 requested_ip = 0;
1772 timeout = tryagain_timeout; 1771 timeout = tryagain_timeout;
1773 packet_num = 0; 1772 packet_num = 0;
@@ -1778,12 +1777,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1778#endif 1777#endif
1779 /* enter bound state */ 1778 /* enter bound state */
1780 temp_addr.s_addr = packet.yiaddr; 1779 temp_addr.s_addr = packet.yiaddr;
1781 bb_error_msg("lease of %s obtained, lease time %u", 1780 bb_info_msg("lease of %s obtained, lease time %u",
1782 inet_ntoa(temp_addr), (unsigned)lease_seconds); 1781 inet_ntoa(temp_addr), (unsigned)lease_seconds);
1783 requested_ip = packet.yiaddr; 1782 requested_ip = packet.yiaddr;
1784 1783
1785 start = monotonic_sec(); 1784 start = monotonic_sec();
1786 udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); 1785 udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew");
1787 already_waited_sec = (unsigned)monotonic_sec() - start; 1786 already_waited_sec = (unsigned)monotonic_sec() - start;
1788 timeout = lease_seconds / 2; 1787 timeout = lease_seconds / 2;
1789 if ((unsigned)timeout < already_waited_sec) { 1788 if ((unsigned)timeout < already_waited_sec) {
@@ -1791,7 +1790,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1791 timeout = already_waited_sec = 0; 1790 timeout = already_waited_sec = 0;
1792 } 1791 }
1793 1792
1794 state = BOUND; 1793 client_data.state = BOUND;
1795 change_listen_mode(LISTEN_NONE); 1794 change_listen_mode(LISTEN_NONE);
1796 if (opt & OPT_q) { /* quit after lease */ 1795 if (opt & OPT_q) { /* quit after lease */
1797 goto ret0; 1796 goto ret0;
@@ -1831,14 +1830,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1831 goto non_matching_svid; 1830 goto non_matching_svid;
1832 } 1831 }
1833 /* return to init state */ 1832 /* return to init state */
1834 bb_error_msg("received %s", "DHCP NAK"); 1833 bb_info_msg("received %s", "DHCP NAK");
1835 udhcp_run_script(&packet, "nak"); 1834 udhcp_run_script(&packet, "nak");
1836 if (state != REQUESTING) 1835 if (client_data.state != REQUESTING)
1837 udhcp_run_script(NULL, "deconfig"); 1836 udhcp_run_script(NULL, "deconfig");
1838 change_listen_mode(LISTEN_RAW); 1837 change_listen_mode(LISTEN_RAW);
1839 sleep(3); /* avoid excessive network traffic */ 1838 sleep(3); /* avoid excessive network traffic */
1840 state = INIT_SELECTING; 1839 client_data.state = INIT_SELECTING;
1841 client_config.first_secs = 0; /* make secs field count from 0 */ 1840 client_data.first_secs = 0; /* make secs field count from 0 */
1842 requested_ip = 0; 1841 requested_ip = 0;
1843 timeout = 0; 1842 timeout = 0;
1844 packet_num = 0; 1843 packet_num = 0;
@@ -1856,7 +1855,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv)
1856 perform_release(server_addr, requested_ip); 1855 perform_release(server_addr, requested_ip);
1857 retval = 0; 1856 retval = 0;
1858 ret: 1857 ret:
1859 /*if (client_config.pidfile) - remove_pidfile has its own check */ 1858 /*if (client_data.pidfile) - remove_pidfile has its own check */
1860 remove_pidfile(client_config.pidfile); 1859 remove_pidfile(client_data.pidfile);
1861 return retval; 1860 return retval;
1862} 1861}
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h
index 7fdbc9a6c..42fe71a36 100644
--- a/networking/udhcp/dhcpc.h
+++ b/networking/udhcp/dhcpc.h
@@ -7,7 +7,7 @@
7 7
8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN 8PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
9 9
10struct client_config_t { 10struct client_data_t {
11 uint8_t client_mac[6]; /* Our mac address */ 11 uint8_t client_mac[6]; /* Our mac address */
12 IF_FEATURE_UDHCP_PORT(uint16_t port;) 12 IF_FEATURE_UDHCP_PORT(uint16_t port;)
13 int ifindex; /* Index number of the interface to use */ 13 int ifindex; /* Index number of the interface to use */
@@ -24,14 +24,18 @@ struct client_config_t {
24 24
25 uint16_t first_secs; 25 uint16_t first_secs;
26 uint16_t last_secs; 26 uint16_t last_secs;
27
28 int sockfd;
29 smallint listen_mode;
30 smallint state;
27} FIX_ALIASING; 31} FIX_ALIASING;
28 32
29/* server_config sits in 1st half of bb_common_bufsiz1 */ 33/* server_config sits in 1st half of bb_common_bufsiz1 */
30#define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2])) 34#define client_data (*(struct client_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2]))
31 35
32#if ENABLE_FEATURE_UDHCP_PORT 36#if ENABLE_FEATURE_UDHCP_PORT
33#define CLIENT_PORT (client_config.port) 37#define CLIENT_PORT (client_data.port)
34#define CLIENT_PORT6 (client_config.port) 38#define CLIENT_PORT6 (client_data.port)
35#else 39#else
36#define CLIENT_PORT 68 40#define CLIENT_PORT 68
37#define CLIENT_PORT6 546 41#define CLIENT_PORT6 546
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c
index 0c55fa5e4..058f86bca 100644
--- a/networking/udhcp/dhcpd.c
+++ b/networking/udhcp/dhcpd.c
@@ -48,14 +48,25 @@
48#define g_leases ((struct dyn_lease*)ptr_to_globals) 48#define g_leases ((struct dyn_lease*)ptr_to_globals)
49/* struct server_config_t server_config is in bb_common_bufsiz1 */ 49/* struct server_config_t server_config is in bb_common_bufsiz1 */
50 50
51struct static_lease {
52 struct static_lease *next;
53 uint32_t nip;
54 uint8_t mac[6];
55 uint8_t opt[1];
56};
57
51/* Takes the address of the pointer to the static_leases linked list, 58/* Takes the address of the pointer to the static_leases linked list,
52 * address to a 6 byte mac address, 59 * address to a 6 byte mac address,
53 * 4 byte IP address */ 60 * 4 byte IP address */
54static void add_static_lease(struct static_lease **st_lease_pp, 61static void add_static_lease(struct static_lease **st_lease_pp,
55 uint8_t *mac, 62 uint8_t *mac,
56 uint32_t nip) 63 uint32_t nip,
64 const char *opts)
57{ 65{
58 struct static_lease *st_lease; 66 struct static_lease *st_lease;
67 unsigned optlen;
68
69 optlen = (opts ? 1+1+strnlen(opts, 120) : 0);
59 70
60 /* Find the tail of the list */ 71 /* Find the tail of the list */
61 while ((st_lease = *st_lease_pp) != NULL) { 72 while ((st_lease = *st_lease_pp) != NULL) {
@@ -63,15 +74,34 @@ static void add_static_lease(struct static_lease **st_lease_pp,
63 } 74 }
64 75
65 /* Add new node */ 76 /* Add new node */
66 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease)); 77 *st_lease_pp = st_lease = xzalloc(sizeof(*st_lease) + optlen);
67 memcpy(st_lease->mac, mac, 6); 78 memcpy(st_lease->mac, mac, 6);
68 st_lease->nip = nip; 79 st_lease->nip = nip;
69 /*st_lease->next = NULL;*/ 80 /*st_lease->next = NULL;*/
81 if (optlen) {
82 st_lease->opt[OPT_CODE] = DHCP_HOST_NAME;
83 optlen -= 2;
84 st_lease->opt[OPT_LEN] = optlen;
85 memcpy(&st_lease->opt[OPT_DATA], opts, optlen);
86 }
87
88#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
89 /* Print out static leases just to check what's going on */
90 if (dhcp_verbose >= 2) {
91 bb_info_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
92 st_lease->mac[0], st_lease->mac[1], st_lease->mac[2],
93 st_lease->mac[3], st_lease->mac[4], st_lease->mac[5],
94 st_lease->nip
95 );
96 }
97#endif
70} 98}
71 99
72/* Find static lease IP by mac */ 100/* Find static lease IP by mac */
73static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac) 101static uint32_t get_static_nip_by_mac(void *mac)
74{ 102{
103 struct static_lease *st_lease = server_config.static_leases;
104
75 while (st_lease) { 105 while (st_lease) {
76 if (memcmp(st_lease->mac, mac, 6) == 0) 106 if (memcmp(st_lease->mac, mac, 6) == 0)
77 return st_lease->nip; 107 return st_lease->nip;
@@ -81,8 +111,10 @@ static uint32_t get_static_nip_by_mac(struct static_lease *st_lease, void *mac)
81 return 0; 111 return 0;
82} 112}
83 113
84static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip) 114static int is_nip_reserved_as_static(uint32_t nip)
85{ 115{
116 struct static_lease *st_lease = server_config.static_leases;
117
86 while (st_lease) { 118 while (st_lease) {
87 if (st_lease->nip == nip) 119 if (st_lease->nip == nip)
88 return 1; 120 return 1;
@@ -92,30 +124,6 @@ static int is_nip_reserved(struct static_lease *st_lease, uint32_t nip)
92 return 0; 124 return 0;
93} 125}
94 126
95#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2
96/* Print out static leases just to check what's going on */
97/* Takes the address of the pointer to the static_leases linked list */
98static void log_static_leases(struct static_lease **st_lease_pp)
99{
100 struct static_lease *cur;
101
102 if (dhcp_verbose < 2)
103 return;
104
105 cur = *st_lease_pp;
106 while (cur) {
107 bb_error_msg("static lease: mac:%02x:%02x:%02x:%02x:%02x:%02x nip:%x",
108 cur->mac[0], cur->mac[1], cur->mac[2],
109 cur->mac[3], cur->mac[4], cur->mac[5],
110 cur->nip
111 );
112 cur = cur->next;
113 }
114}
115#else
116# define log_static_leases(st_lease_pp) ((void)0)
117#endif
118
119/* Find the oldest expired lease, NULL if there are no expired leases */ 127/* Find the oldest expired lease, NULL if there are no expired leases */
120static struct dyn_lease *oldest_expired_lease(void) 128static struct dyn_lease *oldest_expired_lease(void)
121{ 129{
@@ -242,7 +250,7 @@ static int nobody_responds_to_arp(uint32_t nip, const uint8_t *safe_mac, unsigne
242 return r; 250 return r;
243 251
244 temp.s_addr = nip; 252 temp.s_addr = nip;
245 bb_error_msg("%s belongs to someone, reserving it for %u seconds", 253 bb_info_msg("%s belongs to someone, reserving it for %u seconds",
246 inet_ntoa(temp), (unsigned)server_config.conflict_time); 254 inet_ntoa(temp), (unsigned)server_config.conflict_time);
247 add_lease(NULL, nip, server_config.conflict_time, NULL, 0); 255 add_lease(NULL, nip, server_config.conflict_time, NULL, 0);
248 return 0; 256 return 0;
@@ -288,7 +296,7 @@ static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arppi
288 if (nip == server_config.server_nip) 296 if (nip == server_config.server_nip)
289 goto next_addr; 297 goto next_addr;
290 /* is this a static lease addr? */ 298 /* is this a static lease addr? */
291 if (is_nip_reserved(server_config.static_leases, nip)) 299 if (is_nip_reserved_as_static(nip))
292 goto next_addr; 300 goto next_addr;
293 301
294 lease = find_lease_by_nip(nip); 302 lease = find_lease_by_nip(nip);
@@ -340,6 +348,7 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
340 char *line; 348 char *line;
341 char *mac_string; 349 char *mac_string;
342 char *ip_string; 350 char *ip_string;
351 char *opts;
343 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */ 352 struct ether_addr mac_bytes; /* it's "struct { uint8_t mac[6]; }" */
344 uint32_t nip; 353 uint32_t nip;
345 354
@@ -354,14 +363,16 @@ static int FAST_FUNC read_staticlease(const char *const_line, void *arg)
354 if (!ip_string || !udhcp_str2nip(ip_string, &nip)) 363 if (!ip_string || !udhcp_str2nip(ip_string, &nip))
355 return 0; 364 return 0;
356 365
357 add_static_lease(arg, (uint8_t*) &mac_bytes, nip); 366 opts = strtok_r(NULL, " \t", &line);
367 /* opts might be NULL, that's not an error */
358 368
359 log_static_leases(arg); 369 add_static_lease(arg, (uint8_t*) &mac_bytes, nip, opts);
360 370
361 return 1; 371 return 1;
362} 372}
363 373
364static int FAST_FUNC read_optset(const char *line, void *arg) { 374static int FAST_FUNC read_optset(const char *line, void *arg)
375{
365 return udhcp_str2optset(line, arg, 376 return udhcp_str2optset(line, arg,
366 dhcp_optflags, dhcp_option_strings, 377 dhcp_optflags, dhcp_option_strings,
367 /*dhcpv6:*/ 0 378 /*dhcpv6:*/ 0
@@ -518,13 +529,13 @@ static NOINLINE void read_leases(const char *file)
518 expires = 0; 529 expires = 0;
519 530
520 /* Check if there is a different static lease for this IP or MAC */ 531 /* Check if there is a different static lease for this IP or MAC */
521 static_nip = get_static_nip_by_mac(server_config.static_leases, lease.lease_mac); 532 static_nip = get_static_nip_by_mac(lease.lease_mac);
522 if (static_nip) { 533 if (static_nip) {
523 /* NB: we do not add lease even if static_nip == lease.lease_nip. 534 /* NB: we do not add lease even if static_nip == lease.lease_nip.
524 */ 535 */
525 continue; 536 continue;
526 } 537 }
527 if (is_nip_reserved(server_config.static_leases, lease.lease_nip)) 538 if (is_nip_reserved_as_static(lease.lease_nip))
528 continue; 539 continue;
529 540
530 /* NB: add_lease takes "relative time", IOW, 541 /* NB: add_lease takes "relative time", IOW,
@@ -602,6 +613,15 @@ static void send_packet(struct dhcp_packet *dhcp_pkt, int force_broadcast)
602 send_packet_to_client(dhcp_pkt, force_broadcast); 613 send_packet_to_client(dhcp_pkt, force_broadcast);
603} 614}
604 615
616static void send_packet_verbose(struct dhcp_packet *dhcp_pkt, const char *fmt)
617{
618 struct in_addr addr;
619 addr.s_addr = dhcp_pkt->yiaddr;
620 bb_info_msg(fmt, inet_ntoa(addr));
621 /* send_packet emits error message itself if it detects failure */
622 send_packet(dhcp_pkt, /*force_bcast:*/ 0);
623}
624
605static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type) 625static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacket, char type)
606{ 626{
607 /* Sets op, htype, hlen, cookie fields 627 /* Sets op, htype, hlen, cookie fields
@@ -621,14 +641,49 @@ static void init_packet(struct dhcp_packet *packet, struct dhcp_packet *oldpacke
621 */ 641 */
622static void add_server_options(struct dhcp_packet *packet) 642static void add_server_options(struct dhcp_packet *packet)
623{ 643{
624 struct option_set *curr = server_config.options; 644 struct option_set *config_opts;
645 uint8_t *client_hostname_opt;
646
647 client_hostname_opt = NULL;
648 if (packet->yiaddr) { /* if we aren't from send_inform()... */
649 struct static_lease *st_lease = server_config.static_leases;
650 while (st_lease) {
651 if (st_lease->nip == packet->yiaddr) {
652 if (st_lease->opt[0] != 0)
653 client_hostname_opt = st_lease->opt;
654 break;
655 }
656 st_lease = st_lease->next;
657 }
658 }
625 659
626 while (curr) { 660 config_opts = server_config.options;
627 if (curr->data[OPT_CODE] != DHCP_LEASE_TIME) 661 while (config_opts) {
628 udhcp_add_binary_option(packet, curr->data); 662 if (config_opts->data[OPT_CODE] != DHCP_LEASE_TIME) {
629 curr = curr->next; 663 /* ^^^^
664 * DHCP_LEASE_TIME is already filled, or in case of
665 * send_inform(), should not be filled at all.
666 */
667 if (config_opts->data[OPT_CODE] != DHCP_HOST_NAME
668 || !client_hostname_opt
669 ) {
670 /* Why "!client_hostname_opt":
671 * add hostname only if client has no hostname
672 * on its static lease line.
673 * (Not that "opt hostname HOST"
674 * makes much sense in udhcpd.conf,
675 * that'd give all clients the same hostname,
676 * but it's a valid configuration).
677 */
678 udhcp_add_binary_option(packet, config_opts->data);
679 }
680 }
681 config_opts = config_opts->next;
630 } 682 }
631 683
684 if (client_hostname_opt)
685 udhcp_add_binary_option(packet, client_hostname_opt);
686
632 packet->siaddr_nip = server_config.siaddr_nip; 687 packet->siaddr_nip = server_config.siaddr_nip;
633 688
634 if (server_config.sname) 689 if (server_config.sname)
@@ -657,12 +712,11 @@ static uint32_t select_lease_time(struct dhcp_packet *packet)
657static NOINLINE void send_offer(struct dhcp_packet *oldpacket, 712static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
658 uint32_t static_lease_nip, 713 uint32_t static_lease_nip,
659 struct dyn_lease *lease, 714 struct dyn_lease *lease,
660 uint8_t *requested_ip_opt, 715 uint32_t requested_nip,
661 unsigned arpping_ms) 716 unsigned arpping_ms)
662{ 717{
663 struct dhcp_packet packet; 718 struct dhcp_packet packet;
664 uint32_t lease_time_sec; 719 uint32_t lease_time_sec;
665 struct in_addr addr;
666 720
667 init_packet(&packet, oldpacket, DHCPOFFER); 721 init_packet(&packet, oldpacket, DHCPOFFER);
668 722
@@ -671,7 +725,6 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
671 /* Else: */ 725 /* Else: */
672 if (!static_lease_nip) { 726 if (!static_lease_nip) {
673 /* We have no static lease for client's chaddr */ 727 /* We have no static lease for client's chaddr */
674 uint32_t req_nip;
675 const char *p_host_name; 728 const char *p_host_name;
676 729
677 if (lease) { 730 if (lease) {
@@ -682,18 +735,16 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
682 packet.yiaddr = lease->lease_nip; 735 packet.yiaddr = lease->lease_nip;
683 } 736 }
684 /* Or: if client has requested an IP */ 737 /* Or: if client has requested an IP */
685 else if (requested_ip_opt != NULL 738 else if (requested_nip != 0
686 /* (read IP) */
687 && (move_from_unaligned32(req_nip, requested_ip_opt), 1)
688 /* and the IP is in the lease range */ 739 /* and the IP is in the lease range */
689 && ntohl(req_nip) >= server_config.start_ip 740 && ntohl(requested_nip) >= server_config.start_ip
690 && ntohl(req_nip) <= server_config.end_ip 741 && ntohl(requested_nip) <= server_config.end_ip
691 /* and */ 742 /* and */
692 && ( !(lease = find_lease_by_nip(req_nip)) /* is not already taken */ 743 && ( !(lease = find_lease_by_nip(requested_nip)) /* is not already taken */
693 || is_expired_lease(lease) /* or is taken, but expired */ 744 || is_expired_lease(lease) /* or is taken, but expired */
694 ) 745 )
695 ) { 746 ) {
696 packet.yiaddr = req_nip; 747 packet.yiaddr = requested_nip;
697 } 748 }
698 else { 749 else {
699 /* Otherwise, find a free IP */ 750 /* Otherwise, find a free IP */
@@ -721,10 +772,8 @@ static NOINLINE void send_offer(struct dhcp_packet *oldpacket,
721 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 772 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
722 add_server_options(&packet); 773 add_server_options(&packet);
723 774
724 addr.s_addr = packet.yiaddr;
725 bb_error_msg("sending OFFER of %s", inet_ntoa(addr));
726 /* send_packet emits error message itself if it detects failure */ 775 /* send_packet emits error message itself if it detects failure */
727 send_packet(&packet, /*force_bcast:*/ 0); 776 send_packet_verbose(&packet, "sending OFFER to %s");
728} 777}
729 778
730/* NOINLINE: limit stack usage in caller */ 779/* NOINLINE: limit stack usage in caller */
@@ -743,7 +792,6 @@ static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
743{ 792{
744 struct dhcp_packet packet; 793 struct dhcp_packet packet;
745 uint32_t lease_time_sec; 794 uint32_t lease_time_sec;
746 struct in_addr addr;
747 const char *p_host_name; 795 const char *p_host_name;
748 796
749 init_packet(&packet, oldpacket, DHCPACK); 797 init_packet(&packet, oldpacket, DHCPACK);
@@ -751,12 +799,9 @@ static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr)
751 799
752 lease_time_sec = select_lease_time(oldpacket); 800 lease_time_sec = select_lease_time(oldpacket);
753 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec)); 801 udhcp_add_simple_option(&packet, DHCP_LEASE_TIME, htonl(lease_time_sec));
754
755 add_server_options(&packet); 802 add_server_options(&packet);
756 803
757 addr.s_addr = yiaddr; 804 send_packet_verbose(&packet, "sending ACK to %s");
758 bb_error_msg("sending ACK to %s", inet_ntoa(addr));
759 send_packet(&packet, /*force_bcast:*/ 0);
760 805
761 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME); 806 p_host_name = (const char*) udhcp_get_option(oldpacket, DHCP_HOST_NAME);
762 add_lease(packet.chaddr, packet.yiaddr, 807 add_lease(packet.chaddr, packet.yiaddr,
@@ -796,6 +841,7 @@ static NOINLINE void send_inform(struct dhcp_packet *oldpacket)
796 add_server_options(&packet); 841 add_server_options(&packet);
797 842
798 send_packet(&packet, /*force_bcast:*/ 0); 843 send_packet(&packet, /*force_bcast:*/ 0);
844 // or maybe? send_packet_verbose(&packet, "sending ACK to %s");
799} 845}
800 846
801int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 847int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -865,7 +911,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
865 write_pidfile(server_config.pidfile); 911 write_pidfile(server_config.pidfile);
866 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */ 912 /* if (!..) bb_perror_msg("can't create pidfile %s", pidfile); */
867 913
868 bb_error_msg("started, v"BB_VER); 914 bb_info_msg("started, v"BB_VER);
869 915
870 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME); 916 option = udhcp_find_option(server_config.options, DHCP_LEASE_TIME);
871 server_config.max_lease_sec = DEFAULT_LEASE_TIME; 917 server_config.max_lease_sec = DEFAULT_LEASE_TIME;
@@ -908,7 +954,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
908 int tv; 954 int tv;
909 uint8_t *server_id_opt; 955 uint8_t *server_id_opt;
910 uint8_t *requested_ip_opt; 956 uint8_t *requested_ip_opt;
911 uint32_t requested_nip = requested_nip; /* for compiler */ 957 uint32_t requested_nip;
912 uint32_t static_lease_nip; 958 uint32_t static_lease_nip;
913 struct dyn_lease *lease, fake_lease; 959 struct dyn_lease *lease, fake_lease;
914 960
@@ -944,12 +990,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
944 990
945 if (pfds[0].revents) switch (udhcp_sp_read()) { 991 if (pfds[0].revents) switch (udhcp_sp_read()) {
946 case SIGUSR1: 992 case SIGUSR1:
947 bb_error_msg("received %s", "SIGUSR1"); 993 bb_info_msg("received %s", "SIGUSR1");
948 write_leases(); 994 write_leases();
949 /* why not just reset the timeout, eh */ 995 /* why not just reset the timeout, eh */
950 goto continue_with_autotime; 996 goto continue_with_autotime;
951 case SIGTERM: 997 case SIGTERM:
952 bb_error_msg("received %s", "SIGTERM"); 998 bb_info_msg("received %s", "SIGTERM");
953 write_leases(); 999 write_leases();
954 goto ret0; 1000 goto ret0;
955 } 1001 }
@@ -973,16 +1019,16 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
973 continue; 1019 continue;
974 } 1020 }
975 if (packet.hlen != 6) { 1021 if (packet.hlen != 6) {
976 bb_error_msg("MAC length != 6, ignoring packet"); 1022 bb_info_msg("MAC length != 6, ignoring packet");
977 continue; 1023 continue;
978 } 1024 }
979 if (packet.op != BOOTREQUEST) { 1025 if (packet.op != BOOTREQUEST) {
980 bb_error_msg("not a REQUEST, ignoring packet"); 1026 bb_info_msg("not a REQUEST, ignoring packet");
981 continue; 1027 continue;
982 } 1028 }
983 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); 1029 state = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE);
984 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) { 1030 if (state == NULL || state[0] < DHCP_MINTYPE || state[0] > DHCP_MAXTYPE) {
985 bb_error_msg("no or bad message type option, ignoring packet"); 1031 bb_info_msg("no or bad message type option, ignoring packet");
986 continue; 1032 continue;
987 } 1033 }
988 1034
@@ -999,9 +1045,9 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
999 } 1045 }
1000 1046
1001 /* Look for a static/dynamic lease */ 1047 /* Look for a static/dynamic lease */
1002 static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); 1048 static_lease_nip = get_static_nip_by_mac(&packet.chaddr);
1003 if (static_lease_nip) { 1049 if (static_lease_nip) {
1004 bb_error_msg("found static lease: %x", static_lease_nip); 1050 bb_info_msg("found static lease: %x", static_lease_nip);
1005 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6); 1051 memcpy(&fake_lease.lease_mac, &packet.chaddr, 6);
1006 fake_lease.lease_nip = static_lease_nip; 1052 fake_lease.lease_nip = static_lease_nip;
1007 fake_lease.expires = 0; 1053 fake_lease.expires = 0;
@@ -1011,6 +1057,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
1011 } 1057 }
1012 1058
1013 /* Get REQUESTED_IP if present */ 1059 /* Get REQUESTED_IP if present */
1060 requested_nip = 0;
1014 requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP); 1061 requested_ip_opt = udhcp_get_option32(&packet, DHCP_REQUESTED_IP);
1015 if (requested_ip_opt) { 1062 if (requested_ip_opt) {
1016 move_from_unaligned32(requested_nip, requested_ip_opt); 1063 move_from_unaligned32(requested_nip, requested_ip_opt);
@@ -1021,7 +1068,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv)
1021 case DHCPDISCOVER: 1068 case DHCPDISCOVER:
1022 log1("received %s", "DISCOVER"); 1069 log1("received %s", "DISCOVER");
1023 1070
1024 send_offer(&packet, static_lease_nip, lease, requested_ip_opt, arpping_ms); 1071 send_offer(&packet, static_lease_nip, lease, requested_nip, arpping_ms);
1025 break; 1072 break;
1026 1073
1027 case DHCPREQUEST: 1074 case DHCPREQUEST:
diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h
index b8f96b029..ba11d77e8 100644
--- a/networking/udhcp/dhcpd.h
+++ b/networking/udhcp/dhcpd.h
@@ -15,11 +15,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
15#define DHCPD_CONF_FILE "/etc/udhcpd.conf" 15#define DHCPD_CONF_FILE "/etc/udhcpd.conf"
16 16
17 17
18struct static_lease { 18struct static_lease;
19 struct static_lease *next;
20 uint32_t nip;
21 uint8_t mac[6];
22};
23 19
24struct server_config_t { 20struct server_config_t {
25 char *interface; /* interface to use */ 21 char *interface; /* interface to use */
@@ -58,7 +54,7 @@ struct server_config_t {
58} FIX_ALIASING; 54} FIX_ALIASING;
59 55
60#define server_config (*(struct server_config_t*)bb_common_bufsiz1) 56#define server_config (*(struct server_config_t*)bb_common_bufsiz1)
61/* client_config sits in 2nd half of bb_common_bufsiz1 */ 57/* client_data sits in 2nd half of bb_common_bufsiz1 */
62 58
63#if ENABLE_FEATURE_UDHCP_PORT 59#if ENABLE_FEATURE_UDHCP_PORT
64#define SERVER_PORT (server_config.port) 60#define SERVER_PORT (server_config.port)
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index ff16904f7..64af802a3 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -40,7 +40,7 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
40 if (dhcp_verbose < 2) 40 if (dhcp_verbose < 2)
41 return; 41 return;
42 42
43 bb_error_msg( 43 bb_info_msg(
44 //" op %x" 44 //" op %x"
45 //" htype %x" 45 //" htype %x"
46 " hlen %x" 46 " hlen %x"
@@ -73,7 +73,7 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet)
73 //, packet->options[] 73 //, packet->options[]
74 ); 74 );
75 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; 75 *bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0';
76 bb_error_msg(" chaddr %s", buf); 76 bb_info_msg(" chaddr %s", buf);
77} 77}
78#endif 78#endif
79 79
@@ -92,7 +92,7 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd)
92 if (bytes < offsetof(struct dhcp_packet, options) 92 if (bytes < offsetof(struct dhcp_packet, options)
93 || packet->cookie != htonl(DHCP_MAGIC) 93 || packet->cookie != htonl(DHCP_MAGIC)
94 ) { 94 ) {
95 bb_error_msg("packet with bad magic, ignoring"); 95 bb_info_msg("packet with bad magic, ignoring");
96 return -2; 96 return -2;
97 } 97 }
98 log1("received %s", "a packet"); 98 log1("received %s", "a packet");
diff --git a/networking/wget.c b/networking/wget.c
index d907cee30..44cec2cb5 100644
--- a/networking/wget.c
+++ b/networking/wget.c
@@ -312,7 +312,7 @@ static void progress_meter(int flag)
312 } 312 }
313} 313}
314#else 314#else
315static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { } 315static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) {}
316#endif 316#endif
317 317
318 318
diff --git a/networking/zcip.c b/networking/zcip.c
index 434762f12..f95b6f7fb 100644
--- a/networking/zcip.c
+++ b/networking/zcip.c
@@ -195,7 +195,7 @@ static int run(char *argv[3], const char *param, uint32_t nip)
195 putenv(env_ip); 195 putenv(env_ip);
196 fmt -= 3; 196 fmt -= 3;
197 } 197 }
198 bb_error_msg(fmt, argv[2], argv[0], addr); 198 bb_info_msg(fmt, argv[2], argv[0], addr);
199 status = spawn_and_wait(argv + 1); 199 status = spawn_and_wait(argv + 1);
200 if (nip != 0) 200 if (nip != 0)
201 bb_unsetenv_and_free(env_ip); 201 bb_unsetenv_and_free(env_ip);
@@ -339,7 +339,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv)
339#if BB_MMU 339#if BB_MMU
340 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/); 340 bb_daemonize(0 /*was: DAEMON_CHDIR_ROOT*/);
341#endif 341#endif
342 bb_error_msg("start, interface %s", argv_intf); 342 bb_info_msg("start, interface %s", argv_intf);
343 } 343 }
344 344
345 // Run the dynamic address negotiation protocol, 345 // Run the dynamic address negotiation protocol,
diff --git a/procps/ps.c b/procps/ps.c
index c08d03146..a4de11379 100644
--- a/procps/ps.c
+++ b/procps/ps.c
@@ -542,7 +542,7 @@ static void format_process(const procps_status_t *ps)
542 len = out[i].width - len + 1; 542 len = out[i].width - len + 1;
543 if (++i == out_cnt) /* do not pad last field */ 543 if (++i == out_cnt) /* do not pad last field */
544 break; 544 break;
545 p += sprintf(p, "%*s", len, ""); 545 p += sprintf(p, "%*s", len, " "); /* " ", not "", to ensure separation of fields */
546 } 546 }
547 printf("%.*s\n", terminal_width, buffer); 547 printf("%.*s\n", terminal_width, buffer);
548} 548}
diff --git a/shell/Config.src b/shell/Config.src
index bc7218fe5..d7623f774 100644
--- a/shell/Config.src
+++ b/shell/Config.src
@@ -99,6 +99,11 @@ config FEATURE_SH_MATH_64
99 slightly larger, but will allow computation with very large numbers. 99 slightly larger, but will allow computation with very large numbers.
100 This is not in POSIX, so do not rely on this in portable code. 100 This is not in POSIX, so do not rely on this in portable code.
101 101
102config FEATURE_SH_MATH_BASE
103 bool "Support BASE#nnnn literals"
104 default y
105 depends on FEATURE_SH_MATH
106
102config FEATURE_SH_EXTRA_QUIET 107config FEATURE_SH_EXTRA_QUIET
103 bool "Hide message on interactive shell startup" 108 bool "Hide message on interactive shell startup"
104 default y 109 default y
diff --git a/shell/ash_test/ash-misc/export1.right b/shell/ash_test/ash-misc/export1.right
new file mode 100644
index 000000000..56647af8e
--- /dev/null
+++ b/shell/ash_test/ash-misc/export1.right
@@ -0,0 +1 @@
|\w \\ \ \|
diff --git a/shell/ash_test/ash-misc/export1.tests b/shell/ash_test/ash-misc/export1.tests
new file mode 100755
index 000000000..4ffb40bdc
--- /dev/null
+++ b/shell/ash_test/ash-misc/export1.tests
@@ -0,0 +1,2 @@
1export Z='\w \\ \ \'
2echo "|$Z|"
diff --git a/shell/ash_test/ash-vars/param_expand_default.right b/shell/ash_test/ash-vars/param_expand_default.right
index 3eecd1375..7a42f67e8 100644
--- a/shell/ash_test/ash-vars/param_expand_default.right
+++ b/shell/ash_test/ash-vars/param_expand_default.right
@@ -5,3 +5,5 @@ _aaaa _aaaa _aaaa _aaaa _aaaa
5_ _ _ _word _word 5_ _ _ _word _word
6_ _ _ _ _word 6_ _ _ _ _word
7_fff _fff _fff _fff _fff 7_fff _fff _fff _fff _fff
81:1
90:0
diff --git a/shell/ash_test/ash-vars/param_expand_default.tests b/shell/ash_test/ash-vars/param_expand_default.tests
index 5e42d30e3..dbd3e2218 100755
--- a/shell/ash_test/ash-vars/param_expand_default.tests
+++ b/shell/ash_test/ash-vars/param_expand_default.tests
@@ -1,6 +1,5 @@
1# first try some invalid patterns (do in subshell due to parsing error) 1# first try some invalid patterns (do in subshell due to parsing error)
2# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) 2# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
3# valid in bash and ash (same as $-): "$THIS_SH" -c 'echo ${-}' SHELL
4"$THIS_SH" -c 'echo ${:-}' SHELL 3"$THIS_SH" -c 'echo ${:-}' SHELL
5 4
6# now some funky ones 5# now some funky ones
@@ -21,3 +20,8 @@ echo _$f _${f-} _${f:-} _${f-word} _${f:-word}
21 20
22f=fff 21f=fff
23echo _$f _${f-} _${f:-} _${f-word} _${f:-word} 22echo _$f _${f-} _${f:-} _${f-word} _${f:-word}
23
24set --
25set -- "${1-}"; echo 1:$#
26set --
27set -- ${1-}; echo 0:$#
diff --git a/shell/hush.c b/shell/hush.c
index b3ae73b9b..4b08232a4 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -466,9 +466,9 @@
466 466
467#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n" 467#define JOB_STATUS_FORMAT "[%u] %-22s %.40s\n"
468 468
469#define _SPECIAL_VARS_STR "_*@$!?#" 469#define _SPECIAL_VARS_STR "_*@$!?#-"
470#define SPECIAL_VARS_STR ("_*@$!?#" + 1) 470#define SPECIAL_VARS_STR ("_*@$!?#-" + 1)
471#define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) 471#define NUMERIC_SPECVARS_STR ("_*@$!?#-" + 3)
472#if BASH_PATTERN_SUBST 472#if BASH_PATTERN_SUBST
473/* Support / and // replace ops */ 473/* Support / and // replace ops */
474/* Note that // is stored as \ in "encoded" string representation */ 474/* Note that // is stored as \ in "encoded" string representation */
@@ -854,8 +854,7 @@ struct globals {
854 /* 'interactive_fd' is a fd# open to ctty, if we have one 854 /* 'interactive_fd' is a fd# open to ctty, if we have one
855 * _AND_ if we decided to act interactively */ 855 * _AND_ if we decided to act interactively */
856 int interactive_fd; 856 int interactive_fd;
857 const char *PS1; 857 IF_NOT_FEATURE_EDITING_FANCY_PROMPT(char *PS1;)
858 IF_FEATURE_EDITING_FANCY_PROMPT(const char *PS2;)
859# define G_interactive_fd (G.interactive_fd) 858# define G_interactive_fd (G.interactive_fd)
860#else 859#else
861# define G_interactive_fd 0 860# define G_interactive_fd 0
@@ -903,6 +902,7 @@ struct globals {
903#else 902#else
904# define G_x_mode 0 903# define G_x_mode 0
905#endif 904#endif
905 char opt_s;
906#if ENABLE_HUSH_INTERACTIVE 906#if ENABLE_HUSH_INTERACTIVE
907 smallint promptmode; /* 0: PS1, 1: PS2 */ 907 smallint promptmode; /* 0: PS1, 1: PS2 */
908#endif 908#endif
@@ -968,8 +968,8 @@ struct globals {
968 smallint we_have_children; 968 smallint we_have_children;
969#endif 969#endif
970#if ENABLE_HUSH_LINENO_VAR 970#if ENABLE_HUSH_LINENO_VAR
971 unsigned lineno; 971 unsigned parse_lineno;
972 char *lineno_var; 972 unsigned execute_lineno;
973#endif 973#endif
974 HFILE *HFILE_list; 974 HFILE *HFILE_list;
975 /* Which signals have non-DFL handler (even with no traps set)? 975 /* Which signals have non-DFL handler (even with no traps set)?
@@ -1009,6 +1009,7 @@ struct globals {
1009 int debug_indent; 1009 int debug_indent;
1010#endif 1010#endif
1011 struct sigaction sa; 1011 struct sigaction sa;
1012 char optstring_buf[sizeof("eixs")];
1012#if BASH_EPOCH_VARS 1013#if BASH_EPOCH_VARS
1013 char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3]; 1014 char epoch_buf[sizeof("%lu.nnnnnn") + sizeof(long)*3];
1014#endif 1015#endif
@@ -1448,13 +1449,6 @@ static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch)
1448#endif 1449#endif
1449 1450
1450 1451
1451#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
1452static void cmdedit_update_prompt(void);
1453#else
1454# define cmdedit_update_prompt() ((void)0)
1455#endif
1456
1457
1458/* Utility functions 1452/* Utility functions
1459 */ 1453 */
1460/* Replace each \x with x in place, return ptr past NUL. */ 1454/* Replace each \x with x in place, return ptr past NUL. */
@@ -2039,7 +2033,8 @@ static sighandler_t pick_sighandler(unsigned sig)
2039static void hush_exit(int exitcode) 2033static void hush_exit(int exitcode)
2040{ 2034{
2041#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 2035#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT
2042 save_history(G.line_input_state); 2036 if (G.line_input_state)
2037 save_history(G.line_input_state);
2043#endif 2038#endif
2044 2039
2045 fflush_all(); 2040 fflush_all();
@@ -2229,6 +2224,10 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
2229 if (strcmp(name, "RANDOM") == 0) 2224 if (strcmp(name, "RANDOM") == 0)
2230 return utoa(next_random(&G.random_gen)); 2225 return utoa(next_random(&G.random_gen));
2231#endif 2226#endif
2227#if ENABLE_HUSH_LINENO_VAR
2228 if (strcmp(name, "LINENO") == 0)
2229 return utoa(G.execute_lineno);
2230#endif
2232#if BASH_EPOCH_VARS 2231#if BASH_EPOCH_VARS
2233 { 2232 {
2234 const char *fmt = NULL; 2233 const char *fmt = NULL;
@@ -2248,32 +2247,20 @@ static const char* FAST_FUNC get_local_var_value(const char *name)
2248 return NULL; 2247 return NULL;
2249} 2248}
2250 2249
2250#if ENABLE_HUSH_GETOPTS
2251static void handle_changed_special_names(const char *name, unsigned name_len) 2251static void handle_changed_special_names(const char *name, unsigned name_len)
2252{ 2252{
2253 if (ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT 2253 if (name_len == 6) {
2254 && name_len == 3 && name[0] == 'P' && name[1] == 'S'
2255 ) {
2256 cmdedit_update_prompt();
2257 return;
2258 }
2259
2260 if ((ENABLE_HUSH_LINENO_VAR || ENABLE_HUSH_GETOPTS)
2261 && name_len == 6
2262 ) {
2263#if ENABLE_HUSH_LINENO_VAR
2264 if (strncmp(name, "LINENO", 6) == 0) {
2265 G.lineno_var = NULL;
2266 return;
2267 }
2268#endif
2269#if ENABLE_HUSH_GETOPTS
2270 if (strncmp(name, "OPTIND", 6) == 0) { 2254 if (strncmp(name, "OPTIND", 6) == 0) {
2271 G.getopt_count = 0; 2255 G.getopt_count = 0;
2272 return; 2256 return;
2273 } 2257 }
2274#endif
2275 } 2258 }
2276} 2259}
2260#else
2261/* Do not even bother evaluating arguments */
2262# define handle_changed_special_names(...) ((void)0)
2263#endif
2277 2264
2278/* str holds "NAME=VAL" and is expected to be malloced. 2265/* str holds "NAME=VAL" and is expected to be malloced.
2279 * We take ownership of it. 2266 * We take ownership of it.
@@ -2289,6 +2276,7 @@ static int set_local_var(char *str, unsigned flags)
2289 char *free_me = NULL; 2276 char *free_me = NULL;
2290 char *eq_sign; 2277 char *eq_sign;
2291 int name_len; 2278 int name_len;
2279 int retval;
2292 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT); 2280 unsigned local_lvl = (flags >> SETFLAG_VARLVL_SHIFT);
2293 2281
2294 eq_sign = strchr(str, '='); 2282 eq_sign = strchr(str, '=');
@@ -2402,24 +2390,24 @@ static int set_local_var(char *str, unsigned flags)
2402#endif 2390#endif
2403 if (flags & SETFLAG_EXPORT) 2391 if (flags & SETFLAG_EXPORT)
2404 cur->flg_export = 1; 2392 cur->flg_export = 1;
2393 retval = 0;
2405 if (cur->flg_export) { 2394 if (cur->flg_export) {
2406 if (flags & SETFLAG_UNEXPORT) { 2395 if (flags & SETFLAG_UNEXPORT) {
2407 cur->flg_export = 0; 2396 cur->flg_export = 0;
2408 /* unsetenv was already done */ 2397 /* unsetenv was already done */
2409 } else { 2398 } else {
2410 int i;
2411 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level); 2399 debug_printf_env("%s: putenv '%s'/%u\n", __func__, cur->varstr, cur->var_nest_level);
2412 i = putenv(cur->varstr); 2400 retval = putenv(cur->varstr);
2413 /* only now we can free old exported malloced string */ 2401 /* fall through to "free(free_me)" -
2414 free(free_me); 2402 * only now we can free old exported malloced string
2415 return i; 2403 */
2416 } 2404 }
2417 } 2405 }
2418 free(free_me); 2406 free(free_me);
2419 2407
2420 handle_changed_special_names(cur->varstr, name_len - 1); 2408 handle_changed_special_names(cur->varstr, name_len - 1);
2421 2409
2422 return 0; 2410 return retval;
2423} 2411}
2424 2412
2425static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) 2413static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val)
@@ -2462,7 +2450,7 @@ static int unset_local_var_len(const char *name, int name_len)
2462 cur_pp = &cur->next; 2450 cur_pp = &cur->next;
2463 } 2451 }
2464 2452
2465 /* Handle "unset PS1" et al even if did not find the variable to unset */ 2453 /* Handle "unset LINENO" et al even if did not find the variable to unset */
2466 handle_changed_special_names(name, name_len); 2454 handle_changed_special_names(name, name_len);
2467 2455
2468 return EXIT_SUCCESS; 2456 return EXIT_SUCCESS;
@@ -2581,36 +2569,27 @@ static void reinit_unicode_for_hush(void)
2581 * \ 2569 * \
2582 * It exercises a lot of corner cases. 2570 * It exercises a lot of corner cases.
2583 */ 2571 */
2584# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2585static void cmdedit_update_prompt(void)
2586{
2587 G.PS1 = get_local_var_value("PS1");
2588 if (G.PS1 == NULL)
2589 G.PS1 = "";
2590 G.PS2 = get_local_var_value("PS2");
2591 if (G.PS2 == NULL)
2592 G.PS2 = "";
2593}
2594# endif
2595static const char *setup_prompt_string(void) 2572static const char *setup_prompt_string(void)
2596{ 2573{
2597 const char *prompt_str; 2574 const char *prompt_str;
2598 2575
2599 debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode); 2576 debug_printf_prompt("%s promptmode:%d\n", __func__, G.promptmode);
2600 2577
2601 IF_FEATURE_EDITING_FANCY_PROMPT( prompt_str = G.PS2;) 2578# if ENABLE_FEATURE_EDITING_FANCY_PROMPT
2602 IF_NOT_FEATURE_EDITING_FANCY_PROMPT(prompt_str = "> ";) 2579 prompt_str = get_local_var_value(G.promptmode == 0 ? "PS1" : "PS2");
2580 if (!prompt_str)
2581 prompt_str = "";
2582# else
2583 prompt_str = "> "; /* if PS2, else... */
2603 if (G.promptmode == 0) { /* PS1 */ 2584 if (G.promptmode == 0) { /* PS1 */
2604 if (!ENABLE_FEATURE_EDITING_FANCY_PROMPT) { 2585 /* No fancy prompts supported, (re)generate "CURDIR $ " by hand */
2605 /* No fancy prompts supported, (re)generate "CURDIR $ " by hand */ 2586 free(G.PS1);
2606 free((char*)G.PS1); 2587 /* bash uses $PWD value, even if it is set by user.
2607 /* bash uses $PWD value, even if it is set by user. 2588 * It uses current dir only if PWD is unset.
2608 * It uses current dir only if PWD is unset. 2589 * We always use current dir. */
2609 * We always use current dir. */ 2590 G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
2610 G.PS1 = xasprintf("%s %c ", get_cwd(0), (geteuid() != 0) ? '$' : '#');
2611 }
2612 prompt_str = G.PS1;
2613 } 2591 }
2592# endif
2614 debug_printf("prompt_str '%s'\n", prompt_str); 2593 debug_printf("prompt_str '%s'\n", prompt_str);
2615 return prompt_str; 2594 return prompt_str;
2616} 2595}
@@ -2747,8 +2726,8 @@ static int i_getch(struct in_str *i)
2747 i->last_char = ch; 2726 i->last_char = ch;
2748#if ENABLE_HUSH_LINENO_VAR 2727#if ENABLE_HUSH_LINENO_VAR
2749 if (ch == '\n') { 2728 if (ch == '\n') {
2750 G.lineno++; 2729 G.parse_lineno++;
2751 debug_printf_parse("G.lineno++ = %u\n", G.lineno); 2730 debug_printf_parse("G.parse_lineno++ = %u\n", G.parse_lineno);
2752 } 2731 }
2753#endif 2732#endif
2754 return ch; 2733 return ch;
@@ -3750,8 +3729,8 @@ static int done_command(struct parse_context *ctx)
3750 clear_and_ret: 3729 clear_and_ret:
3751 memset(command, 0, sizeof(*command)); 3730 memset(command, 0, sizeof(*command));
3752#if ENABLE_HUSH_LINENO_VAR 3731#if ENABLE_HUSH_LINENO_VAR
3753 command->lineno = G.lineno; 3732 command->lineno = G.parse_lineno;
3754 debug_printf_parse("command->lineno = G.lineno (%u)\n", G.lineno); 3733 debug_printf_parse("command->lineno = G.parse_lineno (%u)\n", G.parse_lineno);
3755#endif 3734#endif
3756 return pi->num_cmds; /* used only for 0/nonzero check */ 3735 return pi->num_cmds; /* used only for 0/nonzero check */
3757} 3736}
@@ -4198,7 +4177,7 @@ static int done_word(struct parse_context *ctx)
4198#if ENABLE_HUSH_LOOPS 4177#if ENABLE_HUSH_LOOPS
4199 if (ctx->ctx_res_w == RES_FOR) { 4178 if (ctx->ctx_res_w == RES_FOR) {
4200 if (ctx->word.has_quoted_part 4179 if (ctx->word.has_quoted_part
4201 || !is_well_formed_var_name(command->argv[0], '\0') 4180 || endofname(command->argv[0])[0] != '\0'
4202 ) { 4181 ) {
4203 /* bash says just "not a valid identifier" */ 4182 /* bash says just "not a valid identifier" */
4204 syntax_error("not a valid identifier in for"); 4183 syntax_error("not a valid identifier in for");
@@ -4912,6 +4891,7 @@ static int parse_dollar(o_string *as_string,
4912 case '#': /* number of args */ 4891 case '#': /* number of args */
4913 case '*': /* args */ 4892 case '*': /* args */
4914 case '@': /* args */ 4893 case '@': /* args */
4894 case '-': /* $- option flags set by set builtin or shell options (-i etc) */
4915 goto make_one_char_var; 4895 goto make_one_char_var;
4916 case '{': { 4896 case '{': {
4917 char len_single_ch; 4897 char len_single_ch;
@@ -5086,11 +5066,10 @@ static int parse_dollar(o_string *as_string,
5086 case '_': 5066 case '_':
5087 goto make_var; 5067 goto make_var;
5088#if 0 5068#if 0
5089 /* TODO: $_ and $-: */ 5069 /* TODO: $_: */
5090 /* $_ Shell or shell script name; or last argument of last command 5070 /* $_ Shell or shell script name; or last argument of last command
5091 * (if last command wasn't a pipe; if it was, bash sets $_ to ""); 5071 * (if last command wasn't a pipe; if it was, bash sets $_ to "");
5092 * but in command's env, set to full pathname used to invoke it */ 5072 * but in command's env, set to full pathname used to invoke it */
5093 /* $- Option flags set by set builtin or shell options (-i etc) */
5094 ch = i_getch(input); 5073 ch = i_getch(input);
5095 nommu_addchr(as_string, ch); 5074 nommu_addchr(as_string, ch);
5096 ch = i_peek_and_eat_bkslash_nl(input); 5075 ch = i_peek_and_eat_bkslash_nl(input);
@@ -5372,7 +5351,7 @@ static struct pipe *parse_stream(char **pstring,
5372 if ((ctx.is_assignment == MAYBE_ASSIGNMENT 5351 if ((ctx.is_assignment == MAYBE_ASSIGNMENT
5373 || ctx.is_assignment == WORD_IS_KEYWORD) 5352 || ctx.is_assignment == WORD_IS_KEYWORD)
5374 && ch == '=' 5353 && ch == '='
5375 && is_well_formed_var_name(ctx.word.data, '=') 5354 && endofname(ctx.word.data)[0] == '='
5376 ) { 5355 ) {
5377 ctx.is_assignment = DEFINITELY_ASSIGNMENT; 5356 ctx.is_assignment = DEFINITELY_ASSIGNMENT;
5378 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]); 5357 debug_printf_parse("ctx.is_assignment='%s'\n", assignment_flag[ctx.is_assignment]);
@@ -6119,6 +6098,12 @@ static int encode_then_append_var_plusminus(o_string *output, int n,
6119 /* string has no special chars 6098 /* string has no special chars
6120 * && string has no $IFS chars 6099 * && string has no $IFS chars
6121 */ 6100 */
6101 if (dquoted) {
6102 /* Prints 1 (quoted expansion is a "" word, not nothing):
6103 * set -- "${notexist-}"; echo $#
6104 */
6105 output->has_quoted_part = 1;
6106 }
6122 return expand_vars_to_list(output, n, str); 6107 return expand_vars_to_list(output, n, str);
6123 } 6108 }
6124 6109
@@ -6415,6 +6400,26 @@ static NOINLINE int expand_one_var(o_string *output, int n,
6415 case '#': /* argc */ 6400 case '#': /* argc */
6416 val = utoa(G.global_argc ? G.global_argc-1 : 0); 6401 val = utoa(G.global_argc ? G.global_argc-1 : 0);
6417 break; 6402 break;
6403 case '-': { /* active options */
6404 /* Check set_mode() to see what option chars we support */
6405 char *cp;
6406 val = cp = G.optstring_buf;
6407 if (G.o_opt[OPT_O_ERREXIT])
6408 *cp++ = 'e';
6409 if (G_interactive_fd)
6410 *cp++ = 'i';
6411 if (G_x_mode)
6412 *cp++ = 'x';
6413 /* If G.o_opt[OPT_O_NOEXEC] is true,
6414 * commands read but are not executed,
6415 * so $- can not execute too, 'n' is never seen in $-.
6416 */
6417 if (G.opt_s)
6418 *cp++ = 's';
6419//TODO: show 'c' if executed via "hush -c 'CMDS'" (bash only, not ash)
6420 *cp = '\0';
6421 break;
6422 }
6418 default: 6423 default:
6419 val = get_local_var_value(var); 6424 val = get_local_var_value(var);
6420 } 6425 }
@@ -7275,22 +7280,22 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger)
7275static void parse_and_run_string(const char *s) 7280static void parse_and_run_string(const char *s)
7276{ 7281{
7277 struct in_str input; 7282 struct in_str input;
7278 //IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) 7283 //IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
7279 7284
7280 setup_string_in_str(&input, s); 7285 setup_string_in_str(&input, s);
7281 parse_and_run_stream(&input, '\0'); 7286 parse_and_run_stream(&input, '\0');
7282 //IF_HUSH_LINENO_VAR(G.lineno = sv;) 7287 //IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
7283} 7288}
7284 7289
7285static void parse_and_run_file(HFILE *fp) 7290static void parse_and_run_file(HFILE *fp)
7286{ 7291{
7287 struct in_str input; 7292 struct in_str input;
7288 IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) 7293 IF_HUSH_LINENO_VAR(unsigned sv = G.parse_lineno;)
7289 7294
7290 IF_HUSH_LINENO_VAR(G.lineno = 1;) 7295 IF_HUSH_LINENO_VAR(G.parse_lineno = 1;)
7291 setup_file_in_str(&input, fp); 7296 setup_file_in_str(&input, fp);
7292 parse_and_run_stream(&input, ';'); 7297 parse_and_run_stream(&input, ';');
7293 IF_HUSH_LINENO_VAR(G.lineno = sv;) 7298 IF_HUSH_LINENO_VAR(G.parse_lineno = sv;)
7294} 7299}
7295 7300
7296#if ENABLE_HUSH_TICK 7301#if ENABLE_HUSH_TICK
@@ -7598,10 +7603,10 @@ static int save_fd_on_redirect(int fd, int avoid_fd, struct squirrel **sqp)
7598 avoid_fd = 9; 7603 avoid_fd = 9;
7599 7604
7600#if ENABLE_HUSH_INTERACTIVE 7605#if ENABLE_HUSH_INTERACTIVE
7601 if (fd == G.interactive_fd) { 7606 if (fd == G_interactive_fd) {
7602 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */ 7607 /* Testcase: "ls -l /proc/$$/fd 255>&-" should work */
7603 G.interactive_fd = xdup_CLOEXEC_and_close(G.interactive_fd, avoid_fd); 7608 G_interactive_fd = xdup_CLOEXEC_and_close(G_interactive_fd, avoid_fd);
7604 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G.interactive_fd); 7609 debug_printf_redir("redirect_fd %d: matches interactive_fd, moving it to %d\n", fd, G_interactive_fd);
7605 return 1; /* "we closed fd" */ 7610 return 1; /* "we closed fd" */
7606 } 7611 }
7607#endif 7612#endif
@@ -7677,7 +7682,7 @@ static void restore_redirects(struct squirrel *sq)
7677 free(sq); 7682 free(sq);
7678 } 7683 }
7679 7684
7680 /* If moved, G.interactive_fd stays on new fd, not restoring it */ 7685 /* If moved, G_interactive_fd stays on new fd, not restoring it */
7681} 7686}
7682 7687
7683#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU 7688#if ENABLE_FEATURE_SH_STANDALONE && BB_MMU
@@ -7694,7 +7699,7 @@ static int internally_opened_fd(int fd, struct squirrel *sq)
7694 int i; 7699 int i;
7695 7700
7696#if ENABLE_HUSH_INTERACTIVE 7701#if ENABLE_HUSH_INTERACTIVE
7697 if (fd == G.interactive_fd) 7702 if (fd == G_interactive_fd)
7698 return 1; 7703 return 1;
7699#endif 7704#endif
7700 /* If this one of script's fds? */ 7705 /* If this one of script's fds? */
@@ -8989,8 +8994,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
8989 struct variable *old_vars; 8994 struct variable *old_vars;
8990 8995
8991#if ENABLE_HUSH_LINENO_VAR 8996#if ENABLE_HUSH_LINENO_VAR
8992 if (G.lineno_var) 8997 G.execute_lineno = command->lineno;
8993 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
8994#endif 8998#endif
8995 8999
8996 if (argv[command->assignment_cnt] == NULL) { 9000 if (argv[command->assignment_cnt] == NULL) {
@@ -9223,8 +9227,7 @@ static NOINLINE int run_pipe(struct pipe *pi)
9223 xpiped_pair(pipefds); 9227 xpiped_pair(pipefds);
9224 9228
9225#if ENABLE_HUSH_LINENO_VAR 9229#if ENABLE_HUSH_LINENO_VAR
9226 if (G.lineno_var) 9230 G.execute_lineno = command->lineno;
9227 strcpy(G.lineno_var + sizeof("LINENO=")-1, utoa(command->lineno));
9228#endif 9231#endif
9229 9232
9230 command->pid = BB_MMU ? fork() : vfork(); 9233 command->pid = BB_MMU ? fork() : vfork();
@@ -9908,14 +9911,6 @@ int hush_main(int argc, char **argv)
9908 /* Export PWD */ 9911 /* Export PWD */
9909 set_pwd_var(SETFLAG_EXPORT); 9912 set_pwd_var(SETFLAG_EXPORT);
9910 9913
9911#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
9912 /* Set (but not export) PS1/2 unless already set */
9913 if (!get_local_var_value("PS1"))
9914 set_local_var_from_halves("PS1", "\\w \\$ ");
9915 if (!get_local_var_value("PS2"))
9916 set_local_var_from_halves("PS2", "> ");
9917#endif
9918
9919#if BASH_HOSTNAME_VAR 9914#if BASH_HOSTNAME_VAR
9920 /* Set (but not export) HOSTNAME unless already set */ 9915 /* Set (but not export) HOSTNAME unless already set */
9921 if (!get_local_var_value("HOSTNAME")) { 9916 if (!get_local_var_value("HOSTNAME")) {
@@ -9927,6 +9922,11 @@ int hush_main(int argc, char **argv)
9927 /* IFS is not inherited from the parent environment */ 9922 /* IFS is not inherited from the parent environment */
9928 set_local_var_from_halves("IFS", defifs); 9923 set_local_var_from_halves("IFS", defifs);
9929 9924
9925 if (!get_local_var_value("PATH"))
9926 set_local_var_from_halves("PATH", bb_default_root_path);
9927
9928 /* PS1/PS2 are set later, if we determine that we are interactive */
9929
9930 /* bash also exports SHLVL and _, 9930 /* bash also exports SHLVL and _,
9931 * and sets (but doesn't export) the following variables: 9931 * and sets (but doesn't export) the following variables:
9932 * BASH=/bin/bash 9932 * BASH=/bin/bash
@@ -9960,21 +9960,7 @@ int hush_main(int argc, char **argv)
9960 * PS4='+ ' 9960 * PS4='+ '
9961 */ 9961 */
9962 9962
9963#if ENABLE_HUSH_LINENO_VAR
9964 if (ENABLE_HUSH_LINENO_VAR) {
9965 char *p = xasprintf("LINENO=%*s", (int)(sizeof(int)*3), "");
9966 set_local_var(p, /*flags*/ 0);
9967 G.lineno_var = p; /* can't assign before set_local_var("LINENO=...") */
9968 }
9969#endif
9970
9971#if ENABLE_FEATURE_EDITING
9972 G.line_input_state = new_line_input_t(FOR_SHELL);
9973#endif
9974
9975 /* Initialize some more globals to non-zero values */ 9963 /* Initialize some more globals to non-zero values */
9976 cmdedit_update_prompt();
9977
9978 die_func = restore_ttypgrp_and__exit; 9964 die_func = restore_ttypgrp_and__exit;
9979 9965
9980 /* Shell is non-interactive at first. We need to call 9966 /* Shell is non-interactive at first. We need to call
@@ -10192,6 +10178,7 @@ int hush_main(int argc, char **argv)
10192#endif 10178#endif
10193 goto final_return; 10179 goto final_return;
10194 } 10180 }
10181 G.opt_s = 1;
10195 10182
10196 /* Up to here, shell was non-interactive. Now it may become one. 10183 /* Up to here, shell was non-interactive. Now it may become one.
10197 * NB: don't forget to (re)run install_special_sighandlers() as needed. 10184 * NB: don't forget to (re)run install_special_sighandlers() as needed.
@@ -10260,6 +10247,9 @@ int hush_main(int argc, char **argv)
10260 } 10247 }
10261 enable_restore_tty_pgrp_on_exit(); 10248 enable_restore_tty_pgrp_on_exit();
10262 10249
10250# if ENABLE_FEATURE_EDITING
10251 G.line_input_state = new_line_input_t(FOR_SHELL);
10252# endif
10263# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 10253# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
10264 { 10254 {
10265 const char *hp = get_local_var_value("HISTFILE"); 10255 const char *hp = get_local_var_value("HISTFILE");
@@ -10308,14 +10298,23 @@ int hush_main(int argc, char **argv)
10308 * (--norc turns this off, --rcfile <file> overrides) 10298 * (--norc turns this off, --rcfile <file> overrides)
10309 */ 10299 */
10310 10300
10311 if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) { 10301 if (G_interactive_fd) {
10312 /* note: ash and hush share this string */ 10302#if ENABLE_HUSH_INTERACTIVE && ENABLE_FEATURE_EDITING_FANCY_PROMPT
10313 printf("\n\n%s %s\n" 10303 /* Set (but not export) PS1/2 unless already set */
10314 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n") 10304 if (!get_local_var_value("PS1"))
10315 "\n", 10305 set_local_var_from_halves("PS1", "\\w \\$ ");
10316 bb_banner, 10306 if (!get_local_var_value("PS2"))
10317 "hush - the humble shell" 10307 set_local_var_from_halves("PS2", "> ");
10318 ); 10308#endif
10309 if (!ENABLE_FEATURE_SH_EXTRA_QUIET) {
10310 /* note: ash and hush share this string */
10311 printf("\n\n%s %s\n"
10312 IF_HUSH_HELP("Enter 'help' for a list of built-in commands.\n")
10313 "\n",
10314 bb_banner,
10315 "hush - the humble shell"
10316 );
10317 }
10319 } 10318 }
10320 10319
10321 parse_and_run_file(hfopen(NULL)); /* stdin */ 10320 parse_and_run_file(hfopen(NULL)); /* stdin */
@@ -10378,7 +10377,8 @@ static int FAST_FUNC builtin_help(char **argv UNUSED_PARAM)
10378#if MAX_HISTORY && ENABLE_FEATURE_EDITING 10377#if MAX_HISTORY && ENABLE_FEATURE_EDITING
10379static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM) 10378static int FAST_FUNC builtin_history(char **argv UNUSED_PARAM)
10380{ 10379{
10381 show_history(G.line_input_state); 10380 if (G.line_input_state)
10381 show_history(G.line_input_state);
10382 return EXIT_SUCCESS; 10382 return EXIT_SUCCESS;
10383} 10383}
10384#endif 10384#endif
@@ -10687,9 +10687,7 @@ static int helper_export_local(char **argv, unsigned flags)
10687{ 10687{
10688 do { 10688 do {
10689 char *name = *argv; 10689 char *name = *argv;
10690 char *name_end = strchrnul(name, '='); 10690 const char *name_end = endofname(name);
10691
10692 /* So far we do not check that name is valid (TODO?) */
10693 10691
10694 if (*name_end == '\0') { 10692 if (*name_end == '\0') {
10695 struct variable *var, **vpp; 10693 struct variable *var, **vpp;
@@ -10747,8 +10745,15 @@ static int helper_export_local(char **argv, unsigned flags)
10747 */ 10745 */
10748 name = xasprintf("%s=", name); 10746 name = xasprintf("%s=", name);
10749 } else { 10747 } else {
10748 if (*name_end != '=') {
10749 bb_error_msg("'%s': bad variable name", name);
10750 /* do not parse following argv[]s: */
10751 return 1;
10752 }
10750 /* (Un)exporting/making local NAME=VALUE */ 10753 /* (Un)exporting/making local NAME=VALUE */
10751 name = xstrdup(name); 10754 name = xstrdup(name);
10755 /* Testcase: export PS1='\w \$ ' */
10756 unbackslash(name);
10752 } 10757 }
10753 debug_printf_env("%s: set_local_var('%s')\n", __func__, name); 10758 debug_printf_env("%s: set_local_var('%s')\n", __func__, name);
10754 if (set_local_var(name, flags)) 10759 if (set_local_var(name, flags))
diff --git a/shell/hush_test/hush-misc/export1.right b/shell/hush_test/hush-misc/export1.right
new file mode 100644
index 000000000..56647af8e
--- /dev/null
+++ b/shell/hush_test/hush-misc/export1.right
@@ -0,0 +1 @@
|\w \\ \ \|
diff --git a/shell/hush_test/hush-misc/export1.tests b/shell/hush_test/hush-misc/export1.tests
new file mode 100755
index 000000000..4ffb40bdc
--- /dev/null
+++ b/shell/hush_test/hush-misc/export1.tests
@@ -0,0 +1,2 @@
1export Z='\w \\ \ \'
2echo "|$Z|"
diff --git a/shell/hush_test/hush-vars/param_expand_default.right b/shell/hush_test/hush-vars/param_expand_default.right
index acc717205..8bd0814b0 100644
--- a/shell/hush_test/hush-vars/param_expand_default.right
+++ b/shell/hush_test/hush-vars/param_expand_default.right
@@ -1,8 +1,9 @@
1hush: syntax error: unterminated ${name} 1hush: syntax error: unterminated ${name}
2hush: syntax error: unterminated ${name}
3_0 _0 2_0 _0
4_ _ _ _word _word 3_ _ _ _word _word
5_aaaa _aaaa _aaaa _aaaa _aaaa 4_aaaa _aaaa _aaaa _aaaa _aaaa
6_ _ _ _word _word 5_ _ _ _word _word
7_ _ _ _ _word 6_ _ _ _ _word
8_fff _fff _fff _fff _fff 7_fff _fff _fff _fff _fff
81:1
90:0
diff --git a/shell/hush_test/hush-vars/param_expand_default.tests b/shell/hush_test/hush-vars/param_expand_default.tests
index 16e5f8efe..dbd3e2218 100755
--- a/shell/hush_test/hush-vars/param_expand_default.tests
+++ b/shell/hush_test/hush-vars/param_expand_default.tests
@@ -1,7 +1,5 @@
1# first try some invalid patterns (do in subshell due to parsing error) 1# first try some invalid patterns (do in subshell due to parsing error)
2# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages) 2# (set argv0 to "SHELL" to avoid "/path/to/shell: blah" in error messages)
3# valid in bash and ash (same as $-), not supported in hush (yet?):
4"$THIS_SH" -c 'echo ${-}' SHELL
5"$THIS_SH" -c 'echo ${:-}' SHELL 3"$THIS_SH" -c 'echo ${:-}' SHELL
6 4
7# now some funky ones 5# now some funky ones
@@ -22,3 +20,8 @@ echo _$f _${f-} _${f:-} _${f-word} _${f:-word}
22 20
23f=fff 21f=fff
24echo _$f _${f-} _${f:-} _${f-word} _${f:-word} 22echo _$f _${f-} _${f:-} _${f-word} _${f:-word}
23
24set --
25set -- "${1-}"; echo 1:$#
26set --
27set -- ${1-}; echo 0:$#
diff --git a/shell/math.c b/shell/math.c
index 611b3beab..eaf4f2453 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -513,6 +513,46 @@ static const char op_tokens[] ALIGN1 = {
513}; 513};
514#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7]) 514#define ptr_to_rparen (&op_tokens[sizeof(op_tokens)-7])
515 515
516#if ENABLE_FEATURE_SH_MATH_BASE
517static arith_t strto_arith_t(const char *nptr, char **endptr)
518{
519 unsigned base;
520 arith_t n;
521
522# if ENABLE_FEATURE_SH_MATH_64
523 n = strtoull(nptr, endptr, 0);
524# else
525 n = strtoul(nptr, endptr, 0);
526# endif
527 if (**endptr != '#'
528 || (*nptr < '1' || *nptr > '9')
529 || (n < 2 || n > 64)
530 ) {
531 return n;
532 }
533
534 /* It's "N#nnnn" or "NN#nnnn" syntax, NN can't start with 0,
535 * NN is in 2..64 range.
536 */
537 base = (unsigned)n;
538 n = 0;
539 nptr = *endptr + 1;
540 /* bash allows "N#" (empty "nnnn" part) */
541 while (isdigit(*nptr)) {
542 /* bash does not check for overflows */
543 n = n * base + (*nptr++ - '0');
544 }
545 *endptr = (char*)nptr;
546 return n;
547}
548#else /* !ENABLE_FEATURE_SH_MATH_BASE */
549# if ENABLE_FEATURE_SH_MATH_64
550# define strto_arith_t(nptr, endptr) strtoull(nptr, endptr, 0)
551# else
552# define strto_arith_t(nptr, endptr) strtoul(nptr, endptr, 0)
553# endif
554#endif
555
516static arith_t FAST_FUNC 556static arith_t FAST_FUNC
517evaluate_string(arith_state_t *math_state, const char *expr) 557evaluate_string(arith_state_t *math_state, const char *expr)
518{ 558{
@@ -591,7 +631,7 @@ evaluate_string(arith_state_t *math_state, const char *expr)
591 /* Number */ 631 /* Number */
592 numstackptr->var = NULL; 632 numstackptr->var = NULL;
593 errno = 0; 633 errno = 0;
594 numstackptr->val = strto_arith_t(expr, (char**) &expr, 0); 634 numstackptr->val = strto_arith_t(expr, (char**) &expr);
595 if (errno) 635 if (errno)
596 numstackptr->val = 0; /* bash compat */ 636 numstackptr->val = 0; /* bash compat */
597 goto num; 637 goto num;
diff --git a/shell/math.h b/shell/math.h
index 90eb49144..a3fe51b6b 100644
--- a/shell/math.h
+++ b/shell/math.h
@@ -66,11 +66,9 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
66#if ENABLE_FEATURE_SH_MATH_64 66#if ENABLE_FEATURE_SH_MATH_64
67typedef long long arith_t; 67typedef long long arith_t;
68#define ARITH_FMT "%"LL_FMT"d" 68#define ARITH_FMT "%"LL_FMT"d"
69#define strto_arith_t strtoull
70#else 69#else
71typedef long arith_t; 70typedef long arith_t;
72#define ARITH_FMT "%ld" 71# define ARITH_FMT "%ld"
73#define strto_arith_t strtoul
74#endif 72#endif
75 73
76typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name); 74typedef const char* FAST_FUNC (*arith_var_lookup_t)(const char *name);
diff --git a/shell/shell_common.c b/shell/shell_common.c
index 70ecf2095..d1df5888c 100644
--- a/shell/shell_common.c
+++ b/shell/shell_common.c
@@ -26,19 +26,6 @@ const char defifsvar[] ALIGN1 = "IFS= \t\n\r";
26#endif 26#endif
27const char defoptindvar[] ALIGN1 = "OPTIND=1"; 27const char defoptindvar[] ALIGN1 = "OPTIND=1";
28 28
29
30int FAST_FUNC is_well_formed_var_name(const char *s, char terminator)
31{
32 if (!s || !(isalpha(*s) || *s == '_'))
33 return 0;
34
35 do
36 s++;
37 while (isalnum(*s) || *s == '_');
38
39 return *s == terminator;
40}
41
42/* read builtin */ 29/* read builtin */
43 30
44/* Needs to be interruptible: shell must handle traps and shell-special signals 31/* Needs to be interruptible: shell must handle traps and shell-special signals
@@ -76,7 +63,7 @@ shell_builtin_read(struct builtin_read_params *params)
76 argv = params->argv; 63 argv = params->argv;
77 pp = argv; 64 pp = argv;
78 while (*pp) { 65 while (*pp) {
79 if (!is_well_formed_var_name(*pp, '\0')) { 66 if (endofname(*pp)[0] != '\0') {
80 /* Mimic bash message */ 67 /* Mimic bash message */
81 bb_error_msg("read: '%s': not a valid identifier", *pp); 68 bb_error_msg("read: '%s': not a valid identifier", *pp);
82 return (const char *)(uintptr_t)1; 69 return (const char *)(uintptr_t)1;
@@ -384,99 +371,138 @@ shell_builtin_read(struct builtin_read_params *params)
384struct limits { 371struct limits {
385 uint8_t cmd; /* RLIMIT_xxx fit into it */ 372 uint8_t cmd; /* RLIMIT_xxx fit into it */
386 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */ 373 uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */
387 char option;
388 const char *name; 374 const char *name;
389}; 375};
390 376
391static const struct limits limits_tbl[] = { 377static const struct limits limits_tbl[] = {
392#ifdef RLIMIT_FSIZE 378 { RLIMIT_CORE, 9, "core file size (blocks)" }, // -c
393 { RLIMIT_FSIZE, 9, 'f', "file size (blocks)" }, 379 { RLIMIT_DATA, 10, "data seg size (kb)" }, // -d
380 { RLIMIT_NICE, 0, "scheduling priority" }, // -e
381 { RLIMIT_FSIZE, 9, "file size (blocks)" }, // -f
382#define LIMIT_F_IDX 3
383#ifdef RLIMIT_SIGPENDING
384 { RLIMIT_SIGPENDING, 0, "pending signals" }, // -i
394#endif 385#endif
395#ifdef RLIMIT_CPU 386#ifdef RLIMIT_MEMLOCK
396 { RLIMIT_CPU, 0, 't', "cpu time (seconds)" }, 387 { RLIMIT_MEMLOCK, 10, "max locked memory (kb)" }, // -l
397#endif 388#endif
398#ifdef RLIMIT_DATA 389#ifdef RLIMIT_RSS
399 { RLIMIT_DATA, 10, 'd', "data seg size (kb)" }, 390 { RLIMIT_RSS, 10, "max memory size (kb)" }, // -m
400#endif 391#endif
401#ifdef RLIMIT_STACK 392#ifdef RLIMIT_NOFILE
402 { RLIMIT_STACK, 10, 's', "stack size (kb)" }, 393 { RLIMIT_NOFILE, 0, "open files" }, // -n
403#endif 394#endif
404#ifdef RLIMIT_CORE 395#ifdef RLIMIT_MSGQUEUE
405 { RLIMIT_CORE, 9, 'c', "core file size (blocks)" }, 396 { RLIMIT_MSGQUEUE, 0, "POSIX message queues (bytes)" }, // -q
406#endif 397#endif
407#ifdef RLIMIT_RSS 398#ifdef RLIMIT_RTPRIO
408 { RLIMIT_RSS, 10, 'm', "resident set size (kb)" }, 399 { RLIMIT_RTPRIO, 0, "real-time priority" }, // -r
409#endif 400#endif
410#ifdef RLIMIT_MEMLOCK 401#ifdef RLIMIT_STACK
411 { RLIMIT_MEMLOCK, 10, 'l', "locked memory (kb)" }, 402 { RLIMIT_STACK, 10, "stack size (kb)" }, // -s
412#endif 403#endif
413#ifdef RLIMIT_NPROC 404#ifdef RLIMIT_CPU
414 { RLIMIT_NPROC, 0, 'p', "processes" }, 405 { RLIMIT_CPU, 0, "cpu time (seconds)" }, // -t
415#endif 406#endif
416#ifdef RLIMIT_NOFILE 407#ifdef RLIMIT_NPROC
417 { RLIMIT_NOFILE, 0, 'n', "file descriptors" }, 408 { RLIMIT_NPROC, 0, "max user processes" }, // -u
418#endif 409#endif
419#ifdef RLIMIT_AS 410#ifdef RLIMIT_AS
420 { RLIMIT_AS, 10, 'v', "address space (kb)" }, 411 { RLIMIT_AS, 10, "virtual memory (kb)" }, // -v
421#endif 412#endif
422#ifdef RLIMIT_LOCKS 413#ifdef RLIMIT_LOCKS
423 { RLIMIT_LOCKS, 0, 'w', "locks" }, 414 { RLIMIT_LOCKS, 0, "file locks" }, // -x
415#endif
416};
417// bash also shows:
418//pipe size (512 bytes, -p) 8
419
420static const char limit_chars[] ALIGN1 =
421 "c"
422 "d"
423 "e"
424 "f"
425#ifdef RLIMIT_SIGPENDING
426 "i"
427#endif
428#ifdef RLIMIT_MEMLOCK
429 "l"
430#endif
431#ifdef RLIMIT_RSS
432 "m"
433#endif
434#ifdef RLIMIT_NOFILE
435 "n"
424#endif 436#endif
425#ifdef RLIMIT_NICE 437#ifdef RLIMIT_MSGQUEUE
426 { RLIMIT_NICE, 0, 'e', "scheduling priority" }, 438 "q"
427#endif 439#endif
428#ifdef RLIMIT_RTPRIO 440#ifdef RLIMIT_RTPRIO
429 { RLIMIT_RTPRIO, 0, 'r', "real-time priority" }, 441 "r"
430#endif 442#endif
431}; 443#ifdef RLIMIT_STACK
432 444 "s"
433enum {
434 OPT_hard = (1 << 0),
435 OPT_soft = (1 << 1),
436};
437
438/* "-": treat args as parameters of option with ASCII code 1 */
439static const char ulimit_opt_string[] ALIGN1 = "-HSa"
440#ifdef RLIMIT_FSIZE
441 "f::"
442#endif 445#endif
443#ifdef RLIMIT_CPU 446#ifdef RLIMIT_CPU
444 "t::" 447 "t"
445#endif 448#endif
446#ifdef RLIMIT_DATA 449#ifdef RLIMIT_NPROC
447 "d::" 450 "u"
448#endif 451#endif
449#ifdef RLIMIT_STACK 452#ifdef RLIMIT_AS
450 "s::" 453 "v"
451#endif 454#endif
452#ifdef RLIMIT_CORE 455#ifdef RLIMIT_LOCKS
453 "c::" 456 "x"
454#endif 457#endif
455#ifdef RLIMIT_RSS 458;
456 "m::" 459
460/* "-": treat args as parameters of option with ASCII code 1 */
461static const char ulimit_opt_string[] ALIGN1 = "-HSa"
462 "c::"
463 "d::"
464 "e::"
465 "f::"
466#ifdef RLIMIT_SIGPENDING
467 "i::"
457#endif 468#endif
458#ifdef RLIMIT_MEMLOCK 469#ifdef RLIMIT_MEMLOCK
459 "l::" 470 "l::"
460#endif 471#endif
461#ifdef RLIMIT_NPROC 472#ifdef RLIMIT_RSS
462 "p::" 473 "m::"
463#endif 474#endif
464#ifdef RLIMIT_NOFILE 475#ifdef RLIMIT_NOFILE
465 "n::" 476 "n::"
466#endif 477#endif
478#ifdef RLIMIT_MSGQUEUE
479 "q::"
480#endif
481#ifdef RLIMIT_RTPRIO
482 "r::"
483#endif
484#ifdef RLIMIT_STACK
485 "s::"
486#endif
487#ifdef RLIMIT_CPU
488 "t::"
489#endif
490#ifdef RLIMIT_NPROC
491 "u::"
492#endif
467#ifdef RLIMIT_AS 493#ifdef RLIMIT_AS
468 "v::" 494 "v::"
469#endif 495#endif
470#ifdef RLIMIT_LOCKS 496#ifdef RLIMIT_LOCKS
471 "w::" 497 "x::"
472#endif
473#ifdef RLIMIT_NICE
474 "e::"
475#endif
476#ifdef RLIMIT_RTPRIO
477 "r::"
478#endif 498#endif
479 ; 499;
500
501enum {
502 OPT_hard = (1 << 0),
503 OPT_soft = (1 << 1),
504 OPT_all = (1 << 2),
505};
480 506
481static void printlim(unsigned opts, const struct rlimit *limit, 507static void printlim(unsigned opts, const struct rlimit *limit,
482 const struct limits *l) 508 const struct limits *l)
@@ -484,7 +510,7 @@ static void printlim(unsigned opts, const struct rlimit *limit,
484 rlim_t val; 510 rlim_t val;
485 511
486 val = limit->rlim_max; 512 val = limit->rlim_max;
487 if (!(opts & OPT_hard)) 513 if (opts & OPT_soft)
488 val = limit->rlim_cur; 514 val = limit->rlim_cur;
489 515
490 if (val == RLIM_INFINITY) 516 if (val == RLIM_INFINITY)
@@ -498,8 +524,11 @@ static void printlim(unsigned opts, const struct rlimit *limit,
498int FAST_FUNC 524int FAST_FUNC
499shell_builtin_ulimit(char **argv) 525shell_builtin_ulimit(char **argv)
500{ 526{
527 struct rlimit limit;
528 unsigned opt_cnt;
501 unsigned opts; 529 unsigned opts;
502 unsigned argc; 530 unsigned argc;
531 unsigned i;
503 532
504 /* We can't use getopt32: need to handle commands like 533 /* We can't use getopt32: need to handle commands like
505 * ulimit 123 -c2 -l 456 534 * ulimit 123 -c2 -l 456
@@ -510,12 +539,48 @@ shell_builtin_ulimit(char **argv)
510 */ 539 */
511 GETOPT_RESET(); 540 GETOPT_RESET();
512 541
542// bash 4.4.23:
543//
544// -H and/or -S change meaning even of options *before* them: ulimit -f 2000 -H
545// sets hard limit, ulimit -a -H prints hard limits.
546//
547// -a is equivalent for requesting all limits to be shown.
548//
549// If -a is specified, attempts to set limits are ignored:
550// ulimit -m 1000; ulimit -m 2000 -a
551// shows 1000, not 2000. HOWEVER, *implicit* -f form "ulimit 2000 -a"
552// DOES set -f limit [we don't implement this quirk], "ulimit -a 2000" does not.
553// Options are still parsed: ulimit -az complains about unknown -z opt.
554//
555// -a is not cumulative: "ulimit -a -a" = "ulimit -a -f -m" = "ulimit -a"
556//
557// -HSa can be combined in one argument and with one other option (example: -Sm),
558// but other options can't: limit value is an optional argument,
559// thus "-mf" means "-m f", f is the parameter of -m.
560//
561// Limit can be set and then printed: ulimit -m 2000 -m
562// If set more than once, they are set and printed in order:
563// try ulimit -m -m 1000 -m -m 2000 -m -m 3000 -m
564//
565// Limits are shown in the order of options given:
566// ulimit -m -f is not the same as ulimit -f -m.
567//
568// If both -S and -H are given, show soft limit.
569//
570// Short printout (limit value only) is printed only if just one option
571// is given: ulimit -m. ulimit -f -m prints verbose lines.
572// ulimit -f -f prints same verbose line twice.
573// ulimit -m 10000 -f prints verbose line for -f.
574
513 argc = string_array_len(argv); 575 argc = string_array_len(argv);
514 576
577 /* First pass over options: detect -H/-S/-a status,
578 * and "bare ulimit" and "only one option" cases
579 * by counting other opts.
580 */
581 opt_cnt = 0;
515 opts = 0; 582 opts = 0;
516 while (1) { 583 while (1) {
517 struct rlimit limit;
518 const struct limits *l;
519 int opt_char = getopt(argc, argv, ulimit_opt_string); 584 int opt_char = getopt(argc, argv, ulimit_opt_string);
520 585
521 if (opt_char == -1) 586 if (opt_char == -1)
@@ -528,74 +593,94 @@ shell_builtin_ulimit(char **argv)
528 opts |= OPT_soft; 593 opts |= OPT_soft;
529 continue; 594 continue;
530 } 595 }
531
532 if (opt_char == 'a') { 596 if (opt_char == 'a') {
533 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 597 opts |= OPT_all;
534 getrlimit(l->cmd, &limit);
535 printf("-%c: %-30s ", l->option, l->name);
536 printlim(opts, &limit, l);
537 }
538 continue; 598 continue;
539 } 599 }
600 if (opt_char == '?') {
601 /* bad option. getopt already complained. */
602 return EXIT_FAILURE;
603 }
604 opt_cnt++;
605 } /* while (there are options) */
606
607 if (!(opts & (OPT_hard | OPT_soft)))
608 opts |= (OPT_hard | OPT_soft);
609 if (opts & OPT_all) {
610 for (i = 0; i < ARRAY_SIZE(limits_tbl); i++) {
611 getrlimit(limits_tbl[i].cmd, &limit);
612 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
613 printlim(opts, &limit, &limits_tbl[i]);
614 }
615 return EXIT_SUCCESS;
616 }
540 617
541 if (opt_char == 1) 618 /* Second pass: set or print limits, in order */
619 GETOPT_RESET();
620 while (1) {
621 char *val_str;
622 int opt_char = getopt(argc, argv, ulimit_opt_string);
623
624 if (opt_char == -1)
625 break;
626 if (opt_char == 'H')
627 continue;
628 if (opt_char == 'S')
629 continue;
630 //if (opt_char == 'a') - impossible
631
632 if (opt_char == 1) /* if "ulimit NNN", -f is assumed */
542 opt_char = 'f'; 633 opt_char = 'f';
543 for (l = limits_tbl; l != &limits_tbl[ARRAY_SIZE(limits_tbl)]; l++) { 634 i = strchrnul(limit_chars, opt_char) - limit_chars;
544 if (opt_char == l->option) { 635 //if (i >= ARRAY_SIZE(limits_tbl)) - bad option, impossible
545 char *val_str; 636
546 637 val_str = optarg;
547 getrlimit(l->cmd, &limit); 638 if (!val_str && argv[optind] && argv[optind][0] != '-')
548 639 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */
549 val_str = optarg; 640
550 if (!val_str && argv[optind] && argv[optind][0] != '-') 641 getrlimit(limits_tbl[i].cmd, &limit);
551 val_str = argv[optind++]; /* ++ skips NN in "-c NN" case */ 642 if (!val_str) {
552 if (val_str) { 643 if (opt_cnt > 1)
553 rlim_t val; 644 printf("%-32s(-%c) ", limits_tbl[i].name, limit_chars[i]);
554 645 printlim(opts, &limit, &limits_tbl[i]);
555 if (strcmp(val_str, "unlimited") == 0) 646 } else {
556 val = RLIM_INFINITY; 647 rlim_t val = RLIM_INFINITY;
557 else { 648 if (strcmp(val_str, "unlimited") != 0) {
558 if (sizeof(val) == sizeof(int)) 649 if (sizeof(val) == sizeof(int))
559 val = bb_strtou(val_str, NULL, 10); 650 val = bb_strtou(val_str, NULL, 10);
560 else if (sizeof(val) == sizeof(long)) 651 else if (sizeof(val) == sizeof(long))
561 val = bb_strtoul(val_str, NULL, 10); 652 val = bb_strtoul(val_str, NULL, 10);
562 else 653 else
563 val = bb_strtoull(val_str, NULL, 10); 654 val = bb_strtoull(val_str, NULL, 10);
564 if (errno) { 655 if (errno) {
565 bb_error_msg("invalid number '%s'", val_str); 656 bb_error_msg("invalid number '%s'", val_str);
566 return EXIT_FAILURE; 657 return EXIT_FAILURE;
567 }
568 val <<= l->factor_shift;
569 }
570//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
571 /* from man bash: "If neither -H nor -S
572 * is specified, both the soft and hard
573 * limits are set. */
574 if (!opts)
575 opts = OPT_hard + OPT_soft;
576 if (opts & OPT_hard)
577 limit.rlim_max = val;
578 if (opts & OPT_soft)
579 limit.rlim_cur = val;
580//bb_error_msg("setrlimit(%d, %lld, %lld)", l->cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
581 if (setrlimit(l->cmd, &limit) < 0) {
582 bb_perror_msg("error setting limit");
583 return EXIT_FAILURE;
584 }
585 } else {
586 printlim(opts, &limit, l);
587 } 658 }
588 break; 659 val <<= limits_tbl[i].factor_shift;
660 }
661//bb_error_msg("opt %c val_str:'%s' val:%lld", opt_char, val_str, (long long)val);
662 /* from man bash: "If neither -H nor -S
663 * is specified, both the soft and hard
664 * limits are set. */
665 if (opts & OPT_hard)
666 limit.rlim_max = val;
667 if (opts & OPT_soft)
668 limit.rlim_cur = val;
669//bb_error_msg("setrlimit(%d, %lld, %lld)", limits_tbl[i].cmd, (long long)limit.rlim_cur, (long long)limit.rlim_max);
670 if (setrlimit(limits_tbl[i].cmd, &limit) < 0) {
671 bb_perror_msg("error setting limit");
672 return EXIT_FAILURE;
589 } 673 }
590 } /* for (every possible opt) */
591
592 if (l == &limits_tbl[ARRAY_SIZE(limits_tbl)]) {
593 /* bad option. getopt already complained. */
594 break;
595 } 674 }
596 } /* while (there are options) */ 675 } /* while (there are options) */
597 676
598 return 0; 677 if (opt_cnt == 0) {
678 /* "bare ulimit": treat it as if it was -f */
679 getrlimit(limits_tbl[LIMIT_F_IDX].cmd, &limit);
680 printlim(opts, &limit, &limits_tbl[LIMIT_F_IDX]);
681 }
682
683 return EXIT_SUCCESS;
599} 684}
600#else 685#else
601int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM) 686int FAST_FUNC shell_builtin_ulimit(char **argv UNUSED_PARAM)
diff --git a/shell/shell_common.h b/shell/shell_common.h
index a1323021d..7b478f1df 100644
--- a/shell/shell_common.h
+++ b/shell/shell_common.h
@@ -26,8 +26,6 @@ extern const char defifsvar[] ALIGN1; /* "IFS= \t\n" */
26 26
27extern const char defoptindvar[] ALIGN1; /* "OPTIND=1" */ 27extern const char defoptindvar[] ALIGN1; /* "OPTIND=1" */
28 28
29int FAST_FUNC is_well_formed_var_name(const char *s, char terminator);
30
31/* Builtins */ 29/* Builtins */
32 30
33struct builtin_read_params { 31struct builtin_read_params {
diff --git a/testsuite/bunzip2.tests b/testsuite/bunzip2.tests
index edb332748..69e34dfd0 100755
--- a/testsuite/bunzip2.tests
+++ b/testsuite/bunzip2.tests
@@ -562,7 +562,7 @@ if test "${0##*/}" = "bunzip2.tests"; then
562 fi 562 fi
563 563
564 errout="`${bb}bunzip2 <bz2_issue_12.bz2 2>&1 >/dev/null`" 564 errout="`${bb}bunzip2 <bz2_issue_12.bz2 2>&1 >/dev/null`"
565 if test x"$errout:$?" = x"bunzip2: bunzip error -3:1"; then 565 if test x"$errout:$?" = x"bunzip2: bunzip error -5:1"; then
566 echo "PASS: $unpack: bz2_issue_12.bz2 corrupted example" 566 echo "PASS: $unpack: bz2_issue_12.bz2 corrupted example"
567 else 567 else
568 echo "FAIL: $unpack: bz2_issue_12.bz2 corrupted example" 568 echo "FAIL: $unpack: bz2_issue_12.bz2 corrupted example"
diff --git a/testsuite/sed.tests b/testsuite/sed.tests
index 675cb4f10..67ff87e93 100755
--- a/testsuite/sed.tests
+++ b/testsuite/sed.tests
@@ -361,6 +361,12 @@ testing "sed /regex/,+N{...} addresses work" \
361 "" \ 361 "" \
362 "1\n2\n3\n4\n5\n" 362 "1\n2\n3\n4\n5\n"
363 363
364testing "sed /regex/,+N{...} addresses work 2" \
365 "sed -n '/a/,+1 p'" \
366 "a\n1\na\n2\na\n3\n" \
367 "" \
368 "a\n1\nc\nc\na\n2\na\n3\n"
369
364testing "sed /regex/,+N{...} -i works" \ 370testing "sed /regex/,+N{...} -i works" \
365 "cat - >input2; sed /^4/,+2{d} -i input input2; echo \$?; cat input input2; rm input2" \ 371 "cat - >input2; sed /^4/,+2{d} -i input input2; echo \$?; cat input input2; rm input2" \
366 "0\n""1\n2\n3\n7\n8\n""1\n2\n7\n8\n" \ 372 "0\n""1\n2\n3\n7\n8\n""1\n2\n7\n8\n" \
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index bf480e9bf..2248f2cba 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -20,10 +20,11 @@
20//kbuild:lib-$(CONFIG_LOSETUP) += losetup.o 20//kbuild:lib-$(CONFIG_LOSETUP) += losetup.o
21 21
22//usage:#define losetup_trivial_usage 22//usage:#define losetup_trivial_usage
23//usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE - associate loop devices\n" 23//usage: "[-r] [-o OFS] {-f|LOOPDEV} FILE: associate loop devices\n"
24//usage: " losetup -d LOOPDEV - disassociate\n" 24//usage: " losetup -c LOOPDEV: reread file size\n"
25//usage: " losetup -a - show status\n" 25//usage: " losetup -d LOOPDEV: disassociate\n"
26//usage: " losetup -f - show next free loop device" 26//usage: " losetup -a: show status\n"
27//usage: " losetup -f: show next free loop device"
27//usage:#define losetup_full_usage "\n\n" 28//usage:#define losetup_full_usage "\n\n"
28//usage: " -o OFS Start OFS bytes into FILE" 29//usage: " -o OFS Start OFS bytes into FILE"
29//usage: "\n -r Read-only" 30//usage: "\n -r Read-only"
@@ -50,14 +51,15 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
50 char *opt_o; 51 char *opt_o;
51 char dev[LOOP_NAMESIZE]; 52 char dev[LOOP_NAMESIZE];
52 enum { 53 enum {
53 OPT_d = (1 << 0), 54 OPT_c = (1 << 0),
54 OPT_o = (1 << 1), 55 OPT_d = (1 << 1),
55 OPT_f = (1 << 2), 56 OPT_o = (1 << 2),
56 OPT_a = (1 << 3), 57 OPT_f = (1 << 3),
57 OPT_r = (1 << 4), /* must be last */ 58 OPT_a = (1 << 4),
59 OPT_r = (1 << 5),
58 }; 60 };
59 61
60 opt = getopt32(argv, "^" "do:far" "\0" "?2:d--ofar:a--ofr", &opt_o); 62 opt = getopt32(argv, "^" "cdo:far" "\0" "?2:d--ofar:a--ofr", &opt_o);
61 argv += optind; 63 argv += optind;
62 64
63 /* LOOPDEV */ 65 /* LOOPDEV */
@@ -73,6 +75,16 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
73 return EXIT_SUCCESS; 75 return EXIT_SUCCESS;
74 } 76 }
75 77
78 /* -c LOOPDEV */
79 if (opt == OPT_c && argv[0]) {
80 int fd = xopen(argv[0], O_RDONLY);
81#ifndef LOOP_SET_CAPACITY
82# define LOOP_SET_CAPACITY 0x4C07
83#endif
84 xioctl(fd, LOOP_SET_CAPACITY, /*ignored:*/0);
85 return EXIT_SUCCESS;
86 }
87
76 /* -d LOOPDEV */ 88 /* -d LOOPDEV */
77 if (opt == OPT_d && argv[0]) { 89 if (opt == OPT_d && argv[0]) {
78 if (del_loop(argv[0])) 90 if (del_loop(argv[0]))
diff --git a/util-linux/mount.c b/util-linux/mount.c
index 526b4130c..e6bad7c2c 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -1194,7 +1194,10 @@ static int daemonize(void)
1194 return 1; 1194 return 1;
1195} 1195}
1196#else 1196#else
1197static inline int daemonize(void) { return -ENOSYS; } 1197static inline int daemonize(void)
1198{
1199 return -ENOSYS;
1200}
1198#endif 1201#endif
1199 1202
1200/* TODO */ 1203/* TODO */