diff options
author | Ron Yorston <rmy@pobox.com> | 2021-06-07 11:34:06 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2021-06-07 11:34:06 +0100 |
commit | abe872e2a0342357a5608342cb2892e94027b3e7 (patch) | |
tree | 297cdccf332fbb5e4eb31b1eac643180059f9b5f | |
parent | 1f33f42d7bcb019b268d938df643a7a785dc19ab (diff) | |
parent | 4d983dcddeee94892d3072e84c7c9a01d4696055 (diff) | |
download | busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.tar.gz busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.tar.bz2 busybox-w32-abe872e2a0342357a5608342cb2892e94027b3e7.zip |
Merge branch 'busybox' into merge
36 files changed, 977 insertions, 441 deletions
diff --git a/archival/cpio.c b/archival/cpio.c index 94303389e..d84f6937d 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -418,7 +418,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
418 | if (argv[0] == NULL) | 418 | if (argv[0] == NULL) |
419 | bb_show_usage(); | 419 | bb_show_usage(); |
420 | if (opt & OPT_CREATE_LEADING_DIR) | 420 | if (opt & OPT_CREATE_LEADING_DIR) |
421 | mkdir(argv[0], 0777); | 421 | /* GNU cpio 2.13: "cpio -d -p a/b/c" works */ |
422 | bb_make_directory(argv[0], -1, FILEUTILS_RECUR); | ||
422 | /* Crude existence check: | 423 | /* Crude existence check: |
423 | * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); | 424 | * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); |
424 | * We can also xopen, fstat, IS_DIR, later fchdir. | 425 | * We can also xopen, fstat, IS_DIR, later fchdir. |
@@ -428,6 +429,11 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) | |||
428 | * a diffrerent problem earlier. | 429 | * a diffrerent problem earlier. |
429 | * This is good enough for now. | 430 | * This is good enough for now. |
430 | */ | 431 | */ |
432 | //FIXME: GNU cpio -d -p DIR does not immediately create DIR - | ||
433 | //it just prepends "DIR/" to the names of files to be created. | ||
434 | //The first file (fails to) be copied, and then the -d logic | ||
435 | //triggers and creates all necessary directories. | ||
436 | //IOW: bare "cpio -d -p DIR" + ^C shouldn't create anything. | ||
431 | #if !BB_MMU | 437 | #if !BB_MMU |
432 | pp.rd = 3; | 438 | pp.rd = 3; |
433 | pp.wr = 4; | 439 | pp.wr = 4; |
diff --git a/console-tools/showkey.c b/console-tools/showkey.c index 4d7a9b9e5..84eb38a0a 100644 --- a/console-tools/showkey.c +++ b/console-tools/showkey.c | |||
@@ -106,7 +106,7 @@ int showkey_main(int argc UNUSED_PARAM, char **argv) | |||
106 | xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); | 106 | xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); |
107 | 107 | ||
108 | // we should exit on any signal; signals should interrupt read | 108 | // we should exit on any signal; signals should interrupt read |
109 | bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); | 109 | bb_signals_norestart(BB_FATAL_SIGS, record_signo); |
110 | 110 | ||
111 | // inform user that program ends after time of inactivity | 111 | // inform user that program ends after time of inactivity |
112 | printf(press_keys, "10s after last keypress"); | 112 | printf(press_keys, "10s after last keypress"); |
diff --git a/coreutils/head.c b/coreutils/head.c index efb023c6f..9586f869f 100644 --- a/coreutils/head.c +++ b/coreutils/head.c | |||
@@ -29,17 +29,18 @@ | |||
29 | //usage:#define head_trivial_usage | 29 | //usage:#define head_trivial_usage |
30 | //usage: "[OPTIONS] [FILE]..." | 30 | //usage: "[OPTIONS] [FILE]..." |
31 | //usage:#define head_full_usage "\n\n" | 31 | //usage:#define head_full_usage "\n\n" |
32 | //usage: "Print first 10 lines of FILEs (or stdin) to stdout.\n" | 32 | //usage: "Print first 10 lines of FILEs (or stdin).\n" |
33 | //usage: "With more than one FILE, precede each with a filename header.\n" | 33 | //usage: "With more than one FILE, precede each with a filename header.\n" |
34 | //usage: "\n -n N[kbm] Print first N lines" | 34 | //usage: "\n -n N[bkm] Print first N lines" |
35 | //usage: IF_FEATURE_FANCY_HEAD( | ||
36 | //usage: "\n -n -N[bkm] Print all except N last lines" | ||
37 | //usage: "\n -c [-]N[bkm] Print first N bytes" | ||
38 | //usage: ) | ||
39 | //usage: "\n (b:*512 k:*1024 m:*1024^2)" | ||
35 | //usage: IF_FEATURE_FANCY_HEAD( | 40 | //usage: IF_FEATURE_FANCY_HEAD( |
36 | //usage: "\n -n -N[kbm] Print all except N last lines" | ||
37 | //usage: "\n -c [-]N[kbm] Print first N bytes" | ||
38 | //usage: "\n -q Never print headers" | 41 | //usage: "\n -q Never print headers" |
39 | //usage: "\n -v Always print headers" | 42 | //usage: "\n -v Always print headers" |
40 | //usage: ) | 43 | //usage: ) |
41 | //usage: "\n" | ||
42 | //usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." | ||
43 | //usage: | 44 | //usage: |
44 | //usage:#define head_example_usage | 45 | //usage:#define head_example_usage |
45 | //usage: "$ head -n 2 /etc/passwd\n" | 46 | //usage: "$ head -n 2 /etc/passwd\n" |
diff --git a/coreutils/ls.c b/coreutils/ls.c index 67f6c8c56..0330f62df 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c | |||
@@ -109,11 +109,11 @@ | |||
109 | //usage:#define ls_full_usage "\n\n" | 109 | //usage:#define ls_full_usage "\n\n" |
110 | //usage: "List directory contents\n" | 110 | //usage: "List directory contents\n" |
111 | //usage: "\n -1 One column output" | 111 | //usage: "\n -1 One column output" |
112 | //usage: "\n -a Include entries which start with ." | 112 | //usage: "\n -a Include names starting with ." |
113 | //usage: "\n -A Like -a, but exclude . and .." | 113 | //usage: "\n -A Like -a, but exclude . and .." |
114 | ////usage: "\n -C List by columns" - don't show, this is a default anyway | 114 | ////usage: "\n -C List by columns" - don't show, this is a default anyway |
115 | //usage: "\n -x List by lines" | 115 | //usage: "\n -x List by lines" |
116 | //usage: "\n -d List directory entries instead of contents" | 116 | //usage: "\n -d List directory names, not contents" |
117 | //usage: IF_FEATURE_LS_FOLLOWLINKS( | 117 | //usage: IF_FEATURE_LS_FOLLOWLINKS( |
118 | //usage: "\n -L Follow symlinks" | 118 | //usage: "\n -L Follow symlinks" |
119 | //usage: "\n -H Follow symlinks on command line" | 119 | //usage: "\n -H Follow symlinks on command line" |
@@ -122,10 +122,10 @@ | |||
122 | //usage: "\n -R Recurse" | 122 | //usage: "\n -R Recurse" |
123 | //usage: ) | 123 | //usage: ) |
124 | //usage: IF_FEATURE_LS_FILETYPES( | 124 | //usage: IF_FEATURE_LS_FILETYPES( |
125 | //usage: "\n -p Append / to dir entries" | 125 | //usage: "\n -p Append / to directory names" |
126 | //usage: "\n -F Append indicator (one of */=@|) to entries" | 126 | //usage: "\n -F Append indicator (one of */=@|) to names" |
127 | //usage: ) | 127 | //usage: ) |
128 | //usage: "\n -l Long listing format" | 128 | //usage: "\n -l Long format" |
129 | //usage: "\n -i List inode numbers" | 129 | //usage: "\n -i List inode numbers" |
130 | //usage: "\n -n List numeric UIDs and GIDs instead of names" | 130 | //usage: "\n -n List numeric UIDs and GIDs instead of names" |
131 | //usage: "\n -s List allocated blocks" | 131 | //usage: "\n -s List allocated blocks" |
@@ -134,7 +134,7 @@ | |||
134 | //usage: "\n -lu List atime" | 134 | //usage: "\n -lu List atime" |
135 | //usage: ) | 135 | //usage: ) |
136 | //usage: IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS( | 136 | //usage: IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS( |
137 | //usage: "\n --full-time List full date and time" | 137 | //usage: "\n --full-time List full date/time" |
138 | //usage: )) | 138 | //usage: )) |
139 | //usage: IF_FEATURE_HUMAN_READABLE( | 139 | //usage: IF_FEATURE_HUMAN_READABLE( |
140 | //usage: "\n -h Human readable sizes (1K 243M 2G)" | 140 | //usage: "\n -h Human readable sizes (1K 243M 2G)" |
@@ -160,7 +160,7 @@ | |||
160 | //usage: "\n -w N Format N columns wide" | 160 | //usage: "\n -w N Format N columns wide" |
161 | //usage: ) | 161 | //usage: ) |
162 | //usage: IF_FEATURE_LS_COLOR( | 162 | //usage: IF_FEATURE_LS_COLOR( |
163 | //usage: "\n --color[={always,never,auto}] Control coloring" | 163 | //usage: "\n --color[={always,never,auto}]" |
164 | //usage: ) | 164 | //usage: ) |
165 | 165 | ||
166 | #include "libbb.h" | 166 | #include "libbb.h" |
@@ -187,7 +187,7 @@ | |||
187 | 187 | ||
188 | 188 | ||
189 | enum { | 189 | enum { |
190 | TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ | 190 | TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ |
191 | 191 | ||
192 | SPLIT_FILE = 0, | 192 | SPLIT_FILE = 0, |
193 | SPLIT_DIR = 1, | 193 | SPLIT_DIR = 1, |
@@ -298,7 +298,7 @@ struct dnode { | |||
298 | // but there are invisible fields as well | 298 | // but there are invisible fields as well |
299 | // (such as nanosecond-resolution timespamps) | 299 | // (such as nanosecond-resolution timespamps) |
300 | // and padding, which we also don't want to store. | 300 | // and padding, which we also don't want to store. |
301 | // We also can pre-parse dev_t dn_rdev (in glibc, it's huge). | 301 | // We also pre-parse dev_t dn_rdev (in glibc, it's huge). |
302 | // On 32-bit uclibc: dnode size went from 112 to 84 bytes. | 302 | // On 32-bit uclibc: dnode size went from 112 to 84 bytes. |
303 | // | 303 | // |
304 | /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ | 304 | /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ |
@@ -1182,11 +1182,15 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1182 | 1182 | ||
1183 | #if ENABLE_FEATURE_LS_COLOR | 1183 | #if ENABLE_FEATURE_LS_COLOR |
1184 | /* set G_show_color = 1/0 */ | 1184 | /* set G_show_color = 1/0 */ |
1185 | if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) { | 1185 | if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) { |
1186 | char *p = getenv("LS_COLORS"); | 1186 | char *p = getenv("LS_COLORS"); |
1187 | /* LS_COLORS is unset, or (not empty && not "none") ? */ | 1187 | /* LS_COLORS is unset, or (not empty && not "none") ? */ |
1188 | if (!p || (p[0] && strcmp(p, "none") != 0)) | 1188 | if (!p || (p[0] && strcmp(p, "none") != 0)) { |
1189 | G_show_color = 1; | 1189 | if (isatty(STDOUT_FILENO)) { |
1190 | /* check isatty() last because it's expensive (syscall) */ | ||
1191 | G_show_color = 1; | ||
1192 | } | ||
1193 | } | ||
1190 | } | 1194 | } |
1191 | if (opt & OPT_color) { | 1195 | if (opt & OPT_color) { |
1192 | if (color_opt[0] == 'n') | 1196 | if (color_opt[0] == 'n') |
@@ -1195,7 +1199,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) | |||
1195 | case 3: | 1199 | case 3: |
1196 | case 4: | 1200 | case 4: |
1197 | case 5: | 1201 | case 5: |
1198 | if (isatty(STDOUT_FILENO)) { | 1202 | if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { |
1199 | case 0: | 1203 | case 0: |
1200 | case 1: | 1204 | case 1: |
1201 | case 2: | 1205 | case 2: |
diff --git a/coreutils/tail.c b/coreutils/tail.c index 08fde6cdd..6201eb023 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c | |||
@@ -48,19 +48,20 @@ | |||
48 | //usage:#define tail_trivial_usage | 48 | //usage:#define tail_trivial_usage |
49 | //usage: "[OPTIONS] [FILE]..." | 49 | //usage: "[OPTIONS] [FILE]..." |
50 | //usage:#define tail_full_usage "\n\n" | 50 | //usage:#define tail_full_usage "\n\n" |
51 | //usage: "Print last 10 lines of FILEs (or stdin) to stdout.\n" | 51 | //usage: "Print last 10 lines of FILEs (or stdin) to.\n" |
52 | //usage: "With more than one FILE, precede each with a filename header.\n" | 52 | //usage: "With more than one FILE, precede each with a filename header.\n" |
53 | //usage: "\n -f Print data as file grows" | 53 | //usage: "\n -c [+]N[bkm] Print last N bytes" |
54 | //usage: "\n -c [+]N[kbm] Print last N bytes" | 54 | //usage: "\n -n N[bkm] Print last N lines" |
55 | //usage: "\n -n N[kbm] Print last N lines" | 55 | //usage: "\n -n +N[bkm] Start on Nth line and print the rest" |
56 | //usage: "\n -n +N[kbm] Start on Nth line and print the rest" | 56 | //usage: "\n (b:*512 k:*1024 m:*1024^2)" |
57 | //usage: IF_FEATURE_FANCY_TAIL( | 57 | //usage: IF_FEATURE_FANCY_TAIL( |
58 | //usage: "\n -q Never print headers" | 58 | //usage: "\n -q Never print headers" |
59 | //usage: "\n -s SECONDS Wait SECONDS between reads with -f" | ||
60 | //usage: "\n -v Always print headers" | 59 | //usage: "\n -v Always print headers" |
60 | //usage: ) | ||
61 | //usage: "\n -f Print data as file grows" | ||
62 | //usage: IF_FEATURE_FANCY_TAIL( | ||
61 | //usage: "\n -F Same as -f, but keep retrying" | 63 | //usage: "\n -F Same as -f, but keep retrying" |
62 | //usage: "\n" | 64 | //usage: "\n -s SECONDS Wait SECONDS between reads with -f" |
63 | //usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." | ||
64 | //usage: ) | 65 | //usage: ) |
65 | //usage: | 66 | //usage: |
66 | //usage:#define tail_example_usage | 67 | //usage:#define tail_example_usage |
@@ -118,7 +119,7 @@ int tail_main(int argc, char **argv) | |||
118 | 119 | ||
119 | char *tailbuf; | 120 | char *tailbuf; |
120 | size_t tailbufsize; | 121 | size_t tailbufsize; |
121 | unsigned header_threshhold = 1; | 122 | unsigned header_threshold = 1; |
122 | unsigned nfiles; | 123 | unsigned nfiles; |
123 | int i, opt; | 124 | int i, opt; |
124 | 125 | ||
@@ -151,10 +152,10 @@ int tail_main(int argc, char **argv) | |||
151 | if (opt & 0x2) count = eat_num(str_c); // -c | 152 | if (opt & 0x2) count = eat_num(str_c); // -c |
152 | if (opt & 0x4) count = eat_num(str_n); // -n | 153 | if (opt & 0x4) count = eat_num(str_n); // -n |
153 | #if ENABLE_FEATURE_FANCY_TAIL | 154 | #if ENABLE_FEATURE_FANCY_TAIL |
154 | /* q: make it impossible for nfiles to be > header_threshhold */ | 155 | /* q: make it impossible for nfiles to be > header_threshold */ |
155 | if (opt & 0x8) header_threshhold = UINT_MAX; // -q | 156 | if (opt & 0x8) header_threshold = UINT_MAX; // -q |
156 | //if (opt & 0x10) // -s | 157 | //if (opt & 0x10) // -s |
157 | if (opt & 0x20) header_threshhold = 0; // -v | 158 | if (opt & 0x20) header_threshold = 0; // -v |
158 | # define FOLLOW_RETRY (opt & 0x40) | 159 | # define FOLLOW_RETRY (opt & 0x40) |
159 | #else | 160 | #else |
160 | # define FOLLOW_RETRY 0 | 161 | # define FOLLOW_RETRY 0 |
@@ -215,7 +216,7 @@ int tail_main(int argc, char **argv) | |||
215 | if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) | 216 | if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) |
216 | continue; /* may happen with -F */ | 217 | continue; /* may happen with -F */ |
217 | 218 | ||
218 | if (nfiles > header_threshhold) { | 219 | if (nfiles > header_threshold) { |
219 | tail_xprint_header(fmt, argv[i]); | 220 | tail_xprint_header(fmt, argv[i]); |
220 | fmt = header_fmt_str; | 221 | fmt = header_fmt_str; |
221 | } | 222 | } |
@@ -345,9 +346,11 @@ int tail_main(int argc, char **argv) | |||
345 | int nread; | 346 | int nread; |
346 | const char *filename = argv[i]; | 347 | const char *filename = argv[i]; |
347 | int fd = fds[i]; | 348 | int fd = fds[i]; |
349 | int new_fd = -1; | ||
350 | struct stat sbuf; | ||
348 | 351 | ||
349 | if (FOLLOW_RETRY) { | 352 | if (FOLLOW_RETRY) { |
350 | struct stat sbuf, fsbuf; | 353 | struct stat fsbuf; |
351 | 354 | ||
352 | if (fd < 0 | 355 | if (fd < 0 |
353 | || fstat(fd, &fsbuf) < 0 | 356 | || fstat(fd, &fsbuf) < 0 |
@@ -355,39 +358,51 @@ int tail_main(int argc, char **argv) | |||
355 | || fsbuf.st_dev != sbuf.st_dev | 358 | || fsbuf.st_dev != sbuf.st_dev |
356 | || fsbuf.st_ino != sbuf.st_ino | 359 | || fsbuf.st_ino != sbuf.st_ino |
357 | ) { | 360 | ) { |
358 | int new_fd; | 361 | /* Looks like file has been created/renamed/deleted */ |
359 | |||
360 | if (fd >= 0) | ||
361 | close(fd); | ||
362 | new_fd = open(filename, O_RDONLY); | 362 | new_fd = open(filename, O_RDONLY); |
363 | if (new_fd >= 0) { | 363 | if (new_fd >= 0) { |
364 | bb_error_msg("%s has %s; following end of new file", | 364 | bb_error_msg("%s has %s; following end of new file", |
365 | filename, (fd < 0) ? "appeared" : "been replaced" | 365 | filename, (fd < 0) ? "appeared" : "been replaced" |
366 | ); | 366 | ); |
367 | if (fd < 0) { | ||
368 | /* No previously open fd for this file, | ||
369 | * start using new_fd immediately. */ | ||
370 | fds[i] = fd = new_fd; | ||
371 | new_fd = -1; | ||
372 | } | ||
367 | } else if (fd >= 0) { | 373 | } else if (fd >= 0) { |
368 | bb_perror_msg("%s has become inaccessible", filename); | 374 | bb_perror_msg("%s has been renamed or deleted", filename); |
369 | } | 375 | } |
370 | fds[i] = fd = new_fd; | ||
371 | } | 376 | } |
372 | } | 377 | } |
373 | if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) | 378 | if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) |
374 | continue; | 379 | continue; |
375 | if (nfiles > header_threshhold) { | 380 | if (nfiles > header_threshold) { |
376 | fmt = header_fmt_str; | 381 | fmt = header_fmt_str; |
377 | } | 382 | } |
378 | for (;;) { | 383 | for (;;) { |
379 | /* tail -f keeps following files even if they are truncated */ | 384 | /* tail -f keeps following files even if they are truncated */ |
380 | struct stat sbuf; | ||
381 | /* /proc files report zero st_size, don't lseek them */ | 385 | /* /proc files report zero st_size, don't lseek them */ |
382 | if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) { | 386 | if (fstat(fd, &sbuf) == 0 |
387 | /* && S_ISREG(sbuf.st_mode) TODO? */ | ||
388 | && sbuf.st_size > 0 | ||
389 | ) { | ||
383 | off_t current = lseek(fd, 0, SEEK_CUR); | 390 | off_t current = lseek(fd, 0, SEEK_CUR); |
384 | if (sbuf.st_size < current) | 391 | if (sbuf.st_size < current) { |
392 | //bb_perror_msg("%s: file truncated", filename); - says coreutils 8.32 | ||
385 | xlseek(fd, 0, SEEK_SET); | 393 | xlseek(fd, 0, SEEK_SET); |
394 | } | ||
386 | } | 395 | } |
387 | 396 | ||
388 | nread = tail_read(fd, tailbuf, BUFSIZ); | 397 | nread = tail_read(fd, tailbuf, BUFSIZ); |
389 | if (nread <= 0) | 398 | if (nread <= 0) { |
390 | break; | 399 | if (new_fd < 0) |
400 | break; | ||
401 | /* Switch to "tail -F"ing the new file */ | ||
402 | xmove_fd(new_fd, fd); | ||
403 | new_fd = -1; | ||
404 | continue; | ||
405 | } | ||
391 | if (fmt && (fd != prev_fd)) { | 406 | if (fmt && (fd != prev_fd)) { |
392 | tail_xprint_header(fmt, filename); | 407 | tail_xprint_header(fmt, filename); |
393 | fmt = NULL; | 408 | fmt = NULL; |
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index 585a4b58f..f528c88ff 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c | |||
@@ -113,13 +113,24 @@ enum { | |||
113 | }; | 113 | }; |
114 | 114 | ||
115 | /* Is this a valid filename (upper/lower alpha, digits, | 115 | /* Is this a valid filename (upper/lower alpha, digits, |
116 | * underscores, and hyphens only?) | 116 | * underscores, hyphens, and non-leading dots only?) |
117 | */ | 117 | */ |
118 | static bool invalid_name(const char *c) | 118 | static bool invalid_name(const char *c) |
119 | { | 119 | { |
120 | c = bb_basename(c); | 120 | c = bb_basename(c); |
121 | 121 | ||
122 | while (*c && (isalnum(*c) || *c == '_' || *c == '-')) | 122 | if (*c == '.') |
123 | return *c; | ||
124 | |||
125 | /* Debian run-parts 4.8.3, manpage: | ||
126 | * "...the names must consist entirely of ASCII letters, | ||
127 | * ASCII digits, ASCII underscores, and ASCII minus-hyphens. | ||
128 | * However, the name must not begin with a period." | ||
129 | * The last sentence is a giveaway that something is fishy | ||
130 | * (why mention leading dot if dots are not allowed anyway?). | ||
131 | * Yes, you guessed it right: in fact non-leading dots ARE allowed. | ||
132 | */ | ||
133 | while (isalnum(*c) || *c == '_' || *c == '-' || *c == '.') | ||
123 | c++; | 134 | c++; |
124 | 135 | ||
125 | return *c; /* TRUE (!0) if terminating NUL is not reached */ | 136 | return *c; /* TRUE (!0) if terminating NUL is not reached */ |
diff --git a/editors/vi.c b/editors/vi.c index 3dcde9b24..a4d6b21b4 100644 --- a/editors/vi.c +++ b/editors/vi.c | |||
@@ -307,7 +307,6 @@ struct globals { | |||
307 | #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash | 307 | #define err_method (vi_setops & VI_ERR_METHOD) // indicate error with beep or flash |
308 | #define ignorecase (vi_setops & VI_IGNORECASE) | 308 | #define ignorecase (vi_setops & VI_IGNORECASE) |
309 | #define showmatch (vi_setops & VI_SHOWMATCH ) | 309 | #define showmatch (vi_setops & VI_SHOWMATCH ) |
310 | #define openabove (vi_setops & VI_TABSTOP ) | ||
311 | // order of constants and strings must match | 310 | // order of constants and strings must match |
312 | #define OPTS_STR \ | 311 | #define OPTS_STR \ |
313 | "ai\0""autoindent\0" \ | 312 | "ai\0""autoindent\0" \ |
@@ -316,15 +315,10 @@ struct globals { | |||
316 | "ic\0""ignorecase\0" \ | 315 | "ic\0""ignorecase\0" \ |
317 | "sm\0""showmatch\0" \ | 316 | "sm\0""showmatch\0" \ |
318 | "ts\0""tabstop\0" | 317 | "ts\0""tabstop\0" |
319 | #define set_openabove() (vi_setops |= VI_TABSTOP) | ||
320 | #define clear_openabove() (vi_setops &= ~VI_TABSTOP) | ||
321 | #else | 318 | #else |
322 | #define autoindent (0) | 319 | #define autoindent (0) |
323 | #define expandtab (0) | 320 | #define expandtab (0) |
324 | #define err_method (0) | 321 | #define err_method (0) |
325 | #define openabove (0) | ||
326 | #define set_openabove() ((void)0) | ||
327 | #define clear_openabove() ((void)0) | ||
328 | #endif | 322 | #endif |
329 | 323 | ||
330 | #if ENABLE_FEATURE_VI_READONLY | 324 | #if ENABLE_FEATURE_VI_READONLY |
@@ -380,6 +374,9 @@ struct globals { | |||
380 | #if ENABLE_FEATURE_VI_SEARCH | 374 | #if ENABLE_FEATURE_VI_SEARCH |
381 | char *last_search_pattern; // last pattern from a '/' or '?' search | 375 | char *last_search_pattern; // last pattern from a '/' or '?' search |
382 | #endif | 376 | #endif |
377 | #if ENABLE_FEATURE_VI_SETOPTS | ||
378 | int indentcol; // column of recently autoindent, 0 or -1 | ||
379 | #endif | ||
383 | 380 | ||
384 | // former statics | 381 | // former statics |
385 | #if ENABLE_FEATURE_VI_YANKMARK | 382 | #if ENABLE_FEATURE_VI_YANKMARK |
@@ -505,6 +502,7 @@ struct globals { | |||
505 | #define ioq_start (G.ioq_start ) | 502 | #define ioq_start (G.ioq_start ) |
506 | #define dotcnt (G.dotcnt ) | 503 | #define dotcnt (G.dotcnt ) |
507 | #define last_search_pattern (G.last_search_pattern) | 504 | #define last_search_pattern (G.last_search_pattern) |
505 | #define indentcol (G.indentcol ) | ||
508 | 506 | ||
509 | #define edit_file__cur_line (G.edit_file__cur_line) | 507 | #define edit_file__cur_line (G.edit_file__cur_line) |
510 | #define refresh__old_offset (G.refresh__old_offset) | 508 | #define refresh__old_offset (G.refresh__old_offset) |
@@ -2155,15 +2153,26 @@ static uintptr_t stupid_insert(char *p, char c) // stupidly insert the char c at | |||
2155 | return bias; | 2153 | return bias; |
2156 | } | 2154 | } |
2157 | 2155 | ||
2156 | // find number of characters in indent, p must be at beginning of line | ||
2157 | static size_t indent_len(char *p) | ||
2158 | { | ||
2159 | char *r = p; | ||
2160 | |||
2161 | while (r < (end - 1) && isblank(*r)) | ||
2162 | r++; | ||
2163 | return r - p; | ||
2164 | } | ||
2165 | |||
2158 | #if !ENABLE_FEATURE_VI_UNDO | 2166 | #if !ENABLE_FEATURE_VI_UNDO |
2159 | #define char_insert(a,b,c) char_insert(a,b) | 2167 | #define char_insert(a,b,c) char_insert(a,b) |
2160 | #endif | 2168 | #endif |
2161 | static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | 2169 | static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' |
2162 | { | 2170 | { |
2163 | #if ENABLE_FEATURE_VI_SETOPTS | 2171 | #if ENABLE_FEATURE_VI_SETOPTS |
2164 | char *q; | ||
2165 | size_t len; | 2172 | size_t len; |
2173 | int col, ntab, nspc; | ||
2166 | #endif | 2174 | #endif |
2175 | char *bol = begin_line(p); | ||
2167 | 2176 | ||
2168 | if (c == 22) { // Is this an ctrl-V? | 2177 | if (c == 22) { // Is this an ctrl-V? |
2169 | p += stupid_insert(p, '^'); // use ^ to indicate literal next | 2178 | p += stupid_insert(p, '^'); // use ^ to indicate literal next |
@@ -2185,25 +2194,36 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2185 | if ((p[-1] != '\n') && (dot > text)) { | 2194 | if ((p[-1] != '\n') && (dot > text)) { |
2186 | p--; | 2195 | p--; |
2187 | } | 2196 | } |
2188 | } else if (c == 4) { // ctrl-D reduces indentation | 2197 | #if ENABLE_FEATURE_VI_SETOPTS |
2189 | int prev; | 2198 | if (autoindent) { |
2190 | char *r, *bol; | 2199 | len = indent_len(bol); |
2191 | bol = begin_line(p); | 2200 | if (len && get_column(bol + len) == indentcol) { |
2192 | for (r = bol; r < end_line(p); ++r) { | 2201 | // remove autoindent from otherwise empty line |
2193 | if (!isblank(*r)) | 2202 | text_hole_delete(bol, bol + len - 1, undo); |
2194 | break; | 2203 | p = bol; |
2204 | } | ||
2195 | } | 2205 | } |
2196 | 2206 | #endif | |
2197 | prev = prev_tabstop(get_column(r)); | 2207 | } else if (c == 4) { // ctrl-D reduces indentation |
2208 | char *r = bol + indent_len(bol); | ||
2209 | int prev = prev_tabstop(get_column(r)); | ||
2198 | while (r > bol && get_column(r) > prev) { | 2210 | while (r > bol && get_column(r) > prev) { |
2199 | if (p > bol) | 2211 | if (p > bol) |
2200 | p--; | 2212 | p--; |
2201 | r--; | 2213 | r--; |
2202 | r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED); | 2214 | r = text_hole_delete(r, r, ALLOW_UNDO_QUEUED); |
2203 | } | 2215 | } |
2216 | |||
2217 | #if ENABLE_FEATURE_VI_SETOPTS | ||
2218 | if (autoindent && indentcol && r == end_line(p)) { | ||
2219 | // record changed size of autoindent | ||
2220 | indentcol = get_column(p); | ||
2221 | return p; | ||
2222 | } | ||
2223 | #endif | ||
2204 | #if ENABLE_FEATURE_VI_SETOPTS | 2224 | #if ENABLE_FEATURE_VI_SETOPTS |
2205 | } else if (c == '\t' && expandtab) { // expand tab | 2225 | } else if (c == '\t' && expandtab) { // expand tab |
2206 | int col = get_column(p); | 2226 | col = get_column(p); |
2207 | col = next_tabstop(col) - col + 1; | 2227 | col = next_tabstop(col) - col + 1; |
2208 | while (col--) { | 2228 | while (col--) { |
2209 | # if ENABLE_FEATURE_VI_UNDO | 2229 | # if ENABLE_FEATURE_VI_UNDO |
@@ -2242,27 +2262,46 @@ static char *char_insert(char *p, char c, int undo) // insert the char c at 'p' | |||
2242 | showmatching(p - 1); | 2262 | showmatching(p - 1); |
2243 | } | 2263 | } |
2244 | if (autoindent && c == '\n') { // auto indent the new line | 2264 | if (autoindent && c == '\n') { // auto indent the new line |
2245 | // use current/previous line as template | 2265 | // use indent of current/previous line |
2246 | q = openabove ? p : prev_line(p); | 2266 | bol = indentcol < 0 ? p : prev_line(p); |
2247 | len = strspn(q, " \t"); // space or tab | 2267 | len = indent_len(bol); |
2248 | if (openabove) { | 2268 | col = get_column(bol + len); |
2249 | p--; // this replaces dot_prev() in do_cmd() | 2269 | |
2250 | q += len; // template will be shifted by text_hole_make() | 2270 | if (len && col == indentcol) { |
2271 | // previous line was empty except for autoindent | ||
2272 | // move the indent to the current line | ||
2273 | memmove(bol + 1, bol, len); | ||
2274 | *bol = '\n'; | ||
2275 | return p; | ||
2251 | } | 2276 | } |
2277 | |||
2278 | if (indentcol < 0) | ||
2279 | p--; // open above, indent before newly inserted NL | ||
2280 | |||
2252 | if (len) { | 2281 | if (len) { |
2253 | uintptr_t bias; | 2282 | indentcol = col; |
2254 | bias = text_hole_make(p, len); | 2283 | if (expandtab) { |
2255 | p += bias; | 2284 | ntab = 0; |
2256 | q += bias; | 2285 | nspc = col; |
2286 | } else { | ||
2287 | ntab = col / tabstop; | ||
2288 | nspc = col % tabstop; | ||
2289 | } | ||
2290 | p += text_hole_make(p, ntab + nspc); | ||
2257 | # if ENABLE_FEATURE_VI_UNDO | 2291 | # if ENABLE_FEATURE_VI_UNDO |
2258 | undo_push_insert(p, len, undo); | 2292 | undo_push_insert(p, ntab + nspc, undo); |
2259 | # endif | 2293 | # endif |
2260 | memcpy(p, q, len); | 2294 | memset(p, '\t', ntab); |
2261 | p += len; | 2295 | p += ntab; |
2296 | memset(p, ' ', nspc); | ||
2297 | return p + nspc; | ||
2262 | } | 2298 | } |
2263 | } | 2299 | } |
2264 | #endif | 2300 | #endif |
2265 | } | 2301 | } |
2302 | #if ENABLE_FEATURE_VI_SETOPTS | ||
2303 | indentcol = 0; | ||
2304 | #endif | ||
2266 | return p; | 2305 | return p; |
2267 | } | 2306 | } |
2268 | 2307 | ||
@@ -2647,7 +2686,6 @@ static void setops(char *args, int flg_no) | |||
2647 | index = 1 << (index >> 1); // convert to VI_bit | 2686 | index = 1 << (index >> 1); // convert to VI_bit |
2648 | 2687 | ||
2649 | if (index & VI_TABSTOP) { | 2688 | if (index & VI_TABSTOP) { |
2650 | // don't set this bit in vi_setops, it's reused as 'openabove' | ||
2651 | int t; | 2689 | int t; |
2652 | if (!eq || flg_no) // no "=NNN" or it is "notabstop"? | 2690 | if (!eq || flg_no) // no "=NNN" or it is "notabstop"? |
2653 | goto bad; | 2691 | goto bad; |
@@ -3783,6 +3821,7 @@ static void do_cmd(int c) | |||
3783 | # endif | 3821 | # endif |
3784 | } while (--cmdcnt > 0); | 3822 | } while (--cmdcnt > 0); |
3785 | dot += cnt; | 3823 | dot += cnt; |
3824 | dot_skip_over_ws(); | ||
3786 | # if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS | 3825 | # if ENABLE_FEATURE_VI_YANKMARK && ENABLE_FEATURE_VI_VERBOSE_STATUS |
3787 | yank_status("Put", p, i); | 3826 | yank_status("Put", p, i); |
3788 | # endif | 3827 | # endif |
@@ -4109,17 +4148,18 @@ static void do_cmd(int c) | |||
4109 | break; | 4148 | break; |
4110 | case 'O': // O- open an empty line above | 4149 | case 'O': // O- open an empty line above |
4111 | dot_begin(); | 4150 | dot_begin(); |
4112 | set_openabove(); | 4151 | #if ENABLE_FEATURE_VI_SETOPTS |
4152 | indentcol = -1; | ||
4153 | #endif | ||
4113 | goto dc3; | 4154 | goto dc3; |
4114 | case 'o': // o- open an empty line below | 4155 | case 'o': // o- open an empty line below |
4115 | dot_end(); | 4156 | dot_end(); |
4116 | dc3: | 4157 | dc3: |
4117 | dot = char_insert(dot, '\n', ALLOW_UNDO); | 4158 | dot = char_insert(dot, '\n', ALLOW_UNDO); |
4118 | if (c == 'O' && !autoindent) { | 4159 | if (c == 'O' && !autoindent) { |
4119 | // done in char_insert() for openabove+autoindent | 4160 | // done in char_insert() for 'O'+autoindent |
4120 | dot_prev(); | 4161 | dot_prev(); |
4121 | } | 4162 | } |
4122 | clear_openabove(); | ||
4123 | goto dc_i; | 4163 | goto dc_i; |
4124 | break; | 4164 | break; |
4125 | case 'R': // R- continuous Replace char | 4165 | case 'R': // R- continuous Replace char |
@@ -4238,6 +4278,9 @@ static void do_cmd(int c) | |||
4238 | if (dot != (end-1)) { | 4278 | if (dot != (end-1)) { |
4239 | dot_prev(); | 4279 | dot_prev(); |
4240 | } | 4280 | } |
4281 | } else if (c == 'd') { | ||
4282 | dot_begin(); | ||
4283 | dot_skip_over_ws(); | ||
4241 | } else { | 4284 | } else { |
4242 | dot = save_dot; | 4285 | dot = save_dot; |
4243 | } | 4286 | } |
diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index df1258aaf..6eb10852e 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf | |||
@@ -79,7 +79,7 @@ option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 | |||
79 | option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" | 79 | option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" |
80 | option 14 "dumpfile" | 80 | option 14 "dumpfile" |
81 | 81 | ||
82 | # Currently supported options [hex option value] (for more info, see options.c): | 82 | # Currently supported options [hex option value] (for more info, see common.c): |
83 | #opt lease NUM # [0x33] | 83 | #opt lease NUM # [0x33] |
84 | #opt subnet IP # [0x01] | 84 | #opt subnet IP # [0x01] |
85 | #opt broadcast IP # [0x1c] | 85 | #opt broadcast IP # [0x1c] |
@@ -91,17 +91,20 @@ option 14 "dumpfile" | |||
91 | #opt search STRING_LIST # [0x77] search domains | 91 | #opt search STRING_LIST # [0x77] search domains |
92 | #opt nisdomain STRING # [0x28] | 92 | #opt nisdomain STRING # [0x28] |
93 | #opt timezone NUM # [0x02] (localtime - UTC_time) in seconds. signed | 93 | #opt timezone NUM # [0x02] (localtime - UTC_time) in seconds. signed |
94 | #opt tzstr STRING # [0x64] RFC 4833. IEEE 1003.1 TZ string | ||
95 | #opt tzdbstr STRING # [0x65] RFC 4833. Reference to the TZ database string | ||
94 | #opt tftp STRING # [0x42] tftp server name | 96 | #opt tftp STRING # [0x42] tftp server name |
95 | #opt bootfile STRING # [0x43] tftp file to download (e.g. kernel image) | 97 | #opt bootfile STRING # [0x43] tftp file to download (e.g. kernel image) |
96 | #opt bootsize NUM # [0x0d] size of that file | 98 | #opt bootsize NUM # [0x0d] size of that file |
97 | #opt rootpath STRING # [0x11] (NFS) path to mount as root fs | 99 | #opt rootpath STRING # [0x11] (NFS) path to mount as root fs |
98 | #opt wpad STRING # [0xfc] Web Proxy Auto Discovery Protocol | 100 | #opt wpad STRING # [0xfc] Web Proxy Auto Discovery Protocol |
99 | #opt serverid IP # [0x36] default: server's IP | 101 | #opt serverid IP # [0x36] default: server's IP |
100 | #opt message STRING # [0x38] error message (udhcpd sends it on success too) | 102 | #opt message STRING # [0x38] error message (if set, udhcpd would send it on success too) |
101 | #opt vlanid NUM # [0x84] 802.1P VLAN ID | 103 | #opt vlanid NUM # [0x84] 802.1P VLAN ID |
102 | #opt vlanpriority NUM # [0x85] 802.1Q VLAN priority | 104 | #opt vlanpriority NUM # [0x85] 802.1Q VLAN priority |
105 | #opt vendor STRING # [0x3c] client's vendor string, not intended to be sent by DHCP servers | ||
103 | # RFC 5071: PXELINUX Options | 106 | # RFC 5071: PXELINUX Options |
104 | #opt 0xd0 F100747E # [0xd0] magic | 107 | #opt 0xd0 F100747E # [0xd0] magic needed for other options to be recognized by clients |
105 | #opt pxeconffile STRING # [0xd1] | 108 | #opt pxeconffile STRING # [0xd1] |
106 | #opt pxepathprefix STRING # [0xd2] | 109 | #opt pxepathprefix STRING # [0xd2] |
107 | #opt reboottime NUM # [0xd3] bootstrap timeout | 110 | #opt reboottime NUM # [0xd3] bootstrap timeout |
diff --git a/include/libbb.h b/include/libbb.h index 3b2d23df8..e80ed1e32 100644 --- a/include/libbb.h +++ b/include/libbb.h | |||
@@ -629,7 +629,7 @@ void bb_signals(int sigs, void (*f)(int)) FAST_FUNC; | |||
629 | /* Unlike signal() and bb_signals, sets handler with sigaction() | 629 | /* Unlike signal() and bb_signals, sets handler with sigaction() |
630 | * and in a way that while signal handler is run, no other signals | 630 | * and in a way that while signal handler is run, no other signals |
631 | * will be blocked; syscalls will not be restarted: */ | 631 | * will be blocked; syscalls will not be restarted: */ |
632 | void bb_signals_recursive_norestart(int sigs, void (*f)(int)) FAST_FUNC; | 632 | void bb_signals_norestart(int sigs, void (*f)(int)) FAST_FUNC; |
633 | /* syscalls like read() will be interrupted with EINTR: */ | 633 | /* syscalls like read() will be interrupted with EINTR: */ |
634 | void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC; | 634 | void signal_no_SA_RESTART_empty_mask(int sig, void (*handler)(int)) FAST_FUNC; |
635 | /* syscalls like read() won't be interrupted (though select/poll will be): */ | 635 | /* syscalls like read() won't be interrupted (though select/poll will be): */ |
@@ -1817,6 +1817,7 @@ extern void print_login_issue(const char *issue_file, const char *tty) FAST_FUNC | |||
1817 | extern void print_login_prompt(void) FAST_FUNC; | 1817 | extern void print_login_prompt(void) FAST_FUNC; |
1818 | 1818 | ||
1819 | char *xmalloc_ttyname(int fd) FAST_FUNC RETURNS_MALLOC; | 1819 | char *xmalloc_ttyname(int fd) FAST_FUNC RETURNS_MALLOC; |
1820 | int is_TERM_dumb(void) FAST_FUNC; | ||
1820 | /* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */ | 1821 | /* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */ |
1821 | int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FUNC; | 1822 | int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FUNC; |
1822 | int get_terminal_width(int fd) FAST_FUNC; | 1823 | int get_terminal_width(int fd) FAST_FUNC; |
diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 378510063..5ab4d66f1 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c | |||
@@ -89,6 +89,12 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
89 | root:x:0:0:root:/root:/bin/bash | 89 | root:x:0:0:root:/root:/bin/bash |
90 | user:x:500:500::/home/user:/bin/bash | 90 | user:x:500:500::/home/user:/bin/bash |
91 | 91 | ||
92 | "^" options string is "^optchars""\0""opt_complementary". | ||
93 | |||
94 | "!" If the first character in the applet_opts string is a '!', | ||
95 | report bad options, missing required options, | ||
96 | inconsistent options with all-ones return value (instead of abort. | ||
97 | |||
92 | "+" If the first character in the applet_opts string is a plus, | 98 | "+" If the first character in the applet_opts string is a plus, |
93 | then option processing will stop as soon as a non-option is | 99 | then option processing will stop as soon as a non-option is |
94 | encountered in the argv array. Useful for applets like env | 100 | encountered in the argv array. Useful for applets like env |
@@ -96,10 +102,7 @@ getopt32(char **argv, const char *applet_opts, ...) | |||
96 | env -i ls -d / | 102 | env -i ls -d / |
97 | Here we want env to process just the '-i', not the '-d'. | 103 | Here we want env to process just the '-i', not the '-d'. |
98 | 104 | ||
99 | "!" Report bad options, missing required options, | 105 | (The order of multiple prefixes must be "^!+...") |
100 | inconsistent options with all-ones return value (instead of abort). | ||
101 | |||
102 | "^" options string is "^optchars""\0""opt_complementary". | ||
103 | 106 | ||
104 | uint32_t | 107 | uint32_t |
105 | getopt32long(char **argv, const char *applet_opts, const char *logopts...) | 108 | getopt32long(char **argv, const char *applet_opts, const char *logopts...) |
diff --git a/libbb/signals.c b/libbb/signals.c index e64ba5023..c09a562ed 100644 --- a/libbb/signals.c +++ b/libbb/signals.c | |||
@@ -58,7 +58,7 @@ void FAST_FUNC bb_signals(int sigs, void (*f)(int)) | |||
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
61 | void FAST_FUNC bb_signals_recursive_norestart(int sigs, void (*f)(int)) | 61 | void FAST_FUNC bb_signals_norestart(int sigs, void (*f)(int)) |
62 | { | 62 | { |
63 | int sig_no = 0; | 63 | int sig_no = 0; |
64 | int bit = 1; | 64 | int bit = 1; |
diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index ef990118e..102b5a227 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c | |||
@@ -305,6 +305,12 @@ int FAST_FUNC get_terminal_width(int fd) | |||
305 | return width; | 305 | return width; |
306 | } | 306 | } |
307 | 307 | ||
308 | int FAST_FUNC is_TERM_dumb(void) | ||
309 | { | ||
310 | char *term = getenv("TERM"); | ||
311 | return term && strcmp(term, "dumb") == 0; | ||
312 | } | ||
313 | |||
308 | #if !ENABLE_PLATFORM_MINGW32 | 314 | #if !ENABLE_PLATFORM_MINGW32 |
309 | int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) | 315 | int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) |
310 | { | 316 | { |
diff --git a/networking/httpd_post_upload.cgi b/networking/httpd_post_upload.cgi index e4ffd2bb5..538f7181b 100755 --- a/networking/httpd_post_upload.cgi +++ b/networking/httpd_post_upload.cgi | |||
@@ -18,7 +18,7 @@ | |||
18 | # ^M <--------- extra empty line | 18 | # ^M <--------- extra empty line |
19 | # -----------------------------29995809218093749221856446032--^M | 19 | # -----------------------------29995809218093749221856446032--^M |
20 | 20 | ||
21 | file=/tmp/$$-$RANDOM | 21 | file=$(mktemp) |
22 | 22 | ||
23 | CR=`printf '\r'` | 23 | CR=`printf '\r'` |
24 | 24 | ||
diff --git a/networking/nslookup.c b/networking/nslookup.c index c43ad46f3..de7b5c0e7 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c | |||
@@ -25,7 +25,7 @@ | |||
25 | //usage:#define nslookup_full_usage "\n\n" | 25 | //usage:#define nslookup_full_usage "\n\n" |
26 | //usage: "Query DNS about HOST" | 26 | //usage: "Query DNS about HOST" |
27 | //usage: IF_FEATURE_NSLOOKUP_BIG("\n") | 27 | //usage: IF_FEATURE_NSLOOKUP_BIG("\n") |
28 | //usage: IF_FEATURE_NSLOOKUP_BIG("\nQUERY_TYPE: soa,ns,a,"IF_FEATURE_IPV6("aaaa,")"cname,mx,txt,ptr,any") | 28 | //usage: IF_FEATURE_NSLOOKUP_BIG("\nQUERY_TYPE: soa,ns,a,"IF_FEATURE_IPV6("aaaa,")"cname,mx,txt,ptr,srv,any") |
29 | //usage:#define nslookup_example_usage | 29 | //usage:#define nslookup_example_usage |
30 | //usage: "$ nslookup localhost\n" | 30 | //usage: "$ nslookup localhost\n" |
31 | //usage: "Server: default\n" | 31 | //usage: "Server: default\n" |
diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 8c4afabf6..708e05c2e 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c | |||
@@ -216,17 +216,25 @@ enum { | |||
216 | OPT_K = (1 << 16), | 216 | OPT_K = (1 << 16), |
217 | }; | 217 | }; |
218 | 218 | ||
219 | static void connection_status(void) | 219 | static void if_verbose_print_connection_status(void) |
220 | { | 220 | { |
221 | /* "only 1 client max" desn't need this */ | 221 | if (verbose) { |
222 | if (cmax > 1) | 222 | /* "only 1 client max" desn't need this */ |
223 | bb_error_msg("status %u/%u", cnum, cmax); | 223 | if (cmax > 1) |
224 | bb_error_msg("status %u/%u", cnum, cmax); | ||
225 | } | ||
224 | } | 226 | } |
225 | 227 | ||
228 | /* SIGCHLD handler is reentrancy-safe because SIGCHLD is unmasked | ||
229 | * only over accept() or recvfrom() calls, not over memory allocations | ||
230 | * or printouts. Do need to save/restore errno in order not to mangle | ||
231 | * these syscalls' error code, if any. | ||
232 | */ | ||
226 | static void sig_child_handler(int sig UNUSED_PARAM) | 233 | static void sig_child_handler(int sig UNUSED_PARAM) |
227 | { | 234 | { |
228 | int wstat; | 235 | int wstat; |
229 | pid_t pid; | 236 | pid_t pid; |
237 | int sv_errno = errno; | ||
230 | 238 | ||
231 | while ((pid = wait_any_nohang(&wstat)) > 0) { | 239 | while ((pid = wait_any_nohang(&wstat)) > 0) { |
232 | if (max_per_host) | 240 | if (max_per_host) |
@@ -236,8 +244,8 @@ static void sig_child_handler(int sig UNUSED_PARAM) | |||
236 | if (verbose) | 244 | if (verbose) |
237 | print_waitstat(pid, wstat); | 245 | print_waitstat(pid, wstat); |
238 | } | 246 | } |
239 | if (verbose) | 247 | if_verbose_print_connection_status(); |
240 | connection_status(); | 248 | errno = sv_errno; |
241 | } | 249 | } |
242 | 250 | ||
243 | int tcpudpsvd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 251 | int tcpudpsvd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
@@ -458,7 +466,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
458 | xconnect(0, &remote.u.sa, sa_len); | 466 | xconnect(0, &remote.u.sa, sa_len); |
459 | /* hole? at this point we have no wildcard udp socket... | 467 | /* hole? at this point we have no wildcard udp socket... |
460 | * can this cause clients to get "port unreachable" icmp? | 468 | * can this cause clients to get "port unreachable" icmp? |
461 | * Yup, time window is very small, but it exists (is it?) */ | 469 | * Yup, time window is very small, but it exists (does it?) */ |
462 | /* ..."open new socket", continued */ | 470 | /* ..."open new socket", continued */ |
463 | xbind(sock, &lsa->u.sa, sa_len); | 471 | xbind(sock, &lsa->u.sa, sa_len); |
464 | socket_want_pktinfo(sock); | 472 | socket_want_pktinfo(sock); |
@@ -491,8 +499,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
491 | if (pid != 0) { | 499 | if (pid != 0) { |
492 | /* Parent */ | 500 | /* Parent */ |
493 | cnum++; | 501 | cnum++; |
494 | if (verbose) | 502 | if_verbose_print_connection_status(); |
495 | connection_status(); | ||
496 | if (hccp) | 503 | if (hccp) |
497 | hccp->pid = pid; | 504 | hccp->pid = pid; |
498 | /* clean up changes done by vforked child */ | 505 | /* clean up changes done by vforked child */ |
@@ -586,8 +593,14 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) | |||
586 | 593 | ||
587 | xdup2(0, 1); | 594 | xdup2(0, 1); |
588 | 595 | ||
596 | /* Restore signal handling for the to-be-execed process */ | ||
589 | signal(SIGPIPE, SIG_DFL); /* this one was SIG_IGNed */ | 597 | signal(SIGPIPE, SIG_DFL); /* this one was SIG_IGNed */ |
590 | /* Non-ignored signals revert to SIG_DFL on exec anyway */ | 598 | /* Non-ignored signals revert to SIG_DFL on exec anyway |
599 | * But we can get signals BEFORE execvp(), this is unlikely | ||
600 | * but it would invoke sig_child_handler(), which would | ||
601 | * check waitpid(WNOHANG), then print "status N/M" if verbose. | ||
602 | * I guess we can live with that possibility. | ||
603 | */ | ||
591 | /*signal(SIGCHLD, SIG_DFL);*/ | 604 | /*signal(SIGCHLD, SIG_DFL);*/ |
592 | sig_unblock(SIGCHLD); | 605 | sig_unblock(SIGCHLD); |
593 | 606 | ||
diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c index a395e838d..a11c4e841 100644 --- a/networking/udhcp/arpping.c +++ b/networking/udhcp/arpping.c | |||
@@ -47,6 +47,7 @@ int FAST_FUNC arpping(uint32_t test_nip, | |||
47 | int rv = 1; /* "no reply received" yet */ | 47 | int rv = 1; /* "no reply received" yet */ |
48 | struct sockaddr addr; /* for interface name */ | 48 | struct sockaddr addr; /* for interface name */ |
49 | struct arpMsg arp; | 49 | struct arpMsg arp; |
50 | const char *msg; | ||
50 | 51 | ||
51 | if (!timeo) | 52 | if (!timeo) |
52 | return 1; | 53 | return 1; |
@@ -58,7 +59,7 @@ int FAST_FUNC arpping(uint32_t test_nip, | |||
58 | } | 59 | } |
59 | 60 | ||
60 | if (setsockopt_broadcast(s) == -1) { | 61 | if (setsockopt_broadcast(s) == -1) { |
61 | bb_simple_perror_msg("can't enable bcast on raw socket"); | 62 | bb_simple_perror_msg("can't enable bcast on ARP socket"); |
62 | goto ret; | 63 | goto ret; |
63 | } | 64 | } |
64 | 65 | ||
@@ -131,6 +132,9 @@ int FAST_FUNC arpping(uint32_t test_nip, | |||
131 | 132 | ||
132 | ret: | 133 | ret: |
133 | close(s); | 134 | close(s); |
134 | log1("%srp reply received for this address", rv ? "no a" : "A"); | 135 | msg = "no ARP reply received for this address"; |
136 | if (rv == 0) | ||
137 | msg += 3; | ||
138 | log1s(msg); | ||
135 | return rv; | 139 | return rv; |
136 | } | 140 | } |
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index f2d6907ad..31e525cb0 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c | |||
@@ -49,6 +49,7 @@ const struct dhcp_optflag dhcp_optflags[] = { | |||
49 | { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */ | 49 | { OPTION_U32 , 0x33 }, /* DHCP_LEASE_TIME */ |
50 | { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ | 50 | { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ |
51 | { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ | 51 | { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ |
52 | { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ | ||
52 | //TODO: must be combined with 'sname' and 'file' handling: | 53 | //TODO: must be combined with 'sname' and 'file' handling: |
53 | { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ | 54 | { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ |
54 | { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ | 55 | { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ |
@@ -83,7 +84,6 @@ const struct dhcp_optflag dhcp_optflags[] = { | |||
83 | { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ | 84 | { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ |
84 | { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ | 85 | { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ |
85 | //looks like these opts will work just fine even without these defs: | 86 | //looks like these opts will work just fine even without these defs: |
86 | // { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ | ||
87 | // /* not really a string: */ | 87 | // /* not really a string: */ |
88 | // { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ | 88 | // { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ |
89 | { 0, 0 } /* zeroed terminating entry */ | 89 | { 0, 0 } /* zeroed terminating entry */ |
@@ -120,6 +120,7 @@ const char dhcp_option_strings[] ALIGN1 = | |||
120 | "lease" "\0" /* DHCP_LEASE_TIME */ | 120 | "lease" "\0" /* DHCP_LEASE_TIME */ |
121 | "serverid" "\0" /* DHCP_SERVER_ID */ | 121 | "serverid" "\0" /* DHCP_SERVER_ID */ |
122 | "message" "\0" /* DHCP_ERR_MESSAGE */ | 122 | "message" "\0" /* DHCP_ERR_MESSAGE */ |
123 | "vendor" "\0" /* DHCP_VENDOR */ | ||
123 | "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/ | 124 | "tftp" "\0" /* DHCP_TFTP_SERVER_NAME*/ |
124 | "bootfile" "\0" /* DHCP_BOOT_FILE */ | 125 | "bootfile" "\0" /* DHCP_BOOT_FILE */ |
125 | // "userclass" "\0" /* DHCP_USER_CLASS */ | 126 | // "userclass" "\0" /* DHCP_USER_CLASS */ |
@@ -184,6 +185,13 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { | |||
184 | */ | 185 | */ |
185 | }; | 186 | }; |
186 | 187 | ||
188 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 | ||
189 | void FAST_FUNC log1s(const char *msg) | ||
190 | { | ||
191 | if (dhcp_verbose >= 1) | ||
192 | bb_simple_info_msg(msg); | ||
193 | } | ||
194 | #endif | ||
187 | 195 | ||
188 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 | 196 | #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 |
189 | static void log_option(const char *pfx, const uint8_t *opt) | 197 | static void log_option(const char *pfx, const uint8_t *opt) |
@@ -420,6 +428,40 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) | |||
420 | return 1; | 428 | return 1; |
421 | } | 429 | } |
422 | 430 | ||
431 | void* FAST_FUNC udhcp_insert_new_option( | ||
432 | struct option_set **opt_list, | ||
433 | unsigned code, | ||
434 | unsigned length, | ||
435 | bool dhcpv6) | ||
436 | { | ||
437 | IF_NOT_UDHCPC6(bool dhcpv6 = 0;) | ||
438 | struct option_set *new, **curr; | ||
439 | |||
440 | log2("attaching option %02x to list", code); | ||
441 | new = xmalloc(sizeof(*new)); | ||
442 | if (!dhcpv6) { | ||
443 | new->data = xzalloc(length + OPT_DATA); | ||
444 | new->data[OPT_CODE] = code; | ||
445 | new->data[OPT_LEN] = length; | ||
446 | } else { | ||
447 | new->data = xzalloc(length + D6_OPT_DATA); | ||
448 | new->data[D6_OPT_CODE] = code >> 8; | ||
449 | new->data[D6_OPT_CODE + 1] = code & 0xff; | ||
450 | new->data[D6_OPT_LEN] = length >> 8; | ||
451 | new->data[D6_OPT_LEN + 1] = length & 0xff; | ||
452 | } | ||
453 | |||
454 | curr = opt_list; | ||
455 | //FIXME: DHCP6 codes > 255!! | ||
456 | while (*curr && (*curr)->data[OPT_CODE] < code) | ||
457 | curr = &(*curr)->next; | ||
458 | |||
459 | new->next = *curr; | ||
460 | *curr = new; | ||
461 | |||
462 | return new->data; | ||
463 | } | ||
464 | |||
423 | /* udhcp_str2optset: | 465 | /* udhcp_str2optset: |
424 | * Parse string option representation to binary form and add it to opt_list. | 466 | * Parse string option representation to binary form and add it to opt_list. |
425 | * Called to parse "udhcpc -x OPTNAME:OPTVAL" | 467 | * Called to parse "udhcpc -x OPTNAME:OPTVAL" |
@@ -459,32 +501,12 @@ static NOINLINE void attach_option( | |||
459 | 501 | ||
460 | existing = udhcp_find_option(*opt_list, optflag->code); | 502 | existing = udhcp_find_option(*opt_list, optflag->code); |
461 | if (!existing) { | 503 | if (!existing) { |
462 | struct option_set *new, **curr; | ||
463 | |||
464 | /* make a new option */ | 504 | /* make a new option */ |
465 | log2("attaching option %02x to list", optflag->code); | 505 | uint8_t *p = udhcp_insert_new_option(opt_list, optflag->code, length, dhcpv6); |
466 | new = xmalloc(sizeof(*new)); | 506 | if (!dhcpv6) |
467 | if (!dhcpv6) { | 507 | memcpy(p + OPT_DATA, buffer, length); |
468 | new->data = xmalloc(length + OPT_DATA); | 508 | else |
469 | new->data[OPT_CODE] = optflag->code; | 509 | memcpy(p + D6_OPT_DATA, buffer, length); |
470 | new->data[OPT_LEN] = length; | ||
471 | memcpy(new->data + OPT_DATA, buffer, length); | ||
472 | } else { | ||
473 | new->data = xmalloc(length + D6_OPT_DATA); | ||
474 | new->data[D6_OPT_CODE] = optflag->code >> 8; | ||
475 | new->data[D6_OPT_CODE + 1] = optflag->code & 0xff; | ||
476 | new->data[D6_OPT_LEN] = length >> 8; | ||
477 | new->data[D6_OPT_LEN + 1] = length & 0xff; | ||
478 | memcpy(new->data + D6_OPT_DATA, buffer, | ||
479 | length); | ||
480 | } | ||
481 | |||
482 | curr = opt_list; | ||
483 | while (*curr && (*curr)->data[OPT_CODE] < optflag->code) | ||
484 | curr = &(*curr)->next; | ||
485 | |||
486 | new->next = *curr; | ||
487 | *curr = new; | ||
488 | goto ret; | 510 | goto ret; |
489 | } | 511 | } |
490 | 512 | ||
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index cc0abd269..8c678dd32 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h | |||
@@ -275,7 +275,8 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) | |||
275 | # define IF_UDHCP_VERBOSE(...) __VA_ARGS__ | 275 | # define IF_UDHCP_VERBOSE(...) __VA_ARGS__ |
276 | extern unsigned dhcp_verbose; | 276 | extern unsigned dhcp_verbose; |
277 | # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) | 277 | # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) |
278 | # define log1s(msg) do { if (dhcp_verbose >= 1) bb_simple_info_msg(msg); } while (0) | 278 | //# define log1s(msg) do { if (dhcp_verbose >= 1) bb_simple_info_msg(msg); } while (0) |
279 | void log1s(const char *msg) FAST_FUNC; | ||
279 | # if CONFIG_UDHCP_DEBUG >= 2 | 280 | # if CONFIG_UDHCP_DEBUG >= 2 |
280 | void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; | 281 | void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; |
281 | # define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0) | 282 | # define log2(...) do { if (dhcp_verbose >= 2) bb_info_msg(__VA_ARGS__); } while (0) |
@@ -319,6 +320,16 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; | |||
319 | 320 | ||
320 | /* 2nd param is "uint32_t*" */ | 321 | /* 2nd param is "uint32_t*" */ |
321 | int FAST_FUNC udhcp_str2nip(const char *str, void *arg); | 322 | int FAST_FUNC udhcp_str2nip(const char *str, void *arg); |
323 | |||
324 | #if !ENABLE_UDHCPC6 | ||
325 | #define udhcp_insert_new_option(opt_list, code, length, dhcpv6) \ | ||
326 | udhcp_insert_new_option(opt_list, code, length) | ||
327 | #endif | ||
328 | void* FAST_FUNC udhcp_insert_new_option(struct option_set **opt_list, | ||
329 | unsigned code, | ||
330 | unsigned length, | ||
331 | bool dhcpv6); | ||
332 | |||
322 | /* 2nd param is "struct option_set**" */ | 333 | /* 2nd param is "struct option_set**" */ |
323 | #if !ENABLE_UDHCPC6 | 334 | #if !ENABLE_UDHCPC6 |
324 | #define udhcp_str2optset(str, arg, optflags, option_strings, dhcpv6) \ | 335 | #define udhcp_str2optset(str, arg, optflags, option_strings, dhcpv6) \ |
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c index 0a5cae310..7f288f891 100644 --- a/networking/udhcp/d6_dhcpc.c +++ b/networking/udhcp/d6_dhcpc.c | |||
@@ -441,7 +441,7 @@ static char **fill_envp(const uint8_t *option, const uint8_t *option_end) | |||
441 | return envp; | 441 | return envp; |
442 | } | 442 | } |
443 | 443 | ||
444 | /* Call a script with a par file and env vars */ | 444 | /* Call a script with env vars */ |
445 | static void d6_run_script(const uint8_t *option, const uint8_t *option_end, | 445 | static void d6_run_script(const uint8_t *option, const uint8_t *option_end, |
446 | const char *name) | 446 | const char *name) |
447 | { | 447 | { |
@@ -464,7 +464,7 @@ static void d6_run_script(const uint8_t *option, const uint8_t *option_end, | |||
464 | free(envp); | 464 | free(envp); |
465 | } | 465 | } |
466 | 466 | ||
467 | /* Call a script with a par file and no env var */ | 467 | /* Call a script with no env var */ |
468 | static void d6_run_script_no_option(const char *name) | 468 | static void d6_run_script_no_option(const char *name) |
469 | { | 469 | { |
470 | d6_run_script(NULL, NULL, name); | 470 | d6_run_script(NULL, NULL, name); |
@@ -482,7 +482,6 @@ static ALWAYS_INLINE uint32_t random_xid(void) | |||
482 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) | 482 | static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) |
483 | { | 483 | { |
484 | uint8_t *ptr; | 484 | uint8_t *ptr; |
485 | struct d6_option *clientid; | ||
486 | unsigned secs; | 485 | unsigned secs; |
487 | 486 | ||
488 | memset(packet, 0, sizeof(*packet)); | 487 | memset(packet, 0, sizeof(*packet)); |
@@ -503,9 +502,7 @@ static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid | |||
503 | *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff; | 502 | *((uint16_t*)ptr) = (secs < 0xffff) ? htons(secs) : 0xffff; |
504 | ptr += 2; | 503 | ptr += 2; |
505 | 504 | ||
506 | /* add CLIENTID option */ | 505 | return ptr; |
507 | clientid = (void*)client_data.clientid; | ||
508 | return mempcpy(ptr, clientid, clientid->len + 2+2); | ||
509 | } | 506 | } |
510 | 507 | ||
511 | static uint8_t *add_d6_client_options(uint8_t *ptr) | 508 | static uint8_t *add_d6_client_options(uint8_t *ptr) |
@@ -593,10 +590,10 @@ static NOINLINE int send_d6_info_request(uint32_t xid) | |||
593 | struct d6_packet packet; | 590 | struct d6_packet packet; |
594 | uint8_t *opt_ptr; | 591 | uint8_t *opt_ptr; |
595 | 592 | ||
596 | /* Fill in: msg type, client id */ | 593 | /* Fill in: msg type */ |
597 | opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); | 594 | opt_ptr = init_d6_packet(&packet, D6_MSG_INFORMATION_REQUEST, xid); |
598 | 595 | ||
599 | /* Add options: | 596 | /* Add options: client-id, |
600 | * "param req" option according to -O, options specified with -x | 597 | * "param req" option according to -O, options specified with -x |
601 | */ | 598 | */ |
602 | opt_ptr = add_d6_client_options(opt_ptr); | 599 | opt_ptr = add_d6_client_options(opt_ptr); |
@@ -693,7 +690,7 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip | |||
693 | uint8_t *opt_ptr; | 690 | uint8_t *opt_ptr; |
694 | unsigned len; | 691 | unsigned len; |
695 | 692 | ||
696 | /* Fill in: msg type, client id */ | 693 | /* Fill in: msg type */ |
697 | opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); | 694 | opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); |
698 | 695 | ||
699 | /* Create new IA_NA, optionally with included IAADDR with requested IP */ | 696 | /* Create new IA_NA, optionally with included IAADDR with requested IP */ |
@@ -726,7 +723,7 @@ static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ip | |||
726 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); | 723 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, len); |
727 | } | 724 | } |
728 | 725 | ||
729 | /* Add options: | 726 | /* Add options: client-id, |
730 | * "param req" option according to -O, options specified with -x | 727 | * "param req" option according to -O, options specified with -x |
731 | */ | 728 | */ |
732 | opt_ptr = add_d6_client_options(opt_ptr); | 729 | opt_ptr = add_d6_client_options(opt_ptr); |
@@ -771,7 +768,7 @@ static NOINLINE int send_d6_select(uint32_t xid) | |||
771 | struct d6_packet packet; | 768 | struct d6_packet packet; |
772 | uint8_t *opt_ptr; | 769 | uint8_t *opt_ptr; |
773 | 770 | ||
774 | /* Fill in: msg type, client id */ | 771 | /* Fill in: msg type */ |
775 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); | 772 | opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); |
776 | 773 | ||
777 | /* server id */ | 774 | /* server id */ |
@@ -783,7 +780,7 @@ static NOINLINE int send_d6_select(uint32_t xid) | |||
783 | if (client6_data.ia_pd) | 780 | if (client6_data.ia_pd) |
784 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); | 781 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); |
785 | 782 | ||
786 | /* Add options: | 783 | /* Add options: client-id, |
787 | * "param req" option according to -O, options specified with -x | 784 | * "param req" option according to -O, options specified with -x |
788 | */ | 785 | */ |
789 | opt_ptr = add_d6_client_options(opt_ptr); | 786 | opt_ptr = add_d6_client_options(opt_ptr); |
@@ -844,7 +841,7 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st | |||
844 | struct d6_packet packet; | 841 | struct d6_packet packet; |
845 | uint8_t *opt_ptr; | 842 | uint8_t *opt_ptr; |
846 | 843 | ||
847 | /* Fill in: msg type, client id */ | 844 | /* Fill in: msg type */ |
848 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); | 845 | opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); |
849 | 846 | ||
850 | /* server id */ | 847 | /* server id */ |
@@ -856,7 +853,7 @@ static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, st | |||
856 | if (client6_data.ia_pd) | 853 | if (client6_data.ia_pd) |
857 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); | 854 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); |
858 | 855 | ||
859 | /* Add options: | 856 | /* Add options: client-id, |
860 | * "param req" option according to -O, options specified with -x | 857 | * "param req" option according to -O, options specified with -x |
861 | */ | 858 | */ |
862 | opt_ptr = add_d6_client_options(opt_ptr); | 859 | opt_ptr = add_d6_client_options(opt_ptr); |
@@ -878,6 +875,7 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | |||
878 | { | 875 | { |
879 | struct d6_packet packet; | 876 | struct d6_packet packet; |
880 | uint8_t *opt_ptr; | 877 | uint8_t *opt_ptr; |
878 | struct option_set *ci; | ||
881 | 879 | ||
882 | /* Fill in: msg type, client id */ | 880 | /* Fill in: msg type, client id */ |
883 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); | 881 | opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); |
@@ -889,6 +887,10 @@ int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | |||
889 | /* IA PD */ | 887 | /* IA PD */ |
890 | if (client6_data.ia_pd) | 888 | if (client6_data.ia_pd) |
891 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); | 889 | opt_ptr = mempcpy(opt_ptr, client6_data.ia_pd, client6_data.ia_pd->len + 2+2); |
890 | /* Client-id */ | ||
891 | ci = udhcp_find_option(client_data.options, D6_OPT_CLIENTID); | ||
892 | if (ci) | ||
893 | opt_ptr = mempcpy(opt_ptr, ci->data, D6_OPT_DATA + 2+2 + 6); | ||
892 | 894 | ||
893 | bb_info_msg("sending %s", "release"); | 895 | bb_info_msg("sending %s", "release"); |
894 | return d6_send_kernel_packet_from_client_data_ifindex( | 896 | return d6_send_kernel_packet_from_client_data_ifindex( |
@@ -952,7 +954,8 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac | |||
952 | if (peer_ipv6) | 954 | if (peer_ipv6) |
953 | *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */ | 955 | *peer_ipv6 = packet.ip6.ip6_src; /* struct copy */ |
954 | 956 | ||
955 | log1("received %s", "a packet"); | 957 | log2("received %s", "a packet"); |
958 | /* log2 because more informative msg for valid packets is printed later at log1 level */ | ||
956 | d6_dump_packet(&packet.data); | 959 | d6_dump_packet(&packet.data); |
957 | 960 | ||
958 | bytes -= sizeof(packet.ip6) + sizeof(packet.udp); | 961 | bytes -= sizeof(packet.ip6) + sizeof(packet.udp); |
@@ -1060,9 +1063,6 @@ static int d6_raw_socket(int ifindex) | |||
1060 | log1("attached filter to raw socket fd %d", fd); // log? | 1063 | log1("attached filter to raw socket fd %d", fd); // log? |
1061 | } | 1064 | } |
1062 | #endif | 1065 | #endif |
1063 | |||
1064 | log1s("created raw socket"); | ||
1065 | |||
1066 | return fd; | 1066 | return fd; |
1067 | } | 1067 | } |
1068 | 1068 | ||
@@ -1088,6 +1088,8 @@ static void change_listen_mode(int new_mode) | |||
1088 | 1088 | ||
1089 | static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) | 1089 | static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) |
1090 | { | 1090 | { |
1091 | change_listen_mode(LISTEN_NONE); | ||
1092 | |||
1091 | /* send release packet */ | 1093 | /* send release packet */ |
1092 | if (client_data.state == BOUND | 1094 | if (client_data.state == BOUND |
1093 | || client_data.state == RENEWING | 1095 | || client_data.state == RENEWING |
@@ -1105,21 +1107,9 @@ static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *ou | |||
1105 | * of the states above. | 1107 | * of the states above. |
1106 | */ | 1108 | */ |
1107 | d6_run_script_no_option("deconfig"); | 1109 | d6_run_script_no_option("deconfig"); |
1108 | change_listen_mode(LISTEN_NONE); | ||
1109 | client_data.state = RELEASED; | 1110 | client_data.state = RELEASED; |
1110 | } | 1111 | } |
1111 | 1112 | ||
1112 | ///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) | ||
1113 | ///{ | ||
1114 | /// uint8_t *storage; | ||
1115 | /// int len = strnlen(str, 255); | ||
1116 | /// storage = xzalloc(len + extra + OPT_DATA); | ||
1117 | /// storage[OPT_CODE] = code; | ||
1118 | /// storage[OPT_LEN] = len + extra; | ||
1119 | /// memcpy(storage + extra + OPT_DATA, str, len); | ||
1120 | /// return storage; | ||
1121 | ///} | ||
1122 | |||
1123 | #if BB_MMU | 1113 | #if BB_MMU |
1124 | static void client_background(void) | 1114 | static void client_background(void) |
1125 | { | 1115 | { |
@@ -1184,7 +1174,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1184 | { | 1174 | { |
1185 | const char *str_r; | 1175 | const char *str_r; |
1186 | IF_FEATURE_UDHCP_PORT(char *str_P;) | 1176 | IF_FEATURE_UDHCP_PORT(char *str_P;) |
1187 | void *clientid_mac_ptr; | 1177 | uint8_t *clientid_mac_ptr; |
1188 | llist_t *list_O = NULL; | 1178 | llist_t *list_O = NULL; |
1189 | llist_t *list_x = NULL; | 1179 | llist_t *list_x = NULL; |
1190 | int tryagain_timeout = 20; | 1180 | int tryagain_timeout = 20; |
@@ -1281,6 +1271,18 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1281 | free(optstr); | 1271 | free(optstr); |
1282 | } | 1272 | } |
1283 | 1273 | ||
1274 | clientid_mac_ptr = NULL; | ||
1275 | if (!udhcp_find_option(client_data.options, D6_OPT_CLIENTID)) { | ||
1276 | /* not set, set the default client ID */ | ||
1277 | clientid_mac_ptr = udhcp_insert_new_option( | ||
1278 | &client_data.options, D6_OPT_CLIENTID, | ||
1279 | 2+2 + 6, /*dhcp6:*/ 1); | ||
1280 | clientid_mac_ptr += 2+2; /* skip option code, len */ | ||
1281 | clientid_mac_ptr[1] = 3; /* DUID-LL */ | ||
1282 | clientid_mac_ptr[3] = 1; /* type: ethernet */ | ||
1283 | clientid_mac_ptr += 2+2; /* skip DUID-LL, ethernet */ | ||
1284 | } | ||
1285 | |||
1284 | if (d6_read_interface(client_data.interface, | 1286 | if (d6_read_interface(client_data.interface, |
1285 | &client_data.ifindex, | 1287 | &client_data.ifindex, |
1286 | &client6_data.ll_ip6, | 1288 | &client6_data.ll_ip6, |
@@ -1289,19 +1291,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1289 | return 1; | 1291 | return 1; |
1290 | } | 1292 | } |
1291 | 1293 | ||
1292 | /* Create client ID based on mac, set clientid_mac_ptr */ | ||
1293 | { | ||
1294 | struct d6_option *clientid; | ||
1295 | clientid = xzalloc(2+2+2+2+6); | ||
1296 | clientid->code = D6_OPT_CLIENTID; | ||
1297 | clientid->len = 2+2+6; | ||
1298 | clientid->data[1] = 3; /* DUID-LL */ | ||
1299 | clientid->data[3] = 1; /* ethernet */ | ||
1300 | clientid_mac_ptr = clientid->data + 2+2; | ||
1301 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); | ||
1302 | client_data.clientid = (void*)clientid; | ||
1303 | } | ||
1304 | |||
1305 | #if !BB_MMU | 1294 | #if !BB_MMU |
1306 | /* on NOMMU reexec (i.e., background) early */ | 1295 | /* on NOMMU reexec (i.e., background) early */ |
1307 | if (!(opt & OPT_f)) { | 1296 | if (!(opt & OPT_f)) { |
@@ -1321,7 +1310,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1321 | 1310 | ||
1322 | client_data.state = INIT_SELECTING; | 1311 | client_data.state = INIT_SELECTING; |
1323 | d6_run_script_no_option("deconfig"); | 1312 | d6_run_script_no_option("deconfig"); |
1324 | change_listen_mode(LISTEN_RAW); | ||
1325 | packet_num = 0; | 1313 | packet_num = 0; |
1326 | timeout = 0; | 1314 | timeout = 0; |
1327 | lease_remaining = 0; | 1315 | lease_remaining = 0; |
@@ -1356,14 +1344,17 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1356 | log1("waiting %u seconds", timeout); | 1344 | log1("waiting %u seconds", timeout); |
1357 | diff = (unsigned)monotonic_sec(); | 1345 | diff = (unsigned)monotonic_sec(); |
1358 | retval = poll(pfds, 2, timeout * 1000); | 1346 | retval = poll(pfds, 2, timeout * 1000); |
1347 | diff = (unsigned)monotonic_sec() - diff; | ||
1348 | lease_remaining -= diff; | ||
1349 | if (lease_remaining < 0) | ||
1350 | lease_remaining = 0; | ||
1351 | timeout -= diff; | ||
1352 | if (timeout < 0) | ||
1353 | timeout = 0; | ||
1354 | |||
1359 | if (retval < 0) { | 1355 | if (retval < 0) { |
1360 | /* EINTR? A signal was caught, don't panic */ | 1356 | /* EINTR? A signal was caught, don't panic */ |
1361 | if (errno == EINTR) { | 1357 | if (errno == EINTR) { |
1362 | diff = (unsigned)monotonic_sec() - diff; | ||
1363 | lease_remaining -= diff; | ||
1364 | if (lease_remaining < 0) | ||
1365 | lease_remaining = 0; | ||
1366 | timeout -= diff; | ||
1367 | continue; | 1358 | continue; |
1368 | } | 1359 | } |
1369 | /* Else: an error occured, panic! */ | 1360 | /* Else: an error occured, panic! */ |
@@ -1388,13 +1379,16 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1388 | goto ret0; /* iface is gone? */ | 1379 | goto ret0; /* iface is gone? */ |
1389 | } | 1380 | } |
1390 | 1381 | ||
1391 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); | 1382 | if (clientid_mac_ptr) |
1383 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); | ||
1392 | 1384 | ||
1393 | switch (client_data.state) { | 1385 | switch (client_data.state) { |
1394 | case INIT_SELECTING: | 1386 | case INIT_SELECTING: |
1395 | if (!discover_retries || packet_num < discover_retries) { | 1387 | if (!discover_retries || packet_num < discover_retries) { |
1396 | if (packet_num == 0) | 1388 | if (packet_num == 0) { |
1389 | change_listen_mode(LISTEN_RAW); | ||
1397 | xid = random_xid(); | 1390 | xid = random_xid(); |
1391 | } | ||
1398 | /* multicast */ | 1392 | /* multicast */ |
1399 | if (opt & OPT_l) | 1393 | if (opt & OPT_l) |
1400 | send_d6_info_request(xid); | 1394 | send_d6_info_request(xid); |
@@ -1405,6 +1399,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1405 | continue; | 1399 | continue; |
1406 | } | 1400 | } |
1407 | leasefail: | 1401 | leasefail: |
1402 | change_listen_mode(LISTEN_NONE); | ||
1408 | d6_run_script_no_option("leasefail"); | 1403 | d6_run_script_no_option("leasefail"); |
1409 | #if BB_MMU /* -b is not supported on NOMMU */ | 1404 | #if BB_MMU /* -b is not supported on NOMMU */ |
1410 | if (opt & OPT_b) { /* background if no lease */ | 1405 | if (opt & OPT_b) { /* background if no lease */ |
@@ -1425,7 +1420,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1425 | retval = 1; | 1420 | retval = 1; |
1426 | goto ret; | 1421 | goto ret; |
1427 | } | 1422 | } |
1428 | /* wait before trying again */ | 1423 | /* Wait before trying again */ |
1429 | timeout = tryagain_timeout; | 1424 | timeout = tryagain_timeout; |
1430 | packet_num = 0; | 1425 | packet_num = 0; |
1431 | continue; | 1426 | continue; |
@@ -1441,22 +1436,20 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1441 | * "discover...select...discover..." loops | 1436 | * "discover...select...discover..." loops |
1442 | * were seen in the wild. Treat them similarly | 1437 | * were seen in the wild. Treat them similarly |
1443 | * to "no response to discover" case */ | 1438 | * to "no response to discover" case */ |
1444 | change_listen_mode(LISTEN_RAW); | ||
1445 | client_data.state = INIT_SELECTING; | 1439 | client_data.state = INIT_SELECTING; |
1446 | goto leasefail; | 1440 | goto leasefail; |
1447 | case BOUND: | 1441 | case BOUND: |
1448 | /* 1/2 lease passed, enter renewing state */ | 1442 | /* 1/2 lease passed, enter renewing state */ |
1449 | client_data.state = RENEWING; | 1443 | client_data.state = RENEWING; |
1450 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1444 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1451 | change_listen_mode(LISTEN_KERNEL); | 1445 | got_SIGUSR1: |
1452 | log1s("entering renew state"); | 1446 | log1s("entering renew state"); |
1447 | change_listen_mode(LISTEN_KERNEL); | ||
1453 | /* fall right through */ | 1448 | /* fall right through */ |
1454 | case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ | 1449 | case RENEW_REQUESTED: /* in manual (SIGUSR1) renew */ |
1455 | case_RENEW_REQUESTED: | ||
1456 | case RENEWING: | 1450 | case RENEWING: |
1457 | if (packet_num < 3) { | 1451 | if (packet_num == 0) { |
1458 | packet_num++; | 1452 | /* Send an unicast renew request */ |
1459 | /* send an unicast renew request */ | ||
1460 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind | 1453 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind |
1461 | * a new UDP socket for sending inside send_renew. | 1454 | * a new UDP socket for sending inside send_renew. |
1462 | * I hazard to guess existing listening socket | 1455 | * I hazard to guess existing listening socket |
@@ -1470,27 +1463,36 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1470 | else | 1463 | else |
1471 | send_d6_renew(xid, &srv6_buf, requested_ipv6); | 1464 | send_d6_renew(xid, &srv6_buf, requested_ipv6); |
1472 | timeout = discover_timeout; | 1465 | timeout = discover_timeout; |
1473 | /* ^^^ used to be = lease_remaining / 2 - WAY too long */ | 1466 | packet_num++; |
1474 | continue; | 1467 | continue; |
1468 | } /* else: we had sent one packet, but got no reply */ | ||
1469 | log1s("no response to renew"); | ||
1470 | if (lease_remaining > 30) { | ||
1471 | /* Some lease time remains, try to renew later */ | ||
1472 | change_listen_mode(LISTEN_NONE); | ||
1473 | goto BOUND_for_half_lease; | ||
1475 | } | 1474 | } |
1476 | /* Timed out, enter rebinding state */ | 1475 | /* Enter rebinding state */ |
1477 | log1s("entering rebinding state"); | ||
1478 | client_data.state = REBINDING; | 1476 | client_data.state = REBINDING; |
1479 | /* fall right through */ | 1477 | log1s("entering rebinding state"); |
1480 | case REBINDING: | ||
1481 | /* Switch to bcast receive */ | 1478 | /* Switch to bcast receive */ |
1482 | change_listen_mode(LISTEN_RAW); | 1479 | change_listen_mode(LISTEN_RAW); |
1480 | packet_num = 0; | ||
1481 | /* fall right through */ | ||
1482 | case REBINDING: | ||
1483 | /* Lease is *really* about to run out, | 1483 | /* Lease is *really* about to run out, |
1484 | * try to find DHCP server using broadcast */ | 1484 | * try to find DHCP server using broadcast */ |
1485 | if (lease_remaining > 0) { | 1485 | if (lease_remaining > 0 && packet_num < 3) { |
1486 | if (opt & OPT_l) | 1486 | if (opt & OPT_l) |
1487 | send_d6_info_request(xid); | 1487 | send_d6_info_request(xid); |
1488 | else /* send a broadcast renew request */ | 1488 | else /* send a broadcast renew request */ |
1489 | send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); | 1489 | send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); |
1490 | timeout = discover_timeout; | 1490 | timeout = discover_timeout; |
1491 | packet_num++; | ||
1491 | continue; | 1492 | continue; |
1492 | } | 1493 | } |
1493 | /* Timed out, enter init state */ | 1494 | /* Timed out, enter init state */ |
1495 | change_listen_mode(LISTEN_NONE); | ||
1494 | bb_simple_info_msg("lease lost, entering init state"); | 1496 | bb_simple_info_msg("lease lost, entering init state"); |
1495 | d6_run_script_no_option("deconfig"); | 1497 | d6_run_script_no_option("deconfig"); |
1496 | client_data.state = INIT_SELECTING; | 1498 | client_data.state = INIT_SELECTING; |
@@ -1500,7 +1502,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1500 | continue; | 1502 | continue; |
1501 | /* case RELEASED: */ | 1503 | /* case RELEASED: */ |
1502 | } | 1504 | } |
1503 | /* yah, I know, *you* say it would never happen */ | 1505 | /* RELEASED state (when we got SIGUSR2) ends up here. |
1506 | * (wait for SIGUSR1 to re-init, or for TERM, etc) | ||
1507 | */ | ||
1504 | timeout = INT_MAX; | 1508 | timeout = INT_MAX; |
1505 | continue; /* back to main loop */ | 1509 | continue; /* back to main loop */ |
1506 | } /* if poll timed out */ | 1510 | } /* if poll timed out */ |
@@ -1510,33 +1514,43 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1510 | /* Is it a signal? */ | 1514 | /* Is it a signal? */ |
1511 | switch (udhcp_sp_read()) { | 1515 | switch (udhcp_sp_read()) { |
1512 | case SIGUSR1: | 1516 | case SIGUSR1: |
1517 | if (client_data.state <= REQUESTING) | ||
1518 | /* Initial negotiations in progress, do not disturb */ | ||
1519 | break; | ||
1520 | if (client_data.state == REBINDING) | ||
1521 | /* Do not go back from rebind to renew state */ | ||
1522 | break; | ||
1523 | |||
1524 | if (lease_remaining > 30) /* if renew fails, do not go back to BOUND */ | ||
1525 | lease_remaining = 30; | ||
1513 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1526 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1514 | bb_simple_info_msg("performing DHCP renew"); | 1527 | packet_num = 0; |
1515 | 1528 | ||
1516 | switch (client_data.state) { | 1529 | switch (client_data.state) { |
1517 | /* Try to renew/rebind */ | ||
1518 | case BOUND: | 1530 | case BOUND: |
1519 | case RENEWING: | 1531 | case RENEWING: |
1520 | case REBINDING: | 1532 | /* Try to renew/rebind */ |
1521 | change_listen_mode(LISTEN_KERNEL); | 1533 | change_listen_mode(LISTEN_KERNEL); |
1522 | client_data.state = RENEW_REQUESTED; | 1534 | client_data.state = RENEW_REQUESTED; |
1523 | goto case_RENEW_REQUESTED; | 1535 | goto got_SIGUSR1; |
1524 | 1536 | ||
1525 | /* Start things over */ | 1537 | case RENEW_REQUESTED: |
1526 | case RENEW_REQUESTED: /* two or more SIGUSR1 received */ | 1538 | /* Two SIGUSR1 received, start things over */ |
1539 | change_listen_mode(LISTEN_NONE); | ||
1527 | d6_run_script_no_option("deconfig"); | 1540 | d6_run_script_no_option("deconfig"); |
1528 | /* case REQUESTING: break; */ | 1541 | |
1529 | /* case RELEASED: break; */ | 1542 | default: |
1530 | /* case INIT_SELECTING: break; */ | 1543 | /* case RELEASED: */ |
1544 | /* Wake from SIGUSR2-induced deconfigured state */ | ||
1545 | change_listen_mode(LISTEN_NONE); | ||
1531 | } | 1546 | } |
1532 | change_listen_mode(LISTEN_RAW); | ||
1533 | client_data.state = INIT_SELECTING; | 1547 | client_data.state = INIT_SELECTING; |
1534 | packet_num = 0; | ||
1535 | /* Kill any timeouts, user wants this to hurry along */ | 1548 | /* Kill any timeouts, user wants this to hurry along */ |
1536 | timeout = 0; | 1549 | timeout = 0; |
1537 | continue; | 1550 | continue; |
1538 | case SIGUSR2: | 1551 | case SIGUSR2: |
1539 | perform_d6_release(&srv6_buf, requested_ipv6); | 1552 | perform_d6_release(&srv6_buf, requested_ipv6); |
1553 | /* ^^^ switches to LISTEN_NONE */ | ||
1540 | timeout = INT_MAX; | 1554 | timeout = INT_MAX; |
1541 | continue; | 1555 | continue; |
1542 | case SIGTERM: | 1556 | case SIGTERM: |
@@ -1594,6 +1608,8 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1594 | unsigned address_timeout; | 1608 | unsigned address_timeout; |
1595 | unsigned prefix_timeout; | 1609 | unsigned prefix_timeout; |
1596 | type_is_ok: | 1610 | type_is_ok: |
1611 | change_listen_mode(LISTEN_NONE); | ||
1612 | |||
1597 | address_timeout = 0; | 1613 | address_timeout = 0; |
1598 | prefix_timeout = 0; | 1614 | prefix_timeout = 0; |
1599 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); | 1615 | option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); |
@@ -1604,7 +1620,6 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1604 | packet_end, "nak"); | 1620 | packet_end, "nak"); |
1605 | if (client_data.state != REQUESTING) | 1621 | if (client_data.state != REQUESTING) |
1606 | d6_run_script_no_option("deconfig"); | 1622 | d6_run_script_no_option("deconfig"); |
1607 | change_listen_mode(LISTEN_RAW); | ||
1608 | sleep(3); /* avoid excessive network traffic */ | 1623 | sleep(3); /* avoid excessive network traffic */ |
1609 | client_data.state = INIT_SELECTING; | 1624 | client_data.state = INIT_SELECTING; |
1610 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1625 | client_data.first_secs = 0; /* make secs field count from 0 */ |
@@ -1626,6 +1641,7 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1626 | client6_data.server_id = option; | 1641 | client6_data.server_id = option; |
1627 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { | 1642 | if (packet.d6_msg_type == D6_MSG_ADVERTISE) { |
1628 | /* enter requesting state */ | 1643 | /* enter requesting state */ |
1644 | change_listen_mode(LISTEN_RAW); | ||
1629 | client_data.state = REQUESTING; | 1645 | client_data.state = REQUESTING; |
1630 | timeout = 0; | 1646 | timeout = 0; |
1631 | packet_num = 0; | 1647 | packet_num = 0; |
@@ -1809,12 +1825,9 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1809 | start = monotonic_sec(); | 1825 | start = monotonic_sec(); |
1810 | d6_run_script(packet.d6_options, packet_end, | 1826 | d6_run_script(packet.d6_options, packet_end, |
1811 | (client_data.state == REQUESTING ? "bound" : "renew")); | 1827 | (client_data.state == REQUESTING ? "bound" : "renew")); |
1812 | timeout = (unsigned)lease_remaining / 2; | 1828 | lease_remaining -= (unsigned)monotonic_sec() - start; |
1813 | timeout -= (unsigned)monotonic_sec() - start; | 1829 | if (lease_remaining < 0) |
1814 | packet_num = 0; | 1830 | lease_remaining = 0; |
1815 | |||
1816 | client_data.state = BOUND; | ||
1817 | change_listen_mode(LISTEN_NONE); | ||
1818 | if (opt & OPT_q) { /* quit after lease */ | 1831 | if (opt & OPT_q) { /* quit after lease */ |
1819 | goto ret0; | 1832 | goto ret0; |
1820 | } | 1833 | } |
@@ -1827,6 +1840,11 @@ int udhcpc6_main(int argc UNUSED_PARAM, char **argv) | |||
1827 | opt = ((opt & ~OPT_b) | OPT_f); | 1840 | opt = ((opt & ~OPT_b) | OPT_f); |
1828 | } | 1841 | } |
1829 | #endif | 1842 | #endif |
1843 | |||
1844 | BOUND_for_half_lease: | ||
1845 | timeout = (unsigned)lease_remaining / 2; | ||
1846 | client_data.state = BOUND; | ||
1847 | packet_num = 0; | ||
1830 | continue; /* back to main loop */ | 1848 | continue; /* back to main loop */ |
1831 | } | 1849 | } |
1832 | continue; | 1850 | continue; |
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c index 172f8e1ab..c1949f6e3 100644 --- a/networking/udhcp/d6_packet.c +++ b/networking/udhcp/d6_packet.c | |||
@@ -44,7 +44,8 @@ int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6 | |||
44 | bb_simple_info_msg("packet with bad magic, ignoring"); | 44 | bb_simple_info_msg("packet with bad magic, ignoring"); |
45 | return -2; | 45 | return -2; |
46 | } | 46 | } |
47 | log1("received %s", "a packet"); | 47 | log2("received %s", "a packet"); |
48 | /* log2 because more informative msg for valid packets is printed later at log1 level */ | ||
48 | d6_dump_packet(packet); | 49 | d6_dump_packet(packet); |
49 | 50 | ||
50 | return bytes; | 51 | return bytes; |
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 6666cbce6..4e3d8ca5e 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c | |||
@@ -55,8 +55,7 @@ struct tpacket_auxdata { | |||
55 | #if ENABLE_LONG_OPTS | 55 | #if ENABLE_LONG_OPTS |
56 | static const char udhcpc_longopts[] ALIGN1 = | 56 | static const char udhcpc_longopts[] ALIGN1 = |
57 | "clientid-none\0" No_argument "C" | 57 | "clientid-none\0" No_argument "C" |
58 | "vendorclass\0" Required_argument "V" | 58 | "vendorclass\0" Required_argument "V" //deprecated |
59 | "hostname\0" Required_argument "H" | ||
60 | "fqdn\0" Required_argument "F" | 59 | "fqdn\0" Required_argument "F" |
61 | "interface\0" Required_argument "i" | 60 | "interface\0" Required_argument "i" |
62 | "now\0" No_argument "n" | 61 | "now\0" No_argument "n" |
@@ -84,27 +83,25 @@ static const char udhcpc_longopts[] ALIGN1 = | |||
84 | enum { | 83 | enum { |
85 | OPT_C = 1 << 0, | 84 | OPT_C = 1 << 0, |
86 | OPT_V = 1 << 1, | 85 | OPT_V = 1 << 1, |
87 | OPT_H = 1 << 2, | 86 | OPT_F = 1 << 2, |
88 | OPT_h = 1 << 3, | 87 | OPT_i = 1 << 3, |
89 | OPT_F = 1 << 4, | 88 | OPT_n = 1 << 4, |
90 | OPT_i = 1 << 5, | 89 | OPT_p = 1 << 5, |
91 | OPT_n = 1 << 6, | 90 | OPT_q = 1 << 6, |
92 | OPT_p = 1 << 7, | 91 | OPT_R = 1 << 7, |
93 | OPT_q = 1 << 8, | 92 | OPT_r = 1 << 8, |
94 | OPT_R = 1 << 9, | 93 | OPT_s = 1 << 9, |
95 | OPT_r = 1 << 10, | 94 | OPT_T = 1 << 10, |
96 | OPT_s = 1 << 11, | 95 | OPT_t = 1 << 11, |
97 | OPT_T = 1 << 12, | 96 | OPT_S = 1 << 12, |
98 | OPT_t = 1 << 13, | 97 | OPT_A = 1 << 13, |
99 | OPT_S = 1 << 14, | 98 | OPT_O = 1 << 14, |
100 | OPT_A = 1 << 15, | 99 | OPT_o = 1 << 15, |
101 | OPT_O = 1 << 16, | 100 | OPT_x = 1 << 16, |
102 | OPT_o = 1 << 17, | 101 | OPT_f = 1 << 17, |
103 | OPT_x = 1 << 18, | 102 | OPT_B = 1 << 18, |
104 | OPT_f = 1 << 19, | ||
105 | OPT_B = 1 << 20, | ||
106 | /* The rest has variable bit positions, need to be clever */ | 103 | /* The rest has variable bit positions, need to be clever */ |
107 | OPTBIT_B = 20, | 104 | OPTBIT_B = 18, |
108 | USE_FOR_MMU( OPTBIT_b,) | 105 | USE_FOR_MMU( OPTBIT_b,) |
109 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) | 106 | IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) |
110 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) | 107 | IF_FEATURE_UDHCP_PORT( OPTBIT_P,) |
@@ -569,8 +566,8 @@ static void fill_envp(struct dhcp_packet *packet) | |||
569 | } | 566 | } |
570 | } | 567 | } |
571 | 568 | ||
572 | /* Call a script with a par file and env vars */ | 569 | /* Call a script with env vars */ |
573 | static void udhcp_run_script(struct dhcp_packet *packet, const char *name) | 570 | static void d4_run_script(struct dhcp_packet *packet, const char *name) |
574 | { | 571 | { |
575 | char *argv[3]; | 572 | char *argv[3]; |
576 | 573 | ||
@@ -588,6 +585,10 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) | |||
588 | client_data.envp = NULL; | 585 | client_data.envp = NULL; |
589 | } | 586 | } |
590 | 587 | ||
588 | static void d4_run_script_deconfig(void) | ||
589 | { | ||
590 | d4_run_script(NULL, "deconfig"); | ||
591 | } | ||
591 | 592 | ||
592 | /*** Sending/receiving packets ***/ | 593 | /*** Sending/receiving packets ***/ |
593 | 594 | ||
@@ -613,8 +614,6 @@ static void init_packet(struct dhcp_packet *packet, char type) | |||
613 | packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; | 614 | packet->secs = (secs < 0xffff) ? htons(secs) : 0xffff; |
614 | 615 | ||
615 | memcpy(packet->chaddr, client_data.client_mac, 6); | 616 | memcpy(packet->chaddr, client_data.client_mac, 6); |
616 | if (client_data.clientid) | ||
617 | udhcp_add_binary_option(packet, client_data.clientid); | ||
618 | } | 617 | } |
619 | 618 | ||
620 | static void add_client_options(struct dhcp_packet *packet) | 619 | static void add_client_options(struct dhcp_packet *packet) |
@@ -640,13 +639,6 @@ static void add_client_options(struct dhcp_packet *packet) | |||
640 | packet->options[end + OPT_DATA + len] = DHCP_END; | 639 | packet->options[end + OPT_DATA + len] = DHCP_END; |
641 | } | 640 | } |
642 | 641 | ||
643 | if (client_data.vendorclass) | ||
644 | udhcp_add_binary_option(packet, client_data.vendorclass); | ||
645 | if (client_data.hostname) | ||
646 | udhcp_add_binary_option(packet, client_data.hostname); | ||
647 | if (client_data.fqdn) | ||
648 | udhcp_add_binary_option(packet, client_data.fqdn); | ||
649 | |||
650 | /* Request broadcast replies if we have no IP addr */ | 642 | /* Request broadcast replies if we have no IP addr */ |
651 | if ((option_mask32 & OPT_B) && packet->ciaddr == 0) | 643 | if ((option_mask32 & OPT_B) && packet->ciaddr == 0) |
652 | packet->flags |= htons(BROADCAST_FLAG); | 644 | packet->flags |= htons(BROADCAST_FLAG); |
@@ -715,7 +707,7 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | |||
715 | 707 | ||
716 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 708 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
717 | * random xid field (we override it below), | 709 | * random xid field (we override it below), |
718 | * client-id option (unless -C), message type option: | 710 | * message type option: |
719 | */ | 711 | */ |
720 | init_packet(&packet, DHCPDISCOVER); | 712 | init_packet(&packet, DHCPDISCOVER); |
721 | 713 | ||
@@ -724,7 +716,6 @@ static NOINLINE int send_discover(uint32_t xid, uint32_t requested) | |||
724 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); | 716 | udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); |
725 | 717 | ||
726 | /* Add options: maxsize, | 718 | /* Add options: maxsize, |
727 | * optionally: hostname, fqdn, vendorclass, | ||
728 | * "param req" option according to -O, options specified with -x | 719 | * "param req" option according to -O, options specified with -x |
729 | */ | 720 | */ |
730 | add_client_options(&packet); | 721 | add_client_options(&packet); |
@@ -758,7 +749,7 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste | |||
758 | */ | 749 | */ |
759 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 750 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
760 | * random xid field (we override it below), | 751 | * random xid field (we override it below), |
761 | * client-id option (unless -C), message type option: | 752 | * message type option: |
762 | */ | 753 | */ |
763 | init_packet(&packet, DHCPREQUEST); | 754 | init_packet(&packet, DHCPREQUEST); |
764 | 755 | ||
@@ -768,7 +759,6 @@ static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requeste | |||
768 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 759 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
769 | 760 | ||
770 | /* Add options: maxsize, | 761 | /* Add options: maxsize, |
771 | * optionally: hostname, fqdn, vendorclass, | ||
772 | * "param req" option according to -O, and options specified with -x | 762 | * "param req" option according to -O, and options specified with -x |
773 | */ | 763 | */ |
774 | add_client_options(&packet); | 764 | add_client_options(&packet); |
@@ -805,7 +795,7 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
805 | */ | 795 | */ |
806 | /* Fill in: op, htype, hlen, cookie, chaddr fields, | 796 | /* Fill in: op, htype, hlen, cookie, chaddr fields, |
807 | * random xid field (we override it below), | 797 | * random xid field (we override it below), |
808 | * client-id option (unless -C), message type option: | 798 | * message type option: |
809 | */ | 799 | */ |
810 | init_packet(&packet, DHCPREQUEST); | 800 | init_packet(&packet, DHCPREQUEST); |
811 | 801 | ||
@@ -813,7 +803,6 @@ static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) | |||
813 | packet.ciaddr = ciaddr; | 803 | packet.ciaddr = ciaddr; |
814 | 804 | ||
815 | /* Add options: maxsize, | 805 | /* Add options: maxsize, |
816 | * optionally: hostname, fqdn, vendorclass, | ||
817 | * "param req" option according to -O, and options specified with -x | 806 | * "param req" option according to -O, and options specified with -x |
818 | */ | 807 | */ |
819 | add_client_options(&packet); | 808 | add_client_options(&packet); |
@@ -837,7 +826,7 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req | |||
837 | struct dhcp_packet packet; | 826 | struct dhcp_packet packet; |
838 | 827 | ||
839 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | 828 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, |
840 | * client-id option (unless -C), message type option: | 829 | * message type option: |
841 | */ | 830 | */ |
842 | init_packet(&packet, DHCPDECLINE); | 831 | init_packet(&packet, DHCPDECLINE); |
843 | 832 | ||
@@ -854,6 +843,8 @@ static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t req | |||
854 | 843 | ||
855 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 844 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
856 | 845 | ||
846 | //TODO: add client-id opt? | ||
847 | |||
857 | bb_simple_info_msg("broadcasting decline"); | 848 | bb_simple_info_msg("broadcasting decline"); |
858 | return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); | 849 | return raw_bcast_from_client_data_ifindex(&packet, INADDR_ANY); |
859 | } | 850 | } |
@@ -865,9 +856,10 @@ ALWAYS_INLINE /* one caller, help compiler to use this fact */ | |||
865 | int send_release(uint32_t server, uint32_t ciaddr) | 856 | int send_release(uint32_t server, uint32_t ciaddr) |
866 | { | 857 | { |
867 | struct dhcp_packet packet; | 858 | struct dhcp_packet packet; |
859 | struct option_set *ci; | ||
868 | 860 | ||
869 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, | 861 | /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, |
870 | * client-id option (unless -C), message type option: | 862 | * message type option: |
871 | */ | 863 | */ |
872 | init_packet(&packet, DHCPRELEASE); | 864 | init_packet(&packet, DHCPRELEASE); |
873 | 865 | ||
@@ -876,6 +868,14 @@ int send_release(uint32_t server, uint32_t ciaddr) | |||
876 | 868 | ||
877 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); | 869 | udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); |
878 | 870 | ||
871 | /* RFC 2131 section 3.1.6: | ||
872 | * If the client used a 'client identifier' when it obtained the lease, | ||
873 | * it MUST use the same 'client identifier' in the DHCPRELEASE message. | ||
874 | */ | ||
875 | ci = udhcp_find_option(client_data.options, DHCP_CLIENT_ID); | ||
876 | if (ci) | ||
877 | udhcp_add_binary_option(&packet, ci->data); | ||
878 | |||
879 | bb_info_msg("sending %s", "release"); | 879 | bb_info_msg("sending %s", "release"); |
880 | /* Note: normally we unicast here since "server" is not zero. | 880 | /* Note: normally we unicast here since "server" is not zero. |
881 | * However, there _are_ people who run "address-less" DHCP servers, | 881 | * However, there _are_ people who run "address-less" DHCP servers, |
@@ -886,7 +886,7 @@ int send_release(uint32_t server, uint32_t ciaddr) | |||
886 | 886 | ||
887 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ | 887 | /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ |
888 | /* NOINLINE: limit stack usage in caller */ | 888 | /* NOINLINE: limit stack usage in caller */ |
889 | static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | 889 | static NOINLINE int d4_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) |
890 | { | 890 | { |
891 | int bytes; | 891 | int bytes; |
892 | struct ip_udp_dhcp_packet packet; | 892 | struct ip_udp_dhcp_packet packet; |
@@ -979,11 +979,12 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) | |||
979 | skip_udp_sum_check: | 979 | skip_udp_sum_check: |
980 | 980 | ||
981 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { | 981 | if (packet.data.cookie != htonl(DHCP_MAGIC)) { |
982 | bb_simple_info_msg("packet with bad magic, ignoring"); | 982 | log1s("packet with bad magic, ignoring"); |
983 | return -2; | 983 | return -2; |
984 | } | 984 | } |
985 | 985 | ||
986 | log1("received %s", "a packet"); | 986 | log2("received %s", "a packet"); |
987 | /* log2 because more informative msg for valid packets is printed later at log1 level */ | ||
987 | udhcp_dump_packet(&packet.data); | 988 | udhcp_dump_packet(&packet.data); |
988 | 989 | ||
989 | bytes -= sizeof(packet.ip) + sizeof(packet.udp); | 990 | bytes -= sizeof(packet.ip) + sizeof(packet.udp); |
@@ -1096,8 +1097,6 @@ static int udhcp_raw_socket(int ifindex) | |||
1096 | log1s("can't set PACKET_AUXDATA on raw socket"); | 1097 | log1s("can't set PACKET_AUXDATA on raw socket"); |
1097 | } | 1098 | } |
1098 | 1099 | ||
1099 | log1s("created raw socket"); | ||
1100 | |||
1101 | return fd; | 1100 | return fd; |
1102 | } | 1101 | } |
1103 | 1102 | ||
@@ -1126,6 +1125,8 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip) | |||
1126 | char buffer[sizeof("255.255.255.255")]; | 1125 | char buffer[sizeof("255.255.255.255")]; |
1127 | struct in_addr temp_addr; | 1126 | struct in_addr temp_addr; |
1128 | 1127 | ||
1128 | change_listen_mode(LISTEN_NONE); | ||
1129 | |||
1129 | /* send release packet */ | 1130 | /* send release packet */ |
1130 | if (client_data.state == BOUND | 1131 | if (client_data.state == BOUND |
1131 | || client_data.state == RENEWING | 1132 | || client_data.state == RENEWING |
@@ -1146,23 +1147,10 @@ static void perform_release(uint32_t server_addr, uint32_t requested_ip) | |||
1146 | * Users requested to be notified in all cases, even if not in one | 1147 | * Users requested to be notified in all cases, even if not in one |
1147 | * of the states above. | 1148 | * of the states above. |
1148 | */ | 1149 | */ |
1149 | udhcp_run_script(NULL, "deconfig"); | 1150 | d4_run_script_deconfig(); |
1150 | |||
1151 | change_listen_mode(LISTEN_NONE); | ||
1152 | client_data.state = RELEASED; | 1151 | client_data.state = RELEASED; |
1153 | } | 1152 | } |
1154 | 1153 | ||
1155 | static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) | ||
1156 | { | ||
1157 | uint8_t *storage; | ||
1158 | int len = strnlen(str, 255); | ||
1159 | storage = xzalloc(len + extra + OPT_DATA); | ||
1160 | storage[OPT_CODE] = code; | ||
1161 | storage[OPT_LEN] = len + extra; | ||
1162 | memcpy(storage + extra + OPT_DATA, str, len); | ||
1163 | return storage; | ||
1164 | } | ||
1165 | |||
1166 | #if BB_MMU | 1154 | #if BB_MMU |
1167 | static void client_background(void) | 1155 | static void client_background(void) |
1168 | { | 1156 | { |
@@ -1227,10 +1215,10 @@ int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | |||
1227 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) | 1215 | int udhcpc_main(int argc UNUSED_PARAM, char **argv) |
1228 | { | 1216 | { |
1229 | uint8_t *message; | 1217 | uint8_t *message; |
1230 | const char *str_V, *str_h, *str_F, *str_r; | 1218 | const char *str_V, *str_F, *str_r; |
1231 | IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) | 1219 | IF_FEATURE_UDHCPC_ARPING(const char *str_a = "2000";) |
1232 | IF_FEATURE_UDHCP_PORT(char *str_P;) | 1220 | IF_FEATURE_UDHCP_PORT(char *str_P;) |
1233 | void *clientid_mac_ptr; | 1221 | uint8_t *clientid_mac_ptr; |
1234 | llist_t *list_O = NULL; | 1222 | llist_t *list_O = NULL; |
1235 | llist_t *list_x = NULL; | 1223 | llist_t *list_x = NULL; |
1236 | int tryagain_timeout = 20; | 1224 | int tryagain_timeout = 20; |
@@ -1263,14 +1251,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1263 | /* Parse command line */ | 1251 | /* Parse command line */ |
1264 | opt = getopt32long(argv, "^" | 1252 | opt = getopt32long(argv, "^" |
1265 | /* O,x: list; -T,-t,-A take numeric param */ | 1253 | /* O,x: list; -T,-t,-A take numeric param */ |
1266 | "CV:H:h:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" | 1254 | "CV:F:i:np:qRr:s:T:+t:+SA:+O:*ox:*fB" |
1267 | USE_FOR_MMU("b") | 1255 | USE_FOR_MMU("b") |
1268 | IF_FEATURE_UDHCPC_ARPING("a::") | 1256 | IF_FEATURE_UDHCPC_ARPING("a::") |
1269 | IF_FEATURE_UDHCP_PORT("P:") | 1257 | IF_FEATURE_UDHCP_PORT("P:") |
1270 | "v" | 1258 | "v" |
1271 | "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ | 1259 | "\0" IF_UDHCP_VERBOSE("vv") /* -v is a counter */ |
1272 | , udhcpc_longopts | 1260 | , udhcpc_longopts |
1273 | , &str_V, &str_h, &str_h, &str_F | 1261 | , &str_V, &str_F |
1274 | , &client_data.interface, &client_data.pidfile /* i,p */ | 1262 | , &client_data.interface, &client_data.pidfile /* i,p */ |
1275 | , &str_r /* r */ | 1263 | , &str_r /* r */ |
1276 | , &client_data.script /* s */ | 1264 | , &client_data.script /* s */ |
@@ -1281,14 +1269,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1281 | IF_FEATURE_UDHCP_PORT(, &str_P) | 1269 | IF_FEATURE_UDHCP_PORT(, &str_P) |
1282 | IF_UDHCP_VERBOSE(, &dhcp_verbose) | 1270 | IF_UDHCP_VERBOSE(, &dhcp_verbose) |
1283 | ); | 1271 | ); |
1284 | if (opt & (OPT_h|OPT_H)) { | ||
1285 | //msg added 2011-11 | ||
1286 | bb_simple_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); | ||
1287 | client_data.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); | ||
1288 | } | ||
1289 | if (opt & OPT_F) { | 1272 | if (opt & OPT_F) { |
1273 | char *p; | ||
1274 | unsigned len; | ||
1290 | /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ | 1275 | /* FQDN option format: [0x51][len][flags][0][0]<fqdn> */ |
1291 | client_data.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); | 1276 | len = strlen(str_F); |
1277 | p = udhcp_insert_new_option( | ||
1278 | &client_data.options, DHCP_FQDN, | ||
1279 | len + 3, /*dhcp6:*/ 0); | ||
1292 | /* Flag bits: 0000NEOS | 1280 | /* Flag bits: 0000NEOS |
1293 | * S: 1 = Client requests server to update A RR in DNS as well as PTR | 1281 | * S: 1 = Client requests server to update A RR in DNS as well as PTR |
1294 | * O: 1 = Server indicates to client that DNS has been updated regardless | 1282 | * O: 1 = Server indicates to client that DNS has been updated regardless |
@@ -1297,9 +1285,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1297 | * N: 1 = Client requests server to not update DNS (S must be 0 then) | 1285 | * N: 1 = Client requests server to not update DNS (S must be 0 then) |
1298 | * Two [0] bytes which follow are deprecated and must be 0. | 1286 | * Two [0] bytes which follow are deprecated and must be 0. |
1299 | */ | 1287 | */ |
1300 | client_data.fqdn[OPT_DATA + 0] = 0x1; | 1288 | p[OPT_DATA + 0] = 0x1; |
1301 | /*client_data.fqdn[OPT_DATA + 1] = 0; - xzalloc did it */ | 1289 | /*p[OPT_DATA + 1] = 0; - xzalloc did it */ |
1302 | /*client_data.fqdn[OPT_DATA + 2] = 0; */ | 1290 | /*p[OPT_DATA + 2] = 0; */ |
1291 | memcpy(p + OPT_DATA + 3, str_F, len); /* do not store NUL byte */ | ||
1303 | } | 1292 | } |
1304 | if (opt & OPT_r) | 1293 | if (opt & OPT_r) |
1305 | requested_ip = inet_addr(str_r); | 1294 | requested_ip = inet_addr(str_r); |
@@ -1335,7 +1324,29 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1335 | ); | 1324 | ); |
1336 | free(optstr); | 1325 | free(optstr); |
1337 | } | 1326 | } |
1327 | if (str_V[0] != '\0') { | ||
1328 | char *p; | ||
1329 | unsigned len = strnlen(str_V, 254); | ||
1330 | p = udhcp_insert_new_option( | ||
1331 | &client_data.options, DHCP_VENDOR, | ||
1332 | len, /*dhcp6:*/ 0); | ||
1333 | memcpy(p + OPT_DATA, str_V, len); /* do not store NUL byte */ | ||
1334 | } | ||
1335 | |||
1336 | clientid_mac_ptr = NULL; | ||
1337 | if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) { | ||
1338 | /* not suppressed and not set, create default client ID */ | ||
1339 | clientid_mac_ptr = udhcp_insert_new_option( | ||
1340 | &client_data.options, DHCP_CLIENT_ID, | ||
1341 | 1 + 6, /*dhcp6:*/ 0); | ||
1342 | clientid_mac_ptr[OPT_DATA] = 1; /* type: ethernet */ | ||
1343 | clientid_mac_ptr += OPT_DATA + 1; /* skip option code, len, ethernet */ | ||
1344 | } | ||
1338 | 1345 | ||
1346 | /* Not really necessary (we redo it on every iteration) | ||
1347 | * but allows early (before daemonization) detection | ||
1348 | * of bad interface name. | ||
1349 | */ | ||
1339 | if (udhcp_read_interface(client_data.interface, | 1350 | if (udhcp_read_interface(client_data.interface, |
1340 | &client_data.ifindex, | 1351 | &client_data.ifindex, |
1341 | NULL, | 1352 | NULL, |
@@ -1344,24 +1355,6 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1344 | return 1; | 1355 | return 1; |
1345 | } | 1356 | } |
1346 | 1357 | ||
1347 | clientid_mac_ptr = NULL; | ||
1348 | if (!(opt & OPT_C) && !udhcp_find_option(client_data.options, DHCP_CLIENT_ID)) { | ||
1349 | /* not suppressed and not set, set the default client ID */ | ||
1350 | client_data.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); | ||
1351 | client_data.clientid[OPT_DATA] = 1; /* type: ethernet */ | ||
1352 | clientid_mac_ptr = client_data.clientid + OPT_DATA+1; | ||
1353 | memcpy(clientid_mac_ptr, client_data.client_mac, 6); | ||
1354 | } | ||
1355 | if (str_V[0] != '\0') { | ||
1356 | // can drop -V, str_V, client_data.vendorclass, | ||
1357 | // but need to add "vendor" to the list of recognized | ||
1358 | // string opts for this to work; | ||
1359 | // and need to tweak add_client_options() too... | ||
1360 | // ...so the question is, should we? | ||
1361 | //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); | ||
1362 | client_data.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); | ||
1363 | } | ||
1364 | |||
1365 | #if !BB_MMU | 1358 | #if !BB_MMU |
1366 | /* on NOMMU reexec (i.e., background) early */ | 1359 | /* on NOMMU reexec (i.e., background) early */ |
1367 | if (!(opt & OPT_f)) { | 1360 | if (!(opt & OPT_f)) { |
@@ -1382,8 +1375,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1382 | srand(monotonic_us()); | 1375 | srand(monotonic_us()); |
1383 | 1376 | ||
1384 | client_data.state = INIT_SELECTING; | 1377 | client_data.state = INIT_SELECTING; |
1385 | udhcp_run_script(NULL, "deconfig"); | 1378 | d4_run_script_deconfig(); |
1386 | change_listen_mode(LISTEN_RAW); | ||
1387 | packet_num = 0; | 1379 | packet_num = 0; |
1388 | timeout = 0; | 1380 | timeout = 0; |
1389 | lease_remaining = 0; | 1381 | lease_remaining = 0; |
@@ -1417,14 +1409,17 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1417 | log1("waiting %u seconds", timeout); | 1409 | log1("waiting %u seconds", timeout); |
1418 | diff = (unsigned)monotonic_sec(); | 1410 | diff = (unsigned)monotonic_sec(); |
1419 | retval = poll(pfds, 2, timeout * 1000); | 1411 | retval = poll(pfds, 2, timeout * 1000); |
1412 | diff = (unsigned)monotonic_sec() - diff; | ||
1413 | lease_remaining -= diff; | ||
1414 | if (lease_remaining < 0) | ||
1415 | lease_remaining = 0; | ||
1416 | timeout -= diff; | ||
1417 | if (timeout < 0) | ||
1418 | timeout = 0; | ||
1419 | |||
1420 | if (retval < 0) { | 1420 | if (retval < 0) { |
1421 | /* EINTR? A signal was caught, don't panic */ | 1421 | /* EINTR? A signal was caught, don't panic */ |
1422 | if (errno == EINTR) { | 1422 | if (errno == EINTR) { |
1423 | diff = (unsigned)monotonic_sec() - diff; | ||
1424 | lease_remaining -= diff; | ||
1425 | if (lease_remaining < 0) | ||
1426 | lease_remaining = 0; | ||
1427 | timeout -= diff; | ||
1428 | continue; | 1423 | continue; |
1429 | } | 1424 | } |
1430 | /* Else: an error occurred, panic! */ | 1425 | /* Else: an error occurred, panic! */ |
@@ -1454,8 +1449,10 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1454 | switch (client_data.state) { | 1449 | switch (client_data.state) { |
1455 | case INIT_SELECTING: | 1450 | case INIT_SELECTING: |
1456 | if (!discover_retries || packet_num < discover_retries) { | 1451 | if (!discover_retries || packet_num < discover_retries) { |
1457 | if (packet_num == 0) | 1452 | if (packet_num == 0) { |
1453 | change_listen_mode(LISTEN_RAW); | ||
1458 | xid = random_xid(); | 1454 | xid = random_xid(); |
1455 | } | ||
1459 | /* broadcast */ | 1456 | /* broadcast */ |
1460 | send_discover(xid, requested_ip); | 1457 | send_discover(xid, requested_ip); |
1461 | timeout = discover_timeout; | 1458 | timeout = discover_timeout; |
@@ -1463,7 +1460,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1463 | continue; | 1460 | continue; |
1464 | } | 1461 | } |
1465 | leasefail: | 1462 | leasefail: |
1466 | udhcp_run_script(NULL, "leasefail"); | 1463 | change_listen_mode(LISTEN_NONE); |
1464 | d4_run_script(NULL, "leasefail"); | ||
1467 | #if BB_MMU /* -b is not supported on NOMMU */ | 1465 | #if BB_MMU /* -b is not supported on NOMMU */ |
1468 | if (opt & OPT_b) { /* background if no lease */ | 1466 | if (opt & OPT_b) { /* background if no lease */ |
1469 | bb_simple_info_msg("no lease, forking to background"); | 1467 | bb_simple_info_msg("no lease, forking to background"); |
@@ -1483,7 +1481,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1483 | retval = 1; | 1481 | retval = 1; |
1484 | goto ret; | 1482 | goto ret; |
1485 | } | 1483 | } |
1486 | /* wait before trying again */ | 1484 | /* Wait before trying again */ |
1487 | timeout = tryagain_timeout; | 1485 | timeout = tryagain_timeout; |
1488 | packet_num = 0; | 1486 | packet_num = 0; |
1489 | continue; | 1487 | continue; |
@@ -1499,22 +1497,20 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1499 | * "discover...select...discover..." loops | 1497 | * "discover...select...discover..." loops |
1500 | * were seen in the wild. Treat them similarly | 1498 | * were seen in the wild. Treat them similarly |
1501 | * to "no response to discover" case */ | 1499 | * to "no response to discover" case */ |
1502 | change_listen_mode(LISTEN_RAW); | ||
1503 | client_data.state = INIT_SELECTING; | 1500 | client_data.state = INIT_SELECTING; |
1504 | goto leasefail; | 1501 | goto leasefail; |
1505 | case BOUND: | 1502 | case BOUND: |
1506 | /* 1/2 lease passed, enter renewing state */ | 1503 | /* 1/2 lease passed, enter renewing state */ |
1507 | client_data.state = RENEWING; | 1504 | client_data.state = RENEWING; |
1508 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1505 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1509 | change_listen_mode(LISTEN_KERNEL); | 1506 | got_SIGUSR1: |
1510 | log1s("entering renew state"); | 1507 | log1s("entering renew state"); |
1508 | change_listen_mode(LISTEN_KERNEL); | ||
1511 | /* fall right through */ | 1509 | /* fall right through */ |
1512 | case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ | 1510 | case RENEW_REQUESTED: /* in manual (SIGUSR1) renew */ |
1513 | case_RENEW_REQUESTED: | ||
1514 | case RENEWING: | 1511 | case RENEWING: |
1515 | if (packet_num < 3) { | 1512 | if (packet_num == 0) { |
1516 | packet_num++; | 1513 | /* Send an unicast renew request */ |
1517 | /* send an unicast renew request */ | ||
1518 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind | 1514 | /* Sometimes observed to fail (EADDRNOTAVAIL) to bind |
1519 | * a new UDP socket for sending inside send_renew. | 1515 | * a new UDP socket for sending inside send_renew. |
1520 | * I hazard to guess existing listening socket | 1516 | * I hazard to guess existing listening socket |
@@ -1525,7 +1521,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1525 | */ | 1521 | */ |
1526 | if (send_renew(xid, server_addr, requested_ip) >= 0) { | 1522 | if (send_renew(xid, server_addr, requested_ip) >= 0) { |
1527 | timeout = discover_timeout; | 1523 | timeout = discover_timeout; |
1528 | /* ^^^ used to be = lease_remaining / 2 - WAY too long */ | 1524 | packet_num++; |
1529 | continue; | 1525 | continue; |
1530 | } | 1526 | } |
1531 | /* else: error sending. | 1527 | /* else: error sending. |
@@ -1533,27 +1529,34 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1533 | * which gave us bogus server ID 1.1.1.1 | 1529 | * which gave us bogus server ID 1.1.1.1 |
1534 | * which wasn't reachable (and probably did not exist). | 1530 | * which wasn't reachable (and probably did not exist). |
1535 | */ | 1531 | */ |
1532 | } /* else: we had sent one packet, but got no reply */ | ||
1533 | log1s("no response to renew"); | ||
1534 | if (lease_remaining > 30) { | ||
1535 | /* Some lease time remains, try to renew later */ | ||
1536 | change_listen_mode(LISTEN_NONE); | ||
1537 | goto BOUND_for_half_lease; | ||
1536 | } | 1538 | } |
1537 | //TODO: if 3 renew's failed (no reply) but remaining lease is large, | 1539 | /* Enter rebinding state */ |
1538 | //it might make sense to make a large pause (~1 hour?) and try later? | ||
1539 | /* Timed out or error, enter rebinding state */ | ||
1540 | log1s("entering rebinding state"); | ||
1541 | client_data.state = REBINDING; | 1540 | client_data.state = REBINDING; |
1542 | /* fall right through */ | 1541 | log1s("entering rebinding state"); |
1543 | case REBINDING: | ||
1544 | /* Switch to bcast receive */ | 1542 | /* Switch to bcast receive */ |
1545 | change_listen_mode(LISTEN_RAW); | 1543 | change_listen_mode(LISTEN_RAW); |
1544 | packet_num = 0; | ||
1545 | /* fall right through */ | ||
1546 | case REBINDING: | ||
1546 | /* Lease is *really* about to run out, | 1547 | /* Lease is *really* about to run out, |
1547 | * try to find DHCP server using broadcast */ | 1548 | * try to find DHCP server using broadcast */ |
1548 | if (lease_remaining > 0) { | 1549 | if (lease_remaining > 0 && packet_num < 3) { |
1549 | /* send a broadcast renew request */ | 1550 | /* send a broadcast renew request */ |
1550 | send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); | 1551 | send_renew(xid, 0 /*INADDR_ANY*/, requested_ip); |
1551 | timeout = discover_timeout; | 1552 | timeout = discover_timeout; |
1553 | packet_num++; | ||
1552 | continue; | 1554 | continue; |
1553 | } | 1555 | } |
1554 | /* Timed out, enter init state */ | 1556 | /* Timed out, enter init state */ |
1557 | change_listen_mode(LISTEN_NONE); | ||
1555 | bb_simple_info_msg("lease lost, entering init state"); | 1558 | bb_simple_info_msg("lease lost, entering init state"); |
1556 | udhcp_run_script(NULL, "deconfig"); | 1559 | d4_run_script_deconfig(); |
1557 | client_data.state = INIT_SELECTING; | 1560 | client_data.state = INIT_SELECTING; |
1558 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1561 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1559 | timeout = 0; | 1562 | timeout = 0; |
@@ -1561,7 +1564,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1561 | continue; | 1564 | continue; |
1562 | /* case RELEASED: */ | 1565 | /* case RELEASED: */ |
1563 | } | 1566 | } |
1564 | /* yah, I know, *you* say it would never happen */ | 1567 | /* RELEASED state (when we got SIGUSR2) ends up here. |
1568 | * (wait for SIGUSR1 to re-init, or for TERM, etc) | ||
1569 | */ | ||
1565 | timeout = INT_MAX; | 1570 | timeout = INT_MAX; |
1566 | continue; /* back to main loop */ | 1571 | continue; /* back to main loop */ |
1567 | } /* if poll timed out */ | 1572 | } /* if poll timed out */ |
@@ -1571,33 +1576,42 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1571 | /* Is it a signal? */ | 1576 | /* Is it a signal? */ |
1572 | switch (udhcp_sp_read()) { | 1577 | switch (udhcp_sp_read()) { |
1573 | case SIGUSR1: | 1578 | case SIGUSR1: |
1579 | if (client_data.state <= REQUESTING) | ||
1580 | /* Initial negotiations in progress, do not disturb */ | ||
1581 | break; | ||
1582 | if (client_data.state == REBINDING) | ||
1583 | /* Do not go back from rebind to renew state */ | ||
1584 | break; | ||
1585 | |||
1586 | if (lease_remaining > 30) /* if renew fails, do not go back to BOUND */ | ||
1587 | lease_remaining = 30; | ||
1574 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1588 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1575 | bb_simple_info_msg("performing DHCP renew"); | 1589 | packet_num = 0; |
1576 | 1590 | ||
1577 | switch (client_data.state) { | 1591 | switch (client_data.state) { |
1578 | /* Try to renew/rebind */ | ||
1579 | case BOUND: | 1592 | case BOUND: |
1580 | case RENEWING: | 1593 | case RENEWING: |
1581 | case REBINDING: | 1594 | /* Try to renew/rebind */ |
1582 | change_listen_mode(LISTEN_KERNEL); | ||
1583 | client_data.state = RENEW_REQUESTED; | 1595 | client_data.state = RENEW_REQUESTED; |
1584 | goto case_RENEW_REQUESTED; | 1596 | goto got_SIGUSR1; |
1585 | 1597 | ||
1586 | /* Start things over */ | 1598 | case RENEW_REQUESTED: |
1587 | case RENEW_REQUESTED: /* two or more SIGUSR1 received */ | 1599 | /* Two SIGUSR1 received, start things over */ |
1588 | udhcp_run_script(NULL, "deconfig"); | 1600 | change_listen_mode(LISTEN_NONE); |
1589 | /* case REQUESTING: break; */ | 1601 | d4_run_script_deconfig(); |
1590 | /* case RELEASED: break; */ | 1602 | |
1591 | /* case INIT_SELECTING: break; */ | 1603 | default: |
1604 | /* case RELEASED: */ | ||
1605 | /* Wake from SIGUSR2-induced deconfigured state */ | ||
1606 | change_listen_mode(LISTEN_NONE); | ||
1592 | } | 1607 | } |
1593 | change_listen_mode(LISTEN_RAW); | ||
1594 | client_data.state = INIT_SELECTING; | 1608 | client_data.state = INIT_SELECTING; |
1595 | packet_num = 0; | ||
1596 | /* Kill any timeouts, user wants this to hurry along */ | 1609 | /* Kill any timeouts, user wants this to hurry along */ |
1597 | timeout = 0; | 1610 | timeout = 0; |
1598 | continue; | 1611 | continue; |
1599 | case SIGUSR2: | 1612 | case SIGUSR2: |
1600 | perform_release(server_addr, requested_ip); | 1613 | perform_release(server_addr, requested_ip); |
1614 | /* ^^^ switches to LISTEN_NONE */ | ||
1601 | timeout = INT_MAX; | 1615 | timeout = INT_MAX; |
1602 | continue; | 1616 | continue; |
1603 | case SIGTERM: | 1617 | case SIGTERM: |
@@ -1616,7 +1630,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1616 | if (client_data.listen_mode == LISTEN_KERNEL) | 1630 | if (client_data.listen_mode == LISTEN_KERNEL) |
1617 | len = udhcp_recv_kernel_packet(&packet, client_data.sockfd); | 1631 | len = udhcp_recv_kernel_packet(&packet, client_data.sockfd); |
1618 | else | 1632 | else |
1619 | len = udhcp_recv_raw_packet(&packet, client_data.sockfd); | 1633 | len = d4_recv_raw_packet(&packet, client_data.sockfd); |
1620 | if (len == -1) { | 1634 | if (len == -1) { |
1621 | /* Error is severe, reopen socket */ | 1635 | /* Error is severe, reopen socket */ |
1622 | bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO); | 1636 | bb_error_msg("read error: "STRERROR_FMT", reopening socket" STRERROR_ERRNO); |
@@ -1640,13 +1654,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1640 | || memcmp(packet.chaddr, client_data.client_mac, 6) != 0 | 1654 | || memcmp(packet.chaddr, client_data.client_mac, 6) != 0 |
1641 | ) { | 1655 | ) { |
1642 | //FIXME: need to also check that last 10 bytes are zero | 1656 | //FIXME: need to also check that last 10 bytes are zero |
1643 | log1("chaddr does not match%s", ", ignoring packet"); // log2? | 1657 | log1("chaddr does not match%s", ", ignoring packet"); |
1644 | continue; | 1658 | continue; |
1645 | } | 1659 | } |
1646 | 1660 | ||
1647 | message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); | 1661 | message = udhcp_get_option(&packet, DHCP_MESSAGE_TYPE); |
1648 | if (message == NULL) { | 1662 | if (message == NULL) { |
1649 | bb_info_msg("no message type option%s", ", ignoring packet"); | 1663 | log1("no message type option%s", ", ignoring packet"); |
1650 | continue; | 1664 | continue; |
1651 | } | 1665 | } |
1652 | 1666 | ||
@@ -1654,6 +1668,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1654 | case INIT_SELECTING: | 1668 | case INIT_SELECTING: |
1655 | /* Must be a DHCPOFFER */ | 1669 | /* Must be a DHCPOFFER */ |
1656 | if (*message == DHCPOFFER) { | 1670 | if (*message == DHCPOFFER) { |
1671 | struct in_addr temp_addr; | ||
1657 | uint8_t *temp; | 1672 | uint8_t *temp; |
1658 | 1673 | ||
1659 | /* What exactly is server's IP? There are several values. | 1674 | /* What exactly is server's IP? There are several values. |
@@ -1689,7 +1704,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1689 | move_from_unaligned32(server_addr, temp); | 1704 | move_from_unaligned32(server_addr, temp); |
1690 | } | 1705 | } |
1691 | /*xid = packet.xid; - already is */ | 1706 | /*xid = packet.xid; - already is */ |
1692 | requested_ip = packet.yiaddr; | 1707 | temp_addr.s_addr = requested_ip = packet.yiaddr; |
1708 | log1("received offer of %s", inet_ntoa(temp_addr)); | ||
1693 | 1709 | ||
1694 | /* enter requesting state */ | 1710 | /* enter requesting state */ |
1695 | client_data.state = REQUESTING; | 1711 | client_data.state = REQUESTING; |
@@ -1707,14 +1723,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1707 | char server_str[sizeof("255.255.255.255")]; | 1723 | char server_str[sizeof("255.255.255.255")]; |
1708 | uint8_t *temp; | 1724 | uint8_t *temp; |
1709 | 1725 | ||
1726 | change_listen_mode(LISTEN_NONE); | ||
1727 | |||
1710 | temp_addr.s_addr = server_addr; | 1728 | temp_addr.s_addr = server_addr; |
1711 | strcpy(server_str, inet_ntoa(temp_addr)); | 1729 | strcpy(server_str, inet_ntoa(temp_addr)); |
1712 | temp_addr.s_addr = packet.yiaddr; | 1730 | temp_addr.s_addr = packet.yiaddr; |
1713 | 1731 | ||
1732 | lease_remaining = 60 * 60; | ||
1714 | temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); | 1733 | temp = udhcp_get_option32(&packet, DHCP_LEASE_TIME); |
1715 | if (!temp) { | 1734 | if (temp) { |
1716 | lease_remaining = 60 * 60; | ||
1717 | } else { | ||
1718 | uint32_t lease; | 1735 | uint32_t lease; |
1719 | /* it IS unaligned sometimes, don't "optimize" */ | 1736 | /* it IS unaligned sometimes, don't "optimize" */ |
1720 | move_from_unaligned32(lease, temp); | 1737 | move_from_unaligned32(lease, temp); |
@@ -1758,8 +1775,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1758 | send_decline(/*xid,*/ server_addr, packet.yiaddr); | 1775 | send_decline(/*xid,*/ server_addr, packet.yiaddr); |
1759 | 1776 | ||
1760 | if (client_data.state != REQUESTING) | 1777 | if (client_data.state != REQUESTING) |
1761 | udhcp_run_script(NULL, "deconfig"); | 1778 | d4_run_script_deconfig(); |
1762 | change_listen_mode(LISTEN_RAW); | ||
1763 | client_data.state = INIT_SELECTING; | 1779 | client_data.state = INIT_SELECTING; |
1764 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1780 | client_data.first_secs = 0; /* make secs field count from 0 */ |
1765 | requested_ip = 0; | 1781 | requested_ip = 0; |
@@ -1769,17 +1785,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1769 | } | 1785 | } |
1770 | } | 1786 | } |
1771 | #endif | 1787 | #endif |
1772 | |||
1773 | /* enter bound state */ | 1788 | /* enter bound state */ |
1774 | start = monotonic_sec(); | 1789 | start = monotonic_sec(); |
1775 | udhcp_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); | 1790 | d4_run_script(&packet, client_data.state == REQUESTING ? "bound" : "renew"); |
1776 | timeout = (unsigned)lease_remaining / 2; | 1791 | lease_remaining -= (unsigned)monotonic_sec() - start; |
1777 | //TODO: why / 2? | 1792 | if (lease_remaining < 0) |
1778 | timeout -= (unsigned)monotonic_sec() - start; | 1793 | lease_remaining = 0; |
1779 | packet_num = 0; | ||
1780 | |||
1781 | client_data.state = BOUND; | ||
1782 | change_listen_mode(LISTEN_NONE); | ||
1783 | if (opt & OPT_q) { /* quit after lease */ | 1794 | if (opt & OPT_q) { /* quit after lease */ |
1784 | goto ret0; | 1795 | goto ret0; |
1785 | } | 1796 | } |
@@ -1792,9 +1803,12 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1792 | opt = ((opt & ~OPT_b) | OPT_f); | 1803 | opt = ((opt & ~OPT_b) | OPT_f); |
1793 | } | 1804 | } |
1794 | #endif | 1805 | #endif |
1806 | BOUND_for_half_lease: | ||
1807 | timeout = (unsigned)lease_remaining / 2; | ||
1808 | client_data.state = BOUND; | ||
1795 | /* make future renew packets use different xid */ | 1809 | /* make future renew packets use different xid */ |
1796 | /* xid = random_xid(); ...but why bother? */ | 1810 | /* xid = random_xid(); ...but why bother? */ |
1797 | 1811 | packet_num = 0; | |
1798 | continue; /* back to main loop */ | 1812 | continue; /* back to main loop */ |
1799 | } | 1813 | } |
1800 | if (*message == DHCPNAK) { | 1814 | if (*message == DHCPNAK) { |
@@ -1818,11 +1832,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) | |||
1818 | goto non_matching_svid; | 1832 | goto non_matching_svid; |
1819 | } | 1833 | } |
1820 | /* return to init state */ | 1834 | /* return to init state */ |
1835 | change_listen_mode(LISTEN_NONE); | ||
1821 | bb_info_msg("received %s", "DHCP NAK"); | 1836 | bb_info_msg("received %s", "DHCP NAK"); |
1822 | udhcp_run_script(&packet, "nak"); | 1837 | d4_run_script(&packet, "nak"); |
1823 | if (client_data.state != REQUESTING) | 1838 | if (client_data.state != REQUESTING) |
1824 | udhcp_run_script(NULL, "deconfig"); | 1839 | d4_run_script_deconfig(); |
1825 | change_listen_mode(LISTEN_RAW); | ||
1826 | sleep(3); /* avoid excessive network traffic */ | 1840 | sleep(3); /* avoid excessive network traffic */ |
1827 | client_data.state = INIT_SELECTING; | 1841 | client_data.state = INIT_SELECTING; |
1828 | client_data.first_secs = 0; /* make secs field count from 0 */ | 1842 | client_data.first_secs = 0; /* make secs field count from 0 */ |
diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 7ad01ea8f..cd9ead6bd 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h | |||
@@ -17,10 +17,6 @@ struct client_data_t { | |||
17 | char *pidfile; /* Optionally store the process ID */ | 17 | char *pidfile; /* Optionally store the process ID */ |
18 | const char *script; /* User script to run at dhcp events */ | 18 | const char *script; /* User script to run at dhcp events */ |
19 | struct option_set *options; /* list of DHCP options to send to server */ | 19 | struct option_set *options; /* list of DHCP options to send to server */ |
20 | uint8_t *clientid; /* Optional client id to use */ | ||
21 | uint8_t *vendorclass; /* Optional vendor class-id to use */ | ||
22 | uint8_t *hostname; /* Optional hostname to use */ | ||
23 | uint8_t *fqdn; /* Optional fully qualified domain name to use */ | ||
24 | llist_t *envp; /* list of DHCP options used for env vars */ | 20 | llist_t *envp; /* list of DHCP options used for env vars */ |
25 | 21 | ||
26 | unsigned first_secs; | 22 | unsigned first_secs; |
diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 260130507..91f70970a 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c | |||
@@ -295,12 +295,11 @@ static uint32_t find_free_or_expired_nip(const uint8_t *safe_mac, unsigned arppi | |||
295 | uint32_t nip; | 295 | uint32_t nip; |
296 | struct dyn_lease *lease; | 296 | struct dyn_lease *lease; |
297 | 297 | ||
298 | /* ie, 192.168.55.0 */ | 298 | /* (Addresses ending in .0 or .255 can legitimately be allocated |
299 | if ((addr & 0xff) == 0) | 299 | * in various situations, so _don't_ skip these. The user needs |
300 | goto next_addr; | 300 | * to choose start_ip and end_ip correctly for a particular |
301 | /* ie, 192.168.55.255 */ | 301 | * network environment.) */ |
302 | if ((addr & 0xff) == 0xff) | 302 | |
303 | goto next_addr; | ||
304 | nip = htonl(addr); | 303 | nip = htonl(addr); |
305 | /* skip our own address */ | 304 | /* skip our own address */ |
306 | if (nip == server_data.server_nip) | 305 | if (nip == server_data.server_nip) |
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 4d8e005d4..78f580ce9 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c | |||
@@ -95,7 +95,8 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) | |||
95 | bb_simple_info_msg("packet with bad magic, ignoring"); | 95 | bb_simple_info_msg("packet with bad magic, ignoring"); |
96 | return -2; | 96 | return -2; |
97 | } | 97 | } |
98 | log1("received %s", "a packet"); | 98 | log2("received %s", "a packet"); |
99 | /* log2 because more informative msg for valid packets is printed later at log1 level */ | ||
99 | udhcp_dump_packet(packet); | 100 | udhcp_dump_packet(packet); |
100 | 101 | ||
101 | return bytes; | 102 | return bytes; |
diff --git a/networking/udhcp/socket.c b/networking/udhcp/socket.c index 65a1a8ead..35e10688b 100644 --- a/networking/udhcp/socket.c +++ b/networking/udhcp/socket.c | |||
@@ -82,7 +82,7 @@ int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) | |||
82 | struct sockaddr_in addr; | 82 | struct sockaddr_in addr; |
83 | char *colon; | 83 | char *colon; |
84 | 84 | ||
85 | log1("opening listen socket on *:%d %s", port, inf); | 85 | log2("opening listen socket on *:%d %s", port, inf); |
86 | fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); | 86 | fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); |
87 | 87 | ||
88 | setsockopt_reuseaddr(fd); | 88 | setsockopt_reuseaddr(fd); |
diff --git a/runit/runsv.c b/runit/runsv.c index ecab8cdf5..a4b8af494 100644 --- a/runit/runsv.c +++ b/runit/runsv.c | |||
@@ -149,17 +149,18 @@ static void warn_cannot(const char *m) | |||
149 | warn2_cannot(m, ""); | 149 | warn2_cannot(m, ""); |
150 | } | 150 | } |
151 | 151 | ||
152 | static void s_child(int sig_no UNUSED_PARAM) | 152 | /* SIGCHLD/TERM handler is reentrancy-safe because they are unmasked |
153 | * only over poll() call, not over memory allocations | ||
154 | * or printouts. Do not need to save/restore errno either, | ||
155 | * as poll() error is not checked there. | ||
156 | */ | ||
157 | static void s_chld_term(int sig_no) | ||
153 | { | 158 | { |
159 | if (sig_no == SIGTERM) | ||
160 | sigterm = 1; | ||
154 | write(selfpipe.wr, "", 1); | 161 | write(selfpipe.wr, "", 1); |
155 | } | 162 | } |
156 | 163 | ||
157 | static void s_term(int sig_no UNUSED_PARAM) | ||
158 | { | ||
159 | sigterm = 1; | ||
160 | write(selfpipe.wr, "", 1); /* XXX */ | ||
161 | } | ||
162 | |||
163 | static int open_trunc_or_warn(const char *name) | 164 | static int open_trunc_or_warn(const char *name) |
164 | { | 165 | { |
165 | /* Why O_NDELAY? */ | 166 | /* Why O_NDELAY? */ |
@@ -380,11 +381,14 @@ static void startservice(struct svdir *s) | |||
380 | xdup2(logpipe.wr, 1); | 381 | xdup2(logpipe.wr, 1); |
381 | } | 382 | } |
382 | } | 383 | } |
383 | /* Non-ignored signals revert to SIG_DFL on exec anyway */ | 384 | /* Non-ignored signals revert to SIG_DFL on exec. |
384 | /*bb_signals(0 | 385 | * But we can get signals BEFORE execl(), unlikely as that may be. |
385 | + (1 << SIGCHLD) | 386 | * SIGCHLD is safe (would merely write to selfpipe), |
386 | + (1 << SIGTERM) | 387 | * but SIGTERM would set sigterm = 1 (with vfork, we affect parent). |
387 | , SIG_DFL);*/ | 388 | * Avoid that. |
389 | */ | ||
390 | /*signal(SIGCHLD, SIG_DFL);*/ | ||
391 | signal(SIGTERM, SIG_DFL); | ||
388 | sig_unblock(SIGCHLD); | 392 | sig_unblock(SIGCHLD); |
389 | sig_unblock(SIGTERM); | 393 | sig_unblock(SIGTERM); |
390 | execv(arg[0], (char**) arg); | 394 | execv(arg[0], (char**) arg); |
@@ -511,9 +515,15 @@ int runsv_main(int argc UNUSED_PARAM, char **argv) | |||
511 | ndelay_on(selfpipe.wr); | 515 | ndelay_on(selfpipe.wr); |
512 | 516 | ||
513 | sig_block(SIGCHLD); | 517 | sig_block(SIGCHLD); |
514 | bb_signals_recursive_norestart(1 << SIGCHLD, s_child); | ||
515 | sig_block(SIGTERM); | 518 | sig_block(SIGTERM); |
516 | bb_signals_recursive_norestart(1 << SIGTERM, s_term); | 519 | /* No particular reason why we don't set SA_RESTART |
520 | * (poll() wouldn't restart regardless of that flag), | ||
521 | * we just follow what runit-2.1.2 does: | ||
522 | */ | ||
523 | bb_signals_norestart(0 | ||
524 | + (1 << SIGCHLD) | ||
525 | + (1 << SIGTERM) | ||
526 | , s_chld_term); | ||
517 | 527 | ||
518 | xchdir(dir); | 528 | xchdir(dir); |
519 | /* bss: svd[0].pid = 0; */ | 529 | /* bss: svd[0].pid = 0; */ |
@@ -625,6 +635,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv) | |||
625 | sig_unblock(SIGTERM); | 635 | sig_unblock(SIGTERM); |
626 | sig_unblock(SIGCHLD); | 636 | sig_unblock(SIGCHLD); |
627 | poll(x, 2 + haslog, 3600*1000); | 637 | poll(x, 2 + haslog, 3600*1000); |
638 | /* NB: signal handlers can trash errno of poll() */ | ||
628 | sig_block(SIGTERM); | 639 | sig_block(SIGTERM); |
629 | sig_block(SIGCHLD); | 640 | sig_block(SIGCHLD); |
630 | 641 | ||
diff --git a/runit/svlogd.c b/runit/svlogd.c index 294e31aca..02c305696 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c | |||
@@ -412,19 +412,32 @@ static void processorstart(struct logdir *ld) | |||
412 | int fd; | 412 | int fd; |
413 | 413 | ||
414 | /* child */ | 414 | /* child */ |
415 | /* Non-ignored signals revert to SIG_DFL on exec anyway */ | 415 | /* Non-ignored signals revert to SIG_DFL on exec anyway. |
416 | * But we can get signals BEFORE execl(), this is unlikely | ||
417 | * but wouldn't be good... | ||
418 | */ | ||
416 | /*bb_signals(0 | 419 | /*bb_signals(0 |
417 | + (1 << SIGTERM) | 420 | + (1 << SIGTERM) |
421 | //+ (1 << SIGCHLD) | ||
418 | + (1 << SIGALRM) | 422 | + (1 << SIGALRM) |
419 | + (1 << SIGHUP) | 423 | + (1 << SIGHUP) |
420 | , SIG_DFL);*/ | 424 | , SIG_DFL);*/ |
421 | sig_unblock(SIGTERM); | 425 | /* runit 2.1.2 does not unblock SIGCHLD, a bug? we do: */ |
422 | sig_unblock(SIGALRM); | 426 | sigprocmask(SIG_UNBLOCK, &blocked_sigset, NULL); |
423 | sig_unblock(SIGHUP); | ||
424 | 427 | ||
425 | if (verbose) | 428 | if (verbose) |
426 | bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave); | 429 | bb_error_msg(INFO"processing: %s/%s", ld->name, ld->fnsave); |
427 | fd = xopen(ld->fnsave, O_RDONLY|O_NDELAY); | 430 | |
431 | fd = open_or_warn(ld->fnsave, O_RDONLY|O_NDELAY); | ||
432 | /* Used to have xopen() above, but it causes infinite restarts of processor | ||
433 | * if file is gone - which can happen even because of _us_! | ||
434 | * Users report that if on reboot, time is reset to before existing | ||
435 | * logfiles creation time, rmoldest() deletes the newest logfile (!) | ||
436 | * and we end up here trying to open this now-deleted file. | ||
437 | */ | ||
438 | if (fd < 0) | ||
439 | _exit(0); /* fake "success": do not run processor again */ | ||
440 | |||
428 | xmove_fd(fd, 0); | 441 | xmove_fd(fd, 0); |
429 | ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */ | 442 | ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */ |
430 | fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); | 443 | fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); |
@@ -1098,10 +1111,10 @@ int svlogd_main(int argc, char **argv) | |||
1098 | sigaddset(&blocked_sigset, SIGALRM); | 1111 | sigaddset(&blocked_sigset, SIGALRM); |
1099 | sigaddset(&blocked_sigset, SIGHUP); | 1112 | sigaddset(&blocked_sigset, SIGHUP); |
1100 | sigprocmask(SIG_BLOCK, &blocked_sigset, NULL); | 1113 | sigprocmask(SIG_BLOCK, &blocked_sigset, NULL); |
1101 | bb_signals_recursive_norestart(1 << SIGTERM, sig_term_handler); | 1114 | bb_signals_norestart(1 << SIGTERM, sig_term_handler); |
1102 | bb_signals_recursive_norestart(1 << SIGCHLD, sig_child_handler); | 1115 | bb_signals_norestart(1 << SIGCHLD, sig_child_handler); |
1103 | bb_signals_recursive_norestart(1 << SIGALRM, sig_alarm_handler); | 1116 | bb_signals_norestart(1 << SIGALRM, sig_alarm_handler); |
1104 | bb_signals_recursive_norestart(1 << SIGHUP, sig_hangup_handler); | 1117 | bb_signals_norestart(1 << SIGHUP, sig_hangup_handler); |
1105 | 1118 | ||
1106 | /* Without timestamps, we don't have to print each line | 1119 | /* Without timestamps, we don't have to print each line |
1107 | * separately, so we can look for _last_ newline, not first, | 1120 | * separately, so we can look for _last_ newline, not first, |
diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 92de681ac..8b5b15a1b 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh | |||
@@ -4,6 +4,8 @@ | |||
4 | # but users complain that many sed implementations | 4 | # but users complain that many sed implementations |
5 | # are misinterpreting --. | 5 | # are misinterpreting --. |
6 | 6 | ||
7 | export LC_ALL=C | ||
8 | |||
7 | test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } | 9 | test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } |
8 | 10 | ||
9 | # cd to objtree | 11 | # cd to objtree |
diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index d6c1621b8..2f7fa6618 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c | |||
@@ -342,6 +342,8 @@ int conf_write(const char *name) | |||
342 | time_t now; | 342 | time_t now; |
343 | int use_timestamp = 1; | 343 | int use_timestamp = 1; |
344 | char *env; | 344 | char *env; |
345 | char *source_date_epoch; | ||
346 | struct tm *build_time; | ||
345 | 347 | ||
346 | dirname[0] = 0; | 348 | dirname[0] = 0; |
347 | if (name && name[0]) { | 349 | if (name && name[0]) { |
@@ -378,7 +380,16 @@ int conf_write(const char *name) | |||
378 | } | 380 | } |
379 | sym = sym_lookup("KERNELVERSION", 0); | 381 | sym = sym_lookup("KERNELVERSION", 0); |
380 | sym_calc_value(sym); | 382 | sym_calc_value(sym); |
381 | time(&now); | 383 | |
384 | source_date_epoch = getenv("SOURCE_DATE_EPOCH"); | ||
385 | if (source_date_epoch && *source_date_epoch) { | ||
386 | now = strtoull(source_date_epoch, NULL, 10); | ||
387 | build_time = gmtime(&now); | ||
388 | } else { | ||
389 | time(&now); | ||
390 | build_time = localtime(&now); | ||
391 | } | ||
392 | |||
382 | env = getenv("KCONFIG_NOTIMESTAMP"); | 393 | env = getenv("KCONFIG_NOTIMESTAMP"); |
383 | if (env && *env) | 394 | if (env && *env) |
384 | use_timestamp = 0; | 395 | use_timestamp = 0; |
@@ -398,14 +409,14 @@ int conf_write(const char *name) | |||
398 | if (use_timestamp) { | 409 | if (use_timestamp) { |
399 | size_t ret = \ | 410 | size_t ret = \ |
400 | strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " | 411 | strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " |
401 | "\"%Y-%m-%d %H:%M:%S %Z\"\n", localtime(&now)); | 412 | "\"%Y-%m-%d %H:%M:%S %Z\"\n", build_time); |
402 | /* if user has Factory timezone or some other odd install, the | 413 | /* if user has Factory timezone or some other odd install, the |
403 | * %Z above will overflow the string leaving us with undefined | 414 | * %Z above will overflow the string leaving us with undefined |
404 | * results ... so let's try again without the timezone. | 415 | * results ... so let's try again without the timezone. |
405 | */ | 416 | */ |
406 | if (ret == 0) | 417 | if (ret == 0) |
407 | strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " | 418 | strftime(buf, sizeof(buf), "#define AUTOCONF_TIMESTAMP " |
408 | "\"%Y-%m-%d %H:%M:%S\"\n", localtime(&now)); | 419 | "\"%Y-%m-%d %H:%M:%S\"\n", build_time); |
409 | } else { /* bbox */ | 420 | } else { /* bbox */ |
410 | strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n"); | 421 | strcpy(buf, "#define AUTOCONF_TIMESTAMP \"\"\n"); |
411 | } | 422 | } |
diff --git a/shell/ash.c b/shell/ash.c index 3d6f25802..14712ef54 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -262,6 +262,14 @@ | |||
262 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT | 262 | #define BASH_READ_D ENABLE_ASH_BASH_COMPAT |
263 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT | 263 | #define IF_BASH_READ_D IF_ASH_BASH_COMPAT |
264 | #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT | 264 | #define BASH_WAIT_N ENABLE_ASH_BASH_COMPAT |
265 | /* <(...) and >(...) */ | ||
266 | #if HAVE_DEV_FD | ||
267 | # define BASH_PROCESS_SUBST ENABLE_ASH_BASH_COMPAT | ||
268 | # define IF_BASH_PROCESS_SUBST IF_ASH_BASH_COMPAT | ||
269 | #else | ||
270 | # define BASH_PROCESS_SUBST 0 | ||
271 | # define IF_BASH_PROCESS_SUBST(...) | ||
272 | #endif | ||
265 | 273 | ||
266 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 | 274 | #if defined(__ANDROID_API__) && __ANDROID_API__ <= 24 |
267 | /* Bionic at least up to version 24 has no glob() */ | 275 | /* Bionic at least up to version 24 has no glob() */ |
@@ -973,6 +981,12 @@ out2str(const char *p) | |||
973 | #define CTLENDARI ((unsigned char)'\207') | 981 | #define CTLENDARI ((unsigned char)'\207') |
974 | #define CTLQUOTEMARK ((unsigned char)'\210') | 982 | #define CTLQUOTEMARK ((unsigned char)'\210') |
975 | #define CTL_LAST CTLQUOTEMARK | 983 | #define CTL_LAST CTLQUOTEMARK |
984 | #if BASH_PROCESS_SUBST | ||
985 | # define CTLTOPROC ((unsigned char)'\211') | ||
986 | # define CTLFROMPROC ((unsigned char)'\212') | ||
987 | # undef CTL_LAST | ||
988 | # define CTL_LAST CTLFROMPROC | ||
989 | #endif | ||
976 | 990 | ||
977 | /* variable substitution byte (follows CTLVAR) */ | 991 | /* variable substitution byte (follows CTLVAR) */ |
978 | #define VSTYPE 0x0f /* type of variable substitution */ | 992 | #define VSTYPE 0x0f /* type of variable substitution */ |
@@ -1244,6 +1258,10 @@ trace_puts_quoted(char *s) | |||
1244 | case CTLESC: c = 'e'; goto backslash; | 1258 | case CTLESC: c = 'e'; goto backslash; |
1245 | case CTLVAR: c = 'v'; goto backslash; | 1259 | case CTLVAR: c = 'v'; goto backslash; |
1246 | case CTLBACKQ: c = 'q'; goto backslash; | 1260 | case CTLBACKQ: c = 'q'; goto backslash; |
1261 | #if BASH_PROCESS_SUBST | ||
1262 | case CTLTOPROC: c = 'p'; goto backslash; | ||
1263 | case CTLFROMPROC: c = 'P'; goto backslash; | ||
1264 | #endif | ||
1247 | backslash: | 1265 | backslash: |
1248 | putc('\\', tracefile); | 1266 | putc('\\', tracefile); |
1249 | putc(c, tracefile); | 1267 | putc(c, tracefile); |
@@ -1405,8 +1423,17 @@ sharg(union node *arg, FILE *fp) | |||
1405 | case CTLENDVAR: | 1423 | case CTLENDVAR: |
1406 | putc('}', fp); | 1424 | putc('}', fp); |
1407 | break; | 1425 | break; |
1426 | #if BASH_PROCESS_SUBST | ||
1427 | case CTLTOPROC: | ||
1428 | putc('>', fp); | ||
1429 | goto backq; | ||
1430 | case CTLFROMPROC: | ||
1431 | putc('<', fp); | ||
1432 | goto backq; | ||
1433 | #endif | ||
1408 | case CTLBACKQ: | 1434 | case CTLBACKQ: |
1409 | putc('$', fp); | 1435 | putc('$', fp); |
1436 | IF_BASH_PROCESS_SUBST(backq:) | ||
1410 | putc('(', fp); | 1437 | putc('(', fp); |
1411 | shtree(bqlist->n, -1, NULL, fp); | 1438 | shtree(bqlist->n, -1, NULL, fp); |
1412 | putc(')', fp); | 1439 | putc(')', fp); |
@@ -3663,8 +3690,13 @@ static const uint8_t syntax_index_table[] ALIGN1 = { | |||
3663 | /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, | 3690 | /* 134 CTLARI */ CCTL_CCTL_CCTL_CCTL, |
3664 | /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, | 3691 | /* 135 CTLENDARI */ CCTL_CCTL_CCTL_CCTL, |
3665 | /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, | 3692 | /* 136 CTLQUOTEMARK */ CCTL_CCTL_CCTL_CCTL, |
3693 | #if BASH_PROCESS_SUBST | ||
3694 | /* 137 CTLTOPROC */ CCTL_CCTL_CCTL_CCTL, | ||
3695 | /* 138 CTLFROMPROC */ CCTL_CCTL_CCTL_CCTL, | ||
3696 | #else | ||
3666 | /* 137 */ CWORD_CWORD_CWORD_CWORD, | 3697 | /* 137 */ CWORD_CWORD_CWORD_CWORD, |
3667 | /* 138 */ CWORD_CWORD_CWORD_CWORD, | 3698 | /* 138 */ CWORD_CWORD_CWORD_CWORD, |
3699 | #endif | ||
3668 | /* 139 */ CWORD_CWORD_CWORD_CWORD, | 3700 | /* 139 */ CWORD_CWORD_CWORD_CWORD, |
3669 | /* 140 */ CWORD_CWORD_CWORD_CWORD, | 3701 | /* 140 */ CWORD_CWORD_CWORD_CWORD, |
3670 | /* 141 */ CWORD_CWORD_CWORD_CWORD, | 3702 | /* 141 */ CWORD_CWORD_CWORD_CWORD, |
@@ -5377,9 +5409,24 @@ cmdputs(const char *s) | |||
5377 | quoted >>= 1; | 5409 | quoted >>= 1; |
5378 | subtype = 0; | 5410 | subtype = 0; |
5379 | goto dostr; | 5411 | goto dostr; |
5412 | #if BASH_PROCESS_SUBST | ||
5413 | case CTLBACKQ: | ||
5414 | c = '$'; | ||
5415 | str = "(...)"; | ||
5416 | break; | ||
5417 | case CTLTOPROC: | ||
5418 | c = '>'; | ||
5419 | str = "(...)"; | ||
5420 | break; | ||
5421 | case CTLFROMPROC: | ||
5422 | c = '<'; | ||
5423 | str = "(...)"; | ||
5424 | break; | ||
5425 | #else | ||
5380 | case CTLBACKQ: | 5426 | case CTLBACKQ: |
5381 | str = "$(...)"; | 5427 | str = "$(...)"; |
5382 | goto dostr; | 5428 | goto dostr; |
5429 | #endif | ||
5383 | #if ENABLE_FEATURE_SH_MATH | 5430 | #if ENABLE_FEATURE_SH_MATH |
5384 | case CTLARI: | 5431 | case CTLARI: |
5385 | str = "$(("; | 5432 | str = "$(("; |
@@ -6446,6 +6493,21 @@ redirectsafe(union node *redir, int flags) | |||
6446 | return err; | 6493 | return err; |
6447 | } | 6494 | } |
6448 | 6495 | ||
6496 | #if BASH_PROCESS_SUBST | ||
6497 | static void | ||
6498 | pushfd(int fd) | ||
6499 | { | ||
6500 | struct redirtab *sv; | ||
6501 | |||
6502 | sv = ckzalloc(sizeof(*sv) + sizeof(sv->two_fd[0])); | ||
6503 | sv->pair_count = 1; | ||
6504 | sv->two_fd[0].orig_fd = fd; | ||
6505 | sv->two_fd[0].moved_to = CLOSED; | ||
6506 | sv->next = redirlist; | ||
6507 | redirlist = sv; | ||
6508 | } | ||
6509 | #endif | ||
6510 | |||
6449 | static struct redirtab* | 6511 | static struct redirtab* |
6450 | pushredir(union node *redir) | 6512 | pushredir(union node *redir) |
6451 | { | 6513 | { |
@@ -7084,10 +7146,20 @@ evaltreenr(union node *n, int flags) | |||
7084 | } | 7146 | } |
7085 | 7147 | ||
7086 | static void FAST_FUNC | 7148 | static void FAST_FUNC |
7087 | evalbackcmd(union node *n, struct backcmd *result) | 7149 | evalbackcmd(union node *n, struct backcmd *result |
7150 | IF_BASH_PROCESS_SUBST(, int ctl)) | ||
7088 | { | 7151 | { |
7089 | int pip[2]; | 7152 | int pip[2]; |
7090 | struct job *jp; | 7153 | struct job *jp; |
7154 | #if BASH_PROCESS_SUBST | ||
7155 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
7156 | const int ip = (ctl == CTLTOPROC); | ||
7157 | const int ic = !(ctl == CTLTOPROC); | ||
7158 | #else | ||
7159 | const int ctl = CTLBACKQ; | ||
7160 | const int ip = 0; | ||
7161 | const int ic = 1; | ||
7162 | #endif | ||
7091 | IF_PLATFORM_MINGW32(struct forkshell fs); | 7163 | IF_PLATFORM_MINGW32(struct forkshell fs); |
7092 | 7164 | ||
7093 | result->fd = -1; | 7165 | result->fd = -1; |
@@ -7100,23 +7172,26 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7100 | 7172 | ||
7101 | if (pipe(pip) < 0) | 7173 | if (pipe(pip) < 0) |
7102 | ash_msg_and_raise_perror("can't create pipe"); | 7174 | ash_msg_and_raise_perror("can't create pipe"); |
7103 | jp = makejob(/*n,*/ 1); | 7175 | /* process substitution uses NULL job/node, like openhere() */ |
7176 | jp = (ctl == CTLBACKQ) ? makejob(/*n,*/ 1) : NULL; | ||
7104 | #if ENABLE_PLATFORM_MINGW32 | 7177 | #if ENABLE_PLATFORM_MINGW32 |
7105 | memset(&fs, 0, sizeof(fs)); | 7178 | memset(&fs, 0, sizeof(fs)); |
7106 | fs.fpid = FS_EVALBACKCMD; | 7179 | fs.fpid = FS_EVALBACKCMD; |
7107 | fs.n = n; | 7180 | fs.n = n; |
7108 | fs.fd[0] = pip[0]; | 7181 | fs.fd[0] = pip[0]; |
7109 | fs.fd[1] = pip[1]; | 7182 | fs.fd[1] = pip[1]; |
7110 | spawn_forkshell(&fs, jp, n, FORK_NOJOB); | 7183 | fs.fd[2] = ctl; |
7184 | spawn_forkshell(&fs, jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB); | ||
7111 | #else | 7185 | #else |
7112 | if (forkshell(jp, n, FORK_NOJOB) == 0) { | 7186 | if (forkshell(jp, (ctl == CTLBACKQ) ? n : NULL, FORK_NOJOB) == 0) { |
7113 | /* child */ | 7187 | /* child */ |
7114 | FORCE_INT_ON; | 7188 | FORCE_INT_ON; |
7115 | close(pip[0]); | 7189 | close(pip[ip]); |
7116 | if (pip[1] != 1) { | 7190 | /* ic is index of child end of pipe *and* fd to connect it to */ |
7117 | /*close(1);*/ | 7191 | if (pip[ic] != ic) { |
7118 | dup2_or_raise(pip[1], 1); | 7192 | /*close(ic);*/ |
7119 | close(pip[1]); | 7193 | dup2_or_raise(pip[ic], ic); |
7194 | close(pip[ic]); | ||
7120 | } | 7195 | } |
7121 | /* TODO: eflag clearing makes the following not abort: | 7196 | /* TODO: eflag clearing makes the following not abort: |
7122 | * ash -c 'set -e; z=$(false;echo foo); echo $z' | 7197 | * ash -c 'set -e; z=$(false;echo foo); echo $z' |
@@ -7133,8 +7208,18 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7133 | } | 7208 | } |
7134 | #endif | 7209 | #endif |
7135 | /* parent */ | 7210 | /* parent */ |
7136 | close(pip[1]); | 7211 | #if BASH_PROCESS_SUBST |
7137 | result->fd = pip[0]; | 7212 | if (ctl != CTLBACKQ) { |
7213 | int fd = fcntl(pip[ip], F_DUPFD, 64); | ||
7214 | if (fd > 0) { | ||
7215 | close(pip[ip]); | ||
7216 | pip[ip] = fd; | ||
7217 | } | ||
7218 | pushfd(pip[ip]); | ||
7219 | } | ||
7220 | #endif | ||
7221 | close(pip[ic]); | ||
7222 | result->fd = pip[ip]; | ||
7138 | result->jp = jp; | 7223 | result->jp = jp; |
7139 | 7224 | ||
7140 | out: | 7225 | out: |
@@ -7146,8 +7231,11 @@ evalbackcmd(union node *n, struct backcmd *result) | |||
7146 | * Expand stuff in backwards quotes. | 7231 | * Expand stuff in backwards quotes. |
7147 | */ | 7232 | */ |
7148 | static void | 7233 | static void |
7149 | expbackq(union node *cmd, int flag) | 7234 | expbackq(union node *cmd, int flag IF_BASH_PROCESS_SUBST(, int ctl)) |
7150 | { | 7235 | { |
7236 | #if !BASH_PROCESS_SUBST | ||
7237 | const int ctl = CTLBACKQ; | ||
7238 | #endif | ||
7151 | struct backcmd in; | 7239 | struct backcmd in; |
7152 | int i; | 7240 | int i; |
7153 | char buf[128]; | 7241 | char buf[128]; |
@@ -7162,9 +7250,15 @@ expbackq(union node *cmd, int flag) | |||
7162 | INT_OFF; | 7250 | INT_OFF; |
7163 | startloc = expdest - (char *)stackblock(); | 7251 | startloc = expdest - (char *)stackblock(); |
7164 | pushstackmark(&smark, startloc); | 7252 | pushstackmark(&smark, startloc); |
7165 | evalbackcmd(cmd, &in); | 7253 | evalbackcmd(cmd, &in IF_BASH_PROCESS_SUBST(, ctl)); |
7166 | popstackmark(&smark); | 7254 | popstackmark(&smark); |
7167 | 7255 | ||
7256 | if (ctl != CTLBACKQ) { | ||
7257 | sprintf(buf, DEV_FD_PREFIX"%d", in.fd); | ||
7258 | strtodest(buf, BASESYNTAX); | ||
7259 | goto done; | ||
7260 | } | ||
7261 | |||
7168 | p = in.buf; | 7262 | p = in.buf; |
7169 | i = in.nleft; | 7263 | i = in.nleft; |
7170 | if (i == 0) | 7264 | if (i == 0) |
@@ -7186,6 +7280,7 @@ expbackq(union node *cmd, int flag) | |||
7186 | close(in.fd); | 7280 | close(in.fd); |
7187 | back_exitstatus = waitforjob(in.jp); | 7281 | back_exitstatus = waitforjob(in.jp); |
7188 | } | 7282 | } |
7283 | done: | ||
7189 | INT_ON; | 7284 | INT_ON; |
7190 | 7285 | ||
7191 | /* Eat all trailing newlines */ | 7286 | /* Eat all trailing newlines */ |
@@ -7274,6 +7369,10 @@ argstr(char *p, int flag) | |||
7274 | CTLESC, | 7369 | CTLESC, |
7275 | CTLVAR, | 7370 | CTLVAR, |
7276 | CTLBACKQ, | 7371 | CTLBACKQ, |
7372 | #if BASH_PROCESS_SUBST | ||
7373 | CTLTOPROC, | ||
7374 | CTLFROMPROC, | ||
7375 | #endif | ||
7277 | #if ENABLE_FEATURE_SH_MATH | 7376 | #if ENABLE_FEATURE_SH_MATH |
7278 | CTLARI, | 7377 | CTLARI, |
7279 | CTLENDARI, | 7378 | CTLENDARI, |
@@ -7373,8 +7472,12 @@ argstr(char *p, int flag) | |||
7373 | p = evalvar(p, flag | inquotes); | 7472 | p = evalvar(p, flag | inquotes); |
7374 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); | 7473 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); |
7375 | goto start; | 7474 | goto start; |
7475 | #if BASH_PROCESS_SUBST | ||
7476 | case CTLTOPROC: | ||
7477 | case CTLFROMPROC: | ||
7478 | #endif | ||
7376 | case CTLBACKQ: | 7479 | case CTLBACKQ: |
7377 | expbackq(argbackq->n, flag | inquotes); | 7480 | expbackq(argbackq->n, flag | inquotes IF_BASH_PROCESS_SUBST(, c)); |
7378 | goto start; | 7481 | goto start; |
7379 | #if ENABLE_FEATURE_SH_MATH | 7482 | #if ENABLE_FEATURE_SH_MATH |
7380 | case CTLARI: | 7483 | case CTLARI: |
@@ -12995,8 +13098,9 @@ realeofmark(const char *eofmark) | |||
12995 | #define CHECKEND() {goto checkend; checkend_return:;} | 13098 | #define CHECKEND() {goto checkend; checkend_return:;} |
12996 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} | 13099 | #define PARSEREDIR() {goto parseredir; parseredir_return:;} |
12997 | #define PARSESUB() {goto parsesub; parsesub_return:;} | 13100 | #define PARSESUB() {goto parsesub; parsesub_return:;} |
12998 | #define PARSEBACKQOLD() {oldstyle = 1; goto parsebackq; parsebackq_oldreturn:;} | 13101 | #define PARSEBACKQOLD() {style = OLD; goto parsebackq; parsebackq_oldreturn:;} |
12999 | #define PARSEBACKQNEW() {oldstyle = 0; goto parsebackq; parsebackq_newreturn:;} | 13102 | #define PARSEBACKQNEW() {style = NEW; goto parsebackq; parsebackq_newreturn:;} |
13103 | #define PARSEPROCSUB() {style = PSUB; goto parsebackq; parsebackq_psreturn:;} | ||
13000 | #define PARSEARITH() {goto parsearith; parsearith_return:;} | 13104 | #define PARSEARITH() {goto parsearith; parsearith_return:;} |
13001 | static int | 13105 | static int |
13002 | readtoken1(int c, int syntax, char *eofmark, int striptabs) | 13106 | readtoken1(int c, int syntax, char *eofmark, int striptabs) |
@@ -13007,7 +13111,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13007 | size_t len; | 13111 | size_t len; |
13008 | struct nodelist *bqlist; | 13112 | struct nodelist *bqlist; |
13009 | smallint quotef; | 13113 | smallint quotef; |
13010 | smallint oldstyle; | 13114 | smallint style; |
13115 | enum { OLD, NEW, PSUB }; | ||
13116 | #define oldstyle (style == OLD) | ||
13011 | smallint pssyntax; /* we are expanding a prompt string */ | 13117 | smallint pssyntax; /* we are expanding a prompt string */ |
13012 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) | 13118 | IF_BASH_DOLLAR_SQUOTE(smallint bash_dollar_squote = 0;) |
13013 | /* syntax stack */ | 13119 | /* syntax stack */ |
@@ -13189,6 +13295,15 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
13189 | pungetc(); | 13295 | pungetc(); |
13190 | } | 13296 | } |
13191 | #endif | 13297 | #endif |
13298 | #if BASH_PROCESS_SUBST | ||
13299 | if (c == '<' || c == '>') { | ||
13300 | if (pgetc() == '(') { | ||
13301 | PARSEPROCSUB(); | ||
13302 | break; | ||
13303 | } | ||
13304 | pungetc(); | ||
13305 | } | ||
13306 | #endif | ||
13192 | goto endword; /* exit outer loop */ | 13307 | goto endword; /* exit outer loop */ |
13193 | } | 13308 | } |
13194 | IF_ASH_ALIAS(if (c != PEOA)) | 13309 | IF_ASH_ALIAS(if (c != PEOA)) |
@@ -13673,9 +13788,18 @@ parsebackq: { | |||
13673 | memcpy(out, str, savelen); | 13788 | memcpy(out, str, savelen); |
13674 | STADJUST(savelen, out); | 13789 | STADJUST(savelen, out); |
13675 | } | 13790 | } |
13676 | USTPUTC(CTLBACKQ, out); | 13791 | #if BASH_PROCESS_SUBST |
13792 | if (style == PSUB) | ||
13793 | USTPUTC(c == '<' ? CTLFROMPROC : CTLTOPROC, out); | ||
13794 | else | ||
13795 | #endif | ||
13796 | USTPUTC(CTLBACKQ, out); | ||
13677 | if (oldstyle) | 13797 | if (oldstyle) |
13678 | goto parsebackq_oldreturn; | 13798 | goto parsebackq_oldreturn; |
13799 | #if BASH_PROCESS_SUBST | ||
13800 | else if (style == PSUB) | ||
13801 | goto parsebackq_psreturn; | ||
13802 | #endif | ||
13679 | goto parsebackq_newreturn; | 13803 | goto parsebackq_newreturn; |
13680 | } | 13804 | } |
13681 | 13805 | ||
@@ -14130,6 +14254,9 @@ cmdloop(int top) | |||
14130 | if (doing_jobctl) | 14254 | if (doing_jobctl) |
14131 | showjobs(SHOW_CHANGED|SHOW_STDERR); | 14255 | showjobs(SHOW_CHANGED|SHOW_STDERR); |
14132 | #endif | 14256 | #endif |
14257 | #if BASH_PROCESS_SUBST | ||
14258 | unwindredir(NULL); | ||
14259 | #endif | ||
14133 | inter = 0; | 14260 | inter = 0; |
14134 | if (iflag && top) { | 14261 | if (iflag && top) { |
14135 | inter++; | 14262 | inter++; |
@@ -14864,6 +14991,10 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) | |||
14864 | } | 14991 | } |
14865 | } | 14992 | } |
14866 | 14993 | ||
14994 | if (!ENABLE_ASH_BASH_COMPAT && !argptr) { | ||
14995 | bb_simple_error_msg("read: need variable name"); | ||
14996 | return 1; | ||
14997 | } | ||
14867 | params.argv = argptr; | 14998 | params.argv = argptr; |
14868 | params.setvar = setvar0; | 14999 | params.setvar = setvar0; |
14869 | params.ifs = bltinlookup("IFS"); /* can be NULL */ | 15000 | params.ifs = bltinlookup("IFS"); /* can be NULL */ |
@@ -15578,15 +15709,27 @@ forkshell_openhere(struct forkshell *fs) | |||
15578 | static void | 15709 | static void |
15579 | forkshell_evalbackcmd(struct forkshell *fs) | 15710 | forkshell_evalbackcmd(struct forkshell *fs) |
15580 | { | 15711 | { |
15712 | #if BASH_PROCESS_SUBST | ||
15713 | /* determine end of pipe used by parent (ip) and child (ic) */ | ||
15714 | const int ctl = fs->fd[2]; | ||
15715 | const int ip = (ctl == CTLTOPROC); | ||
15716 | const int ic = !(ctl == CTLTOPROC); | ||
15717 | #else | ||
15718 | const int ip = 0; | ||
15719 | const int ic = 1; | ||
15720 | #endif | ||
15581 | union node *n = fs->n; | 15721 | union node *n = fs->n; |
15582 | int pip[2] = {fs->fd[0], fs->fd[1]}; | 15722 | int pip[2]; |
15723 | |||
15724 | pip[ip] = fs->fd[ip]; | ||
15725 | pip[ic] = fs->fd[ic]; | ||
15583 | 15726 | ||
15584 | FORCE_INT_ON; | 15727 | FORCE_INT_ON; |
15585 | close(pip[0]); | 15728 | close(pip[ip]); |
15586 | if (pip[1] != 1) { | 15729 | if (pip[ic] != ic) { |
15587 | /*close(1);*/ | 15730 | /*close(ic);*/ |
15588 | dup2_or_raise(pip[1], 1); | 15731 | dup2_or_raise(pip[ic], ic); |
15589 | close(pip[1]); | 15732 | close(pip[ic]); |
15590 | } | 15733 | } |
15591 | eflag = 0; | 15734 | eflag = 0; |
15592 | ifsfree(); | 15735 | ifsfree(); |
diff --git a/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch b/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch new file mode 100644 index 000000000..06067dde0 --- /dev/null +++ b/shell/ash_remove_unnecessary_code_in_backquote_expansion.patch | |||
@@ -0,0 +1,135 @@ | |||
1 | From: Herbert Xu <herbert@xxxxxxxxxxxxxxxxxxx> | ||
2 | Date: Thu, 19 Apr 2018 18:16:12 +0800 | ||
3 | |||
4 | > ash originally had support for omitting the fork when expanding a | ||
5 | > builtin in backquotes. dash has gradually been removing this support, | ||
6 | > most recently in commit 66b614e29038e31745c4a5d296f64f8d64f5c377 | ||
7 | > ("[EVAL] Remove unused EV_BACKCMD flag"). | ||
8 | > | ||
9 | > Some traces still remain, however. Remove: | ||
10 | > | ||
11 | > - the buf and nleft elements of the backcmd structure; | ||
12 | > - a misleading comment regarding handling of builtins. | ||
13 | > | ||
14 | > Signed-off-by: Ron Yorston <rmy@xxxxxxxxxxxx> | ||
15 | |||
16 | Unfortunately we may need this at some point in the future due | ||
17 | to changes in POSIX. So let's keep it around for now until we | ||
18 | get things such as `jobs -p` to work. | ||
19 | |||
20 | ************************************* | ||
21 | |||
22 | From: Ron Yorston <rmy@xxxxxxxxxxxx> | ||
23 | Date: Thu, 19 Apr 2018 17:18:47 +0100 | ||
24 | |||
25 | >Unfortunately we may need this at some point in the future due | ||
26 | >to changes in POSIX. So let's keep it around for now until we | ||
27 | >get things such as `jobs -p` to work. | ||
28 | |||
29 | As you wish. | ||
30 | |||
31 | Something even more trivial I noticed later: the TRACE at the end of | ||
32 | expbackq incorrectly refers to the function as evalbackq. | ||
33 | |||
34 | ************************************* | ||
35 | |||
36 | Date: Tue, 10 Apr 2018 13:23:35 +0100 | ||
37 | From: Ron Yorston <rmy@pobox.com> | ||
38 | To: busybox@busybox.net | ||
39 | Subject: [PATCH] ash: remove unnecessary code in backquote expansion | ||
40 | |||
41 | Some traces remain of ash's ancient support for omitting the fork when | ||
42 | expanding a builtin command in backquotes. | ||
43 | |||
44 | Remove: | ||
45 | |||
46 | - the buf and nleft elements of the backcmd structure; | ||
47 | - a misleading comment regarding handling of builtins. | ||
48 | |||
49 | I've submitted a similar patch to dash. | ||
50 | |||
51 | Signed-off-by: Ron Yorston <rmy@pobox.com> | ||
52 | --- | ||
53 | shell/ash.c | 37 +++++++++---------------------------- | ||
54 | 1 file changed, 9 insertions(+), 28 deletions(-) | ||
55 | |||
56 | diff --git a/shell/ash.c b/shell/ash.c | ||
57 | index 45c747dbc..6f1458722 100644 | ||
58 | --- a/shell/ash.c | ||
59 | +++ b/shell/ash.c | ||
60 | @@ -6356,15 +6356,12 @@ exptilde(char *startp, char *p, int flags) | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | - * Execute a command inside back quotes. If it's a builtin command, we | ||
65 | - * want to save its output in a block obtained from malloc. Otherwise | ||
66 | - * we fork off a subprocess and get the output of the command via a pipe. | ||
67 | - * Should be called with interrupts off. | ||
68 | + * Execute a command inside back quotes. We fork off a subprocess and | ||
69 | + * get the output of the command via a pipe. Should be called with | ||
70 | + * interrupts off. | ||
71 | */ | ||
72 | struct backcmd { /* result of evalbackcmd */ | ||
73 | int fd; /* file descriptor to read from */ | ||
74 | - int nleft; /* number of chars in buffer */ | ||
75 | - char *buf; /* buffer */ | ||
76 | struct job *jp; /* job structure for command */ | ||
77 | }; | ||
78 | |||
79 | @@ -6394,8 +6391,6 @@ evalbackcmd(union node *n, struct backcmd *result) | ||
80 | struct job *jp; | ||
81 | |||
82 | result->fd = -1; | ||
83 | - result->buf = NULL; | ||
84 | - result->nleft = 0; | ||
85 | result->jp = NULL; | ||
86 | if (n == NULL) { | ||
87 | goto out; | ||
88 | @@ -6432,8 +6427,7 @@ evalbackcmd(union node *n, struct backcmd *result) | ||
89 | result->jp = jp; | ||
90 | |||
91 | out: | ||
92 | - TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", | ||
93 | - result->fd, result->buf, result->nleft, result->jp)); | ||
94 | + TRACE(("evalbackcmd done: fd=%d jp=0x%x\n", result->fd, result->jp)); | ||
95 | } | ||
96 | |||
97 | /* | ||
98 | @@ -6445,7 +6439,6 @@ expbackq(union node *cmd, int flag) | ||
99 | struct backcmd in; | ||
100 | int i; | ||
101 | char buf[128]; | ||
102 | - char *p; | ||
103 | char *dest; | ||
104 | int startloc; | ||
105 | int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; | ||
106 | @@ -6457,24 +6450,12 @@ expbackq(union node *cmd, int flag) | ||
107 | evalbackcmd(cmd, &in); | ||
108 | popstackmark(&smark); | ||
109 | |||
110 | - p = in.buf; | ||
111 | - i = in.nleft; | ||
112 | - if (i == 0) | ||
113 | - goto read; | ||
114 | - for (;;) { | ||
115 | - memtodest(p, i, syntax, flag & QUOTES_ESC); | ||
116 | - read: | ||
117 | - if (in.fd < 0) | ||
118 | - break; | ||
119 | - i = nonblock_immune_read(in.fd, buf, sizeof(buf)); | ||
120 | - TRACE(("expbackq: read returns %d\n", i)); | ||
121 | - if (i <= 0) | ||
122 | - break; | ||
123 | - p = buf; | ||
124 | - } | ||
125 | - | ||
126 | - free(in.buf); | ||
127 | if (in.fd >= 0) { | ||
128 | + while ((i = nonblock_immune_read(in.fd, buf, sizeof(buf))) > 0) { | ||
129 | + TRACE(("expbackq: read returns %d\n", i)); | ||
130 | + memtodest(buf, i, syntax, flag & QUOTES_ESC); | ||
131 | + } | ||
132 | + | ||
133 | close(in.fd); | ||
134 | back_exitstatus = waitforjob(in.jp); | ||
135 | } | ||
diff --git a/shell/ash_test/ash-psubst/bash_procsub.right b/shell/ash_test/ash-psubst/bash_procsub.right new file mode 100644 index 000000000..aa16a96be --- /dev/null +++ b/shell/ash_test/ash-psubst/bash_procsub.right | |||
@@ -0,0 +1,9 @@ | |||
1 | hello 1 | ||
2 | hello 2 | ||
3 | hello 3 | ||
4 | <(echo "hello 0") | ||
5 | hello 4 | ||
6 | HI THERE | ||
7 | hello error | ||
8 | hello error | ||
9 | hello stderr | ||
diff --git a/shell/ash_test/ash-psubst/bash_procsub.tests b/shell/ash_test/ash-psubst/bash_procsub.tests new file mode 100755 index 000000000..63b836782 --- /dev/null +++ b/shell/ash_test/ash-psubst/bash_procsub.tests | |||
@@ -0,0 +1,33 @@ | |||
1 | # simplest case | ||
2 | cat <(echo "hello 1") | ||
3 | |||
4 | # can have more than one | ||
5 | cat <(echo "hello 2") <(echo "hello 3") | ||
6 | |||
7 | # doesn't work in quotes | ||
8 | echo "<(echo \"hello 0\")" | ||
9 | |||
10 | # process substitution can be nested inside command substitution | ||
11 | echo $(cat <(echo "hello 4")) | ||
12 | |||
13 | # example from http://wiki.bash-hackers.org/syntax/expansion/proc_subst | ||
14 | # process substitutions can be passed to a function as parameters or | ||
15 | # variables | ||
16 | f() { | ||
17 | cat "$1" >"$x" | ||
18 | } | ||
19 | x=>(tr '[:lower:]' '[:upper:]') f <(echo 'hi there') | ||
20 | |||
21 | # process substitution can be combined with redirection on exec | ||
22 | rm -f err | ||
23 | # save stderr | ||
24 | exec 4>&2 | ||
25 | # copy stderr to a file | ||
26 | exec 2> >(tee err) | ||
27 | echo "hello error" >&2 | ||
28 | sync | ||
29 | # restore stderr | ||
30 | exec 2>&4 | ||
31 | cat err | ||
32 | rm -f err | ||
33 | echo "hello stderr" >&2 | ||
diff --git a/shell/hush.c b/shell/hush.c index 144ad3edd..77921e11c 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -4251,7 +4251,7 @@ static int done_word(struct parse_context *ctx) | |||
4251 | || endofname(command->argv[0])[0] != '\0' | 4251 | || endofname(command->argv[0])[0] != '\0' |
4252 | ) { | 4252 | ) { |
4253 | /* bash says just "not a valid identifier" */ | 4253 | /* bash says just "not a valid identifier" */ |
4254 | syntax_error("not a valid identifier in for"); | 4254 | syntax_error("bad variable name in for"); |
4255 | return 1; | 4255 | return 1; |
4256 | } | 4256 | } |
4257 | /* Force FOR to have just one word (variable name) */ | 4257 | /* Force FOR to have just one word (variable name) */ |
@@ -10799,10 +10799,17 @@ static int FAST_FUNC builtin_read(char **argv) | |||
10799 | */ | 10799 | */ |
10800 | params.read_flags = getopt32(argv, | 10800 | params.read_flags = getopt32(argv, |
10801 | # if BASH_READ_D | 10801 | # if BASH_READ_D |
10802 | "!srn:p:t:u:d:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d | 10802 | IF_NOT_HUSH_BASH_COMPAT("^") |
10803 | "!srn:p:t:u:d:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/), | ||
10804 | ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u, ¶ms.opt_d | ||
10803 | # else | 10805 | # else |
10804 | "!srn:p:t:u:", ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u | 10806 | IF_NOT_HUSH_BASH_COMPAT("^") |
10807 | "!srn:p:t:u:" IF_NOT_HUSH_BASH_COMPAT("\0" "-1"/*min 1 arg*/), | ||
10808 | ¶ms.opt_n, ¶ms.opt_p, ¶ms.opt_t, ¶ms.opt_u | ||
10805 | # endif | 10809 | # endif |
10810 | //TODO: print "read: need variable name" | ||
10811 | //for the case of !BASH "read" with no args (now it fails silently) | ||
10812 | //(or maybe extend getopt32() to emit a message if "-1" fails) | ||
10806 | ); | 10813 | ); |
10807 | if ((uint32_t)params.read_flags == (uint32_t)-1) | 10814 | if ((uint32_t)params.read_flags == (uint32_t)-1) |
10808 | return EXIT_FAILURE; | 10815 | return EXIT_FAILURE; |
diff --git a/shell/shell_common.c b/shell/shell_common.c index 1897fee3b..fff356c04 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c | |||
@@ -65,7 +65,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
65 | while (*pp) { | 65 | while (*pp) { |
66 | if (endofname(*pp)[0] != '\0') { | 66 | if (endofname(*pp)[0] != '\0') { |
67 | /* Mimic bash message */ | 67 | /* Mimic bash message */ |
68 | bb_error_msg("read: '%s': not a valid identifier", *pp); | 68 | bb_error_msg("read: '%s': bad variable name", *pp); |
69 | return (const char *)(uintptr_t)1; | 69 | return (const char *)(uintptr_t)1; |
70 | } | 70 | } |
71 | pp++; | 71 | pp++; |
@@ -296,7 +296,7 @@ shell_builtin_read(struct builtin_read_params *params) | |||
296 | * without variable names (bash compat). | 296 | * without variable names (bash compat). |
297 | * Thus, "read" and "read REPLY" are not the same. | 297 | * Thus, "read" and "read REPLY" are not the same. |
298 | */ | 298 | */ |
299 | if (!params->opt_d && argv[0]) { | 299 | if (argv[0]) { |
300 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ | 300 | /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_05 */ |
301 | const char *is_ifs = strchr(ifs, c); | 301 | const char *is_ifs = strchr(ifs, c); |
302 | if (startword && is_ifs) { | 302 | if (startword && is_ifs) { |
diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c index 82596bc0b..df0edee0a 100644 --- a/sysklogd/klogd.c +++ b/sysklogd/klogd.c | |||
@@ -226,7 +226,7 @@ int klogd_main(int argc UNUSED_PARAM, char **argv) | |||
226 | 226 | ||
227 | signal(SIGHUP, SIG_IGN); | 227 | signal(SIGHUP, SIG_IGN); |
228 | /* We want klogd_read to not be restarted, thus _norestart: */ | 228 | /* We want klogd_read to not be restarted, thus _norestart: */ |
229 | bb_signals_recursive_norestart(BB_FATAL_SIGS, record_signo); | 229 | bb_signals_norestart(BB_FATAL_SIGS, record_signo); |
230 | 230 | ||
231 | syslog(LOG_NOTICE, "klogd started: %s", bb_banner); | 231 | syslog(LOG_NOTICE, "klogd started: %s", bb_banner); |
232 | 232 | ||