From f18a82d9b320146e367217aba6664b1efb1be68c Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Tue, 25 Jan 2011 18:03:46 +0200 Subject: diff: return 1 when skipping directories with -r, but without -N Diff in diffutils will return 1 in case -r option is specified without -N something exists only in one of the directories. Signed-off-by: Alexander Shishkin Signed-off-by: Denys Vlasenko --- editors/diff.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/editors/diff.c b/editors/diff.c index cc7ba472e..ca4a4eae7 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -794,7 +794,9 @@ static int FAST_FUNC skip_dir(const char *filename, free(othername); if (r != 0 || !S_ISDIR(osb.st_mode)) { /* other dir doesn't have similarly named - * directory, don't recurse */ + * directory, don't recurse; return 1 upon + * exit, just like diffutils' diff */ + exit_status |= 1; return SKIP; } } @@ -846,9 +848,10 @@ static void diffdir(char *p[2], const char *s_start) break; pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1])); k = pos > 0; - if (pos && !(option_mask32 & FLAG(N))) + if (pos && !(option_mask32 & FLAG(N))) { printf("Only in %s: %s\n", p[k], dp[k]); - else { + exit_status |= 1; + } else { char *fullpath[2], *path[2]; /* if -N */ for (i = 0; i < 2; i++) { -- cgit v1.2.3-55-g6feb From ea023eacad23f6a30cffe4f255a050b91748fc2f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 01:21:20 +0100 Subject: disable length applet. ${#var} and echo -n "$var" | wc -c are portable equivalents Signed-off-by: Denys Vlasenko --- TEST_config_nommu | 1 - TEST_config_noprintf | 1 - TEST_config_rh9 | 1 - coreutils/Config.src | 10 +++++----- coreutils/Kbuild.src | 2 +- coreutils/length.c | 22 ---------------------- coreutils/length.c.disabled | 22 ++++++++++++++++++++++ include/applets.src.h | 2 +- 8 files changed, 29 insertions(+), 32 deletions(-) delete mode 100644 coreutils/length.c create mode 100644 coreutils/length.c.disabled diff --git a/TEST_config_nommu b/TEST_config_nommu index 18f448391..905f65296 100644 --- a/TEST_config_nommu +++ b/TEST_config_nommu @@ -189,7 +189,6 @@ CONFIG_HOSTID=y CONFIG_ID=y CONFIG_INSTALL=y CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y -CONFIG_LENGTH=y CONFIG_LN=y CONFIG_LOGNAME=y CONFIG_LS=y diff --git a/TEST_config_noprintf b/TEST_config_noprintf index 22525ecb6..b72e12856 100644 --- a/TEST_config_noprintf +++ b/TEST_config_noprintf @@ -211,7 +211,6 @@ CONFIG_FALSE=y # CONFIG_ID is not set # CONFIG_INSTALL is not set # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set # CONFIG_LN is not set # CONFIG_LOGNAME is not set # CONFIG_LS is not set diff --git a/TEST_config_rh9 b/TEST_config_rh9 index e45608351..23094e391 100644 --- a/TEST_config_rh9 +++ b/TEST_config_rh9 @@ -200,7 +200,6 @@ CONFIG_HOSTID=y CONFIG_ID=y CONFIG_INSTALL=y CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y -CONFIG_LENGTH=y CONFIG_LN=y CONFIG_LOGNAME=y CONFIG_LS=y diff --git a/coreutils/Config.src b/coreutils/Config.src index c2fd73e59..1a044f96c 100644 --- a/coreutils/Config.src +++ b/coreutils/Config.src @@ -295,11 +295,11 @@ config FEATURE_INSTALL_LONG_OPTIONS help Support long options for the install applet. -config LENGTH - bool "length" - default y - help - length is used to print out the length of a specified string. +####config LENGTH +#### bool "length" +#### default y +#### help +#### length is used to print out the length of a specified string. config LN bool "ln" diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index 4ea0fa50a..6a41c8318 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src @@ -39,7 +39,7 @@ lib-$(CONFIG_HEAD) += head.o lib-$(CONFIG_HOSTID) += hostid.o lib-$(CONFIG_ID) += id.o lib-$(CONFIG_INSTALL) += install.o -lib-$(CONFIG_LENGTH) += length.o +#lib-$(CONFIG_LENGTH) += length.o lib-$(CONFIG_LN) += ln.o lib-$(CONFIG_LOGNAME) += logname.o lib-$(CONFIG_LS) += ls.o diff --git a/coreutils/length.c b/coreutils/length.c deleted file mode 100644 index 7f0b48ccd..000000000 --- a/coreutils/length.c +++ /dev/null @@ -1,22 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2, see file LICENSE in this source tree. - */ - -/* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */ - -#include "libbb.h" - -/* This is a NOFORK applet. Be very careful! */ - -int length_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int length_main(int argc, char **argv) -{ - if ((argc != 2) || (**(++argv) == '-')) { - bb_show_usage(); - } - - printf("%u\n", (unsigned)strlen(*argv)); - - return fflush_all(); -} diff --git a/coreutils/length.c.disabled b/coreutils/length.c.disabled new file mode 100644 index 000000000..7f0b48ccd --- /dev/null +++ b/coreutils/length.c.disabled @@ -0,0 +1,22 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +/* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */ + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int length_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int length_main(int argc, char **argv) +{ + if ((argc != 2) || (**(++argv) == '-')) { + bb_show_usage(); + } + + printf("%u\n", (unsigned)strlen(*argv)); + + return fflush_all(); +} diff --git a/include/applets.src.h b/include/applets.src.h index fa7d0cc55..133f376a3 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -211,7 +211,7 @@ IF_KILLALL(APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall5)) IF_KLOGD(APPLET(klogd, BB_DIR_SBIN, BB_SUID_DROP)) IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP)) -IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length)) +//IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length)) IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP)) IF_SETARCH(APPLET_ODDNAME(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) IF_SETARCH(APPLET_ODDNAME(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) -- cgit v1.2.3-55-g6feb From d8494934a7b7cb8063282b03a6b996c9b7cec42a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 03:26:38 +0100 Subject: getty: explain every bit in termios; remove redundant stuff in termios_final Signed-off-by: Denys Vlasenko --- console-tools/resize.c | 1 + loginutils/getty.c | 67 +++++++++++++++++++++++--------------------------- 2 files changed, 32 insertions(+), 36 deletions(-) diff --git a/console-tools/resize.c b/console-tools/resize.c index fdfe2a6a0..ee0728b71 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -53,6 +53,7 @@ int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) */ fprintf(stderr, ESC"7" ESC"[r" ESC"[999;999H" ESC"[6n"); alarm(3); /* Just in case terminal won't answer */ +//BUG: death by signal won't restore termios scanf(ESC"[%hu;%huR", &w.ws_row, &w.ws_col); fprintf(stderr, ESC"8"); diff --git a/loginutils/getty.c b/loginutils/getty.c index b71d68a1f..29d889f43 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -106,15 +106,15 @@ struct globals { //usage:#define getty_full_usage "\n\n" //usage: "Open a tty, prompt for a login name, then invoke /bin/login\n" //usage: "\nOptions:" -//usage: "\n -h Enable hardware (RTS/CTS) flow control" -//usage: "\n -i Don't display /etc/issue" -//usage: "\n -L Local line, set CLOCAL on it" +//usage: "\n -h Enable hardware RTS/CTS flow control" +//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)" //usage: "\n -m Get baud rate from modem's CONNECT status message" +//usage: "\n -n Don't prompt for login name" //usage: "\n -w Wait for CR or LF before sending /etc/issue" -//usage: "\n -n Don't prompt for a login name" +//usage: "\n -i Don't display /etc/issue" //usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" //usage: "\n -l LOGIN Invoke LOGIN instead of /bin/login" -//usage: "\n -t SEC Terminate after SEC if no username is read" +//usage: "\n -t SEC Terminate after SEC if no login name is read" //usage: "\n -I INITSTR Send INITSTR before anything else" //usage: "\n -H HOST Log HOST into the utmp file as the hostname" //usage: "\n" @@ -251,21 +251,28 @@ static void termios_init(int speed) * reads will be done in raw mode anyway. Errors will be dealt with * later on. */ + /* 8 bits; hangup (drop DTR) on last close; enable receive */ G.termios.c_cflag = CS8 | HUPCL | CREAD; - if (option_mask32 & F_LOCAL) + if (option_mask32 & F_LOCAL) { + /* ignore Carrier Detect pin: + * opens don't block when CD is low, + * losing CD doesn't hang up processes whose ctty is this tty + */ G.termios.c_cflag |= CLOCAL; + } +#ifdef CRTSCTS + if (option_mask32 & F_RTSCTS) + G.termios.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ +#endif G.termios.c_iflag = 0; G.termios.c_lflag = 0; + /* non-raw output; add CR to each NL */ G.termios.c_oflag = OPOST | ONLCR; - G.termios.c_cc[VMIN] = 1; - G.termios.c_cc[VTIME] = 0; + G.termios.c_cc[VMIN] = 1; /* block reads if < 1 char is available */ + G.termios.c_cc[VTIME] = 0; /* no timeout (reads block forever) */ #ifdef __linux__ G.termios.c_line = 0; #endif -#ifdef CRTSCTS - if (option_mask32 & F_RTSCTS) - G.termios.c_cflag |= CRTSCTS; -#endif tcsetattr_stdin_TCSANOW(&G.termios); @@ -274,12 +281,17 @@ static void termios_init(int speed) static void termios_final(void) { - /* General terminal-independent stuff */ - G.termios.c_iflag |= IXON | IXOFF; /* 2-way flow control */ + /* software flow control on output; and on input */ + G.termios.c_iflag |= IXON | IXOFF; + if (G.eol == '\r') { + G.termios.c_iflag |= ICRNL; /* map CR on input to NL */ + } + /* non-raw input; enable SIGINT/QUIT/ec sigs; echo; echo NL on kill char; + * erase entire line via BS-space-BS on kill char */ G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; - /* no longer in lflag: | ECHOCTL | ECHOPRT */ - G.termios.c_oflag |= OPOST; - /* G.termios.c_cflag = 0; */ + /* echo ctrl chars as ^c; (what is ECHOPRT?) */ + /* no longer in c_lflag: | ECHOCTL | ECHOPRT */ + G.termios.c_cc[VINTR] = DEF_INTR; G.termios.c_cc[VQUIT] = DEF_QUIT; G.termios.c_cc[VEOF] = DEF_EOF; @@ -290,22 +302,8 @@ static void termios_final(void) #ifdef VSWTCH G.termios.c_cc[VSWTCH] = DEF_SWITCH; #endif - - /* Account for special characters seen in input */ - if (G.eol == '\r') { - G.termios.c_iflag |= ICRNL; /* map CR in input to NL */ - /* already done by termios_init */ - /* G.termios.c_oflag |= ONLCR; map NL in output to CR-NL */ - } G.termios.c_cc[VKILL] = DEF_KILL; -#ifdef CRTSCTS - /* Optionally enable hardware flow control */ - if (option_mask32 & F_RTSCTS) - G.termios.c_cflag |= CRTSCTS; -#endif - - /* Finally, make the new settings effective */ if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) bb_perror_msg_and_die("tcsetattr"); } @@ -330,11 +328,7 @@ static void auto_baud(void) * modem status messages is enabled. */ - /* - * Don't block if input queue is empty. - * Errors will be dealt with later on. - */ - G.termios.c_cc[VMIN] = 0; /* don't block if queue empty */ + G.termios.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */ tcsetattr_stdin_TCSANOW(&G.termios); /* @@ -538,6 +532,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) /* Set the optional timer */ alarm(G.timeout); /* if 0, alarm is not set */ +//BUG: death by signal won't restore termios /* Optionally wait for CR or LF before writing /etc/issue */ if (option_mask32 & F_WAITCRLF) { -- cgit v1.2.3-55-g6feb From d7c25e98bfd5dd62c19d6d672410ce61efa16801 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 03:31:23 +0100 Subject: getty: add ECHOE explanation Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 29d889f43..4e194c45f 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -286,7 +286,9 @@ static void termios_final(void) if (G.eol == '\r') { G.termios.c_iflag |= ICRNL; /* map CR on input to NL */ } - /* non-raw input; enable SIGINT/QUIT/ec sigs; echo; echo NL on kill char; + /* non-raw input; enable SIGINT/QUIT/etc sigs; echo; + * echo erase character as BS-space-BS; + * echo NL on kill char; * erase entire line via BS-space-BS on kill char */ G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; /* echo ctrl chars as ^c; (what is ECHOPRT?) */ -- cgit v1.2.3-55-g6feb From 3ff9be31be0c69802b2b29f397915b9dc1689c2e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 11:28:43 +0100 Subject: getty: document bits we don't set - maybe we should set some of them? Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 7 deletions(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 4e194c45f..2d2184a76 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -264,10 +264,17 @@ static void termios_init(int speed) if (option_mask32 & F_RTSCTS) G.termios.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ #endif + /* Other bits in c_cflag: + * CSTOPB 2 stop bits (1 otherwise) + * PARENB Enable parity bit + * PARODD Use odd parity (else even) + * LOBLK Block job control output (??) + */ G.termios.c_iflag = 0; G.termios.c_lflag = 0; /* non-raw output; add CR to each NL */ G.termios.c_oflag = OPOST | ONLCR; + G.termios.c_cc[VMIN] = 1; /* block reads if < 1 char is available */ G.termios.c_cc[VTIME] = 0; /* no timeout (reads block forever) */ #ifdef __linux__ @@ -281,18 +288,55 @@ static void termios_init(int speed) static void termios_final(void) { - /* software flow control on output; and on input */ + /* software flow control on output (stop sending if XOFF is recvd); + * and on input (send XOFF when buffer is full) + */ G.termios.c_iflag |= IXON | IXOFF; if (G.eol == '\r') { G.termios.c_iflag |= ICRNL; /* map CR on input to NL */ } - /* non-raw input; enable SIGINT/QUIT/etc sigs; echo; - * echo erase character as BS-space-BS; - * echo NL on kill char; - * erase entire line via BS-space-BS on kill char */ + /* Other bits in c_iflag: + * IXANY Any recvd char enables output (any char is also a XON) + * INPCK Enable parity check + * IGNPAR Ignore parity errors (drop bad bytes) + * PARMRK Mark parity errors with 0xff, 0x00 prefix + * (else bad byte is received as 0x00) + * ISTRIP Strip parity bit + * IGNBRK Ignore break condition + * BRKINT Send SIGINT on break - maybe set this? + * INLCR Map NL to CR + * IGNCR Ignore CR + * ICRNL Map CR to NL + * IUCLC Map uppercase to lowercase + * IMAXBEL Echo BEL on input line too long + * IUTF8 [Appears to affect tty's idea of char widths, + * observed to improve backspacing through Unicode chars] + */ + + /* line buffered input (NL or EOL or EOF chars end a line); + * recognize INT/QUIT/SUSP chars; + * echo input chars; + * echo BS-SP-BS on erase character; + * echo kill char specially, not as ^c (ECHOKE controls how exactly); + * erase all input via BS-SP-BS on kill char (else go to next line) + */ G.termios.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; - /* echo ctrl chars as ^c; (what is ECHOPRT?) */ - /* no longer in c_lflag: | ECHOCTL | ECHOPRT */ + /* Other bits in c_lflag: + * XCASE Map uppercase to \lowercase [tried, doesn't work] + * ECHONL Echo NL even if ECHO is not set + * NOFLSH Don't flush input buffer after interrupt or quit chars + * IEXTEN Enable extended functions (??) + * [glibc says it enables c_cc[LNEXT] "enter literal char" + * and c_cc[VDISCARD] "toggle discard buffered output" chars] + * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this? + * ECHOPRT On erase, echo erased chars + * [qwe input looks like "qwe\ewq/" on screen] + * FLUSHO Output being flushed (c_cc[VDISCARD] is in effect) + * PENDIN Retype pending input at next read or input char + * (c_cc[VREPRINT] is being processes) + * TOSTOP Send SIGTTOU for background output + * (why "stty sane" unsets this bit?) + */ G.termios.c_cc[VINTR] = DEF_INTR; G.termios.c_cc[VQUIT] = DEF_QUIT; @@ -305,6 +349,14 @@ static void termios_final(void) G.termios.c_cc[VSWTCH] = DEF_SWITCH; #endif G.termios.c_cc[VKILL] = DEF_KILL; + /* Other control chars: + * VEOL2 + * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname + * VREPRINT - reprint current input buffer + * VLNEXT, VDISCARD, VSTATUS + * VSUSP, VDSUSP - send (delayed) SIGTSTP + * VSTART, VSTOP - chars used for IXON/IXOFF + */ if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) bb_perror_msg_and_die("tcsetattr"); -- cgit v1.2.3-55-g6feb From e3d4c03852f17b20eafaedf957afa1b0bf03c66f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 11:58:37 +0100 Subject: stty: cosmetic fix to settings table; no code changes Signed-off-by: Denys Vlasenko --- coreutils/stty.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/coreutils/stty.c b/coreutils/stty.c index 1dd01c4dd..d8184a34f 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -345,7 +345,7 @@ static const char mode_name[] = MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif @@ -425,7 +425,7 @@ static const char mode_name[] = #endif MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) - MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ) + MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) @@ -437,15 +437,15 @@ static const char mode_name[] = #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif ; @@ -502,7 +502,7 @@ static const struct mode_info mode_info[] = { MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) #if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif @@ -582,7 +582,7 @@ static const struct mode_info mode_info[] = { #endif MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) - MI_ENTRY("crterase", local, REV | OMIT, ECHOE, 0 ) + MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) @@ -594,15 +594,15 @@ static const struct mode_info mode_info[] = { #endif #if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif #if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif #if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif }; -- cgit v1.2.3-55-g6feb From ddd1ec1c279da19a79238ce9df820d79415fa33a Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Wed, 26 Jan 2011 15:15:19 +0100 Subject: getty: wait up to 5 seconds for the output buffer to drain Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 56 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 2d2184a76..035534157 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -224,6 +224,12 @@ static void open_tty(void) } } +static void set_termios(void) +{ + if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) + bb_perror_msg_and_die("tcsetattr"); +} + /* We manipulate termios this way: * - first, we read existing termios settings * - termios_init modifies some parts and sets it @@ -233,25 +239,31 @@ static void open_tty(void) */ static void termios_init(int speed) { - /* Flush input and output queues, important for modems! - * Users report losing previously queued output chars, and I hesitate - * to use tcdrain here instead of tcflush - I imagine it can block. - * Using small sleep instead. + /* Try to drain output buffer, with 5 sec timeout. + * Added on request from users of ~600 baud serial interface + * with biggish buffer on a 90MHz CPU. + * They were losing hundreds of bytes of buffered output + * on tcflush. */ - usleep(100*1000); /* 0.1 sec */ + signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo); + alarm(5); + tcdrain(STDIN_FILENO); + alarm(0); + signal(SIGALRM, SIG_DFL); /* do not break -t TIMEOUT! */ + + /* Flush input and output queues, important for modems! */ tcflush(STDIN_FILENO, TCIOFLUSH); /* Set speed if it wasn't specified as "0" on command line */ if (speed != B0) cfsetspeed(&G.termios, speed); - /* - * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. + /* Initial termios settings: 8-bit characters, raw-mode, blocking i/o. * Special characters are set after we have read the login name; all * reads will be done in raw mode anyway. Errors will be dealt with * later on. */ - /* 8 bits; hangup (drop DTR) on last close; enable receive */ + /* 8 bits; hang up (drop DTR) on last close; enable receive */ G.termios.c_cflag = CS8 | HUPCL | CREAD; if (option_mask32 & F_LOCAL) { /* ignore Carrier Detect pin: @@ -266,9 +278,8 @@ static void termios_init(int speed) #endif /* Other bits in c_cflag: * CSTOPB 2 stop bits (1 otherwise) - * PARENB Enable parity bit - * PARODD Use odd parity (else even) - * LOBLK Block job control output (??) + * PARENB Enable parity bit (both on input and output) + * PARODD Odd parity (else even) */ G.termios.c_iflag = 0; G.termios.c_lflag = 0; @@ -281,7 +292,7 @@ static void termios_init(int speed) G.termios.c_line = 0; #endif - tcsetattr_stdin_TCSANOW(&G.termios); + set_termios(); debug("term_io 2\n"); } @@ -309,8 +320,8 @@ static void termios_final(void) * ICRNL Map CR to NL * IUCLC Map uppercase to lowercase * IMAXBEL Echo BEL on input line too long - * IUTF8 [Appears to affect tty's idea of char widths, - * observed to improve backspacing through Unicode chars] + * IUTF8 Appears to affect tty's idea of char widths, + * observed to improve backspacing through Unicode chars */ /* line buffered input (NL or EOL or EOF chars end a line); @@ -324,16 +335,16 @@ static void termios_final(void) /* Other bits in c_lflag: * XCASE Map uppercase to \lowercase [tried, doesn't work] * ECHONL Echo NL even if ECHO is not set + * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this? + * ECHOPRT On erase, echo erased chars + * [qwe input looks like "qwe\ewq/" on screen] * NOFLSH Don't flush input buffer after interrupt or quit chars * IEXTEN Enable extended functions (??) * [glibc says it enables c_cc[LNEXT] "enter literal char" * and c_cc[VDISCARD] "toggle discard buffered output" chars] - * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this? - * ECHOPRT On erase, echo erased chars - * [qwe input looks like "qwe\ewq/" on screen] * FLUSHO Output being flushed (c_cc[VDISCARD] is in effect) * PENDIN Retype pending input at next read or input char - * (c_cc[VREPRINT] is being processes) + * (c_cc[VREPRINT] is being processed) * TOSTOP Send SIGTTOU for background output * (why "stty sane" unsets this bit?) */ @@ -358,8 +369,7 @@ static void termios_final(void) * VSTART, VSTOP - chars used for IXON/IXOFF */ - if (tcsetattr_stdin_TCSANOW(&G.termios) < 0) - bb_perror_msg_and_die("tcsetattr"); + set_termios(); } /* extract baud rate from modem status message */ @@ -383,7 +393,7 @@ static void auto_baud(void) */ G.termios.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */ - tcsetattr_stdin_TCSANOW(&G.termios); + set_termios(); /* * Wait for a while, then read everything the modem has said so far and @@ -407,7 +417,7 @@ static void auto_baud(void) /* Restore terminal settings. Errors will be dealt with later on */ G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */ - tcsetattr_stdin_TCSANOW(&G.termios); + set_termios(); } /* get user name, establish parity, speed, erase, kill, eol; @@ -614,7 +624,7 @@ int getty_main(int argc UNUSED_PARAM, char **argv) /* We are here only if G.numspeed > 1 */ baud_index = (baud_index + 1) % G.numspeed; cfsetspeed(&G.termios, G.speeds[baud_index]); - tcsetattr_stdin_TCSANOW(&G.termios); + set_termios(); } } -- cgit v1.2.3-55-g6feb From cf9d33a894230479b317ccee120342e3a32c836c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 15:56:51 +0100 Subject: getty: do not clear all c_cflag's (we were clearing baud bits!) Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 035534157..3cf296ed1 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -258,13 +258,34 @@ static void termios_init(int speed) if (speed != B0) cfsetspeed(&G.termios, speed); - /* Initial termios settings: 8-bit characters, raw-mode, blocking i/o. + /* Initial termios settings: 8-bit characters, raw mode, blocking i/o. * Special characters are set after we have read the login name; all - * reads will be done in raw mode anyway. Errors will be dealt with - * later on. + * reads will be done in raw mode anyway. */ - /* 8 bits; hang up (drop DTR) on last close; enable receive */ - G.termios.c_cflag = CS8 | HUPCL | CREAD; + /* Clear all bits except: */ + G.termios.c_cflag &= (0 + /* 2 stop bits (1 otherwise) + * Enable parity bit (both on input and output) + * Odd parity (else even) + */ + | CSTOPB | PARENB | PARODD +#ifdef CBAUDEX + | CMSPAR /* mark or space parity */ +#endif + | CBAUD /* (output) baud rate */ +#ifdef CBAUDEX + | CBAUDEX /* (output) baud rate */ +#endif +#ifdef CIBAUD + | CIBAUD /* input baud rate */ +#endif +#ifdef CRTSCTS + | CRTSCTS /* flow control using RTS/CTS pins */ +#endif + | CLOCAL + ); + /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */ + G.termios.c_cflag |= CS8 | HUPCL | CREAD; if (option_mask32 & F_LOCAL) { /* ignore Carrier Detect pin: * opens don't block when CD is low, @@ -274,13 +295,8 @@ static void termios_init(int speed) } #ifdef CRTSCTS if (option_mask32 & F_RTSCTS) - G.termios.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ + G.termios.c_cflag |= CRTSCTS; #endif - /* Other bits in c_cflag: - * CSTOPB 2 stop bits (1 otherwise) - * PARENB Enable parity bit (both on input and output) - * PARODD Odd parity (else even) - */ G.termios.c_iflag = 0; G.termios.c_lflag = 0; /* non-raw output; add CR to each NL */ @@ -415,7 +431,7 @@ static void auto_baud(void) } } - /* Restore terminal settings. Errors will be dealt with later on */ + /* Restore terminal settings */ G.termios.c_cc[VMIN] = 1; /* restore to value set by termios_init */ set_termios(); } -- cgit v1.2.3-55-g6feb From ffd81f2003deaf3471e1da818735df91841399c4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 16:06:16 +0100 Subject: getty: do clear CLOCAL and CRTSCTS unless told otherwise Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 3cf296ed1..f158a264c 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -279,10 +279,6 @@ static void termios_init(int speed) #ifdef CIBAUD | CIBAUD /* input baud rate */ #endif -#ifdef CRTSCTS - | CRTSCTS /* flow control using RTS/CTS pins */ -#endif - | CLOCAL ); /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */ G.termios.c_cflag |= CS8 | HUPCL | CREAD; -- cgit v1.2.3-55-g6feb From df7b6577c6abaff551b15ccc80917553afde33fb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 16:11:19 +0100 Subject: id: fix inverted if (!ENABLE_DESKTOP) Signed-off-by: Denys Vlasenko --- coreutils/id.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/coreutils/id.c b/coreutils/id.c index ed1dc862e..0639325c3 100644 --- a/coreutils/id.c +++ b/coreutils/id.c @@ -176,10 +176,9 @@ int id_main(int argc UNUSED_PARAM, char **argv) prefix = ","; } } else if (n < 0) { /* error in get_groups() */ - if (!ENABLE_DESKTOP) + if (ENABLE_DESKTOP) bb_error_msg_and_die("can't get groups"); - else - return EXIT_FAILURE; + return EXIT_FAILURE; } if (ENABLE_FEATURE_CLEAN_UP) free(groups); -- cgit v1.2.3-55-g6feb From f36368ed3767381b68cb626df4d6865ec392621e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 16:14:47 +0100 Subject: getty: restore CRTSCTS comment Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index f158a264c..4dfe579c1 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -291,7 +291,7 @@ static void termios_init(int speed) } #ifdef CRTSCTS if (option_mask32 & F_RTSCTS) - G.termios.c_cflag |= CRTSCTS; + G.termios.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ #endif G.termios.c_iflag = 0; G.termios.c_lflag = 0; -- cgit v1.2.3-55-g6feb From 4907f6ec58bfe1f7622027669c53df208054d334 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 26 Jan 2011 16:20:54 +0100 Subject: getty: fix "ifdef CMSPAR" Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loginutils/getty.c b/loginutils/getty.c index 4dfe579c1..34f72c465 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -269,7 +269,7 @@ static void termios_init(int speed) * Odd parity (else even) */ | CSTOPB | PARENB | PARODD -#ifdef CBAUDEX +#ifdef CMSPAR | CMSPAR /* mark or space parity */ #endif | CBAUD /* (output) baud rate */ -- cgit v1.2.3-55-g6feb From aa4f9a2fd8a077c4e61e78fc397b47e541b0c140 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 28 Jan 2011 19:14:17 +0100 Subject: libbb/copy_file.c: use smallints instead of signed chars Signed-off-by: Denys Vlasenko --- libbb/copy_file.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 57d9dbfdb..9333a8d49 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -78,9 +78,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; - signed char retval = 0; - signed char dest_exists = 0; - signed char ovr; + smallint retval = 0; + smallint dest_exists = 0; + smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) @@ -147,7 +147,6 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) return -1; } - /* Create DEST */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); @@ -156,6 +155,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { + /* Create DEST */ mode_t mode; saved_umask = umask(0); -- cgit v1.2.3-55-g6feb From b5233f8556d330ae866b903f64a5f14535e4b171 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 31 Jan 2011 05:35:23 +0100 Subject: tar: add -h and -T to help text Signed-off-by: Denys Vlasenko --- archival/tar.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/archival/tar.c b/archival/tar.c index 813f86e82..972f8d06d 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -720,11 +720,16 @@ static void handle_SIGCHLD(int status) #endif //usage:#define tar_trivial_usage -//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") -//usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") -//usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " -//usage: IF_FEATURE_TAR_FROM("[-X FILE] ") -//usage: "[-f TARFILE] [-C DIR] [FILE]..." +//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" +//usage: IF_FEATURE_SEAMLESS_Z("Z") +//usage: IF_FEATURE_SEAMLESS_GZ("z") +//usage: IF_FEATURE_SEAMLESS_BZ2("j") +//usage: IF_FEATURE_SEAMLESS_LZMA("a") +//usage: IF_FEATURE_TAR_CREATE("h") +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") +//usage: "vO] " +//usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ") +//usage: "[-f TARFILE] [-C DIR] [FILE]..." //usage:#define tar_full_usage "\n\n" //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") @@ -739,6 +744,9 @@ static void handle_SIGCHLD(int status) //usage: "\n f Name of TARFILE ('-' for stdin/out)" //usage: "\n C Change to DIR before operation" //usage: "\n v Verbose" +//usage: IF_FEATURE_SEAMLESS_Z( +//usage: "\n Z (De)compress using compress" +//usage: ) //usage: IF_FEATURE_SEAMLESS_GZ( //usage: "\n z (De)compress using gzip" //usage: ) @@ -748,9 +756,6 @@ static void handle_SIGCHLD(int status) //usage: IF_FEATURE_SEAMLESS_LZMA( //usage: "\n a (De)compress using lzma" //usage: ) -//usage: IF_FEATURE_SEAMLESS_Z( -//usage: "\n Z (De)compress using compress" -//usage: ) //usage: "\n O Extract to stdout" //usage: IF_FEATURE_TAR_CREATE( //usage: "\n h Follow symlinks" -- cgit v1.2.3-55-g6feb From 625cfd87d9282c9698a02cd6acd870ee0baee407 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 31 Jan 2011 05:55:52 +0100 Subject: fdisk_osf: simplify ifdef (incidentally, adds support for Microblaze) Signed-off-by: Denys Vlasenko --- util-linux/fdisk_osf.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c index 79be0cd0f..65e6bd7c4 100644 --- a/util-linux/fdisk_osf.c +++ b/util-linux/fdisk_osf.c @@ -43,19 +43,15 @@ #define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" -#if defined(i386) || defined(__sparc__) || defined(__arm__) \ - || defined(__m68k__) || defined(__mips__) || defined(__s390__) \ - || defined(__s390__) || defined(__s390x__) \ - || defined(__sh__) || defined(__x86_64__) || defined(__avr32__) \ - || defined(__nds32__) -# define BSD_LABELSECTOR 1 -# define BSD_LABELOFFSET 0 -#elif defined(__alpha__) || defined(__powerpc__) || defined(__ia64__) \ +#if defined(__alpha__) \ + || defined(__powerpc__) \ + || defined(__ia64__) \ || defined(__hppa__) # define BSD_LABELSECTOR 0 # define BSD_LABELOFFSET 64 #else -# error unknown architecture +# define BSD_LABELSECTOR 1 +# define BSD_LABELOFFSET 0 #endif #define BSD_BBSIZE 8192 /* size of boot area, with label */ -- cgit v1.2.3-55-g6feb From 55ae0e9238e1979f0200700ec5dbd0df8d32f7a2 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Mon, 31 Jan 2011 06:27:35 +0100 Subject: df,find_mount_point: optionally don't ignore rootfs Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- coreutils/df.c | 2 +- libbb/Config.src | 19 +++++++++++++++++++ libbb/find_mount_point.c | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/coreutils/df.c b/coreutils/df.c index af9b77b23..70fd1f4fd 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -160,7 +160,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) } /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */ - if (strcmp(device, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) continue; #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY diff --git a/libbb/Config.src b/libbb/Config.src index 85892d3fe..dfb897d5f 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -161,6 +161,25 @@ config FEATURE_COPYBUF_KB Bigger buffers will be allocated with mmap, with fallback to 4 kb stack buffer if mmap fails. +config FEATURE_SKIP_ROOTFS + bool "Skip rootfs in mount table" + default y + help + Ignore rootfs entry in mount table. + + In Linux, kernel has a special filesystem, rootfs, which is initially + mounted on /. It contains initramfs data, if kernel is configured + to have one. Usually, another file system is mounted over / early + in boot process, and therefore most tools which manipulate + mount table, such as df, will skip rootfs entry. + + However, some systems do not mount anything on /. + If you need to configure busybox for one of these systems, + you may find useful to turn this option off to make df show + initramfs statistic. + + Otherwise, choose Y. + config MONOTONIC_SYSCALL bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" default n diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c index 361698a6b..56637ad92 100644 --- a/libbb/find_mount_point.c +++ b/libbb/find_mount_point.c @@ -43,7 +43,7 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) /* rootfs mount in Linux 2.6 exists always, * and it makes sense to always ignore it. * Otherwise people can't reference their "real" root! */ - if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0) continue; if (strcmp(name, mountEntry->mnt_dir) == 0 -- cgit v1.2.3-55-g6feb From 8ae386bf195c6ea53232bacd2eb8cf26676962e4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 1 Feb 2011 23:24:25 +0100 Subject: revert commit 1396221d5a741ef8e1e8abca88836b341a3cab84 Signed-off-by: Denys Vlasenko --- modutils/modutils.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/modutils/modutils.c b/modutils/modutils.c index 565d0d22f..415dbbe44 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c @@ -71,12 +71,11 @@ char* FAST_FUNC parse_cmdline_module_options(char **argv) optlen = 0; while (*++argv) { options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); - /* Older versions were enclosing space-containing *argv in "", - * but both modprobe and insmod from module-init-tools 3.11.1 - * don't do this anymore. (As to extra trailing space, - * insmod adds it but modprobe does not. We do in both cases) - */ - optlen += sprintf(options + optlen, "%s ", *argv); + /* Spaces handled by "" pairs, but no way of escaping quotes */ +//TODO: module-init-tools version 3.11.1 quotes only value: +//it generates var="val with spaces", not "var=val with spaces" +//(and it won't quote var *name* even if it has spaces) + optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv); } return options; } -- cgit v1.2.3-55-g6feb From c5830bdf6558edbc567d7c5dce1ff8059049e202 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 00:00:36 +0100 Subject: modprobe/insmod: fix parameter quoting function old new delta parse_cmdline_module_options 102 157 +55 modprobe_main 657 662 +5 insmod_main 68 70 +2 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 62/0) Total: 62 bytes Signed-off-by: Denys Vlasenko --- modutils/insmod.c | 2 +- modutils/modprobe.c | 2 +- modutils/modutils.c | 32 +++++++++++++++++++++++++------- modutils/modutils.h | 2 +- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/modutils/insmod.c b/modutils/insmod.c index e5b46f402..94e4e2863 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -59,7 +59,7 @@ int insmod_main(int argc UNUSED_PARAM, char **argv) if (!filename) bb_show_usage(); - rc = bb_init_module(filename, parse_cmdline_module_options(argv)); + rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0)); if (rc) bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); diff --git a/modutils/modprobe.c b/modutils/modprobe.c index e3bacac56..8d2ccc562 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -589,7 +589,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* First argument is module name, rest are parameters */ DBG("probing just module %s", *argv); add_probe(argv[0]); - G.cmdline_mopts = parse_cmdline_module_options(argv); + G.cmdline_mopts = parse_cmdline_module_options(argv, /*quote_spaces:*/ 1); } /* Happens if all requested modules are already loaded */ diff --git a/modutils/modutils.c b/modutils/modutils.c index 415dbbe44..6187ca72f 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c @@ -62,7 +62,7 @@ char* FAST_FUNC filename2modname(const char *filename, char *modname) return modname; } -char* FAST_FUNC parse_cmdline_module_options(char **argv) +char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces) { char *options; int optlen; @@ -70,13 +70,31 @@ char* FAST_FUNC parse_cmdline_module_options(char **argv) options = xzalloc(1); optlen = 0; while (*++argv) { - options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); - /* Spaces handled by "" pairs, but no way of escaping quotes */ -//TODO: module-init-tools version 3.11.1 quotes only value: -//it generates var="val with spaces", not "var=val with spaces" -//(and it won't quote var *name* even if it has spaces) - optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv); + const char *fmt; + const char *var; + const char *val; + + var = *argv; + options = xrealloc(options, optlen + 2 + strlen(var) + 2); + fmt = "%.*s%s "; + val = strchrnul(var, '='); + if (quote_spaces) { + /* + * modprobe (module-init-tools version 3.11.1) compat: + * quote only value: + * var="val with spaces", not "var=val with spaces" + * (note: var *name* is not checked for spaces!) + */ + if (*val) { /* has var=val format. skip '=' */ + val++; + if (strchr(val, ' ')) + fmt = "%.*s\"%s\" "; + } + } + optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val); } + /* Remove trailing space. Disabled */ + /* if (optlen != 0) options[optlen-1] = '\0'; */ return options; } diff --git a/modutils/modutils.h b/modutils/modutils.h index 863bc26d3..5f059c716 100644 --- a/modutils/modutils.h +++ b/modutils/modutils.h @@ -21,7 +21,7 @@ void replace(char *s, char what, char with) FAST_FUNC; char *replace_underscores(char *s) FAST_FUNC; int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; char *filename2modname(const char *filename, char *modname) FAST_FUNC; -char *parse_cmdline_module_options(char **argv) FAST_FUNC; +char *parse_cmdline_module_options(char **argv, int quote_spaces) FAST_FUNC; /* insmod for 2.4 and modprobe's options (insmod 2.6 has no options at all): */ #define INSMOD_OPTS \ -- cgit v1.2.3-55-g6feb From 099e528919e2219772265e99ab8a43d188c1b8db Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 00:59:35 +0100 Subject: ps: implement -o stat function old new delta func_stat - 24 +24 out_spec 300 320 +20 Signed-off-by: Denys Vlasenko --- miscutils/timeout.c | 2 +- procps/ps.c | 42 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 48b8d8fc0..841669416 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -83,7 +83,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) bb_daemonize_or_rexec(0, argv); /* Here we are grandchild. Sleep, then kill grandparent */ grandchild: - /* Just sleep(NUGE_NUM); kill(parent) may kill wrong process! */ + /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ while (1) { sleep(1); if (--timeout <= 0) diff --git a/procps/ps.c b/procps/ps.c index 48b55a785..6945780ec 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -18,15 +18,34 @@ enum { MAX_WIDTH = 2*1024 }; #include /* for times() */ #ifndef AT_CLKTCK -#define AT_CLKTCK 17 +# define AT_CLKTCK 17 #endif - +/* TODO: + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html + * specifies (for XSI-conformant systems) following default columns + * (l and f mark columns shown with -l and -f respectively): + * F l Flags (octal and additive) associated with the process (??) + * S l The state of the process + * UID f,l The user ID; the login name is printed with -f + * PID The process ID + * PPID f,l The parent process + * C f,l Processor utilization + * PRI l The priority of the process; higher numbers mean lower priority + * NI l Nice value + * ADDR l The address of the process + * SZ l The size in blocks of the core image of the process + * WCHAN l The event for which the process is waiting or sleeping + * STIME f Starting time of the process + * TTY The controlling terminal for the process + * TIME The cumulative execution time for the process + * CMD The command name; the full command line is shown with -f + */ #if ENABLE_SELINUX -#define SELINUX_O_PREFIX "label," -#define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") +# define SELINUX_O_PREFIX "label," +# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") #else -#define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") +# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") #endif typedef struct { @@ -68,7 +87,8 @@ static ptrdiff_t find_elf_note(ptrdiff_t findme) { ptrdiff_t *ep = (ptrdiff_t *) environ; - while (*ep++); + while (*ep++) + continue; while (*ep) { if (ep[0] == findme) { return ep[1]; @@ -184,6 +204,11 @@ static void func_comm(char *buf, int size, const procps_status_t *ps) safe_strncpy(buf, ps->comm, size+1); } +static void func_stat(char *buf, int size, const procps_status_t *ps) +{ + safe_strncpy(buf, ps->state, size+1); +} + static void func_args(char *buf, int size, const procps_status_t *ps) { read_cmdline(buf, size+1, ps->pid, ps->comm); @@ -300,7 +325,7 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps) */ static const ps_out_t out_spec[] = { -// Mandated by POSIX: +/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, @@ -322,7 +347,8 @@ static const ps_out_t out_spec[] = { #endif { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, -// Not mandated by POSIX, but useful: +/* Not mandated, but useful: */ + { 4 , "stat" ,"STAT" ,func_stat ,PSSCAN_STAT }, { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, #if ENABLE_SELINUX { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, -- cgit v1.2.3-55-g6feb From c71b469f5daceb717e31cc9ce46b0e058e2c57b6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 03:28:56 +0100 Subject: libbb: make BB_EXECVP/LP try to exec real binary if there's no /proc/self/exe Signed-off-by: Denys Vlasenko --- include/libbb.h | 12 +++++++----- libbb/execable.c | 10 +++++----- libbb/vfork_daemon_rexec.c | 12 ++++++------ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 182b47988..e69e27944 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -867,14 +867,16 @@ int exists_execable(const char *filename) FAST_FUNC; * but it may exec busybox and call applet instead of searching PATH. */ #if ENABLE_FEATURE_PREFER_APPLETS -int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; -#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) +int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC; #define BB_EXECLP(prog,cmd,...) \ - execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \ - cmd, __VA_ARGS__) + do { \ + if (find_applet_by_name(prog) >= 0) \ + execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \ + execlp(prog, cmd, __VA_ARGS__); \ + } while (0) #else #define BB_EXECVP(prog,cmd) execvp(prog,cmd) -#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) +#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__) #endif int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; diff --git a/libbb/execable.c b/libbb/execable.c index d37640007..178a00a5f 100644 --- a/libbb/execable.c +++ b/libbb/execable.c @@ -68,12 +68,12 @@ int FAST_FUNC exists_execable(const char *filename) } #if ENABLE_FEATURE_PREFER_APPLETS -/* just like the real execvp, but try to launch an applet named 'file' first - */ -int FAST_FUNC bb_execvp(const char *file, char *const argv[]) +/* just like the real execvp, but try to launch an applet named 'file' first */ +int FAST_FUNC BB_EXECVP(const char *file, char *const argv[]) { - return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, - argv); + if (find_applet_by_name(file) >= 0) + execvp(bb_busybox_exec_path, argv); + return execvp(file, argv); } #endif diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 5e0fb0d73..cb4781a59 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -182,17 +182,17 @@ int FAST_FUNC spawn_and_wait(char **argv) int a = find_applet_by_name(argv[0]); if (a >= 0 && (APPLET_IS_NOFORK(a) -#if BB_MMU +# if BB_MMU || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ -#endif +# endif )) { -#if BB_MMU +# if BB_MMU if (APPLET_IS_NOFORK(a)) -#endif +# endif { return run_nofork_applet(a, argv); } -#if BB_MMU +# if BB_MMU /* MMU only */ /* a->noexec is true */ rc = fork(); @@ -201,7 +201,7 @@ int FAST_FUNC spawn_and_wait(char **argv) /* child */ xfunc_error_retval = EXIT_FAILURE; run_applet_no_and_exit(a, argv); -#endif +# endif } #endif /* FEATURE_PREFER_APPLETS */ rc = spawn(argv); -- cgit v1.2.3-55-g6feb From b72baeb00328576df415f9a4b4f3d5f202e3be11 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 18:38:57 +0100 Subject: hush: use FEATURE_SH_NOFORK to enable NOFORK trick Also expands docs Signed-off-by: Denys Vlasenko --- docs/nofork_noexec.txt | 27 +++++++++++++++++++++++---- include/libbb.h | 1 + shell/Config.src | 9 +++++---- shell/hush.c | 11 +++++------ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index 06c789aff..c58f5a83f 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -44,9 +44,11 @@ NOEXEC trick is disabled for NOMMU build. NOFORK NOFORK applet should work correctly if another applet simply runs -_main(argc,argv) and then continues with its business (xargs, -find, shells can do it). This poses much more serious limitations -on what applet can/cannot do: +_main(argc,argv) and then continues with its business. +xargs, find, shells do it (grep for "spawn_and_wait" and +"run_nofork_applet" to find more users). + +This poses much more serious limitations on what applet can do: * all NOEXEC limitations apply. * do not ever exit() or exec(). @@ -56,7 +58,7 @@ on what applet can/cannot do: is taken from xfunc_error_retval. - fflush_stdout_and_exit(n) is ok to use. * do not use shared global data, or save/restore shared global data - prior to returning. (e.g. bb_common_bufsiz1 is off-limits). + (e.g. bb_common_bufsiz1) prior to returning. - getopt32() is ok to use. You do not need to save/restore option_mask32, it is already done by core code. * if you allocate memory, you can use xmalloc() only on the very first @@ -77,3 +79,20 @@ script loops. Applets which mess with signal handlers, termios etc are probably not worth the effort. Any NOFORK applet is also a NOEXEC applet. + + + Relevant CONFIG options + +FEATURE_PREFER_APPLETS + BB_EXECVP(cmd, argv) will try to exec /proc/self/exe + if command's name matches some applet name + applet tables will contain NOFORK/NOEXEC bits + spawn_and_wait(argv) will do NOFORK/NOEXEC tricks + +FEATURE_SH_STANDALONE (needs FEATURE_PREFER_APPLETS=y) + shells will try to exec /proc/self/exe if command's name matches + some applet name + shells will do NOEXEC trick on NOEXEC applets + +FEATURE_SH_NOFORK (needs FEATURE_PREFER_APPLETS=y) + shells will do NOFORK trick on NOFORK applets diff --git a/include/libbb.h b/include/libbb.h index e69e27944..88dceb11d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -859,6 +859,7 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const # define update_utmp(pid, new_type, tty_name, username, hostname) ((void)0) #endif + int execable_file(const char *name) FAST_FUNC; char *find_execable(const char *filename, char **PATHp) FAST_FUNC; int exists_execable(const char *filename) FAST_FUNC; diff --git a/shell/Config.src b/shell/Config.src index c9c2439e7..e96c21620 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -123,9 +123,9 @@ config FEATURE_SH_NOFORK default n depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS help - This option causes busybox shells [currently only ash] - to not execute typical fork/exec/wait sequence, but call _main - directly, if possible. (Sometimes it is not possible: for example, + This option causes busybox shells to not execute typical + fork/exec/wait sequence, but call _main directly, + if possible. (Sometimes it is not possible: for example, this is not possible in pipes). This will be done only for some applets (those which are marked @@ -133,6 +133,7 @@ config FEATURE_SH_NOFORK This may significantly speed up some shell scripts. - This feature is relatively new. Use with care. + This feature is relatively new. Use with care. Report bugs + to project mailing list. endmenu diff --git a/shell/hush.c b/shell/hush.c index 1709fd9d1..10788b8e7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6615,7 +6615,7 @@ static int checkjobs_and_fg_shell(struct pipe *fg_pipe) * cmd ; ... { list } ; ... * cmd && ... { list } && ... * cmd || ... { list } || ... - * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], + * If it is, then we can run cmd as a builtin, NOFORK, * or (if SH_STANDALONE) an applet, and we can run the { list } * with run_list. If it isn't one of these, we fork and exec cmd. * @@ -6797,13 +6797,12 @@ static NOINLINE int run_pipe(struct pipe *pi) } /* Expand the rest into (possibly) many strings each */ - if (0) {} #if ENABLE_HUSH_BASH_COMPAT - else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { + if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); - } + } else #endif - else { + { argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); } @@ -6865,7 +6864,7 @@ static NOINLINE int run_pipe(struct pipe *pi) return rcode; } - if (ENABLE_FEATURE_SH_STANDALONE) { + if (ENABLE_FEATURE_SH_NOFORK) { int n = find_applet_by_name(argv_expanded[0]); if (n >= 0 && APPLET_IS_NOFORK(n)) { rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); -- cgit v1.2.3-55-g6feb From 6307357effb79c8fbc6ccc9d4528c8c1c48a4831 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Feb 2011 19:05:25 +0100 Subject: move nofork_save_area from libbb.h to vfork_daemon_rexec.c Signed-off-by: Denys Vlasenko --- include/libbb.h | 11 ----------- libbb/getopt32.c | 2 +- libbb/vfork_daemon_rexec.c | 48 ++++++++++++++++++---------------------------- 3 files changed, 20 insertions(+), 41 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 88dceb11d..a0e23697c 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -911,19 +911,8 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC; int wait4pid(pid_t pid) FAST_FUNC; /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */ int spawn_and_wait(char **argv) FAST_FUNC; -struct nofork_save_area { - jmp_buf die_jmp; - const char *applet_name; - uint32_t option_mask32; - int die_sleep; - uint8_t xfunc_error_retval; - smallint saved; -}; -void save_nofork_data(struct nofork_save_area *save) FAST_FUNC; -void restore_nofork_data(struct nofork_save_area *save) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; -int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) FAST_FUNC; /* Helpers for daemonization. * diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 25bae319e..abd412043 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -531,7 +531,7 @@ getopt32(char **argv, const char *applet_opts, ...) /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. - * run_nofork_applet_prime() does this, but we might end up here + * run_nofork_applet() does this, but we might end up here * also via gunzip_main() -> gzip_main(). Play safe. */ #ifdef __GLIBC__ diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index cb4781a59..af938bed3 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -68,17 +68,22 @@ pid_t FAST_FUNC xspawn(char **argv) } #if ENABLE_FEATURE_PREFER_APPLETS -void FAST_FUNC save_nofork_data(struct nofork_save_area *save) +struct nofork_save_area { + jmp_buf die_jmp; + const char *applet_name; + uint32_t option_mask32; + int die_sleep; + uint8_t xfunc_error_retval; +}; +static void save_nofork_data(struct nofork_save_area *save) { memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); save->applet_name = applet_name; save->xfunc_error_retval = xfunc_error_retval; save->option_mask32 = option_mask32; save->die_sleep = die_sleep; - save->saved = 1; } - -void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) +static void restore_nofork_data(struct nofork_save_area *save) { memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); applet_name = save->applet_name; @@ -87,19 +92,17 @@ void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) die_sleep = save->die_sleep; } -int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) +int FAST_FUNC run_nofork_applet(int applet_no, char **argv) { int rc, argc; + struct nofork_save_area old; + + save_nofork_data(&old); applet_name = APPLET_NAME(applet_no); xfunc_error_retval = EXIT_FAILURE; - /* Special flag for xfunc_die(). If xfunc will "die" - * in NOFORK applet, xfunc_die() sees negative - * die_sleep and longjmp here instead. */ - die_sleep = -1; - /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. * @@ -129,6 +132,11 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n while (argv[argc]) argc++; + /* Special flag for xfunc_die(). If xfunc will "die" + * in NOFORK applet, xfunc_die() sees negative + * die_sleep and longjmp here instead. */ + die_sleep = -1; + rc = setjmp(die_jmp); if (!rc) { /* Some callers (xargs) @@ -137,15 +145,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); /* Finally we can call NOFORK applet's main() */ rc = applet_main[applet_no](argc, tmp_argv); - - /* The whole reason behind nofork_save_area is that _main - * may exit non-locally! For example, in hush Ctrl-Z tries - * (modulo bugs) to dynamically create a child (backgrounded task) - * if it detects that Ctrl-Z was pressed when a NOFORK was running. - * Testcase: interactive "rm -i". - * Don't fool yourself into thinking "and _main() returns - * quickly here" and removing "useless" nofork_save_area code. */ - } else { /* xfunc died in NOFORK applet */ /* in case they meant to return 0... */ if (rc == -2222) @@ -153,7 +152,7 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n } /* Restoring some globals */ - restore_nofork_data(old); + restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ #ifdef __GLIBC__ @@ -164,15 +163,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } - -int FAST_FUNC run_nofork_applet(int applet_no, char **argv) -{ - struct nofork_save_area old; - - /* Saving globals */ - save_nofork_data(&old); - return run_nofork_applet_prime(&old, applet_no, argv); -} #endif /* FEATURE_PREFER_APPLETS */ int FAST_FUNC spawn_and_wait(char **argv) -- cgit v1.2.3-55-g6feb From b7c9fb27cba3d697e602f8cbf88cde135d8d6c5e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Feb 2011 00:05:48 +0100 Subject: whitespace fixes Signed-off-by: Denys Vlasenko --- applets/usage_pod.c | 4 ++-- archival/lzop.c | 2 +- e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c | 4 ++-- editors/sed.c | 2 +- libbb/crc32.c | 2 +- libbb/getopt32.c | 8 ++++---- loginutils/getty.c | 2 +- modutils/modprobe.c | 2 +- networking/httpd_ssi.c | 4 ++-- networking/ntpd.c | 2 +- procps/pstree.c | 2 +- shell/shell_common.c | 6 +++--- util-linux/flock.c | 2 +- 13 files changed, 21 insertions(+), 21 deletions(-) diff --git a/applets/usage_pod.c b/applets/usage_pod.c index da0baefc6..0b1c4aadb 100644 --- a/applets/usage_pod.c +++ b/applets/usage_pod.c @@ -31,8 +31,8 @@ #include "usage.h" #define MAKE_USAGE(aname, usage) { aname, usage }, static struct usage_data { - const char *aname; - const char *usage; + const char *aname; + const char *usage; } usage_array[] = { #include "applets.h" }; diff --git a/archival/lzop.c b/archival/lzop.c index 094e78cf9..62455c313 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -401,7 +401,7 @@ struct globals { #define INIT_G() do { } while (0) //#define G (*ptr_to_globals) //#define INIT_G() do { -// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); +// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); //} while (0) diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c index b9aab440a..7d37d232d 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c @@ -155,8 +155,8 @@ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) blk_t ext2fs_inode_data_blocks(ext2_filsys fs, struct ext2_inode *inode) { - return inode->i_blocks - - (inode->i_file_acl ? fs->blocksize >> 9 : 0); + return inode->i_blocks - + (inode->i_file_acl ? fs->blocksize >> 9 : 0); } diff --git a/editors/sed.c b/editors/sed.c index b91acfb7f..d3555243f 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -124,7 +124,7 @@ struct globals { } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; #define INIT_G() do { \ G.sed_cmd_tail = &G.sed_cmd_head; \ diff --git a/libbb/crc32.c b/libbb/crc32.c index c63bf0772..ac9836cc9 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l const void *end = (uint8_t*)buf + len; while (buf != end) { - val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); buf = (uint8_t*)buf + 1; } return val; diff --git a/libbb/getopt32.c b/libbb/getopt32.c index abd412043..f3f1cfcba 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -80,9 +80,9 @@ const char *applet_long_options This struct allows you to define long options: static const char applet_longopts[] ALIGN1 = - //"name\0" has_arg val - "verbose\0" No_argument "v" - ; + //"name\0" has_arg val + "verbose\0" No_argument "v" + ; applet_long_options = applet_longopts; The last member of struct option (val) typically is set to @@ -226,7 +226,7 @@ Special characters: if specified together. In this case you must set opt_complementary = "b--cf:c--bf:f--bc". If two of the mutually exclusive options are found, getopt32 will call - bb_show_usage() and die. + bb_show_usage() and die. "x--x" Variation of the above, it means that -x option should occur at most once. diff --git a/loginutils/getty.c b/loginutils/getty.c index 34f72c465..3f20c8e81 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -334,7 +334,7 @@ static void termios_final(void) * IMAXBEL Echo BEL on input line too long * IUTF8 Appears to affect tty's idea of char widths, * observed to improve backspacing through Unicode chars - */ + */ /* line buffered input (NL or EOL or EOF chars end a line); * recognize INT/QUIT/SUSP chars; diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 8d2ccc562..0d28da7ea 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -170,7 +170,7 @@ struct globals { #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; diff --git a/networking/httpd_ssi.c b/networking/httpd_ssi.c index 87f43fcfa..cfe64eb46 100644 --- a/networking/httpd_ssi.c +++ b/networking/httpd_ssi.c @@ -52,9 +52,9 @@ httpd_ssi.c -o httpd_ssi static char* skip_whitespace(char *s) { - while (*s == ' ' || *s == '\t') ++s; + while (*s == ' ' || *s == '\t') ++s; - return s; + return s; } static char line[64 * 1024]; diff --git a/networking/ntpd.c b/networking/ntpd.c index 8fe529edb..3ed05ba29 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -882,7 +882,7 @@ fit(peer_t *p, double rd) // /* Do we have a loop? */ // if (p->refid == p->dstaddr || p->refid == s.refid) // return 0; - return 1; + return 1; } static peer_t* select_and_cluster(void) diff --git a/procps/pstree.c b/procps/pstree.c index ddf5dba59..4cd8cb458 100644 --- a/procps/pstree.c +++ b/procps/pstree.c @@ -76,7 +76,7 @@ struct globals { }; #define G (*ptr_to_globals) #define INIT_G() do { \ - SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ } while (0) diff --git a/shell/shell_common.c b/shell/shell_common.c index e9effd2d0..f02ed81ea 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -368,9 +368,9 @@ shell_builtin_ulimit(char **argv) #endif /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - argc = 1; - while (argv[argc]) - argc++; + argc = 1; + while (argv[argc]) + argc++; opts = 0; while (1) { diff --git a/util-linux/flock.c b/util-linux/flock.c index be3d552fa..77fe1f809 100644 --- a/util-linux/flock.c +++ b/util-linux/flock.c @@ -19,7 +19,7 @@ int flock_main(int argc UNUSED_PARAM, char **argv) }; #if ENABLE_LONG_OPTS - static const char getopt_longopts[] ALIGN1 = + static const char getopt_longopts[] ALIGN1 = "shared\0" No_argument "s" "exclusive\0" No_argument "x" "unlock\0" No_argument "u" -- cgit v1.2.3-55-g6feb From 3237f5c307c066a008909f35115e21c9473504ab Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Feb 2011 04:00:23 +0100 Subject: tar: support -T - and -X - Signed-off-by: Denys Vlasenko --- archival/tar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/tar.c b/archival/tar.c index 972f8d06d..e9dc41fe1 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -655,7 +655,7 @@ static llist_t *append_file_list_to_list(llist_t *list) llist_t *newlist = NULL; while (list) { - src_stream = xfopen_for_read(llist_pop(&list)); + src_stream = xfopen_stdin(llist_pop(&list)); while ((line = xmalloc_fgetline(src_stream)) != NULL) { /* kill trailing '/' unless the string is just "/" */ char *cp = last_char_is(line, '/'); -- cgit v1.2.3-55-g6feb From c5d0f15dbd8087f60b377fa9fc18d08698429189 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Feb 2011 14:14:09 +0100 Subject: libbb: spawn should remove child which failed to exec Signed-off-by: Denys Vlasenko --- libbb/vfork_daemon_rexec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index af938bed3..a75eafbd3 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -52,6 +52,7 @@ pid_t FAST_FUNC spawn(char **argv) * Interested party can wait on pid and learn exit code. * If 111 - then it (most probably) failed to exec */ if (failed) { + safe_waitpid(pid, NULL, 0); /* prevent zombie */ errno = failed; return -1; } -- cgit v1.2.3-55-g6feb From 8c52f803976c79812a75b9317107cc0a8fb94c7f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Feb 2011 17:36:21 +0100 Subject: ash: cosmetic cleanups Signed-off-by: Denys Vlasenko --- shell/ash.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 0bcbf9028..0e27a073c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -105,7 +105,7 @@ //config: Enable job control in the ash shell. //config: //config:config ASH_ALIAS -//config: bool "alias support" +//config: bool "Alias support" //config: default y //config: depends on ASH //config: help @@ -116,28 +116,28 @@ //config: default y //config: depends on ASH //config: help -//config: Enable getopts builtin in the ash shell. +//config: Enable support for getopts builtin in ash. //config: //config:config ASH_BUILTIN_ECHO //config: bool "Builtin version of 'echo'" //config: default y //config: depends on ASH //config: help -//config: Enable support for echo, builtin to ash. +//config: Enable support for echo builtin in ash. //config: //config:config ASH_BUILTIN_PRINTF //config: bool "Builtin version of 'printf'" //config: default y //config: depends on ASH //config: help -//config: Enable support for printf, builtin to ash. +//config: Enable support for printf builtin in ash. //config: //config:config ASH_BUILTIN_TEST //config: bool "Builtin version of 'test'" //config: default y //config: depends on ASH //config: help -//config: Enable support for test, builtin to ash. +//config: Enable support for test builtin in ash. //config: //config:config ASH_CMDCMD //config: bool "'command' command to override shell builtins" @@ -153,7 +153,7 @@ //config: default n //config: depends on ASH //config: help -//config: Enable "check for new mail" in the ash shell. +//config: Enable "check for new mail" function in the ash shell. //config: //config:config ASH_OPTIMIZE_FOR_SIZE //config: bool "Optimize for size instead of speed" @@ -1880,7 +1880,9 @@ change_lc_ctype(const char *value) #endif #if ENABLE_ASH_MAIL static void chkmail(void); -static void changemail(const char *) FAST_FUNC; +static void changemail(const char *var_value) FAST_FUNC; +#else +# define chkmail() ((void)0) #endif static void changepath(const char *) FAST_FUNC; #if ENABLE_ASH_RANDOM_SUPPORT @@ -9563,9 +9565,9 @@ preadfd(void) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { -#if ENABLE_FEATURE_TAB_COMPLETION +# if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); -#endif +# endif nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); if (nr == 0) { /* Ctrl+C pressed */ @@ -9586,8 +9588,7 @@ preadfd(void) nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); #endif -#if 0 -/* nonblock_safe_read() handles this problem */ +#if 0 /* disabled: nonblock_safe_read() handles this problem */ if (nr < 0) { if (parsefile->fd == 0 && errno == EWOULDBLOCK) { int flags = fcntl(0, F_GETFL); @@ -12072,9 +12073,7 @@ cmdloop(int top) inter = 0; if (iflag && top) { inter++; -#if ENABLE_ASH_MAIL chkmail(); -#endif } n = parsecmd(inter); #if DEBUG -- cgit v1.2.3-55-g6feb From 046341e8bd91a2a2c0d44b40217fa1c5ce1dd949 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Feb 2011 17:53:59 +0100 Subject: ash: optional support for $TMOUT variable Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 +++- shell/ash.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/include/libbb.h b/include/libbb.h index a0e23697c..6358e654a 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1393,12 +1393,14 @@ enum { }; line_input_t *new_line_input_t(int flags) FAST_FUNC; /* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */ -/* maxsize must be >= 2. +/* + * maxsize must be >= 2. * Returns: * -1 on read errors or EOF, or on bare Ctrl-D, * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ +/* NB: ash has timeout code which can be moved into read_line_input, if needed */ int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC; #else #define MAX_HISTORY 0 diff --git a/shell/ash.c b/shell/ash.c index 0e27a073c..bdc64790c 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -97,6 +97,14 @@ //config: help //config: Enable bash-compatible extensions. //config: +//config:config ASH_IDLE_TIMEOUT +//config: bool "Idle timeout variable" +//config: default n +//config: depends on ASH +//config: help +//config: Enables bash-like auto-logout after "$TMOUT" seconds +//config: of idle time. +//config: //config:config ASH_JOB_CONTROL //config: bool "Job control" //config: default y @@ -12048,6 +12056,23 @@ evalcmd(int argc UNUSED_PARAM, char **argv) return exitstatus; } +#if ENABLE_ASH_IDLE_TIMEOUT +static smallint timed_out; + +static void alrm_sighandler(int sig UNUSED_PARAM) +{ + /* Close stdin, making interactive command reading stop. + * Otherwise, timeout doesn't trigger until is pressed. + */ + int sv = errno; + close(0); + open("/dev/null", O_RDONLY); + errno = sv; + + timed_out = 1; +} +#endif + /* * Read and execute commands. * "Top" is nonzero for the top level command loop; @@ -12064,6 +12089,20 @@ cmdloop(int top) TRACE(("cmdloop(%d) called\n", top)); for (;;) { int skip; +#if ENABLE_ASH_IDLE_TIMEOUT + int tmout_seconds = 0; + + if (top && iflag) { + const char *tmout_var = lookupvar("TMOUT"); + if (tmout_var) { + tmout_seconds = atoi(tmout_var); + if (tmout_seconds > 0) { + signal(SIGALRM, alrm_sighandler); + alarm(tmout_seconds); + } + } + } +#endif setstackmark(&smark); #if JOBS @@ -12076,6 +12115,14 @@ cmdloop(int top) chkmail(); } n = parsecmd(inter); +#if ENABLE_ASH_IDLE_TIMEOUT + if (timed_out) { + printf("\007timed out waiting for input: auto-logout\n"); + break; + } + if (tmout_seconds > 0) + alarm(0); +#endif #if DEBUG if (DEBUG > 2 && debug && (n != NODE_EOF)) showtree(n); -- cgit v1.2.3-55-g6feb From 3e2834fe72b023155904e118c4f71a8ff73a90ec Mon Sep 17 00:00:00 2001 From: Reuben Dowle Date: Sat, 5 Feb 2011 03:18:08 +0100 Subject: ubimkvol,ubirmvol,ubirsvol: new applets function old new delta ubi_tools_main - 658 +658 packed_usage 28269 28376 +107 bbconfig_config_bz2 4968 5007 +39 applet_names 2407 2434 +27 applet_main 1396 1408 +12 applet_nameofs 698 704 +6 applet_install_loc 175 176 +1 ubi_attach_detach_main 175 - -175 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 6/0 up/down: 850/-175) Total: 675 bytes Signed-off-by: Reuben Dowle Signed-off-by: Denys Vlasenko --- miscutils/ubi_attach_detach.c | 154 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 136 insertions(+), 18 deletions(-) diff --git a/miscutils/ubi_attach_detach.c b/miscutils/ubi_attach_detach.c index aa8a5171a..fef9250ee 100644 --- a/miscutils/ubi_attach_detach.c +++ b/miscutils/ubi_attach_detach.c @@ -3,34 +3,69 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_attach_detach, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach)) -//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_attach_detach, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach)) - -//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_attach_detach.o -//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_attach_detach.o - //config:config UBIATTACH //config: bool "ubiattach" -//config: default n +//config: default y //config: depends on PLATFORM_LINUX //config: help //config: Attach MTD device to an UBI device. //config: //config:config UBIDETACH //config: bool "ubidetach" -//config: default n +//config: default y //config: depends on PLATFORM_LINUX //config: help //config: Detach MTD device from an UBI device. +//config: +//config:config UBIMKVOL +//config: bool "ubimkvol" +//config: default y +//config: depends on PLATFORM_LINUX +//config: help +//config: Create a UBI volume. +//config: +//config:config UBIRMVOL +//config: bool "ubirmvol" +//config: default y +//config: depends on PLATFORM_LINUX +//config: help +//config: Delete a UBI volume. +//config: +//config:config UBIRSVOL +//config: bool "ubirsvol" +//config: default y +//config: depends on PLATFORM_LINUX +//config: help +//config: Resize a UBI volume. + +//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach)) +//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach)) +//applet:IF_UBIMKVOL(APPLET_ODDNAME(ubimkvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubimkvol)) +//applet:IF_UBIRMVOL(APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) +//applet:IF_UBIRSVOL(APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) + +//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_attach_detach.o +//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_attach_detach.o +//kbuild:lib-$(CONFIG_UBIMKVOL) += ubi_attach_detach.o +//kbuild:lib-$(CONFIG_UBIRMVOL) += ubi_attach_detach.o +//kbuild:lib-$(CONFIG_UBIRSVOL) += ubi_attach_detach.o #include "libbb.h" #include #define OPTION_M (1 << 0) #define OPTION_D (1 << 1) - -#define do_attach (ENABLE_UBIATTACH && \ - (!ENABLE_UBIDETACH || (applet_name[3] == 'a'))) +#define OPTION_n (1 << 2) +#define OPTION_N (1 << 3) +#define OPTION_s (1 << 4) +#define OPTION_a (1 << 5) +#define OPTION_t (1 << 6) + +#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') +#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') +#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') +#define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm') +#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') //usage:#define ubiattach_trivial_usage //usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" @@ -46,20 +81,54 @@ //usage: "Detach MTD device from UBI\n" //usage: "\nOptions:" //usage: "\n -d UBI_NUM UBI device number" +//usage: +//usage:#define ubimkvol_trivial_usage +//usage: "UBI_DEVICE -N NAME -s SIZE" +//usage:#define ubimkvol_full_usage "\n\n" +//usage: "Create UBI Volume\n" +//usage: "\nOptions:" +//usage: "\n -a ALIGNMENT Volume alignment (default 1)" +//usage: "\n -n VOLID Volume ID, if not specified, it" +//usage: "\n will be assigned automatically" +//usage: "\n -N NAME Volume name" +//usage: "\n -s SIZE Size in bytes" +//usage: "\n -t TYPE Volume type (static|dynamic)" +//usage: +//usage:#define ubirmvol_trivial_usage +//usage: "UBI_DEVICE -n VOLID" +//usage:#define ubirmvol_full_usage "\n\n" +//usage: "Remove UBI Volume\n" +//usage: "\nOptions:" +//usage: "\n -n VOLID Volume ID" +//usage: +//usage:#define ubirsvol_trivial_usage +//usage: "UBI_DEVICE -N NAME -s SIZE" +//usage:#define ubirsvol_full_usage "\n\n" +//usage: "Resize UBI Volume\n" +//usage: "\nOptions:" +//usage: "\n -N NAME Volume name" +//usage: "\n -s SIZE Size in bytes" -int ubi_attach_detach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int ubi_attach_detach_main(int argc UNUSED_PARAM, char **argv) +int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ubi_tools_main(int argc UNUSED_PARAM, char **argv) { unsigned opts; char *ubi_ctrl; //struct stat st; - struct ubi_attach_req req; int fd; int mtd_num; int dev_num = UBI_DEV_NUM_AUTO; - - opt_complementary = "=1:m+:d+"; - opts = getopt32(argv, "m:d:", &mtd_num, &dev_num); + int vol_id = UBI_VOL_NUM_AUTO; + char *vol_name = NULL; + int size_bytes; + int alignment = 1; + char *type = NULL; + + opt_complementary = "=1:m+:d+:n+:s+:a+"; + opts = getopt32(argv, "m:d:n:N:s:a:t:", + &mtd_num, &dev_num, &vol_id, + &vol_name, &size_bytes, &alignment, &type + ); ubi_ctrl = argv[optind]; fd = xopen(ubi_ctrl, O_RDWR); @@ -68,6 +137,7 @@ int ubi_attach_detach_main(int argc UNUSED_PARAM, char **argv) // bb_error_msg_and_die("%s: not a char device", ubi_ctrl); if (do_attach) { + struct ubi_attach_req req; if (!(opts & OPTION_M)) bb_error_msg_and_die("%s device not specified", "MTD"); @@ -76,11 +146,59 @@ int ubi_attach_detach_main(int argc UNUSED_PARAM, char **argv) req.ubi_num = dev_num; xioctl(fd, UBI_IOCATT, &req); - } else { /* detach */ + } else + if (do_detach) { if (!(opts & OPTION_D)) bb_error_msg_and_die("%s device not specified", "UBI"); xioctl(fd, UBI_IOCDET, &dev_num); + } else + if (do_mkvol) { + struct ubi_mkvol_req req; + int vol_name_len; + if (!(opts & OPTION_s)) + bb_error_msg_and_die("%s size not specified", "UBI"); + if (!(opts & OPTION_N)) + bb_error_msg_and_die("%s name not specified", "UBI"); + vol_name_len = strlen(vol_name); + if (vol_name_len > UBI_MAX_VOLUME_NAME) + bb_error_msg_and_die("%s volume name too long", "UBI"); + + memset(&req, 0, sizeof(req)); + req.vol_id = vol_id; + if (opts & OPTION_t) { + if (type[0] == 's') + req.vol_type = UBI_STATIC_VOLUME; + else + req.vol_type = UBI_DYNAMIC_VOLUME; + } else { + req.vol_type = UBI_DYNAMIC_VOLUME; + } + req.alignment = alignment; + req.bytes = size_bytes; + strncpy(req.name, vol_name, UBI_MAX_VOLUME_NAME); + req.name_len = vol_name_len; + + xioctl(fd, UBI_IOCMKVOL, &req); + } else + if (do_rmvol) { + if (!(opts & OPTION_n)) + bb_error_msg_and_die("%s volume id not specified", "UBI"); + + xioctl(fd, UBI_IOCRMVOL, &vol_id); + } else + if (do_rsvol) { + struct ubi_rsvol_req req; + if (!(opts & OPTION_s)) + bb_error_msg_and_die("%s size not specified", "UBI"); + if (!(opts & OPTION_n)) + bb_error_msg_and_die("%s volume id not specified", "UBI"); + + memset(&req, 0, sizeof(req)); + req.bytes = size_bytes; + req.vol_id = vol_id; + + xioctl(fd, UBI_IOCRSVOL, &req); } if (ENABLE_FEATURE_CLEAN_UP) -- cgit v1.2.3-55-g6feb From 07078c29663c6530e6a35b136422448c3bd6d105 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Wed, 26 Jan 2011 11:30:34 -0800 Subject: Let fbsplash display images even when a second buffer is active If a previous application uses double buffering and makes the second buffer visible, fbsplash's images (written to the first buffer) otherwise won't be visible. Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- miscutils/fbsplash.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index 6b84563a3..150992343 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c @@ -83,11 +83,14 @@ static void fb_open(const char *strfb_device) // map the device in memory G.addr = mmap(NULL, - G.scr_var.xres * G.scr_var.yres + G.scr_var.xres * G.scr_var.yres_virtual * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/, PROT_WRITE, MAP_SHARED, fbfd, 0); if (G.addr == MAP_FAILED) bb_perror_msg_and_die("mmap"); + + // point to the start of the visible screen + G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * BYTES_PER_PIXEL; close(fbfd); } -- cgit v1.2.3-55-g6feb From 1bb52a9b73772d47a49bcaee0eb4eeb0c68b9b4c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Feb 2011 03:58:43 +0100 Subject: ping: fix IPv6 pinging. Closes bug 3187 Signed-off-by: Denys Vlasenko --- networking/ping.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/ping.c b/networking/ping.c index 11ce24eb5..28ccbb0bb 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -484,7 +484,7 @@ static void sendping4(int junk UNUSED_PARAM) #if ENABLE_PING6 static void sendping6(int junk UNUSED_PARAM) { - struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4); + struct icmp6_hdr *pkt = G.snd_packet; //memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4); pkt->icmp6_type = ICMP6_ECHO_REQUEST; -- cgit v1.2.3-55-g6feb From 281e7b8848108f26253ffc466fc149c04665a2c2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Feb 2011 17:51:45 +0100 Subject: ping: trivial simplification. -2 bytes Signed-off-by: Denys Vlasenko --- networking/ping.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index 28ccbb0bb..c2ff42e2c 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -419,16 +419,18 @@ static void print_stats_and_exit(int junk UNUSED_PARAM) exit(nreceived == 0 || (deadline && nreceived < pingcount)); } -static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) +static void sendping_tail(void (*sp)(int), int size_pkt) { int sz; CLR((uint16_t)ntransmitted % MAX_DUP_CHK); ntransmitted++; + size_pkt += datalen; + /* sizeof(pingaddr) can be larger than real sa size, but I think * it doesn't matter */ - sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr)); + sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); if (sz != size_pkt) bb_error_msg_and_die(bb_msg_write_error); @@ -479,7 +481,7 @@ static void sendping4(int junk UNUSED_PARAM) pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); - sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN); + sendping_tail(sendping4, ICMP_MINLEN); } #if ENABLE_PING6 static void sendping6(int junk UNUSED_PARAM) @@ -498,7 +500,7 @@ static void sendping6(int junk UNUSED_PARAM) //TODO? pkt->icmp_cksum = in_cksum(...); - sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); + sendping_tail(sendping6, sizeof(struct icmp6_hdr)); } #endif -- cgit v1.2.3-55-g6feb From fbea22056014a05a0c6619eb458d4955869b5e93 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Feb 2011 18:00:58 +0100 Subject: udhcpc: fix a problem with binary-encoded options function old new delta attach_option 395 413 +18 Signed-off-by: Denys Vlasenko --- networking/udhcp/common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 311f79e7e..0a60261ab 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -375,7 +375,7 @@ static NOINLINE void attach_option( new->data = xmalloc(length + OPT_DATA); new->data[OPT_CODE] = optflag->code; new->data[OPT_LEN] = length; - memcpy(new->data + OPT_DATA, buffer, length); + memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length); curr = opt_list; while (*curr && (*curr)->data[OPT_CODE] < optflag->code) -- cgit v1.2.3-55-g6feb From ca18e25525267736e7e919987c50569f27d70d36 Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Sun, 6 Feb 2011 12:29:25 -0500 Subject: runlevel/wall: depend on utmp feature These utils use funcs from utmp.h (like setutent), but utmp.h is only included when FEATURE_UTMP is enabled. Otherwise we get build failures due to missing defines/prototypes. So depend on this option. Signed-off-by: Mike Frysinger --- miscutils/Config.src | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miscutils/Config.src b/miscutils/Config.src index da52e14c6..b5866bbd7 100644 --- a/miscutils/Config.src +++ b/miscutils/Config.src @@ -583,6 +583,7 @@ config RFKILL config RUNLEVEL bool "runlevel" default y + depends on FEATURE_UTMP help find the current and previous system runlevel. @@ -658,6 +659,7 @@ config VOLNAME config WALL bool "wall" default y + depends on FEATURE_UTMP help Write a message to all users that are logged in. -- cgit v1.2.3-55-g6feb From aef441cb4d567da5575c498141b21eb38dc3fdaf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Feb 2011 20:01:11 +0100 Subject: tar: fix a bug where autodetection messes up -z on extract Signed-off-by: Denys Vlasenko --- archival/libarchive/get_header_tar_gz.c | 4 ++-- archival/tar.c | 6 ++++-- include/archive.h | 20 ++++++++++---------- testsuite/tar.tests | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 14 deletions(-) diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c index b09f8691c..889fed0d9 100644 --- a/archival/libarchive/get_header_tar_gz.c +++ b/archival/libarchive/get_header_tar_gz.c @@ -9,7 +9,7 @@ char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) { #if BB_MMU - unsigned char magic[2]; + uint16_t magic; #endif /* Can't lseek over pipes */ @@ -21,7 +21,7 @@ char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) #if BB_MMU xread(archive_handle->src_fd, &magic, 2); /* Can skip this check, but error message will be less clear */ - if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { + if (magic != GZIP_MAGIC) { bb_error_msg_and_die("invalid gzip magic"); } #endif diff --git a/archival/tar.c b/archival/tar.c index e9dc41fe1..1e3cecf44 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1060,8 +1060,10 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->src_fd = tar_fd; tar_handle->seek = seek_by_read; } else { - if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) { - get_header_ptr = get_header_tar; + if (ENABLE_FEATURE_TAR_AUTODETECT + && flags == O_RDONLY + && get_header_ptr == get_header_tar + ) { tar_handle->src_fd = open_zipped(tar_filename); if (tar_handle->src_fd < 0) bb_perror_msg_and_die("can't open '%s'", tar_filename); diff --git a/include/archive.h b/include/archive.h index ba6d323e0..49c478728 100644 --- a/include/archive.h +++ b/include/archive.h @@ -8,22 +8,22 @@ enum { #if BB_BIG_ENDIAN COMPRESS_MAGIC = 0x1f9d, GZIP_MAGIC = 0x1f8b, - BZIP2_MAGIC = 'B' * 256 + 'Z', + BZIP2_MAGIC = 256 * 'B' + 'Z', /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ /* More info at: http://tukaani.org/xz/xz-file-format.txt */ - XZ_MAGIC1 = 0xfd * 256 + '7', - XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, + XZ_MAGIC1 = 256 * 0xfd + '7', + XZ_MAGIC2 = 256 * (256 * (256 * 'z' + 'X') + 'Z') + 0, /* Different form: 32 bits, then 16 bits: */ - XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', - XZ_MAGIC2a = 'Z' * 256 + 0, + XZ_MAGIC1a = 256 * (256 * (256 * 0xfd + '7') + 'z') + 'X', + XZ_MAGIC2a = 256 * 'Z' + 0, #else COMPRESS_MAGIC = 0x9d1f, GZIP_MAGIC = 0x8b1f, - BZIP2_MAGIC = 'Z' * 256 + 'B', - XZ_MAGIC1 = '7' * 256 + 0xfd, - XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', - XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, - XZ_MAGIC2a = 0 * 256 + 'Z', + BZIP2_MAGIC = 'B' + 'Z' * 256, + XZ_MAGIC1 = 0xfd + '7' * 256, + XZ_MAGIC2 = 'z' + ('X' + ('Z' + 0 * 256) * 256) * 256, + XZ_MAGIC1a = 0xfd + ('7' + ('z' + 'X' * 256) * 256) * 256, + XZ_MAGIC2a = 'Z' + 0 * 256, #endif }; diff --git a/testsuite/tar.tests b/testsuite/tar.tests index f2f4e9348..824d6d54e 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -154,6 +154,20 @@ dr-xr-x--- input_dir SKIP= } +# Had a bug where on extrace autodetect first "switched off" -z +# and then failed to recognize .tgz extension +testing "tar extract tgz" "\ +dd count=1 bs=1M if=/dev/zero of=F0 2>/dev/null +tar -czf F0.tgz F0 +rm F0 +tar -xzvf F0.tgz && echo Ok +rm F0 || echo BAD +" "\ +F0 +Ok +" \ +"" "" + cd .. && rm -rf tar.tempdir || exit 1 -- cgit v1.2.3-55-g6feb From b8ab4b038803df195eee9844c3597dd640c00393 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Feb 2011 20:02:15 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- testsuite/tar.tests | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testsuite/tar.tests b/testsuite/tar.tests index 824d6d54e..472064f7f 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -154,7 +154,7 @@ dr-xr-x--- input_dir SKIP= } -# Had a bug where on extrace autodetect first "switched off" -z +# Had a bug where on extract autodetect first "switched off" -z # and then failed to recognize .tgz extension testing "tar extract tgz" "\ dd count=1 bs=1M if=/dev/zero of=F0 2>/dev/null -- cgit v1.2.3-55-g6feb From 8ee2adab21328761b80e0cbc513eda7eaa880b24 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Feb 2011 02:03:51 +0100 Subject: echo: do not retry on write errors function old new delta echo_main 297 336 +39 stpcpy - 22 +22 run_pipe 1561 1566 +5 pseudo_exec_argv 187 192 +5 hush_exit 75 80 +5 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 4/0 up/down: 98/0) Total: 76 bytes Signed-off-by: Denys Vlasenko --- coreutils/echo.c | 87 +++++++++++++----------- shell/ash_test/ash-misc/echo_write_error.right | 2 + shell/ash_test/ash-misc/echo_write_error.tests | 7 ++ shell/ash_test/ash-redir/redir.right | 1 + shell/hush.c | 8 ++- shell/hush_test/hush-misc/echo_write_error.right | 2 + shell/hush_test/hush-misc/echo_write_error.tests | 7 ++ 7 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 shell/ash_test/ash-misc/echo_write_error.right create mode 100644 shell/ash_test/ash-misc/echo_write_error.tests create mode 100644 shell/hush_test/hush-misc/echo_write_error.right create mode 100755 shell/hush_test/hush-misc/echo_write_error.tests diff --git a/coreutils/echo.c b/coreutils/echo.c index 3821e594e..5fa3d10c5 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -29,46 +29,42 @@ /* NB: can be used by shell even if not enabled as applet */ +/* + * NB2: we don't use stdio, we need better error handing. + * Examples include writing into non-opened stdout and error on write. + * + * With stdio, output gets shoveled into stdout buffer, and even + * fflush cannot clear it out. It seems that even if libc receives + * EBADF on write attempts, it feels determined to output data no matter what. + * If echo is called by shell, it will try writing again later, and possibly + * will clobber future output. Not good. + * + * Solaris has fpurge which discards buffered input. glibc has __fpurge. + * But this function is not standard. + */ + int echo_main(int argc UNUSED_PARAM, char **argv) { + char **pp; const char *arg; + char *out; + char *buffer; + unsigned buflen; + int r; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = '\\', nflag = 1, /* 1 -- print '\n' */ }; - /* We must check that stdout is not closed. - * The reason for this is highly non-obvious. - * echo_main is used from shell. Shell must correctly handle "echo foo" - * if stdout is closed. With stdio, output gets shoveled into - * stdout buffer, and even fflush cannot clear it out. It seems that - * even if libc receives EBADF on write attempts, it feels determined - * to output data no matter what. So it will try later, - * and possibly will clobber future output. Not good. */ -// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? - if (fcntl(1, F_GETFL) == -1) - return 1; /* match coreutils 6.10 (sans error msg to stderr) */ - //if (dup2(1, 1) != 1) - old way - // return 1; - - arg = *++argv; - if (!arg) - goto newline_ret; + argv++; #else const char *p; char nflag = 1; char eflag = 0; - /* We must check that stdout is not closed. */ - if (fcntl(1, F_GETFL) == -1) - return 1; - - while (1) { - arg = *++argv; - if (!arg) - goto newline_ret; - if (*arg != '-') + while ((arg = *++argv) != NULL) { + if (!arg || arg[0] != '-') break; /* If it appears that we are handling options, then make sure @@ -77,7 +73,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) */ p = arg + 1; if (!*p) /* A single '-', so echo it. */ - goto just_echo; + break; do { if (!strrchr("neE", *p)) @@ -95,19 +91,27 @@ int echo_main(int argc UNUSED_PARAM, char **argv) } just_echo: #endif - while (1) { - /* arg is already == *argv and isn't NULL */ + + buflen = 1; + pp = argv; + while ((arg = *pp) != NULL) { + buflen += strlen(arg) + 1; + pp++; + } + out = buffer = xmalloc(buflen); + + while ((arg = *argv) != NULL) { int c; if (!eflag) { /* optimization for very common case */ - fputs(arg, stdout); + out = stpcpy(out, arg); } else while ((c = *arg++)) { if (c == eflag) { /* Check for escape seq. */ if (*arg == 'c') { /* '\c' means cancel newline and * ignore all subsequent chars. */ - goto ret; + goto do_write; } #if !ENABLE_FEATURE_FANCY_ECHO /* SUSv3 specifies that octal escapes must begin with '0'. */ @@ -127,21 +131,26 @@ int echo_main(int argc UNUSED_PARAM, char **argv) c = bb_process_escape_sequence(&arg); } } - bb_putchar(c); + *out++ = c; } - arg = *++argv; - if (!arg) + if (!*++argv) break; - bb_putchar(' '); + *out++ = ' '; } - newline_ret: if (nflag) { - bb_putchar('\n'); + *out++ = '\n'; } - ret: - return fflush_all(); + + do_write: + r = full_write(STDOUT_FILENO, buffer, out - buffer); + free(buffer); + if (r < 0) { + bb_perror_msg(bb_msg_write_error); + return 1; + } + return 0; } /*- diff --git a/shell/ash_test/ash-misc/echo_write_error.right b/shell/ash_test/ash-misc/echo_write_error.right new file mode 100644 index 000000000..3e91a13d3 --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.right @@ -0,0 +1,2 @@ +ash: write error: Broken pipe +Ok: 1 diff --git a/shell/ash_test/ash-misc/echo_write_error.tests b/shell/ash_test/ash-misc/echo_write_error.tests new file mode 100644 index 000000000..0a40c9ff7 --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right index 2a02d41ce..c1a6e729a 100644 --- a/shell/ash_test/ash-redir/redir.right +++ b/shell/ash_test/ash-redir/redir.right @@ -1 +1,2 @@ +ash: write error: Bad file descriptor TEST diff --git a/shell/hush.c b/shell/hush.c index 10788b8e7..e857e7464 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1418,6 +1418,7 @@ static void sigexit(int sig) static void hush_exit(int exitcode) NORETURN; static void hush_exit(int exitcode) { + fflush_all(); if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { /* Prevent recursion: * trap "echo Hi; exit" EXIT; exit @@ -6105,10 +6106,13 @@ static void exec_builtin(char ***to_free, char **argv) { #if BB_MMU - int rcode = x->b_function(argv); + int rcode; + fflush_all(); + rcode = x->b_function(argv); fflush_all(); _exit(rcode); #else + fflush_all(); /* On NOMMU, we must never block! * Example: { sleep 99 | read line; } & echo Ok */ @@ -6832,6 +6836,7 @@ static NOINLINE int run_pipe(struct pipe *pi) if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", x->b_cmd, argv_expanded[1]); + fflush_all(); rcode = x->b_function(argv_expanded) & 0xff; fflush_all(); } @@ -7641,6 +7646,7 @@ int hush_main(int argc, char **argv) G.global_argc -= builtin_argc; /* skip [BARGV...] "" */ G.global_argv += builtin_argc; G.global_argv[-1] = NULL; /* replace "" */ + fflush_all(); G.last_exitcode = x->b_function(argv + optind - 1); } goto final_return; diff --git a/shell/hush_test/hush-misc/echo_write_error.right b/shell/hush_test/hush-misc/echo_write_error.right new file mode 100644 index 000000000..ddcad4363 --- /dev/null +++ b/shell/hush_test/hush-misc/echo_write_error.right @@ -0,0 +1,2 @@ +hush: write error: Broken pipe +Ok: 1 diff --git a/shell/hush_test/hush-misc/echo_write_error.tests b/shell/hush_test/hush-misc/echo_write_error.tests new file mode 100755 index 000000000..0a40c9ff7 --- /dev/null +++ b/shell/hush_test/hush-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } -- cgit v1.2.3-55-g6feb From 5a746dcec5c1e09c3cff0326c3b205d2427861f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Feb 2011 02:19:02 +0100 Subject: scripts/kconfig/mconf.c: stop-gap fix for buffer overflow Signed-off-by: Denys Vlasenko --- scripts/kconfig/mconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 0c548bfc0..d292b46cc 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -256,7 +256,7 @@ search_help[] = N_( " USB$ => find all CONFIG_ symbols ending with USB\n" "\n"); -static char buf[4096], *bufptr = buf; +static char buf[4096*10], *bufptr = buf; static char input_buf[4096]; static const char filename[] = ".config"; static char *args[1024], **argptr = args; -- cgit v1.2.3-55-g6feb From dd807c16f99b4ead544289b83c88cc2488542f72 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Feb 2011 14:58:57 +0100 Subject: incorporate header fixes proposed in bug 3097 Not sure these are *really* needed, but I suppose they don't hurt Signed-off-by: Denys Vlasenko --- include/libbb.h | 3 +++ include/platform.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/include/libbb.h b/include/libbb.h index 6358e654a..dd82e9754 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -33,6 +33,9 @@ #include #include #include +#ifndef major +# include +#endif #include #include #include diff --git a/include/platform.h b/include/platform.h index 9d6e21626..f0b8ec10a 100644 --- a/include/platform.h +++ b/include/platform.h @@ -362,7 +362,7 @@ typedef unsigned smalluint; #endif -#if defined(__GLIBC__) +#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L) || defined(__GLIBC__) # define fdprintf dprintf #endif -- cgit v1.2.3-55-g6feb From 66c5b12dbf85142eea257ba6047191d7c0ee43f3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Feb 2011 05:07:02 +0100 Subject: ash: fix TMOUT not restoring tty attributes function old new delta pgetc 420 500 +80 readtoken1 3202 3239 +37 read_line_input 3316 3337 +21 udhcpc_main 2610 2630 +20 file_get 266 272 +6 expandarg 958 963 +5 localcmd 257 259 +2 addLines 85 87 +2 read_line 94 95 +1 ed_main 2540 2541 +1 timed_out 1 - -1 lineedit_read_key 256 255 -1 alrm_sighandler 44 - -44 cmdloop 539 434 -105 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 10/2 up/down: 175/-151) Total: 24 bytes text data bss dec hex filename 887379 936 17200 905515 dd12b busybox_old 887411 936 17192 905539 dd143 busybox_unstripped Signed-off-by: Denys Vlasenko --- editors/ed.c | 6 ++--- include/libbb.h | 5 ++-- libbb/lineedit.c | 12 ++++----- shell/ash.c | 73 ++++++++++++++++++++---------------------------------- shell/hush.c | 2 +- util-linux/fdisk.c | 2 +- 6 files changed, 39 insertions(+), 61 deletions(-) diff --git a/editors/ed.c b/editors/ed.c index 859668406..b1b6a8d27 100644 --- a/editors/ed.c +++ b/editors/ed.c @@ -129,7 +129,7 @@ static void doCommands(void) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(": ", buf, sizeof(buf), NULL); + len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) return; endbuf = &buf[len - 1]; @@ -227,7 +227,7 @@ static void doCommands(void) } if (!dirty) return; - len = read_line_input("Really quit? ", buf, 16, NULL); + len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); /* read error/EOF - no way to continue */ if (len < 0) return; @@ -541,7 +541,7 @@ static void addLines(int num) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input("", buf, sizeof(buf), NULL); + len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) { /* Previously, ctrl-C was exiting to shell. * Now we exit to ed prompt. Is in important? */ diff --git a/include/libbb.h b/include/libbb.h index dd82e9754..78b390611 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1403,12 +1403,11 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC; * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -/* NB: ash has timeout code which can be moved into read_line_input, if needed */ -int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC; +int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; #else #define MAX_HISTORY 0 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; -#define read_line_input(prompt, command, maxsize, state) \ +#define read_line_input(state, prompt, command, maxsize, timeout) \ read_line_input(prompt, command, maxsize) #endif diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 5dd835cca..afd28b75c 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1809,10 +1809,9 @@ static void win_changed(int nsig) errno = sv_errno; } -static int lineedit_read_key(char *read_key_buffer) +static int lineedit_read_key(char *read_key_buffer, int timeout) { int64_t ic; - int timeout = -1; #if ENABLE_UNICODE_SUPPORT char unicode_buf[MB_CUR_MAX + 1]; int unicode_idx = 0; @@ -1917,7 +1916,7 @@ static int isrtl_str(void) * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) +int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) { int len; #if ENABLE_FEATURE_TAB_COMPLETION @@ -1991,7 +1990,6 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li new_settings.c_cc[VINTR] = _POSIX_VDISABLE; tcsetattr_stdin_TCSANOW(&new_settings); - /* Now initialize things */ previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); win_changed(0); /* do initial resizing */ #if ENABLE_USERNAME_OR_HOMEDIR @@ -2033,7 +2031,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li int32_t ic, ic_raw; fflush_all(); - ic = ic_raw = lineedit_read_key(read_key_buffer); + ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); #if ENABLE_FEATURE_EDITING_VI newdelflag = 1; @@ -2194,7 +2192,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case 'd'|VI_CMDMODE_BIT: { int nc, sc; - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ goto return_error_indicator; if (ic == ic_raw) { /* "cc", "dd" */ @@ -2258,7 +2256,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li break; case 'r'|VI_CMDMODE_BIT: //FIXME: unicode case? - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ goto return_error_indicator; if (ic < ' ' || ic > 255) { diff --git a/shell/ash.c b/shell/ash.c index bdc64790c..aaf21cd6f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -102,8 +102,7 @@ //config: default n //config: depends on ASH //config: help -//config: Enables bash-like auto-logout after "$TMOUT" seconds -//config: of idle time. +//config: Enables bash-like auto-logout after $TMOUT seconds of idle time. //config: //config:config ASH_JOB_CONTROL //config: bool "Job control" @@ -408,6 +407,9 @@ static const char *var_end(const char *var) /* ============ Interrupts / exceptions */ + +static void exitshell(void) NORETURN; + /* * These macros allow the user to suspend the handling of interrupt signals * over a period of time. This is similar to SIGHOLD or to sigblock, but @@ -9573,10 +9575,21 @@ preadfd(void) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { + int timeout = -1; +# if ENABLE_ASH_IDLE_TIMEOUT + if (iflag) { + const char *tmout_var = lookupvar("TMOUT"); + if (tmout_var) { + timeout = atoi(tmout_var) * 1000; + if (timeout <= 0) + timeout = -1; + } + } +# endif # if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); # endif - nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); + nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); if (nr == 0) { /* Ctrl+C pressed */ if (trap[SIGINT]) { @@ -9587,9 +9600,17 @@ preadfd(void) } goto retry; } - if (nr < 0 && errno == 0) { - /* Ctrl+D pressed */ - nr = 0; + if (nr < 0) { + if (errno == 0) { + /* Ctrl+D pressed */ + nr = 0; + } +# if ENABLE_ASH_IDLE_TIMEOUT + else if (errno == EAGAIN && timeout > 0) { + printf("\007timed out waiting for input: auto-logout\n"); + exitshell(); + } +# endif } } #else @@ -12056,23 +12077,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv) return exitstatus; } -#if ENABLE_ASH_IDLE_TIMEOUT -static smallint timed_out; - -static void alrm_sighandler(int sig UNUSED_PARAM) -{ - /* Close stdin, making interactive command reading stop. - * Otherwise, timeout doesn't trigger until is pressed. - */ - int sv = errno; - close(0); - open("/dev/null", O_RDONLY); - errno = sv; - - timed_out = 1; -} -#endif - /* * Read and execute commands. * "Top" is nonzero for the top level command loop; @@ -12089,20 +12093,6 @@ cmdloop(int top) TRACE(("cmdloop(%d) called\n", top)); for (;;) { int skip; -#if ENABLE_ASH_IDLE_TIMEOUT - int tmout_seconds = 0; - - if (top && iflag) { - const char *tmout_var = lookupvar("TMOUT"); - if (tmout_var) { - tmout_seconds = atoi(tmout_var); - if (tmout_seconds > 0) { - signal(SIGALRM, alrm_sighandler); - alarm(tmout_seconds); - } - } - } -#endif setstackmark(&smark); #if JOBS @@ -12115,14 +12105,6 @@ cmdloop(int top) chkmail(); } n = parsecmd(inter); -#if ENABLE_ASH_IDLE_TIMEOUT - if (timed_out) { - printf("\007timed out waiting for input: auto-logout\n"); - break; - } - if (tmout_seconds > 0) - alarm(0); -#endif #if DEBUG if (DEBUG > 2 && debug && (n != NODE_EOF)) showtree(n); @@ -12850,7 +12832,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv) /* * Called to exit the shell. */ -static void exitshell(void) NORETURN; static void exitshell(void) { diff --git a/shell/hush.c b/shell/hush.c index e857e7464..00ef361cd 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1902,7 +1902,7 @@ static void get_user_input(struct in_str *i) G.flag_SIGINT = 0; /* buglet: SIGINT will not make new prompt to appear _at once_, * only after . (^C will work) */ - r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state); + r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); /* catch *SIGINT* etc (^C is handled by read_line_input) */ check_and_run_traps(0); } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 02785ab85..0b93c22cc 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -548,7 +548,7 @@ read_line(const char *prompt) { int sz; - sz = read_line_input(prompt, line_buffer, sizeof(line_buffer), NULL); + sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1); if (sz <= 0) exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ -- cgit v1.2.3-55-g6feb From 698e8095fa8d5b5b039168205dd24698b95dc6a6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Feb 2011 05:35:04 +0100 Subject: use unistd.h before _POSIX_VERSION Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 - include/platform.h | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/include/libbb.h b/include/libbb.h index 78b390611..d390e6840 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -39,7 +39,6 @@ #include #include #include -#include #include #ifdef HAVE_MNTENT_H # include diff --git a/include/platform.h b/include/platform.h index f0b8ec10a..00ebe563b 100644 --- a/include/platform.h +++ b/include/platform.h @@ -362,6 +362,7 @@ typedef unsigned smalluint; #endif +#include #if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200809L) || defined(__GLIBC__) # define fdprintf dprintf #endif -- cgit v1.2.3-55-g6feb From e7212a4ce5aa3570f7195c48335f0280a0fd4383 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 9 Feb 2011 01:33:41 +0100 Subject: scripts/mkconfigs: don't use invalid basic regexp \? are GNU extension and thus are non-standard Signed-off-by: Denys Vlasenko --- scripts/mkconfigs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/mkconfigs b/scripts/mkconfigs index 47ac53330..7488d294e 100755 --- a/scripts/mkconfigs +++ b/scripts/mkconfigs @@ -42,7 +42,7 @@ echo "\ */ static const char bbconfig_config[] ALIGN1 =" -grep '^#\? \?CONFIG_' "$config" \ +grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ | sed -e 's/\"/\\\"/g' -e 's/^/"/' -e 's/$/\\n"/' echo ";" -- cgit v1.2.3-55-g6feb From f13347130245f9fb86ecb3b9c217d3c558a717a9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 9 Feb 2011 04:39:09 +0100 Subject: iproute: fix handling of "dev IFACE" selector Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 38 ++++++++++++++++++++++++-------------- networking/libiproute/libnetlink.c | 1 + 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index f6071b463..14fc16c4d 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -31,8 +31,8 @@ struct filter_t { //int type; - read-only //int typemask; - unused //int tos, tosmask; - unused - int iif, iifmask; - int oif, oifmask; + int iif; + int oif; //int realm, realmmask; - unused //inet_prefix rprefsrc; - read-only inet_prefix rvia; @@ -182,17 +182,25 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, ) { return 0; } - if (G_filter.flushb - && r->rtm_family == AF_INET6 - && r->rtm_dst_len == 0 - && r->rtm_type == RTN_UNREACHABLE - && tb[RTA_PRIORITY] - && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 - ) { - return 0; + if (G_filter.oif != 0) { + if (!tb[RTA_OIF]) + return 0; + if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF])) + return 0; } if (G_filter.flushb) { + /* We are creating route flush commands */ + + if (r->rtm_family == AF_INET6 + && r->rtm_dst_len == 0 + && r->rtm_type == RTN_UNREACHABLE + && tb[RTA_PRIORITY] + && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 + ) { + return 0; + } + struct nlmsghdr *fn; if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { if (flush_update()) @@ -208,6 +216,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, return 0; } + /* We are printing routes */ + if (n->nlmsg_type == RTM_DELROUTE) { printf("Deleted "); } @@ -257,10 +267,12 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } - if (tb[RTA_OIF] && G_filter.oifmask != -1) { + if (tb[RTA_OIF]) { printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); } + /* Todo: parse & show "proto kernel", "scope link" here */ + if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. @@ -292,7 +304,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, printf(" error %d", ci->rta_error); } } - if (tb[RTA_IIF] && G_filter.iifmask != -1) { + if (tb[RTA_IIF] && G_filter.iif == 0) { printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); } bb_putchar('\n'); @@ -662,12 +674,10 @@ static int iproute_list_or_flush(char **argv, int flush) if (id) { idx = xll_name_to_index(id); G_filter.iif = idx; - G_filter.iifmask = -1; } if (od) { idx = xll_name_to_index(od); G_filter.oif = idx; - G_filter.oifmask = -1; } } diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index 7291ee2f1..547013ff6 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -55,6 +55,7 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty return rtnl_send(rth, (void*)&req, sizeof(req)); } +//TODO: pass rth->fd instead of full rth? int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; -- cgit v1.2.3-55-g6feb From 77350aa93392d36dc419d3e11bda6bf9bed993ff Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 06:28:09 +0100 Subject: tc: less ugly check for bad sizeof(G) Signed-off-by: Denys Vlasenko --- networking/tc.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/networking/tc.c b/networking/tc.c index 2e2473a70..9b3245546 100644 --- a/networking/tc.c +++ b/networking/tc.c @@ -43,17 +43,15 @@ struct globals { __u32 filter_proto; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +struct BUG_G_too_big { + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; +}; #define filter_ifindex (G.filter_ifindex) #define filter_qdisc (G.filter_qdisc) #define filter_parent (G.filter_parent) #define filter_prio (G.filter_prio) #define filter_proto (G.filter_proto) - -void BUG_tc_globals_too_big(void); -#define INIT_G() do { \ - if (sizeof(G) > COMMON_BUFSIZE) \ - BUG_tc_globals_too_big(); \ -} while (0) +#define INIT_G() do { } while (0) /* Allocates a buffer containing the name of a class id. * The caller must free the returned memory. */ -- cgit v1.2.3-55-g6feb From df4e16c9af6d6270d91d17d31c6098ecb259e5cc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 06:29:06 +0100 Subject: wget: use FEATURE_COPYBUF_KB-sized buffer. Much faster for local transfers function old new delta base64enc - 53 +53 gethdr 190 200 +10 ftpcmd 129 133 +4 progress_meter 160 122 -38 retrieve_file_data 431 392 -39 base64enc_512 46 - -46 wget_main 2456 2220 -236 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/3 up/down: 67/-359) Total: -292 bytes Signed-off-by: Denys Vlasenko --- libbb/Config.src | 2 +- networking/wget.c | 121 +++++++++++++++++++++++++++--------------------------- 2 files changed, 62 insertions(+), 61 deletions(-) diff --git a/libbb/Config.src b/libbb/Config.src index dfb897d5f..18bdc5151 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -156,7 +156,7 @@ config FEATURE_COPYBUF_KB range 1 1024 default 4 help - Size of buffer used by cp, mv, install etc. + Size of buffer used by cp, mv, install, wget etc. Buffers which are 4 kb or less will be allocated on stack. Bigger buffers will be allocated with mmap, with fallback to 4 kb stack buffer if mmap fails. diff --git a/networking/wget.c b/networking/wget.c index 0db9b3365..8e636bd39 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -35,12 +35,16 @@ struct globals { #endif smallint chunked; /* chunked transfer encoding */ smallint got_clen; /* got content-length: from server */ + /* Local downloads do benefit from big buffer. + * With 512 byte buffer, it was measured to be + * an order of magnitude slower than with big one. + */ + uint64_t just_to_align_next_member; + char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024]; } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) -struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; -}; +#define G (*ptr_to_globals) #define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) \ } while (0) @@ -158,14 +162,14 @@ static char *safe_fgets(char *s, int size, FILE *stream) } #if ENABLE_FEATURE_WGET_AUTHENTICATION -/* Base64-encode character string. buf is assumed to be char buf[512]. */ -static char *base64enc_512(char buf[512], const char *str) +/* Base64-encode character string. */ +static char *base64enc(const char *str) { unsigned len = strlen(str); - if (len > 512/4*3 - 10) /* paranoia */ - len = 512/4*3 - 10; - bb_uuencode(buf, str, len, bb_uuenc_tbl_base64); - return buf; + if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */ + len = sizeof(G.wget_buf)/4*3 - 10; + bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64); + return G.wget_buf; } #endif @@ -191,7 +195,7 @@ static FILE *open_socket(len_and_sockaddr *lsa) return fp; } -static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) +static int ftpcmd(const char *s1, const char *s2, FILE *fp) { int result; if (s1) { @@ -203,18 +207,18 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) do { char *buf_ptr; - if (fgets(buf, 510, fp) == NULL) { + if (fgets(G.wget_buf, sizeof(G.wget_buf)-2, fp) == NULL) { bb_perror_msg_and_die("error getting response"); } - buf_ptr = strstr(buf, "\r\n"); + buf_ptr = strstr(G.wget_buf, "\r\n"); if (buf_ptr) { *buf_ptr = '\0'; } - } while (!isdigit(buf[0]) || buf[3] != ' '); + } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); - buf[3] = '\0'; - result = xatoi_positive(buf); - buf[3] = ' '; + G.wget_buf[3] = '\0'; + result = xatoi_positive(G.wget_buf); + G.wget_buf[3] = ' '; return result; } @@ -278,7 +282,7 @@ static void parse_url(char *src_url, struct host_info *h) sp = h->host; } -static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) +static char *gethdr(FILE *fp /*, int *istrunc*/) { char *s, *hdrval; int c; @@ -286,24 +290,24 @@ static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) /* *istrunc = 0; */ /* retrieve header line */ - if (fgets(buf, bufsiz, fp) == NULL) + if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL) return NULL; /* see if we are at the end of the headers */ - for (s = buf; *s == '\r'; ++s) + for (s = G.wget_buf; *s == '\r'; ++s) continue; if (*s == '\n') return NULL; /* convert the header name to lower case */ - for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { + for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { /* tolower for "A-Z", no-op for "0-9a-z-." */ *s = (*s | 0x20); } /* verify we are at the end of the header name */ if (*s != ':') - bb_error_msg_and_die("bad header line: %s", sanitize_string(buf)); + bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf)); /* locate the start of the header value */ *s++ = '\0'; @@ -366,7 +370,6 @@ static char *URL_escape(const char *str) static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) { - char buf[512]; FILE *sfp; char *str; int port; @@ -375,8 +378,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ target->user = xstrdup("anonymous:busybox@"); sfp = open_socket(lsa); - if (ftpcmd(NULL, NULL, sfp, buf) != 220) - bb_error_msg_and_die("%s", sanitize_string(buf+4)); + if (ftpcmd(NULL, NULL, sfp) != 220) + bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4)); /* * Splitting username:password pair, @@ -385,24 +388,24 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ str = strchr(target->user, ':'); if (str) *str++ = '\0'; - switch (ftpcmd("USER ", target->user, sfp, buf)) { + switch (ftpcmd("USER ", target->user, sfp)) { case 230: break; case 331: - if (ftpcmd("PASS ", str, sfp, buf) == 230) + if (ftpcmd("PASS ", str, sfp) == 230) break; /* fall through (failed login) */ default: - bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4)); + bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4)); } - ftpcmd("TYPE I", NULL, sfp, buf); + ftpcmd("TYPE I", NULL, sfp); /* * Querying file size */ - if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) { - G.content_len = BB_STRTOOFF(buf+4, NULL, 10); + if (ftpcmd("SIZE ", target->path, sfp) == 213) { + G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("SIZE value is garbage"); } @@ -412,20 +415,20 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ /* * Entering passive mode */ - if (ftpcmd("PASV", NULL, sfp, buf) != 227) { + if (ftpcmd("PASV", NULL, sfp) != 227) { pasv_error: - bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf)); + bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf)); } // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] // Server's IP is N1.N2.N3.N4 (we ignore it) // Server's port for data connection is P1*256+P2 - str = strrchr(buf, ')'); + str = strrchr(G.wget_buf, ')'); if (str) str[0] = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port = xatou_range(str+1, 0, 255); *str = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port += xatou_range(str+1, 0, 255) * 256; set_nport(lsa, htons(port)); @@ -433,20 +436,19 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ *dfpp = open_socket(lsa); if (G.beg_range) { - sprintf(buf, "REST %"OFF_FMT"u", G.beg_range); - if (ftpcmd(buf, NULL, sfp, buf) == 350) + sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range); + if (ftpcmd(G.wget_buf, NULL, sfp) == 350) G.content_len -= G.beg_range; } - if (ftpcmd("RETR ", target->path, sfp, buf) > 150) - bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf)); + if (ftpcmd("RETR ", target->path, sfp) > 150) + bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf)); return sfp; } static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) { - char buf[512]; #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT # if ENABLE_FEATURE_WGET_TIMEOUT unsigned second_cnt; @@ -468,9 +470,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) int n; unsigned rdsz; - rdsz = sizeof(buf); + rdsz = sizeof(G.wget_buf); if (G.got_clen) { - if (G.content_len < (off_t)sizeof(buf)) { + if (G.content_len < (off_t)sizeof(G.wget_buf)) { if ((int)G.content_len <= 0) break; rdsz = (unsigned)G.content_len; @@ -493,7 +495,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) progress_meter(PROGRESS_BUMP); } #endif - n = safe_fread(buf, rdsz, dfp); + n = safe_fread(G.wget_buf, rdsz, dfp); if (n <= 0) { if (ferror(dfp)) { /* perror will not work: ferror doesn't set errno */ @@ -501,7 +503,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) } break; } - xwrite(output_fd, buf, n); + xwrite(output_fd, G.wget_buf, n); #if ENABLE_FEATURE_WGET_STATUSBAR G.transferred += n; progress_meter(PROGRESS_BUMP); @@ -513,10 +515,10 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) if (!G.chunked) break; - safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ + safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */ get_clen: - safe_fgets(buf, sizeof(buf), dfp); - G.content_len = STRTOOFF(buf, NULL, 16); + safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); + G.content_len = STRTOOFF(G.wget_buf, NULL, 16); /* FIXME: error check? */ if (G.content_len == 0) break; /* all done! */ @@ -529,7 +531,6 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wget_main(int argc UNUSED_PARAM, char **argv) { - char buf[512]; struct host_info server, target; len_and_sockaddr *lsa; unsigned opt; @@ -709,11 +710,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, - base64enc_512(buf, target.user)); + base64enc(target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", - base64enc_512(buf, server.user)); + base64enc(server.user)); } #endif @@ -743,10 +744,10 @@ int wget_main(int argc UNUSED_PARAM, char **argv) * Retrieve HTTP response line and check for "200" status code. */ read_response: - if (fgets(buf, sizeof(buf), sfp) == NULL) + if (fgets(G.wget_buf, sizeof(G.wget_buf), sfp) == NULL) bb_error_msg_and_die("no response from server"); - str = buf; + str = G.wget_buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check @@ -755,7 +756,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) switch (status) { case 0: case 100: - while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) + while (gethdr(sfp /*, &n*/) != NULL) /* eat all remaining headers */; goto read_response; case 200: @@ -795,13 +796,13 @@ However, in real world it was observed that some web servers break; /* fall through */ default: - bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); + bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); } /* * Retrieve HTTP headers. */ - while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { + while ((str = gethdr(sfp /*, &n*/)) != NULL) { /* gethdr converted "FOO:" string to lowercase */ smalluint key; /* strip trailing whitespace */ @@ -810,7 +811,7 @@ However, in real world it was observed that some web servers *s = '\0'; s--; } - key = index_in_strings(keywords, buf) + 1; + key = index_in_strings(keywords, G.wget_buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { @@ -881,9 +882,9 @@ However, in real world it was observed that some web servers if (dfp != sfp) { /* It's ftp. Close it properly */ fclose(dfp); - if (ftpcmd(NULL, NULL, sfp, buf) != 226) - bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); - /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ + if (ftpcmd(NULL, NULL, sfp) != 226) + bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); + /* ftpcmd("QUIT", NULL, sfp); - why bother? */ } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From e3ece7878bff0a32a992c1f5f340ad223c009679 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 09:50:07 +0100 Subject: fix trivial build failure Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index 14fc16c4d..393a376ac 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -190,6 +190,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, } if (G_filter.flushb) { + struct nlmsghdr *fn; + /* We are creating route flush commands */ if (r->rtm_family == AF_INET6 @@ -201,12 +203,11 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, return 0; } - struct nlmsghdr *fn; if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { if (flush_update()) bb_error_msg_and_die("flush"); } - fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); + fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; -- cgit v1.2.3-55-g6feb From 0fac2f7b5b0bacf2c1ad73215acb312e012f0227 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 09:55:05 +0100 Subject: wget: remove functions which retry on EINTR function old new delta retrieve_file_data 392 353 -39 safe_fgets 58 - -58 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 0/1 up/down: 0/-97) Total: -97 bytes Signed-off-by: Denys Vlasenko --- networking/wget.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 8e636bd39..8028f1230 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -128,6 +128,7 @@ static void strip_ipv6_scope_id(char *host) overlapping_strcpy(scope, cp); } +#if 0 /* were needed when we used signal-driven progress bar */ /* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, * and a short count if an eof or non-interrupt error is encountered. */ static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) @@ -160,6 +161,7 @@ static char *safe_fgets(char *s, int size, FILE *stream) return ret; } +#endif #if ENABLE_FEATURE_WGET_AUTHENTICATION /* Base64-encode character string. */ @@ -495,7 +497,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) progress_meter(PROGRESS_BUMP); } #endif - n = safe_fread(G.wget_buf, rdsz, dfp); + n = fread(G.wget_buf, 1, rdsz, dfp); if (n <= 0) { if (ferror(dfp)) { /* perror will not work: ferror doesn't set errno */ @@ -515,9 +517,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) if (!G.chunked) break; - safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */ + fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */ get_clen: - safe_fgets(G.wget_buf, sizeof(G.wget_buf), dfp); + fgets(G.wget_buf, sizeof(G.wget_buf), dfp); G.content_len = STRTOOFF(G.wget_buf, NULL, 16); /* FIXME: error check? */ if (G.content_len == 0) -- cgit v1.2.3-55-g6feb From dee0fc9da1b53efc4c5e0596428dda556995bc26 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 10:01:49 +0100 Subject: save 10 bytes on strings Signed-off-by: Denys Vlasenko --- libbb/messages.c | 2 +- networking/wget.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libbb/messages.c b/libbb/messages.c index 2acbc3bca..fad82c9da 100644 --- a/libbb/messages.c +++ b/libbb/messages.c @@ -22,7 +22,7 @@ const char bb_banner[] ALIGN1 = BANNER; -const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted"; +const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory"; const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'"; const char bb_msg_unknown[] ALIGN1 = "(unknown)"; const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket"; diff --git a/networking/wget.c b/networking/wget.c index 8028f1230..74d90040f 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -192,7 +192,7 @@ static FILE *open_socket(len_and_sockaddr *lsa) /* hopefully it understands what ESPIPE means... */ fp = fdopen(xconnect_stream(lsa), "r+"); if (fp == NULL) - bb_perror_msg_and_die("fdopen"); + bb_perror_msg_and_die(bb_msg_memory_exhausted); return fp; } -- cgit v1.2.3-55-g6feb From b2f00ac22a24b68e74978d04f443cfa01c665fe9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 10:18:22 +0100 Subject: reset: "ESC(K" selects German, why do we use THAT? Change to "ESC(B" (US) Signed-off-by: Denys Vlasenko --- console-tools/reset.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/console-tools/reset.c b/console-tools/reset.c index 1806ce742..a23e4f408 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c @@ -31,12 +31,12 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) { /* See 'man 4 console_codes' for details: * "ESC c" -- Reset - * "ESC ( K" -- Select user mapping + * "ESC ( B" -- Select G0 Character Set (B = US) * "ESC [ 0 m" -- Reset all display attributes * "ESC [ J" -- Erase to the end of screen * "ESC [ ? 25 h" -- Make cursor visible */ - printf(ESC"c" ESC"(K" ESC"[0m" ESC"[J" ESC"[?25h"); + printf(ESC"c" ESC"(B" ESC"[0m" ESC"[J" ESC"[?25h"); /* http://bugs.busybox.net/view.php?id=1414: * people want it to reset echo etc: */ #if ENABLE_STTY -- cgit v1.2.3-55-g6feb From b44e9760e101b0eddf49de2ecd5f8fcbf2f289a4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 10:24:51 +0100 Subject: getty: extend its config help Signed-off-by: Denys Vlasenko --- loginutils/Config.src | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/loginutils/Config.src b/loginutils/Config.src index 4c771bbc4..897d8fb0c 100644 --- a/loginutils/Config.src +++ b/loginutils/Config.src @@ -181,7 +181,19 @@ config GETTY default y select FEATURE_SYSLOG help - getty lets you log in on a tty, it is normally invoked by init. + getty lets you log in on a tty. It is normally invoked by init. + + Note that you can save a few bytes by disabling it and + using login applet directly. + If you need to reset tty attributes before calling login, + this script approximates getty: + + exec /dev/$1 2>&1 || exit 1 + stty sane; stty ispeed 38400; stty ospeed 38400 + reset + printf "%s login: " "`hostname`" + read -r login + exec /bin/login "$login" config LOGIN bool "login" -- cgit v1.2.3-55-g6feb From 95897f9fd2f7122c7d26d93997e1164c0da41c0a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 10:38:13 +0100 Subject: getty config help: fix example script Signed-off-by: Denys Vlasenko --- loginutils/Config.src | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/loginutils/Config.src b/loginutils/Config.src index 897d8fb0c..0d7f50cf1 100644 --- a/loginutils/Config.src +++ b/loginutils/Config.src @@ -189,8 +189,8 @@ config GETTY this script approximates getty: exec /dev/$1 2>&1 || exit 1 - stty sane; stty ispeed 38400; stty ospeed 38400 reset + stty sane; stty ispeed 38400; stty ospeed 38400 printf "%s login: " "`hostname`" read -r login exec /bin/login "$login" -- cgit v1.2.3-55-g6feb From aaf091f97dce15460b52d47c95cac81762be7612 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 11:18:31 +0100 Subject: remve erroneous dependensies on INSTALLER Signed-off-by: Denys Vlasenko --- Config.in | 2 -- 1 file changed, 2 deletions(-) diff --git a/Config.in b/Config.in index 0ae48e9fe..b49181732 100644 --- a/Config.in +++ b/Config.in @@ -126,7 +126,6 @@ config FEATURE_INSTALLER config INSTALL_NO_USR bool "Don't use /usr" default n - depends on FEATURE_INSTALLER help Disable use of /usr. busybox --install and "make install" will install applets only to /bin and /sbin, @@ -701,7 +700,6 @@ config INSTALL_APPLET_SCRIPT_WRAPPERS config INSTALL_APPLET_DONT bool "not installed" - depends on FEATURE_INSTALLER || FEATURE_SH_STANDALONE || FEATURE_PREFER_APPLETS help Do not install applet links. Useful when you plan to use busybox --install for installing links, or plan to use -- cgit v1.2.3-55-g6feb From 9213a55bf0cc833d024975865a96a762b7a90b62 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 13:23:45 +0100 Subject: wget: use closed HTTP/1.1 connection, stop when we dl'ed $content_len bytes function old new delta retrieve_file_data 353 367 +14 Signed-off-by: Denys Vlasenko --- networking/wget.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 74d90040f..931882fde 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -510,8 +510,11 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) G.transferred += n; progress_meter(PROGRESS_BUMP); #endif - if (G.got_clen) + if (G.got_clen) { G.content_len -= n; + if (G.content_len == 0) + break; + } } if (!G.chunked) @@ -709,6 +712,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", target.host, user_agent); + /* Ask server to close the connection as soon as we are done + * (IOW: we do not intend to send more requests) + */ + fprintf(sfp, "Connection: close\r\n"); + #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, @@ -722,22 +730,25 @@ int wget_main(int argc UNUSED_PARAM, char **argv) if (G.beg_range) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); + #if ENABLE_FEATURE_WGET_LONG_OPTIONS if (extra_headers) fputs(extra_headers, sfp); if (opt & WGET_OPT_POST_DATA) { char *estr = URL_escape(post_data); - fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n"); - fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s", - (int) strlen(estr), estr); - /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/ - /*fprintf(sfp, "%s\r\n", estr);*/ + fprintf(sfp, + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %u\r\n" + "\r\n" + "%s", + (int) strlen(estr), estr + ); free(estr); } else #endif - { /* If "Connection:" is needed, document why */ - fprintf(sfp, /* "Connection: close\r\n" */ "\r\n"); + { + fprintf(sfp, "\r\n"); } fflush(sfp); -- cgit v1.2.3-55-g6feb From 805aa9fec923109e90c87eda2f116ee2fa5fe962 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 14:25:51 +0100 Subject: progress bar: better overflow protection; more precise bar function old new delta bb_progress_update 639 749 +110 Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++-- libbb/progress.c | 54 +++++++++++++++++++++++++++++++----------------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index d390e6840..c0178801f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1592,8 +1592,9 @@ typedef struct bb_progress_t { void bb_progress_init(bb_progress_t *p) FAST_FUNC; void bb_progress_update(bb_progress_t *p, const char *curfile, - off_t beg_range, off_t transferred, - off_t totalsize) FAST_FUNC; + uoff_t beg_range, + uoff_t transferred, + uoff_t totalsize) FAST_FUNC; extern const char *applet_name; diff --git a/libbb/progress.c b/libbb/progress.c index 40608b047..ced04ac32 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -62,35 +62,45 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p) void FAST_FUNC bb_progress_update(bb_progress_t *p, const char *curfile, - off_t beg_range, - off_t transferred, - off_t totalsize) + uoff_t beg_range, + uoff_t transferred, + uoff_t totalsize) { uoff_t beg_and_transferred; unsigned since_last_update, elapsed; unsigned ratio; - int barlength, i; + int barlength; + int kiloscale; /* totalsize == 0 if it is unknown */ + beg_and_transferred = beg_range + transferred; + elapsed = monotonic_sec(); since_last_update = elapsed - p->lastupdate_sec; /* Do not update on every call * (we can be called on every network read!) */ - if (since_last_update == 0 && !totalsize) + if (since_last_update == 0 && beg_and_transferred < totalsize) return; - beg_and_transferred = beg_range + transferred; - ratio = 100; - if (beg_and_transferred < totalsize) { - /* Do not update on every call - * (we can be called on every network read!) */ - if (since_last_update == 0) - return; - /* long long helps to have it working even if !LFS */ - ratio = 100ULL * beg_and_transferred / (uoff_t)totalsize; + /* Scale sizes down if they are close to overflowing. + * If off_t is only 32 bits, this allows calculations + * like (100 * transferred / totalsize) without risking overflow. + * Introduced error is < 0.1% + */ + kiloscale = 0; + if (totalsize >= (1 << 20)) { + totalsize >>= 10; + beg_range >>= 10; + transferred >>= 10; + beg_and_transferred >>= 10; + kiloscale++; } + if (beg_and_transferred >= totalsize) + beg_and_transferred = totalsize; + + ratio = 100 * beg_and_transferred / totalsize; #if ENABLE_UNICODE_SUPPORT init_unicode(); { @@ -106,21 +116,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, if (barlength > 0) { /* god bless gcc for variable arrays :) */ char buf[barlength + 1]; - unsigned stars = (unsigned)barlength * ratio / (unsigned)100; + unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; memset(buf, ' ', barlength); buf[barlength] = '\0'; memset(buf, '*', stars); fprintf(stderr, "|%s|", buf); } - i = 0; while (beg_and_transferred >= 100000) { - i++; + kiloscale++; beg_and_transferred >>= 10; } /* see http://en.wikipedia.org/wiki/Tera */ - fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[i]); -#define beg_and_transferred dont_use_beg_and_transferred_below + fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); +#define beg_and_transferred dont_use_beg_and_transferred_below() if (transferred > p->lastsize) { p->lastupdate_sec = elapsed; @@ -137,13 +146,12 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, if (since_last_update >= STALLTIME) { fprintf(stderr, " - stalled -"); } else { - off_t to_download = totalsize - beg_range; - if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { + uoff_t to_download = totalsize - beg_range; + if (!totalsize || (int)elapsed <= 0 || transferred > to_download) { fprintf(stderr, "--:--:-- ETA"); } else { /* to_download / (transferred/elapsed) - elapsed: */ - /* (long long helps to have working ETA even if !LFS) */ - unsigned eta = (unsigned long long)to_download*elapsed/(uoff_t)transferred - elapsed; + unsigned eta = to_download * elapsed / transferred - elapsed; unsigned secs = eta % 3600; unsigned hours = eta / 3600; fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); -- cgit v1.2.3-55-g6feb From f836f01cc3eb39e5e4c7186f50b456b57fae2010 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 23:02:28 +0100 Subject: wget: shrink progress meter code; strink wget and add debug logging function old new delta fgets_and_trim - 73 +73 retrieve_file_data 367 349 -18 bb_progress_update 723 699 -24 wget_main 2220 2190 -30 ftpcmd 133 87 -46 gethdr 200 153 -47 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/5 up/down: 73/-165) Total: -92 bytes Signed-off-by: Denys Vlasenko --- libbb/progress.c | 95 +++++++++++++++++++++++++++++++++++++------------------ networking/wget.c | 74 +++++++++++++++++++++++-------------------- 2 files changed, 105 insertions(+), 64 deletions(-) diff --git a/libbb/progress.c b/libbb/progress.c index ced04ac32..a490b8390 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -60,9 +60,16 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p) p->inited = 1; } +/* File already had beg_size bytes. + * Then we started downloading. + * We downloaded "transferred" bytes so far. + * Download is expected to stop when total size (beg_size + transferred) + * will be "totalsize" bytes. + * If totalsize == 0, then it is unknown. + */ void FAST_FUNC bb_progress_update(bb_progress_t *p, const char *curfile, - uoff_t beg_range, + uoff_t beg_size, uoff_t transferred, uoff_t totalsize) { @@ -72,32 +79,53 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, int barlength; int kiloscale; - /* totalsize == 0 if it is unknown */ - - beg_and_transferred = beg_range + transferred; + beg_and_transferred = beg_size + transferred; elapsed = monotonic_sec(); since_last_update = elapsed - p->lastupdate_sec; - /* Do not update on every call - * (we can be called on every network read!) */ + /* + * Do not update on every call + * (we can be called on every network read!) + */ if (since_last_update == 0 && beg_and_transferred < totalsize) return; - /* Scale sizes down if they are close to overflowing. - * If off_t is only 32 bits, this allows calculations - * like (100 * transferred / totalsize) without risking overflow. - * Introduced error is < 0.1% - */ kiloscale = 0; - if (totalsize >= (1 << 20)) { - totalsize >>= 10; - beg_range >>= 10; - transferred >>= 10; - beg_and_transferred >>= 10; - kiloscale++; + /* + * Scale sizes down if they are close to overflowing. + * This allows calculations like (100 * transferred / totalsize) + * without risking overflow: we guarantee 10 highest bits to be 0. + * Introduced error is less than 1 / 2^12 ~= 0.025% + */ + if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) { + /* + * 64-bit CPU || small off_t: in either case, + * >> is cheap, single-word operation. + * ... || strange off_t: also use this code (it is safe, + * even if suboptimal), because 32/64 optimized one + * works only for 64-bit off_t. + */ + if (totalsize >= (1 << 22)) { + totalsize >>= 10; + beg_size >>= 10; + transferred >>= 10; + beg_and_transferred >>= 10; + kiloscale = 1; + } + } else { + /* 32-bit CPU and 64-bit off_t. + * Pick a shift (40 bits) which is easier to do on 32-bit CPU. + */ + if (totalsize >= (uoff_t)(1ULL << 54)) { + totalsize = (uint32_t)(totalsize >> 32) >> 8; + beg_size = (uint32_t)(beg_size >> 32) >> 8; + transferred = (uint32_t)(transferred >> 32) >> 8; + beg_and_transferred = (uint32_t)(beg_and_transferred >> 32) >> 8; + kiloscale = 4; + } } - if (beg_and_transferred >= totalsize) + if (beg_and_transferred > totalsize) beg_and_transferred = totalsize; ratio = 100 * beg_and_transferred / totalsize; @@ -124,14 +152,14 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, } while (beg_and_transferred >= 100000) { - kiloscale++; beg_and_transferred >>= 10; + kiloscale++; } /* see http://en.wikipedia.org/wiki/Tera */ fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); #define beg_and_transferred dont_use_beg_and_transferred_below() - if (transferred > p->lastsize) { + if (transferred != p->lastsize) { p->lastupdate_sec = elapsed; p->lastsize = transferred; if (since_last_update >= STALLTIME) { @@ -141,20 +169,27 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, } since_last_update = 0; /* we are un-stalled now */ } + elapsed -= p->start_sec; /* now it's "elapsed since start" */ if (since_last_update >= STALLTIME) { fprintf(stderr, " - stalled -"); + } else if (!totalsize || !transferred || (int)elapsed <= 0) { + fprintf(stderr, "--:--:-- ETA"); } else { - uoff_t to_download = totalsize - beg_range; - if (!totalsize || (int)elapsed <= 0 || transferred > to_download) { - fprintf(stderr, "--:--:-- ETA"); - } else { - /* to_download / (transferred/elapsed) - elapsed: */ - unsigned eta = to_download * elapsed / transferred - elapsed; - unsigned secs = eta % 3600; - unsigned hours = eta / 3600; - fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); - } + unsigned eta, secs, hours; + + totalsize -= beg_size; /* now it's "total to upload" */ + + /* Estimated remaining time = + * estimated_sec_to_dl_totalsize_bytes - elapsed_sec = + * totalsize / average_bytes_sec_so_far - elapsed = + * totalsize / (transferred/elapsed) - elapsed = + * totalsize * elapsed / transferred - elapsed + */ + eta = totalsize * elapsed / transferred - elapsed; + secs = eta % 3600; + hours = eta / 3600; + fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); } } diff --git a/networking/wget.c b/networking/wget.c index 931882fde..d81426e8d 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -10,6 +10,10 @@ */ #include "libbb.h" +//#define log_io(...) bb_error_msg(__VA_ARGS__) +#define log_io(...) ((void)0) + + struct host_info { // May be used if we ever will want to free() all xstrdup()s... /* char *allocated; */ @@ -197,25 +201,39 @@ static FILE *open_socket(len_and_sockaddr *lsa) return fp; } +/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ +static char fgets_and_trim(FILE *fp) +{ + char c; + char *buf_ptr; + + if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL) + bb_perror_msg_and_die("error getting response"); + + buf_ptr = strchrnul(G.wget_buf, '\n'); + c = *buf_ptr; + *buf_ptr = '\0'; + buf_ptr = strchrnul(G.wget_buf, '\r'); + *buf_ptr = '\0'; + + log_io("< %s", G.wget_buf); + + return c; +} + static int ftpcmd(const char *s1, const char *s2, FILE *fp) { int result; if (s1) { - if (!s2) s2 = ""; + if (!s2) + s2 = ""; fprintf(fp, "%s%s\r\n", s1, s2); fflush(fp); + log_io("> %s%s", s1, s2); } do { - char *buf_ptr; - - if (fgets(G.wget_buf, sizeof(G.wget_buf)-2, fp) == NULL) { - bb_perror_msg_and_die("error getting response"); - } - buf_ptr = strstr(G.wget_buf, "\r\n"); - if (buf_ptr) { - *buf_ptr = '\0'; - } + fgets_and_trim(fp); } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); G.wget_buf[3] = '\0'; @@ -284,7 +302,7 @@ static void parse_url(char *src_url, struct host_info *h) sp = h->host; } -static char *gethdr(FILE *fp /*, int *istrunc*/) +static char *gethdr(FILE *fp) { char *s, *hdrval; int c; @@ -292,19 +310,16 @@ static char *gethdr(FILE *fp /*, int *istrunc*/) /* *istrunc = 0; */ /* retrieve header line */ - if (fgets(G.wget_buf, sizeof(G.wget_buf), fp) == NULL) - return NULL; + c = fgets_and_trim(fp); - /* see if we are at the end of the headers */ - for (s = G.wget_buf; *s == '\r'; ++s) - continue; - if (*s == '\n') + /* end of the headers? */ + if (G.wget_buf[0] == '\0') return NULL; /* convert the header name to lower case */ for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { /* tolower for "A-Z", no-op for "0-9a-z-." */ - *s = (*s | 0x20); + *s |= 0x20; } /* verify we are at the end of the header name */ @@ -315,20 +330,12 @@ static char *gethdr(FILE *fp /*, int *istrunc*/) *s++ = '\0'; hdrval = skip_whitespace(s); - /* locate the end of header */ - while (*s && *s != '\r' && *s != '\n') - ++s; - - /* end of header found */ - if (*s) { - *s = '\0'; - return hdrval; + if (c != '\n') { + /* Rats! The buffer isn't big enough to hold the entire header value */ + while (c = getc(fp), c != EOF && c != '\n') + continue; } - /* Rats! The buffer isn't big enough to hold the entire header value */ - while (c = getc(fp), c != EOF && c != '\n') - continue; - /* *istrunc = 1; */ return hdrval; } @@ -520,9 +527,9 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) if (!G.chunked) break; - fgets(G.wget_buf, sizeof(G.wget_buf), dfp); /* This is a newline */ + fgets_and_trim(dfp); /* This is a newline */ get_clen: - fgets(G.wget_buf, sizeof(G.wget_buf), dfp); + fgets_and_trim(dfp); G.content_len = STRTOOFF(G.wget_buf, NULL, 16); /* FIXME: error check? */ if (G.content_len == 0) @@ -757,8 +764,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) * Retrieve HTTP response line and check for "200" status code. */ read_response: - if (fgets(G.wget_buf, sizeof(G.wget_buf), sfp) == NULL) - bb_error_msg_and_die("no response from server"); + fgets_and_trim(sfp); str = G.wget_buf; str = skip_non_whitespace(str); -- cgit v1.2.3-55-g6feb From 838d4bb0cd0805e1671073627d86baf100af021b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 10 Feb 2011 23:35:52 +0100 Subject: progress meter: display >999 hours ETA correctly Signed-off-by: Denys Vlasenko --- libbb/progress.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libbb/progress.c b/libbb/progress.c index a490b8390..3999e0f38 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -156,7 +156,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, kiloscale++; } /* see http://en.wikipedia.org/wiki/Tera */ - fprintf(stderr, "%6u%c ", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); + fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); #define beg_and_transferred dont_use_beg_and_transferred_below() if (transferred != p->lastsize) { @@ -173,9 +173,9 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, elapsed -= p->start_sec; /* now it's "elapsed since start" */ if (since_last_update >= STALLTIME) { - fprintf(stderr, " - stalled -"); + fprintf(stderr, " - stalled -"); } else if (!totalsize || !transferred || (int)elapsed <= 0) { - fprintf(stderr, "--:--:-- ETA"); + fprintf(stderr, " --:--:-- ETA"); } else { unsigned eta, secs, hours; @@ -188,8 +188,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, * totalsize * elapsed / transferred - elapsed */ eta = totalsize * elapsed / transferred - elapsed; + if (eta >= 1000*60*60) + eta = 1000*60*60 - 1; secs = eta % 3600; hours = eta / 3600; - fprintf(stderr, "%02u:%02u:%02u ETA", hours, secs / 60, secs % 60); + fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60); } } -- cgit v1.2.3-55-g6feb From e52e67cb512e775fd83ca399cc807c363ba59dcc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 12:59:11 +0100 Subject: libbb/progress.c: make sure we never get negative ETA function old new delta bb_progress_update 738 733 -5 Signed-off-by: Denys Vlasenko --- libbb/progress.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/libbb/progress.c b/libbb/progress.c index 3999e0f38..1062e9a0d 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -79,16 +79,20 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, int barlength; int kiloscale; - beg_and_transferred = beg_size + transferred; - elapsed = monotonic_sec(); since_last_update = elapsed - p->lastupdate_sec; - /* - * Do not update on every call - * (we can be called on every network read!) - */ - if (since_last_update == 0 && beg_and_transferred < totalsize) + + if (totalsize != 0 && transferred >= totalsize - beg_size) { + /* Last call. Do not skip this update */ + transferred = totalsize - beg_size; /* sanitize just in case */ + } + else if (since_last_update == 0) { + /* + * Do not update on every call + * (we can be called on every network read!) + */ return; + } kiloscale = 0; /* @@ -101,32 +105,29 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, /* * 64-bit CPU || small off_t: in either case, * >> is cheap, single-word operation. - * ... || strange off_t: also use this code (it is safe, - * even if suboptimal), because 32/64 optimized one - * works only for 64-bit off_t. + * ... || strange off_t: also use this code + * (it is safe, just suboptimal wrt code size), + * because 32/64 optimized one works only for 64-bit off_t. */ if (totalsize >= (1 << 22)) { totalsize >>= 10; beg_size >>= 10; transferred >>= 10; - beg_and_transferred >>= 10; kiloscale = 1; } } else { /* 32-bit CPU and 64-bit off_t. - * Pick a shift (40 bits) which is easier to do on 32-bit CPU. + * Use a 40-bit shift, it is easier to do on 32-bit CPU. */ if (totalsize >= (uoff_t)(1ULL << 54)) { totalsize = (uint32_t)(totalsize >> 32) >> 8; beg_size = (uint32_t)(beg_size >> 32) >> 8; transferred = (uint32_t)(transferred >> 32) >> 8; - beg_and_transferred = (uint32_t)(beg_and_transferred >> 32) >> 8; kiloscale = 4; } } - if (beg_and_transferred > totalsize) - beg_and_transferred = totalsize; + beg_and_transferred = beg_size + transferred; ratio = 100 * beg_and_transferred / totalsize; #if ENABLE_UNICODE_SUPPORT @@ -163,7 +164,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, p->lastupdate_sec = elapsed; p->lastsize = transferred; if (since_last_update >= STALLTIME) { - /* We "cut off" these seconds from elapsed time + /* We "cut out" these seconds from elapsed time * by adjusting start time */ p->start_sec += since_last_update; } -- cgit v1.2.3-55-g6feb From d55e13964916af6a083be881bffdb493af287c1d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 18:56:13 +0100 Subject: progress meter: move file name to bb_progress_t. +20 bytes We were doing expensive unicode conversion on every update Signed-off-by: Denys Vlasenko --- include/libbb.h | 12 +++++++++--- libbb/progress.c | 24 +++++++++++------------- networking/tftp.c | 10 +++++----- networking/wget.c | 4 ++-- 4 files changed, 27 insertions(+), 23 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index c0178801f..7581cd4c4 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1587,15 +1587,21 @@ typedef struct bb_progress_t { off_t lastsize; unsigned lastupdate_sec; unsigned start_sec; - smallint inited; + const char *curfile; } bb_progress_t; -void bb_progress_init(bb_progress_t *p) FAST_FUNC; -void bb_progress_update(bb_progress_t *p, const char *curfile, +#define is_bb_progress_inited(p) ((p)->curfile != NULL) +#define bb_progress_free(p) do { \ + if (ENABLE_UNICODE_SUPPORT) free((char*)((p)->curfile)); \ + (p)->curfile = NULL; \ +} while (0) +void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC; +void bb_progress_update(bb_progress_t *p, uoff_t beg_range, uoff_t transferred, uoff_t totalsize) FAST_FUNC; + extern const char *applet_name; /* Some older linkers don't perform string merging, we used to have common strings diff --git a/libbb/progress.c b/libbb/progress.c index 1062e9a0d..1d260dd08 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -52,12 +52,17 @@ static unsigned int get_tty2_width(void) return width; } -void FAST_FUNC bb_progress_init(bb_progress_t *p) +void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) { +#if ENABLE_UNICODE_SUPPORT + init_unicode(); + p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); +#else + p->curfile = curfile; +#endif p->start_sec = monotonic_sec(); p->lastupdate_sec = p->start_sec; p->lastsize = 0; - p->inited = 1; } /* File already had beg_size bytes. @@ -68,7 +73,6 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p) * If totalsize == 0, then it is unknown. */ void FAST_FUNC bb_progress_update(bb_progress_t *p, - const char *curfile, uoff_t beg_size, uoff_t transferred, uoff_t totalsize) @@ -130,16 +134,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, beg_and_transferred = beg_size + transferred; ratio = 100 * beg_and_transferred / totalsize; -#if ENABLE_UNICODE_SUPPORT - init_unicode(); - { - char *buf = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); - fprintf(stderr, "\r%s%4u%% ", buf, ratio); - free(buf); - } -#else - fprintf(stderr, "\r%-20.20s%4u%% ", curfile, ratio); -#endif + if (ENABLE_UNICODE_SUPPORT) + fprintf(stderr, "\r%s%4u%% ", p->curfile, ratio); + else + fprintf(stderr, "\r%-20.20s%4u%% ", p->curfile, ratio); barlength = get_tty2_width() - 49; if (barlength > 0) { diff --git a/networking/tftp.c b/networking/tftp.c index fcd933f6a..2a3991755 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -107,19 +107,19 @@ struct BUG_G_too_big { #if ENABLE_FEATURE_TFTP_PROGRESS_BAR static void tftp_progress_update(void) { - bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size); + bb_progress_update(&G.pmt, 0, G.pos, G.size); } static void tftp_progress_init(void) { - bb_progress_init(&G.pmt); + bb_progress_init(&G.pmt, G.file); tftp_progress_update(); } static void tftp_progress_done(void) { - if (G.pmt.inited) { + if (is_bb_progress_inited(&G.pmt)) { tftp_progress_update(); bb_putchar_stderr('\n'); - G.pmt.inited = 0; + bb_progress_free(p); } } #else @@ -445,7 +445,7 @@ static int tftp_protocol( #if ENABLE_FEATURE_TFTP_PROGRESS_BAR if (ENABLE_TFTP && remote_file) /* tftp */ G.pos = (block_nr - 1) * (uoff_t)blksize; - if (G.pmt.inited) + if (is_bb_progress_inited(&G.pmt)) tftp_progress_update(); #endif /* Was it final ACK? then exit */ diff --git a/networking/wget.c b/networking/wget.c index d81426e8d..f2d7daf2f 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -81,9 +81,9 @@ static void progress_meter(int flag) return; if (flag == PROGRESS_START) - bb_progress_init(&G.pmt); + bb_progress_init(&G.pmt, G.curfile); - bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, + bb_progress_update(&G.pmt, G.beg_range, G.transferred, G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); if (flag == PROGRESS_END) { -- cgit v1.2.3-55-g6feb From ab8d00d64fc23602875952c08c030f05f206686c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 19:09:30 +0100 Subject: progress meter: fix bugs found in stall detection and unknown size logic Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++-- libbb/progress.c | 55 ++++++++++++++++++++++++++++++++----------------------- networking/tftp.c | 2 +- 3 files changed, 36 insertions(+), 26 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 7581cd4c4..65c319402 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1584,8 +1584,9 @@ int print_flags_separated(const int *masks, const char *labels, int print_flags(const masks_labels_t *ml, int flags) FAST_FUNC; typedef struct bb_progress_t { - off_t lastsize; - unsigned lastupdate_sec; + unsigned last_size; + unsigned last_update_sec; + unsigned last_change_sec; unsigned start_sec; const char *curfile; } bb_progress_t; diff --git a/libbb/progress.c b/libbb/progress.c index 1d260dd08..df43dad5c 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -61,8 +61,9 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) p->curfile = curfile; #endif p->start_sec = monotonic_sec(); - p->lastupdate_sec = p->start_sec; - p->lastsize = 0; + p->last_update_sec = p->start_sec; + p->last_change_sec = p->start_sec; + p->last_size = 0; } /* File already had beg_size bytes. @@ -79,12 +80,15 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, { uoff_t beg_and_transferred; unsigned since_last_update, elapsed; - unsigned ratio; int barlength; int kiloscale; + //transferred = 1234; /* use for stall detection testing */ + //totalsize = 0; /* use for unknown size download testing */ + elapsed = monotonic_sec(); - since_last_update = elapsed - p->lastupdate_sec; + since_last_update = elapsed - p->last_update_sec; + p->last_update_sec = elapsed; if (totalsize != 0 && transferred >= totalsize - beg_size) { /* Last call. Do not skip this update */ @@ -131,23 +135,27 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, } } - beg_and_transferred = beg_size + transferred; - - ratio = 100 * beg_and_transferred / totalsize; if (ENABLE_UNICODE_SUPPORT) - fprintf(stderr, "\r%s%4u%% ", p->curfile, ratio); + fprintf(stderr, "\r%s", p->curfile); else - fprintf(stderr, "\r%-20.20s%4u%% ", p->curfile, ratio); - - barlength = get_tty2_width() - 49; - if (barlength > 0) { - /* god bless gcc for variable arrays :) */ - char buf[barlength + 1]; - unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; - memset(buf, ' ', barlength); - buf[barlength] = '\0'; - memset(buf, '*', stars); - fprintf(stderr, "|%s|", buf); + fprintf(stderr, "\r%-20.20s", p->curfile); + + beg_and_transferred = beg_size + transferred; + + if (totalsize != 0) { + unsigned ratio = 100 * beg_and_transferred / totalsize; + fprintf(stderr, "%4u%%", ratio); + + barlength = get_tty2_width() - 49; + if (barlength > 0) { + /* god bless gcc for variable arrays :) */ + char buf[barlength + 1]; + unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; + memset(buf, ' ', barlength); + buf[barlength] = '\0'; + memset(buf, '*', stars); + fprintf(stderr, " |%s|", buf); + } } while (beg_and_transferred >= 100000) { @@ -158,9 +166,10 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); #define beg_and_transferred dont_use_beg_and_transferred_below() - if (transferred != p->lastsize) { - p->lastupdate_sec = elapsed; - p->lastsize = transferred; + since_last_update = elapsed - p->last_change_sec; + if ((unsigned)transferred != p->last_size) { + p->last_change_sec = elapsed; + p->last_size = (unsigned)transferred; if (since_last_update >= STALLTIME) { /* We "cut out" these seconds from elapsed time * by adjusting start time */ @@ -173,7 +182,7 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, if (since_last_update >= STALLTIME) { fprintf(stderr, " - stalled -"); - } else if (!totalsize || !transferred || (int)elapsed <= 0) { + } else if (!totalsize || !transferred || (int)elapsed < 0) { fprintf(stderr, " --:--:-- ETA"); } else { unsigned eta, secs, hours; diff --git a/networking/tftp.c b/networking/tftp.c index 2a3991755..35cf0dbd9 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -119,7 +119,7 @@ static void tftp_progress_done(void) if (is_bb_progress_inited(&G.pmt)) { tftp_progress_update(); bb_putchar_stderr('\n'); - bb_progress_free(p); + bb_progress_free(&G.pmt); } } #else -- cgit v1.2.3-55-g6feb From 8766a791e847fdf1f3f00222f18c18833f40abda Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 21:42:00 +0100 Subject: wget: correctly handle rare case when we get EAGAIN _on first_ read Signed-off-by: Denys Vlasenko --- networking/wget.c | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index f2d7daf2f..48688640a 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -487,6 +487,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) rdsz = (unsigned)G.content_len; } } + #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT # if ENABLE_FEATURE_WGET_TIMEOUT second_cnt = G.timeout_seconds; @@ -497,22 +498,41 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) # if ENABLE_FEATURE_WGET_TIMEOUT if (second_cnt != 0 && --second_cnt == 0) { progress_meter(PROGRESS_END); - bb_perror_msg_and_die("download timed out"); + bb_error_msg_and_die("download timed out"); } # endif /* Needed for "stalled" indicator */ progress_meter(PROGRESS_BUMP); } #endif + /* fread internally uses read loop, which in our case + * is usually exited when we get EAGAIN. + * In this case, libc sets error marker on the stream. + * Need to clear it before next fread to avoid possible + * rare false positive ferror below. Rare because usually + * fread gets more than zero bytes, and we don't fall + * into if (n <= 0) ... + */ + clearerr(dfp); + errno = 0; n = fread(G.wget_buf, 1, rdsz, dfp); + /* man fread: + * If error occurs, or EOF is reached, the return value + * is a short item count (or zero). + * fread does not distinguish between EOF and error. + */ if (n <= 0) { - if (ferror(dfp)) { - /* perror will not work: ferror doesn't set errno */ - bb_error_msg_and_die(bb_msg_read_error); - } - break; +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + if (errno == EAGAIN) /* poll lied, there is no data? */ + continue; /* yes */ +#endif + if (ferror(dfp)) + bb_perror_msg_and_die(bb_msg_read_error); + break; /* EOF, not error */ } + xwrite(output_fd, G.wget_buf, n); + #if ENABLE_FEATURE_WGET_STATUSBAR G.transferred += n; progress_meter(PROGRESS_BUMP); -- cgit v1.2.3-55-g6feb From f9af3756687840c76d8ba4e34b33916b6e36ca61 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 22:01:33 +0100 Subject: wget: explain clearerr more clearly Signed-off-by: Denys Vlasenko --- networking/wget.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/networking/wget.c b/networking/wget.c index 48688640a..673113bfc 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -466,6 +466,14 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) polldata.fd = fileno(dfp); polldata.events = POLLIN | POLLPRI; + + /* Must use nonblocking I/O, otherwise fread will loop + * and *block* until it reads full buffer, + * which messes up progress bar and/or timing out. + * Because of nonblocking I/O, we need to dance + * very carefully around EAGAIN. See explanation at + * clearerr() call. + */ ndelay_on(polldata.fd); #endif progress_meter(PROGRESS_START); @@ -504,7 +512,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) /* Needed for "stalled" indicator */ progress_meter(PROGRESS_BUMP); } -#endif + /* fread internally uses read loop, which in our case * is usually exited when we get EAGAIN. * In this case, libc sets error marker on the stream. @@ -515,6 +523,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) */ clearerr(dfp); errno = 0; +#endif n = fread(G.wget_buf, 1, rdsz, dfp); /* man fread: * If error occurs, or EOF is reached, the return value -- cgit v1.2.3-55-g6feb From c60f4460bb3f53c5cfcfd01c99a50eb9ae69f8aa Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 22:23:23 +0100 Subject: wget: chunked mode fix. Closes bug 3229 Signed-off-by: Denys Vlasenko --- networking/wget.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 673113bfc..4ef5900cb 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -466,15 +466,6 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) polldata.fd = fileno(dfp); polldata.events = POLLIN | POLLPRI; - - /* Must use nonblocking I/O, otherwise fread will loop - * and *block* until it reads full buffer, - * which messes up progress bar and/or timing out. - * Because of nonblocking I/O, we need to dance - * very carefully around EAGAIN. See explanation at - * clearerr() call. - */ - ndelay_on(polldata.fd); #endif progress_meter(PROGRESS_START); @@ -483,6 +474,17 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) /* Loops only if chunked */ while (1) { + +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + /* Must use nonblocking I/O, otherwise fread will loop + * and *block* until it reads full buffer, + * which messes up progress bar and/or timeout logic. + * Because of nonblocking I/O, we need to dance + * very carefully around EAGAIN. See explanation at + * clearerr() call. + */ + ndelay_on(polldata.fd); +#endif while (1) { int n; unsigned rdsz; @@ -552,11 +554,15 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) break; } } +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + clearerr(dfp); + ndelay_off(polldata.fd); +#endif if (!G.chunked) break; - fgets_and_trim(dfp); /* This is a newline */ + fgets_and_trim(dfp); /* Eat empty line */ get_clen: fgets_and_trim(dfp); G.content_len = STRTOOFF(G.wget_buf, NULL, 16); -- cgit v1.2.3-55-g6feb From 88ad9da65ef6227e366a60b58be22c83bcf11c18 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 11 Feb 2011 23:06:21 +0100 Subject: wget: display 100% at the _end_ of chunked download Signed-off-by: Denys Vlasenko --- networking/wget.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 4ef5900cb..44eb4cf18 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -556,9 +556,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) } #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT clearerr(dfp); - ndelay_off(polldata.fd); + ndelay_off(polldata.fd); /* else fgets can get very unhappy */ #endif - if (!G.chunked) break; @@ -572,6 +571,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) G.got_clen = 1; } + G.chunked = 0; /* make progress meter show 100% even for chunked */ progress_meter(PROGRESS_END); } -- cgit v1.2.3-55-g6feb From 0b8a7723c7351533826283c07b37cf2daa77ecf8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 01:56:25 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- libbb/systemd_support.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/systemd_support.c b/libbb/systemd_support.c index 981296dbb..542a3efff 100644 --- a/libbb/systemd_support.c +++ b/libbb/systemd_support.c @@ -33,7 +33,7 @@ //config: If you plan to use busybox daemons on a system where daemons //config: are controlled by systemd, enable this option. //config: If you don't use systemd, it is still safe to enable it, -//config: but yhe downside is increased code size. +//config: but the downside is increased code size. //kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o -- cgit v1.2.3-55-g6feb From cef85c2442886eabfc0d023af86843ba90fbe081 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 16:35:24 +0100 Subject: find: significantly improve hext text. +116 bytes Signed-off-by: Denys Vlasenko --- findutils/find.c | 105 +++++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 49 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index f85381b47..e8747f93b 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -112,11 +112,11 @@ //config: This option allows find to restrict searches to a single filesystem. //config: //config:config FEATURE_FIND_MAXDEPTH -//config: bool "Enable -maxdepth N" +//config: bool "Enable -mindepth N and -maxdepth N" //config: default y //config: depends on FIND //config: help -//config: This option enables -maxdepth N option. +//config: This option enables -mindepth N and -maxdepth N option. //config: //config:config FEATURE_FIND_NEWER //config: bool "Enable -newer: compare file modification times" @@ -124,7 +124,7 @@ //config: depends on FIND //config: help //config: Support the 'find -newer' option for finding any files which have -//config: a modified time that is more recent than the specified FILE. +//config: modification time that is more recent than the specified FILE. //config: //config:config FEATURE_FIND_INUM //config: bool "Enable -inum: inode number matching" @@ -684,7 +684,6 @@ static action*** parse_params(char **argv) #endif PARM_print , IF_FEATURE_FIND_PRINT0( PARM_print0 ,) - IF_FEATURE_FIND_DEPTH( PARM_depth ,) IF_FEATURE_FIND_PRUNE( PARM_prune ,) IF_FEATURE_FIND_DELETE( PARM_delete ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) @@ -718,7 +717,6 @@ static action*** parse_params(char **argv) #endif "-print\0" IF_FEATURE_FIND_PRINT0( "-print0\0" ) - IF_FEATURE_FIND_DEPTH( "-depth\0" ) IF_FEATURE_FIND_PRUNE( "-prune\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) @@ -739,7 +737,7 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( "-size\0" ) IF_FEATURE_FIND_CONTEXT("-context\0") IF_FEATURE_FIND_LINKS( "-links\0" ) - ; + ; action*** appp; unsigned cur_group = 0; @@ -828,11 +826,6 @@ static action*** parse_params(char **argv) (void) ALLOC_ACTION(print0); } #endif -#if ENABLE_FEATURE_FIND_DEPTH - else if (parm == PARM_depth) { - G.recurse_flags |= ACTION_DEPTHFIRST; - } -#endif #if ENABLE_FEATURE_FIND_PRUNE else if (parm == PARM_prune) { IF_FEATURE_FIND_NOT( invert_flag = 0; ) @@ -859,9 +852,9 @@ static action*** parse_params(char **argv) if (!*argv) /* did not see ';' or '+' until end */ bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); // find -exec echo Foo ">{}<" ";" - // executes "echo Foo ", + // executes "echo Foo >FILENAME<", // find -exec echo Foo ">{}<" "+" - // executes "echo Foo ...". + // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". // TODO (so far we treat "+" just like ";") if ((argv[0][0] == ';' || argv[0][0] == '+') && argv[0][1] == '\0' @@ -1051,34 +1044,46 @@ static action*** parse_params(char **argv) } //usage:#define find_trivial_usage -//usage: "[PATH]... [EXPRESSION]" +//usage: "[OPTIONS] [PATH]... [ACTION]..." //usage:#define find_full_usage "\n\n" -//usage: "Search for files. The default PATH is the current directory,\n" -//usage: "default EXPRESSION is '-print'\n" -//usage: "\nEXPRESSION may consist of:" +//usage: "Search for files and perform actions on them.\n" +//usage: "First failed action stops processing of current file.\n" +//usage: "Defaults: PATH is current directory, action is '-print'\n" +//usage: "\nOptions:" //usage: "\n -follow Follow symlinks" //usage: IF_FEATURE_FIND_XDEV( //usage: "\n -xdev Don't descend directories on other filesystems" //usage: ) //usage: IF_FEATURE_FIND_MAXDEPTH( //usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" -//usage: "\n tests/actions to command line arguments only" -//usage: ) +//usage: "\n actions to command line arguments only" //usage: "\n -mindepth N Don't act on first N levels" -//usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" +//usage: ) +//usage: IF_FEATURE_FIND_DEPTH( +//usage: "\n -depth Act on directory *after* traversing it" +//usage: ) +//usage: "\n" +//usage: IF_FEATURE_FIND_PAREN( +//usage: "\n ( ACTIONS ) Group actions for -o / -a" +//usage: ) +//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" +//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" +//usage: "\n Note: -a has higher priority than -o" +//usage: "\nActions:" +//usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" //usage: "\n -iname PATTERN Case insensitive -name" //usage: IF_FEATURE_FIND_PATH( -//usage: "\n -path PATTERN Path matches PATTERN" +//usage: "\n -path PATTERN Match path to PATTERN" //usage: ) //usage: IF_FEATURE_FIND_REGEX( -//usage: "\n -regex PATTERN Path matches regex PATTERN" +//usage: "\n -regex PATTERN Match path to regex PATTERN" //usage: ) //usage: IF_FEATURE_FIND_TYPE( -//usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" +//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" //usage: ) //usage: IF_FEATURE_FIND_PERM( -//usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," -//usage: "\n or exactly NNN" +//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," +//usage: "\n or exactly MASK bits are set in mode bits" //usage: ) //usage: IF_FEATURE_FIND_MTIME( //usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," @@ -1100,9 +1105,6 @@ static action*** parse_params(char **argv) //usage: IF_FEATURE_FIND_GROUP( //usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" //usage: ) -//usage: IF_FEATURE_FIND_DEPTH( -//usage: "\n -depth Process directory name after traversing it" -//usage: ) //usage: IF_FEATURE_FIND_SIZE( //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" //usage: "\n +/-N: file size is bigger/smaller than N" @@ -1111,26 +1113,23 @@ static action*** parse_params(char **argv) //usage: "\n -links N Number of links is greater than (+N), less than (-N)," //usage: "\n or exactly N" //usage: ) -//usage: "\n -print Print (default and assumed)" -//usage: IF_FEATURE_FIND_PRINT0( -//usage: "\n -print0 Delimit output with null characters rather than" -//usage: "\n newlines" -//usage: ) //usage: IF_FEATURE_FIND_CONTEXT( -//usage: "\n -context File has specified security context" +//usage: "\n -context CTX File has specified security context" //usage: ) -//usage: IF_FEATURE_FIND_EXEC( -//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" -//usage: "\n matching files" +//usage: "\n If none of the following actions is specified, -print is assumed" +//usage: "\n -print Print file name" +//usage: IF_FEATURE_FIND_PRINT0( +//usage: "\n -print0 Print file name, NUL terminated" //usage: ) //usage: IF_FEATURE_FIND_PRUNE( -//usage: "\n -prune Stop traversing current subtree" +//usage: "\n -prune If current file is directory, don't descend into it" //usage: ) -//usage: IF_FEATURE_FIND_DELETE( -//usage: "\n -delete Delete files, turns on -depth option" +//usage: IF_FEATURE_FIND_EXEC( +//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" +//usage: "\n file name. Fails if CMD exits with nonzero" //usage: ) -//usage: IF_FEATURE_FIND_PAREN( -//usage: "\n (EXPR) Group an expression" +//usage: IF_FEATURE_FIND_DELETE( +//usage: "\n -delete Delete current file/directory. Turns on -depth option" //usage: ) //usage: //usage:#define find_example_usage @@ -1141,14 +1140,16 @@ int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { static const char options[] ALIGN1 = - "-follow\0" -IF_FEATURE_FIND_XDEV( "-xdev\0" ) + "-follow\0" +IF_FEATURE_FIND_XDEV( "-xdev\0" ) IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") - ; +IF_FEATURE_FIND_DEPTH( "-depth\0" ) + ; enum { - OPT_FOLLOW, + OPT_FOLLOW, IF_FEATURE_FIND_XDEV( OPT_XDEV ,) IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) +IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) }; char *arg; @@ -1181,12 +1182,12 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) /* All options always return true. They always take effect * rather than being processed only when their place in the * expression is reached. - * We implement: -follow, -xdev, -maxdepth + * We implement: -follow, -xdev, -mindepth, -maxdepth, -depth */ /* Process options, and replace then with -a */ /* (-a will be ignored by recursive parser later) */ argp = &argv[firstopt]; - while ((arg = argp[0])) { + while ((arg = argp[0]) != NULL) { int opt = index_in_strings(options, arg); if (opt == OPT_FOLLOW) { G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; @@ -1216,8 +1217,14 @@ IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) bb_show_usage(); minmaxdepth[opt - OPT_MINDEPTH] = xatoi_positive(argp[1]); argp[0] = (char*)"-a"; - argp[1] = (char*)"-a"; argp++; + argp[0] = (char*)"-a"; + } +#endif +#if ENABLE_FEATURE_FIND_DEPTH + if (opt == OPT_DEPTH) { + G.recurse_flags |= ACTION_DEPTHFIRST; + argp[0] = (char*)"-a"; } #endif argp++; -- cgit v1.2.3-55-g6feb From 4dea9eb07f27384bdbfa39d7fa58cff776b583fa Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 17:08:16 +0100 Subject: find: fix help text about -prune: it also does assume -print Signed-off-by: Denys Vlasenko --- findutils/find.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index e8747f93b..a3dd632a7 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1116,14 +1116,14 @@ static action*** parse_params(char **argv) //usage: IF_FEATURE_FIND_CONTEXT( //usage: "\n -context CTX File has specified security context" //usage: ) +//usage: IF_FEATURE_FIND_PRUNE( +//usage: "\n -prune If current file is directory, don't descend into it" +//usage: ) //usage: "\n If none of the following actions is specified, -print is assumed" //usage: "\n -print Print file name" //usage: IF_FEATURE_FIND_PRINT0( //usage: "\n -print0 Print file name, NUL terminated" //usage: ) -//usage: IF_FEATURE_FIND_PRUNE( -//usage: "\n -prune If current file is directory, don't descend into it" -//usage: ) //usage: IF_FEATURE_FIND_EXEC( //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" //usage: "\n file name. Fails if CMD exits with nonzero" -- cgit v1.2.3-55-g6feb From 56cdb2fc3725ede59edc53e53127912c186d409b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 17:13:03 +0100 Subject: find: yet another tweak to help text Signed-off-by: Denys Vlasenko --- findutils/find.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index a3dd632a7..69fa873cc 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1044,7 +1044,7 @@ static action*** parse_params(char **argv) } //usage:#define find_trivial_usage -//usage: "[OPTIONS] [PATH]... [ACTION]..." +//usage: "[OPTIONS] [PATH]... [ACTIONS]" //usage:#define find_full_usage "\n\n" //usage: "Search for files and perform actions on them.\n" //usage: "First failed action stops processing of current file.\n" @@ -1063,13 +1063,13 @@ static action*** parse_params(char **argv) //usage: "\n -depth Act on directory *after* traversing it" //usage: ) //usage: "\n" +//usage: "\nActions:" //usage: IF_FEATURE_FIND_PAREN( -//usage: "\n ( ACTIONS ) Group actions for -o / -a" +//usage: "\n ( ACTIONS ) Group actions for -o / -a" //usage: ) -//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" -//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" +//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" +//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" //usage: "\n Note: -a has higher priority than -o" -//usage: "\nActions:" //usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" //usage: "\n -iname PATTERN Case insensitive -name" //usage: IF_FEATURE_FIND_PATH( @@ -1119,7 +1119,7 @@ static action*** parse_params(char **argv) //usage: IF_FEATURE_FIND_PRUNE( //usage: "\n -prune If current file is directory, don't descend into it" //usage: ) -//usage: "\n If none of the following actions is specified, -print is assumed" +//usage: "\nIf none of the following actions is specified, -print is assumed" //usage: "\n -print Print file name" //usage: IF_FEATURE_FIND_PRINT0( //usage: "\n -print0 Print file name, NUL terminated" -- cgit v1.2.3-55-g6feb From 4604dd86c503960c86fd23284806eb5eb700d199 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 18:24:15 +0100 Subject: find: help text: PATH must be first Signed-off-by: Denys Vlasenko --- findutils/find.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/findutils/find.c b/findutils/find.c index 69fa873cc..0ec88fd61 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1044,7 +1044,7 @@ static action*** parse_params(char **argv) } //usage:#define find_trivial_usage -//usage: "[OPTIONS] [PATH]... [ACTIONS]" +//usage: "[PATH]... [OPTIONS] [ACTIONS]" //usage:#define find_full_usage "\n\n" //usage: "Search for files and perform actions on them.\n" //usage: "First failed action stops processing of current file.\n" -- cgit v1.2.3-55-g6feb From 27076b823357a650b3df8e166faab471111d9160 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 18:49:48 +0100 Subject: find: document ! (not) operator Signed-off-by: Denys Vlasenko --- findutils/find.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/findutils/find.c b/findutils/find.c index 0ec88fd61..d49adc26d 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1067,6 +1067,9 @@ static action*** parse_params(char **argv) //usage: IF_FEATURE_FIND_PAREN( //usage: "\n ( ACTIONS ) Group actions for -o / -a" //usage: ) +//usage: IF_FEATURE_FIND_NOT( +//usage: "\n ! ACT Invert ACT's success/failure" +//usage: ) //usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" //usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" //usage: "\n Note: -a has higher priority than -o" -- cgit v1.2.3-55-g6feb From 805f2453d02e9d5cbbbd5c37c6659691e1697630 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 20:26:14 +0100 Subject: find: print/print0/prune _can_ be inverted, fix it Signed-off-by: Denys Vlasenko --- findutils/find.c | 207 +++++++++++++++++++++++++++---------------------------- 1 file changed, 101 insertions(+), 106 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index d49adc26d..65467ae9c 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -53,10 +53,6 @@ * diff -u /tmp/std_find /tmp/bb_find && echo Identical */ -//applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) - -//kbuild:lib-$(CONFIG_FIND) += find.o - //config:config FIND //config: bool "find" //config: default y @@ -230,6 +226,106 @@ //config: help //config: Support the 'find -links' option for matching number of links. +//applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) + +//kbuild:lib-$(CONFIG_FIND) += find.o + +//usage:#define find_trivial_usage +//usage: "[PATH]... [OPTIONS] [ACTIONS]" +//usage:#define find_full_usage "\n\n" +//usage: "Search for files and perform actions on them.\n" +//usage: "First failed action stops processing of current file.\n" +//usage: "Defaults: PATH is current directory, action is '-print'\n" +//usage: "\nOptions:" +//usage: "\n -follow Follow symlinks" +//usage: IF_FEATURE_FIND_XDEV( +//usage: "\n -xdev Don't descend directories on other filesystems" +//usage: ) +//usage: IF_FEATURE_FIND_MAXDEPTH( +//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" +//usage: "\n actions to command line arguments only" +//usage: "\n -mindepth N Don't act on first N levels" +//usage: ) +//usage: IF_FEATURE_FIND_DEPTH( +//usage: "\n -depth Act on directory *after* traversing it" +//usage: ) +//usage: "\n" +//usage: "\nActions:" +//usage: IF_FEATURE_FIND_PAREN( +//usage: "\n ( ACTIONS ) Group actions for -o / -a" +//usage: ) +//usage: IF_FEATURE_FIND_NOT( +//usage: "\n ! ACT Invert ACT's success/failure" +//usage: ) +//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" +//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" +//usage: "\n Note: -a has higher priority than -o" +//usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" +//usage: "\n -iname PATTERN Case insensitive -name" +//usage: IF_FEATURE_FIND_PATH( +//usage: "\n -path PATTERN Match path to PATTERN" +//usage: ) +//usage: IF_FEATURE_FIND_REGEX( +//usage: "\n -regex PATTERN Match path to regex PATTERN" +//usage: ) +//usage: IF_FEATURE_FIND_TYPE( +//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" +//usage: ) +//usage: IF_FEATURE_FIND_PERM( +//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," +//usage: "\n or exactly MASK bits are set in mode bits" +//usage: ) +//usage: IF_FEATURE_FIND_MTIME( +//usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," +//usage: "\n or exactly N days" +//usage: ) +//usage: IF_FEATURE_FIND_MMIN( +//usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," +//usage: "\n or exactly N minutes" +//usage: ) +//usage: IF_FEATURE_FIND_NEWER( +//usage: "\n -newer FILE Modified time is more recent than FILE's" +//usage: ) +//usage: IF_FEATURE_FIND_INUM( +//usage: "\n -inum N File has inode number N" +//usage: ) +//usage: IF_FEATURE_FIND_USER( +//usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" +//usage: ) +//usage: IF_FEATURE_FIND_GROUP( +//usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" +//usage: ) +//usage: IF_FEATURE_FIND_SIZE( +//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" +//usage: "\n +/-N: file size is bigger/smaller than N" +//usage: ) +//usage: IF_FEATURE_FIND_LINKS( +//usage: "\n -links N Number of links is greater than (+N), less than (-N)," +//usage: "\n or exactly N" +//usage: ) +//usage: IF_FEATURE_FIND_CONTEXT( +//usage: "\n -context CTX File has specified security context" +//usage: ) +//usage: IF_FEATURE_FIND_PRUNE( +//usage: "\n -prune If current file is directory, don't descend into it" +//usage: ) +//usage: "\nIf none of the following actions is specified, -print is assumed" +//usage: "\n -print Print file name" +//usage: IF_FEATURE_FIND_PRINT0( +//usage: "\n -print0 Print file name, NUL terminated" +//usage: ) +//usage: IF_FEATURE_FIND_EXEC( +//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" +//usage: "\n file name. Fails if CMD exits with nonzero" +//usage: ) +//usage: IF_FEATURE_FIND_DELETE( +//usage: "\n -delete Delete current file/directory. Turns on -depth option" +//usage: ) +//usage: +//usage:#define find_example_usage +//usage: "$ find / -name passwd\n" +//usage: "/etc/passwd\n" + #include #include "libbb.h" #if ENABLE_FEATURE_FIND_REGEX @@ -815,20 +911,16 @@ static action*** parse_params(char **argv) /* --- Tests and actions --- */ else if (parm == PARM_print) { G.need_print = 0; - /* GNU find ignores '!' here: "find ! -print" */ - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print); } #if ENABLE_FEATURE_FIND_PRINT0 else if (parm == PARM_print0) { G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print0); } #endif #if ENABLE_FEATURE_FIND_PRUNE else if (parm == PARM_prune) { - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(prune); } #endif @@ -844,7 +936,6 @@ static action*** parse_params(char **argv) int i; action_exec *ap; G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) ap = ALLOC_ACTION(exec); ap->exec_argv = ++argv; /* first arg after -exec */ /*ap->exec_argc = 0; - ALLOC_ACTION did it */ @@ -1043,102 +1134,6 @@ static action*** parse_params(char **argv) #undef ALLOC_ACTION } -//usage:#define find_trivial_usage -//usage: "[PATH]... [OPTIONS] [ACTIONS]" -//usage:#define find_full_usage "\n\n" -//usage: "Search for files and perform actions on them.\n" -//usage: "First failed action stops processing of current file.\n" -//usage: "Defaults: PATH is current directory, action is '-print'\n" -//usage: "\nOptions:" -//usage: "\n -follow Follow symlinks" -//usage: IF_FEATURE_FIND_XDEV( -//usage: "\n -xdev Don't descend directories on other filesystems" -//usage: ) -//usage: IF_FEATURE_FIND_MAXDEPTH( -//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" -//usage: "\n actions to command line arguments only" -//usage: "\n -mindepth N Don't act on first N levels" -//usage: ) -//usage: IF_FEATURE_FIND_DEPTH( -//usage: "\n -depth Act on directory *after* traversing it" -//usage: ) -//usage: "\n" -//usage: "\nActions:" -//usage: IF_FEATURE_FIND_PAREN( -//usage: "\n ( ACTIONS ) Group actions for -o / -a" -//usage: ) -//usage: IF_FEATURE_FIND_NOT( -//usage: "\n ! ACT Invert ACT's success/failure" -//usage: ) -//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" -//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" -//usage: "\n Note: -a has higher priority than -o" -//usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" -//usage: "\n -iname PATTERN Case insensitive -name" -//usage: IF_FEATURE_FIND_PATH( -//usage: "\n -path PATTERN Match path to PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_REGEX( -//usage: "\n -regex PATTERN Match path to regex PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_TYPE( -//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" -//usage: ) -//usage: IF_FEATURE_FIND_PERM( -//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," -//usage: "\n or exactly MASK bits are set in mode bits" -//usage: ) -//usage: IF_FEATURE_FIND_MTIME( -//usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N days" -//usage: ) -//usage: IF_FEATURE_FIND_MMIN( -//usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N minutes" -//usage: ) -//usage: IF_FEATURE_FIND_NEWER( -//usage: "\n -newer FILE Modified time is more recent than FILE's" -//usage: ) -//usage: IF_FEATURE_FIND_INUM( -//usage: "\n -inum N File has inode number N" -//usage: ) -//usage: IF_FEATURE_FIND_USER( -//usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_GROUP( -//usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_SIZE( -//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" -//usage: "\n +/-N: file size is bigger/smaller than N" -//usage: ) -//usage: IF_FEATURE_FIND_LINKS( -//usage: "\n -links N Number of links is greater than (+N), less than (-N)," -//usage: "\n or exactly N" -//usage: ) -//usage: IF_FEATURE_FIND_CONTEXT( -//usage: "\n -context CTX File has specified security context" -//usage: ) -//usage: IF_FEATURE_FIND_PRUNE( -//usage: "\n -prune If current file is directory, don't descend into it" -//usage: ) -//usage: "\nIf none of the following actions is specified, -print is assumed" -//usage: "\n -print Print file name" -//usage: IF_FEATURE_FIND_PRINT0( -//usage: "\n -print0 Print file name, NUL terminated" -//usage: ) -//usage: IF_FEATURE_FIND_EXEC( -//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" -//usage: "\n file name. Fails if CMD exits with nonzero" -//usage: ) -//usage: IF_FEATURE_FIND_DELETE( -//usage: "\n -delete Delete current file/directory. Turns on -depth option" -//usage: ) -//usage: -//usage:#define find_example_usage -//usage: "$ find / -name passwd\n" -//usage: "/etc/passwd\n" - int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { @@ -1187,7 +1182,7 @@ IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) * expression is reached. * We implement: -follow, -xdev, -mindepth, -maxdepth, -depth */ - /* Process options, and replace then with -a */ + /* Process options, and replace them with -a */ /* (-a will be ignored by recursive parser later) */ argp = &argv[firstopt]; while ((arg = argp[0]) != NULL) { -- cgit v1.2.3-55-g6feb From 053c12e0de30afbc19019ffa9b0cb01edc44539f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 20:27:13 +0100 Subject: find: remove the hack we use to parse options first, replace with simpler code text data bss dec hex filename 867764 438 7552 875754 d5cea busybox_old 867629 438 7552 875619 d5c63 busybox_unstripped function old new delta parse_params 1377 1440 +63 static.params 151 192 +41 static.options 42 57 +15 fileAction 151 153 +2 find_main 466 267 -199 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 121/-199) Total: -78 bytes Signed-off-by: Denys Vlasenko --- findutils/find.c | 212 ++++++++++++++++++++++++------------------------------- 1 file changed, 91 insertions(+), 121 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 65467ae9c..52ac7b0b3 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -374,8 +374,12 @@ IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) struct globals { IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) IF_FEATURE_FIND_XDEV(int xdev_count;) +#if ENABLE_FEATURE_FIND_MAXDEPTH + int minmaxdepth[2]; +#endif action ***actions; - bool need_print; + smallint need_print; + smallint xdev_on; recurse_flags_t recurse_flags; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) @@ -384,7 +388,8 @@ struct globals { char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ }; \ /* we have to zero it out because of NOEXEC */ \ - memset(&G, 0, offsetof(struct globals, need_print)); \ + memset(&G, 0, sizeof(G)); \ + IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ G.need_print = 1; \ G.recurse_flags = ACTION_RECURSE; \ } while (0) @@ -682,16 +687,15 @@ ACTF(links) static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, - void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), + void *userData UNUSED_PARAM, int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) { int r; -#if ENABLE_FEATURE_FIND_MAXDEPTH -#define minmaxdepth ((int*)userData) - if (depth < minmaxdepth[0]) +#if ENABLE_FEATURE_FIND_MAXDEPTH + if (depth < G.minmaxdepth[0]) return TRUE; /* skip this, continue recursing */ - if (depth > minmaxdepth[1]) + if (depth > G.minmaxdepth[1]) return SKIP; /* stop recursing */ #endif @@ -702,7 +706,7 @@ static int FAST_FUNC fileAction(const char *fileName, #if ENABLE_FEATURE_FIND_MAXDEPTH if (S_ISDIR(statbuf->st_mode)) { - if (depth == minmaxdepth[1]) + if (depth == G.minmaxdepth[1]) return SKIP; } #endif @@ -725,7 +729,6 @@ static int FAST_FUNC fileAction(const char *fileName, /* Cannot return 0: our caller, recursive_action(), * will perror() and skip dirs (if called on dir) */ return (r & SKIP) ? SKIP : TRUE; -#undef minmaxdepth } @@ -770,6 +773,9 @@ static const char* plus_minus_num(const char* str) static action*** parse_params(char **argv) { enum { + OPT_FOLLOW , + IF_FEATURE_FIND_XDEV( OPT_XDEV ,) + IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) PARM_a , PARM_o , IF_FEATURE_FIND_NOT( PARM_char_not ,) @@ -784,7 +790,7 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_DELETE( PARM_delete ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) IF_FEATURE_FIND_PAREN( PARM_char_brace,) - /* All options starting from here require argument */ + /* All options/actions starting from here require argument */ PARM_name , PARM_iname , IF_FEATURE_FIND_PATH( PARM_path ,) @@ -800,24 +806,28 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( PARM_size ,) IF_FEATURE_FIND_CONTEXT(PARM_context ,) IF_FEATURE_FIND_LINKS( PARM_links ,) + IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,OPT_MAXDEPTH,) }; static const char params[] ALIGN1 = - "-a\0" - "-o\0" + "-follow\0" + IF_FEATURE_FIND_XDEV( "-xdev\0" ) + IF_FEATURE_FIND_DEPTH( "-depth\0" ) + "-a\0" + "-o\0" IF_FEATURE_FIND_NOT( "!\0" ) #if ENABLE_DESKTOP - "-and\0" - "-or\0" - IF_FEATURE_FIND_NOT( "-not\0" ) + "-and\0" + "-or\0" + IF_FEATURE_FIND_NOT( "-not\0" ) #endif - "-print\0" + "-print\0" IF_FEATURE_FIND_PRINT0( "-print0\0" ) IF_FEATURE_FIND_PRUNE( "-prune\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) IF_FEATURE_FIND_PAREN( "(\0" ) - /* All options starting from here require argument */ + /* All options/actions starting from here require argument */ "-name\0" "-iname\0" IF_FEATURE_FIND_PATH( "-path\0" ) @@ -833,6 +843,7 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( "-size\0" ) IF_FEATURE_FIND_CONTEXT("-context\0") IF_FEATURE_FIND_LINKS( "-links\0" ) + IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") ; action*** appp; @@ -860,27 +871,13 @@ static action*** parse_params(char **argv) appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ -/* Actions have side effects and return a true or false value - * We implement: -print, -print0, -exec - * - * The rest are tests. - * - * Tests and actions are grouped by operators - * ( expr ) Force precedence - * ! expr True if expr is false - * -not expr Same as ! expr - * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false - * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true - * expr1 , expr2 List; both expr1 and expr2 are always evaluated - * We implement: (), -a, -o - */ while (*argv) { const char *arg = argv[0]; int parm = index_in_strings(params, arg); const char *arg1 = argv[1]; if (parm >= PARM_name) { - /* All options starting from -name require argument */ + /* All options/actions starting from -name require argument */ if (!arg1) bb_error_msg_and_die(bb_msg_requires_arg, arg); argv++; @@ -889,8 +886,37 @@ static action*** parse_params(char **argv) /* We can use big switch() here, but on i386 * it doesn't give smaller code. Other arches? */ - /* --- Operators --- */ - if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { +/* Options always return true. They always take effect + * rather than being processed only when their place in the + * expression is reached. + */ + /* Options */ +#if ENABLE_FEATURE_FIND_XDEV + if (parm == OPT_XDEV) { + G.xdev_on = 1; + } +#endif +#if ENABLE_FEATURE_FIND_MAXDEPTH + else if (parm == OPT_MINDEPTH || parm == OPT_MINDEPTH + 1) { + G.minmaxdepth[parm - OPT_MINDEPTH] = xatoi_positive(arg1); + } +#endif +#if ENABLE_FEATURE_FIND_DEPTH + else if (parm == OPT_DEPTH) { + G.recurse_flags |= ACTION_DEPTHFIRST; + } +#endif +/* Actions are grouped by operators + * ( expr ) Force precedence + * ! expr True if expr is false + * -not expr Same as ! expr + * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false + * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true + * expr1 , expr2 List; both expr1 and expr2 are always evaluated + * We implement: (), -a, -o + */ + /* Operators */ + else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { /* no further special handling required */ } else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { @@ -907,8 +933,7 @@ static action*** parse_params(char **argv) invert_flag ^= 1; } #endif - - /* --- Tests and actions --- */ + /* Actions */ else if (parm == PARM_print) { G.need_print = 0; (void) ALLOC_ACTION(print); @@ -1014,10 +1039,10 @@ static action*** parse_params(char **argv) } #endif #if ENABLE_FEATURE_FIND_PERM -/* -perm mode File's permission bits are exactly mode (octal or symbolic). +/* -perm BITS File's mode bits are exactly BITS (octal or symbolic). * Symbolic modes use mode 0 as a point of departure. - * -perm -mode All of the permission bits mode are set for the file. - * -perm +mode Any of the permission bits mode are set for the file. + * -perm -BITS All of the BITS are set in file's mode. + * -perm +BITS At least one of the BITS is set in file's mode. */ else if (parm == PARM_perm) { action_perm *ap; @@ -1137,111 +1162,56 @@ static action*** parse_params(char **argv) int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { - static const char options[] ALIGN1 = - "-follow\0" -IF_FEATURE_FIND_XDEV( "-xdev\0" ) -IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") -IF_FEATURE_FIND_DEPTH( "-depth\0" ) - ; - enum { - OPT_FOLLOW, -IF_FEATURE_FIND_XDEV( OPT_XDEV ,) -IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) -IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) - }; - - char *arg; - char **argp; int i, firstopt, status = EXIT_SUCCESS; -#if ENABLE_FEATURE_FIND_MAXDEPTH - int minmaxdepth[2] = { 0, INT_MAX }; -#else -#define minmaxdepth NULL -#endif INIT_G(); - for (firstopt = 1; argv[firstopt]; firstopt++) { + argv++; + for (firstopt = 0; argv[firstopt]; firstopt++) { if (argv[firstopt][0] == '-') break; if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!')) break; -#if ENABLE_FEATURE_FIND_PAREN - if (LONE_CHAR(argv[firstopt], '(')) + if (ENABLE_FEATURE_FIND_PAREN && LONE_CHAR(argv[firstopt], '(')) break; -#endif } - if (firstopt == 1) { - argv[0] = (char*)"."; - argv--; + if (firstopt == 0) { + *--argv = (char*)"."; firstopt++; } -/* All options always return true. They always take effect - * rather than being processed only when their place in the - * expression is reached. - * We implement: -follow, -xdev, -mindepth, -maxdepth, -depth - */ - /* Process options, and replace them with -a */ - /* (-a will be ignored by recursive parser later) */ - argp = &argv[firstopt]; - while ((arg = argp[0]) != NULL) { - int opt = index_in_strings(options, arg); - if (opt == OPT_FOLLOW) { - G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; - argp[0] = (char*)"-a"; - } + G.actions = parse_params(&argv[firstopt]); + argv[firstopt] = NULL; + #if ENABLE_FEATURE_FIND_XDEV - if (opt == OPT_XDEV) { - struct stat stbuf; - if (!G.xdev_count) { - G.xdev_count = firstopt - 1; - G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); - for (i = 1; i < firstopt; i++) { - /* not xstat(): shouldn't bomb out on - * "find not_exist exist -xdev" */ - if (stat(argv[i], &stbuf) == 0) - G.xdev_dev[i-1] = stbuf.st_dev; - /* else G.xdev_dev[i-1] stays 0 and - * won't match any real device dev_t */ - } - } - argp[0] = (char*)"-a"; - } -#endif -#if ENABLE_FEATURE_FIND_MAXDEPTH - if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) { - if (!argp[1]) - bb_show_usage(); - minmaxdepth[opt - OPT_MINDEPTH] = xatoi_positive(argp[1]); - argp[0] = (char*)"-a"; - argp++; - argp[0] = (char*)"-a"; - } -#endif -#if ENABLE_FEATURE_FIND_DEPTH - if (opt == OPT_DEPTH) { - G.recurse_flags |= ACTION_DEPTHFIRST; - argp[0] = (char*)"-a"; + if (G.xdev_on) { + struct stat stbuf; + + G.xdev_count = firstopt; + G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); + for (i = 0; argv[i]; i++) { + /* not xstat(): shouldn't bomb out on + * "find not_exist exist -xdev" */ + if (stat(argv[i], &stbuf) == 0) + G.xdev_dev[i] = stbuf.st_dev; + /* else G.xdev_dev[i] stays 0 and + * won't match any real device dev_t + */ } -#endif - argp++; } +#endif - G.actions = parse_params(&argv[firstopt]); - - for (i = 1; i < firstopt; i++) { + for (i = 0; argv[i]; i++) { if (!recursive_action(argv[i], G.recurse_flags,/* flags */ fileAction, /* file action */ fileAction, /* dir action */ -#if ENABLE_FEATURE_FIND_MAXDEPTH - minmaxdepth, /* user data */ -#else NULL, /* user data */ -#endif - 0)) /* depth */ + 0) /* depth */ + ) { status = EXIT_FAILURE; + } } + return status; } -- cgit v1.2.3-55-g6feb From e1a4209a5e9a8efe85bed47b576bdcba17056d2d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 20:37:41 +0100 Subject: find: trim help text a bit Signed-off-by: Denys Vlasenko --- findutils/find.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 52ac7b0b3..9ae84fa0d 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -273,27 +273,27 @@ //usage: ) //usage: IF_FEATURE_FIND_PERM( //usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," -//usage: "\n or exactly MASK bits are set in mode bits" +//usage: "\n or exactly MASK bits are set in file's mode" //usage: ) //usage: IF_FEATURE_FIND_MTIME( -//usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N days" +//usage: "\n -mtime DAYS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N days in the past" //usage: ) //usage: IF_FEATURE_FIND_MMIN( -//usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N minutes" +//usage: "\n -mmin MINS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N minutes in the past" //usage: ) //usage: IF_FEATURE_FIND_NEWER( -//usage: "\n -newer FILE Modified time is more recent than FILE's" +//usage: "\n -newer FILE mtime is more recent than FILE's" //usage: ) //usage: IF_FEATURE_FIND_INUM( //usage: "\n -inum N File has inode number N" //usage: ) //usage: IF_FEATURE_FIND_USER( -//usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" +//usage: "\n -user NAME/ID File is owned by given user" //usage: ) //usage: IF_FEATURE_FIND_GROUP( -//usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" +//usage: "\n -group NAME/ID File is owned by given group" //usage: ) //usage: IF_FEATURE_FIND_SIZE( //usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" -- cgit v1.2.3-55-g6feb From a84eadf9bf4112e16d71304c586dfbb64eb85fed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 12 Feb 2011 23:40:31 +0100 Subject: typo fix in comment Signed-off-by: Denys Vlasenko --- networking/wget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/wget.c b/networking/wget.c index 44eb4cf18..45d428be9 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -717,7 +717,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) G.beg_range = xlseek(output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. - * We are not sure it exists on remove side */ + * We are not sure it exists on remote side */ } redir_limit = 5; -- cgit v1.2.3-55-g6feb From a3661096f2e8b49f66ce6c9bba71aa01b79098e2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 13 Feb 2011 02:33:11 +0100 Subject: wget: support multiple URLs on command line function old new delta wget_main 2190 2310 +120 progress_meter 124 140 +16 parse_url 288 304 +16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 152/0) Total: 152 bytes Signed-off-by: Denys Vlasenko --- networking/wget.c | 289 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 160 insertions(+), 129 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 45d428be9..76bd5e260 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -15,8 +15,7 @@ struct host_info { - // May be used if we ever will want to free() all xstrdup()s... - /* char *allocated; */ + char *allocated; const char *path; const char *user; char *host; @@ -34,6 +33,14 @@ struct globals { const char *curfile; /* Name of current file being transferred */ bb_progress_t pmt; #endif + char *dir_prefix; +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + char *post_data; + char *extra_headers; +#endif + char *fname_out; /* where to direct output (-O) */ + const char *proxy_flag; /* Use proxies if env vars are set */ + const char *user_agent; /* "User-Agent" header field */ #if ENABLE_FEATURE_WGET_TIMEOUT unsigned timeout_seconds; #endif @@ -87,6 +94,7 @@ static void progress_meter(int flag) G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); if (flag == PROGRESS_END) { + bb_progress_free(&G.pmt); bb_putchar_stderr('\n'); G.transferred = 0; } @@ -242,11 +250,12 @@ static int ftpcmd(const char *s1, const char *s2, FILE *fp) return result; } -static void parse_url(char *src_url, struct host_info *h) +static void parse_url(const char *src_url, struct host_info *h) { char *url, *p, *sp; - /* h->allocated = */ url = xstrdup(src_url); + free(h->allocated); + h->allocated = url = xstrdup(src_url); if (strncmp(url, "http://", 7) == 0) { h->port = bb_lookup_port("http", "tcp", 80); @@ -571,103 +580,36 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) G.got_clen = 1; } - G.chunked = 0; /* make progress meter show 100% even for chunked */ + /* Draw full bar and free its resources */ + G.chunked = 0; /* makes it show 100% even for chunked download */ progress_meter(PROGRESS_END); } -int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int wget_main(int argc UNUSED_PARAM, char **argv) +static int download_one_url(const char *url) { - struct host_info server, target; - len_and_sockaddr *lsa; - unsigned opt; + bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; - char *proxy = NULL; - char *dir_prefix = NULL; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - char *post_data; - char *extra_headers = NULL; - llist_t *headers_llist = NULL; -#endif + int output_fd; + len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ - char *fname_out; /* where to direct output (-O) */ - int output_fd = -1; - bool use_proxy; /* Use proxies if env vars are set */ - const char *proxy_flag = "on"; /* Use proxies if env vars are set */ - const char *user_agent = "Wget";/* "User-Agent" header field */ - - static const char keywords[] ALIGN1 = - "content-length\0""transfer-encoding\0""chunked\0""location\0"; - enum { - KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location - }; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - static const char wget_longopts[] ALIGN1 = - /* name, has_arg, val */ - "continue\0" No_argument "c" - "spider\0" No_argument "s" - "quiet\0" No_argument "q" - "output-document\0" Required_argument "O" - "directory-prefix\0" Required_argument "P" - "proxy\0" Required_argument "Y" - "user-agent\0" Required_argument "U" -#if ENABLE_FEATURE_WGET_TIMEOUT - "timeout\0" Required_argument "T" -#endif - /* Ignored: */ - // "tries\0" Required_argument "t" - /* Ignored (we always use PASV): */ - "passive-ftp\0" No_argument "\xff" - "header\0" Required_argument "\xfe" - "post-data\0" Required_argument "\xfd" - /* Ignored (we don't do ssl) */ - "no-check-certificate\0" No_argument "\xfc" - ; -#endif - - INIT_G(); - -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - applet_long_options = wget_longopts; -#endif - /* server.allocated = target.allocated = NULL; */ - opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); - opt = getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", - &fname_out, &dir_prefix, - &proxy_flag, &user_agent, - IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), - NULL /* -t RETRIES */ - IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) - IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) - ); -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (headers_llist) { - int size = 1; - char *cp; - llist_t *ll = headers_llist; - while (ll) { - size += strlen(ll->data) + 2; - ll = ll->link; - } - extra_headers = cp = xmalloc(size); - while (headers_llist) { - cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); - } - } -#endif - - /* TODO: compat issue: should handle "wget URL1 URL2..." */ + char *proxy = NULL; + char *fname_out_alloc; + struct host_info server; + struct host_info target; + server.allocated = NULL; + target.allocated = NULL; + server.user = NULL; target.user = NULL; - parse_url(argv[optind], &target); + + parse_url(url, &target); /* Use the proxy if necessary */ - use_proxy = (strcmp(proxy_flag, "off") != 0); + use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); if (proxy && proxy[0]) { - server.user = NULL; parse_url(proxy, &server); } else { use_proxy = 0; @@ -676,7 +618,8 @@ int wget_main(int argc UNUSED_PARAM, char **argv) if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { - server.host = xstrdup(target.host); + //free(server.allocated); - can't be non-NULL + server.host = server.allocated = xstrdup(target.host); } else { server.host = target.host; } @@ -685,34 +628,31 @@ int wget_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); - /* Guess an output filename, if there was no -O FILE */ - if (!(opt & WGET_OPT_OUTNAME)) { - fname_out = bb_get_last_path_component_nostrip(target.path); + /* If there was no -O FILE, guess output filename */ + output_fd = -1; + fname_out_alloc = NULL; + if (!G.fname_out) { + G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ - if (fname_out[0] == '/' || !fname_out[0]) - fname_out = (char*)"index.html"; + if (G.fname_out[0] == '/' || !G.fname_out[0]) + G.fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ - if (dir_prefix) - fname_out = concat_path_file(dir_prefix, fname_out); + if (G.dir_prefix) + G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); } else { - if (LONE_DASH(fname_out)) { + if (LONE_DASH(G.fname_out)) { /* -O - */ output_fd = 1; - opt &= ~WGET_OPT_CONTINUE; + option_mask32 &= ~WGET_OPT_CONTINUE; } } #if ENABLE_FEATURE_WGET_STATUSBAR - G.curfile = bb_get_last_path_component_nostrip(fname_out); + G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif - /* Impossible? - if ((opt & WGET_OPT_CONTINUE) && !fname_out) - bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)"); - */ - /* Determine where to start transfer */ - if (opt & WGET_OPT_CONTINUE) { - output_fd = open(fname_out, O_WRONLY); + if (option_mask32 & WGET_OPT_CONTINUE) { + output_fd = open(G.fname_out, O_WRONLY); if (output_fd >= 0) { G.beg_range = xlseek(output_fd, 0, SEEK_END); } @@ -723,12 +663,13 @@ int wget_main(int argc UNUSED_PARAM, char **argv) redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); - if (!(opt & WGET_OPT_QUIET)) { + if (!(option_mask32 & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: + G.chunked = G.got_clen = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session @@ -736,6 +677,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) char *str; int status; + /* Open socket to http server */ sfp = open_socket(lsa); @@ -745,14 +687,14 @@ int wget_main(int argc UNUSED_PARAM, char **argv) target.is_ftp ? "f" : "ht", target.host, target.path); } else { - if (opt & WGET_OPT_POST_DATA) + if (option_mask32 & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", - target.host, user_agent); + target.host, G.user_agent); /* Ask server to close the connection as soon as we are done * (IOW: we do not intend to send more requests) @@ -774,11 +716,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); #if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (extra_headers) - fputs(extra_headers, sfp); + if (G.extra_headers) + fputs(G.extra_headers, sfp); - if (opt & WGET_OPT_POST_DATA) { - char *estr = URL_escape(post_data); + if (option_mask32 & WGET_OPT_POST_DATA) { + char *estr = URL_escape(G.post_data); fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n" "Content-Length: %u\r\n" @@ -810,7 +752,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) switch (status) { case 0: case 100: - while (gethdr(sfp /*, &n*/) != NULL) + while (gethdr(sfp) != NULL) /* eat all remaining headers */; goto read_response; case 200: @@ -856,9 +798,16 @@ However, in real world it was observed that some web servers /* * Retrieve HTTP headers. */ - while ((str = gethdr(sfp /*, &n*/)) != NULL) { - /* gethdr converted "FOO:" string to lowercase */ + while ((str = gethdr(sfp)) != NULL) { + static const char keywords[] ALIGN1 = + "content-length\0""transfer-encoding\0""location\0"; + enum { + KEY_content_length = 1, KEY_transfer_encoding, KEY_location + }; smalluint key; + + /* gethdr converted "FOO:" string to lowercase */ + /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { @@ -875,23 +824,22 @@ However, in real world it was observed that some web servers continue; } if (key == KEY_transfer_encoding) { - if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) + if (strcmp(str_tolower(str), "chunked") != 0) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); - G.chunked = G.got_clen = 1; + G.chunked = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); - G.got_clen = 0; - G.chunked = 0; - if (str[0] == '/') - /* free(target.allocated); */ - target.path = /* target.allocated = */ xstrdup(str+1); + if (str[0] == '/') { + free(target.allocated); + target.path = target.allocated = xstrdup(str+1); /* lsa stays the same: it's on the same server */ - else { + } else { parse_url(str, &target); if (!use_proxy) { + free(server.allocated); server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ @@ -916,30 +864,113 @@ However, in real world it was observed that some web servers sfp = prepare_ftp_session(&dfp, &target, lsa); } - if (opt & WGET_OPT_SPIDER) { - if (ENABLE_FEATURE_CLEAN_UP) - fclose(sfp); + free(lsa); + free(server.allocated); + free(target.allocated); + + if (option_mask32 & WGET_OPT_SPIDER) { + free(fname_out_alloc); + fclose(sfp); return EXIT_SUCCESS; } if (output_fd < 0) { int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; /* compat with wget: -O FILE can overwrite */ - if (opt & WGET_OPT_OUTNAME) + if (option_mask32 & WGET_OPT_OUTNAME) o_flags = O_WRONLY | O_CREAT | O_TRUNC; - output_fd = xopen(fname_out, o_flags); + output_fd = xopen(G.fname_out, o_flags); } + free(fname_out_alloc); + retrieve_file_data(dfp, output_fd); xclose(output_fd); if (dfp != sfp) { - /* It's ftp. Close it properly */ + /* It's ftp. Close data connection properly */ fclose(dfp); if (ftpcmd(NULL, NULL, sfp) != 226) bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); /* ftpcmd("QUIT", NULL, sfp); - why bother? */ } + fclose(sfp); return EXIT_SUCCESS; } + +int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int wget_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + static const char wget_longopts[] ALIGN1 = + /* name, has_arg, val */ + "continue\0" No_argument "c" +//FIXME: -s isn't --spider, it's --save-headers! + "spider\0" No_argument "s" + "quiet\0" No_argument "q" + "output-document\0" Required_argument "O" + "directory-prefix\0" Required_argument "P" + "proxy\0" Required_argument "Y" + "user-agent\0" Required_argument "U" +#if ENABLE_FEATURE_WGET_TIMEOUT + "timeout\0" Required_argument "T" +#endif + /* Ignored: */ + // "tries\0" Required_argument "t" + /* Ignored (we always use PASV): */ + "passive-ftp\0" No_argument "\xff" + "header\0" Required_argument "\xfe" + "post-data\0" Required_argument "\xfd" + /* Ignored (we don't do ssl) */ + "no-check-certificate\0" No_argument "\xfc" + ; +#endif + + int exitcode; +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + llist_t *headers_llist = NULL; +#endif + + INIT_G(); + + IF_FEATURE_WGET_TIMEOUT(G.timeout_seconds = 900;) + G.proxy_flag = "on"; /* use proxies if env vars are set */ + G.user_agent = "Wget"; /* "User-Agent" header field */ + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + applet_long_options = wget_longopts; +#endif + opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); + getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", + &G.fname_out, &G.dir_prefix, + &G.proxy_flag, &G.user_agent, + IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), + NULL /* -t RETRIES */ + IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) + IF_FEATURE_WGET_LONG_OPTIONS(, &G.post_data) + ); + argv += optind; + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + if (headers_llist) { + int size = 1; + char *cp; + llist_t *ll = headers_llist; + while (ll) { + size += strlen(ll->data) + 2; + ll = ll->link; + } + G.extra_headers = cp = xmalloc(size); + while (headers_llist) { + cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); + } + } +#endif + + exitcode = 0; + while (*argv) + exitcode |= download_one_url(*argv++); + + return exitcode; +} -- cgit v1.2.3-55-g6feb From 9a5b7f636dad35ac84056768b3669bdca02d2700 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 13 Feb 2011 02:49:43 +0100 Subject: wget: support multiple URLs on command line even without -O :) Signed-off-by: Denys Vlasenko --- networking/wget.c | 70 ++++++++++++------------------------------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index 76bd5e260..6c015dccc 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -140,41 +140,6 @@ static void strip_ipv6_scope_id(char *host) overlapping_strcpy(scope, cp); } -#if 0 /* were needed when we used signal-driven progress bar */ -/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, - * and a short count if an eof or non-interrupt error is encountered. */ -static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) -{ - size_t ret; - char *p = (char*)ptr; - - do { - clearerr(stream); - errno = 0; - ret = fread(p, 1, nmemb, stream); - p += ret; - nmemb -= ret; - } while (nmemb && ferror(stream) && errno == EINTR); - - return p - (char*)ptr; -} - -/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM. - * Returns S, or NULL if an eof or non-interrupt error is encountered. */ -static char *safe_fgets(char *s, int size, FILE *stream) -{ - char *ret; - - do { - clearerr(stream); - errno = 0; - ret = fgets(s, size, stream); - } while (ret == NULL && ferror(stream) && errno == EINTR); - - return ret; -} -#endif - #if ENABLE_FEATURE_WGET_AUTHENTICATION /* Base64-encode character string. */ static char *base64enc(const char *str) @@ -631,7 +596,7 @@ static int download_one_url(const char *url) /* If there was no -O FILE, guess output filename */ output_fd = -1; fname_out_alloc = NULL; - if (!G.fname_out) { + if (!(option_mask32 & WGET_OPT_OUTNAME)) { G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ if (G.fname_out[0] == '/' || !G.fname_out[0]) @@ -865,28 +830,19 @@ However, in real world it was observed that some web servers } free(lsa); - free(server.allocated); - free(target.allocated); - - if (option_mask32 & WGET_OPT_SPIDER) { - free(fname_out_alloc); - fclose(sfp); - return EXIT_SUCCESS; - } - if (output_fd < 0) { - int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; - /* compat with wget: -O FILE can overwrite */ - if (option_mask32 & WGET_OPT_OUTNAME) - o_flags = O_WRONLY | O_CREAT | O_TRUNC; - output_fd = xopen(G.fname_out, o_flags); + if (!(option_mask32 & WGET_OPT_SPIDER)) { + if (output_fd < 0) { + int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; + /* compat with wget: -O FILE can overwrite */ + if (option_mask32 & WGET_OPT_OUTNAME) + o_flags = O_WRONLY | O_CREAT | O_TRUNC; + output_fd = xopen(G.fname_out, o_flags); + } + retrieve_file_data(dfp, output_fd); + xclose(output_fd); } - free(fname_out_alloc); - - retrieve_file_data(dfp, output_fd); - xclose(output_fd); - if (dfp != sfp) { /* It's ftp. Close data connection properly */ fclose(dfp); @@ -896,6 +852,10 @@ However, in real world it was observed that some web servers } fclose(sfp); + free(server.allocated); + free(target.allocated); + free(fname_out_alloc); + return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 07cda2268a6cff59378af16eabc4968d9bebe915 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 13 Feb 2011 04:17:35 +0100 Subject: fix bug 3223 (parameter loading problem for 2.4 kernels) Signed-off-by: Denys Vlasenko --- modutils/modutils-24.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/modutils/modutils-24.c b/modutils/modutils-24.c index 2b34954c0..bbc54e316 100644 --- a/modutils/modutils-24.c +++ b/modutils/modutils-24.c @@ -2444,14 +2444,12 @@ new_process_module_arguments(struct obj_file *f, const char *options) bb_error_msg_and_die("symbol for parameter %s not found", param); /* Number of parameters */ + min = max = 1; if (isdigit(*pinfo)) { - min = strtoul(pinfo, &pinfo, 10); + min = max = strtoul(pinfo, &pinfo, 10); if (*pinfo == '-') max = strtoul(pinfo + 1, &pinfo, 10); - else - max = min; - } else - min = max = 1; + } contents = f->sections[sym->secidx]->contents; loc = contents + sym->value; @@ -2473,7 +2471,8 @@ new_process_module_arguments(struct obj_file *f, const char *options) /* Parse parameter values */ n = 0; p = val; - while (*p != 0) { + while (*p) { + char sv_ch; char *endp; if (++n > max) @@ -2482,21 +2481,25 @@ new_process_module_arguments(struct obj_file *f, const char *options) switch (*pinfo) { case 's': len = strcspn(p, ","); - p[len] = 0; + sv_ch = p[len]; + p[len] = '\0'; obj_string_patch(f, sym->secidx, loc - contents, p); loc += tgt_sizeof_char_p; p += len; + *p = sv_ch; break; case 'c': len = strcspn(p, ","); - p[len] = 0; + sv_ch = p[len]; + p[len] = '\0'; if (len >= charssize) bb_error_msg_and_die("string too long for %s (max %ld)", param, charssize - 1); strcpy((char *) loc, p); loc += charssize; p += len; + *p = sv_ch; break; case 'b': *loc++ = strtoul(p, &endp, 0); -- cgit v1.2.3-55-g6feb From 4ed3c52ce9b3ce5604c4fa075fda374f8cd01eea Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 13 Feb 2011 17:38:34 +0100 Subject: mktemp: make it more compatible with GNU coreutils 8.4 Signed-off-by: Denys Vlasenko --- debianutils/mktemp.c | 40 ++++++++++++++++++++++++++++++++++++---- include/usage.src.h | 20 -------------------- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/debianutils/mktemp.c b/debianutils/mktemp.c index 86881f86d..f4961af59 100644 --- a/debianutils/mktemp.c +++ b/debianutils/mktemp.c @@ -31,6 +31,25 @@ * -p; else /tmp [deprecated] */ +//usage:#define mktemp_trivial_usage +//usage: "[-dt] [-p DIR] [TEMPLATE]" +//usage:#define mktemp_full_usage "\n\n" +//usage: "Create a temporary file with name based on TEMPLATE and print its name.\n" +//usage: "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" +//usage: "Without TEMPLATE, -t tmp.XXXXXX is assumed.\n" +//usage: "\nOptions:" +//usage: "\n -d Make directory, not file" +////usage: "\n -q Fail silently on errors" - we ignore this opt +//usage: "\n -t Prepend base directory name to TEMPLATE" +//usage: "\n -p DIR Use DIR as a base directory (implies -t)" +//usage: "\n" +//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /tmp" +//usage: +//usage:#define mktemp_example_usage +//usage: "$ mktemp /tmp/temp.XXXXXX\n" +//usage: "/tmp/temp.mWiLjM\n" +//usage: "$ ls -la /tmp/temp.mWiLjM\n" +//usage: "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" #include "libbb.h" @@ -40,20 +59,33 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv) const char *path; char *chp; unsigned opts; + enum { + OPT_d = 1 << 0, + OPT_q = 1 << 1, + OPT_t = 1 << 2, + OPT_p = 1 << 3, + }; path = getenv("TMPDIR"); if (!path || path[0] == '\0') path = "/tmp"; - /* -q and -t are ignored */ + /* -q is ignored */ opt_complementary = "?1"; /* 1 argument max */ opts = getopt32(argv, "dqtp:", &path); - chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); - if (!strchr(chp, '/') || (opts & 8)) + chp = argv[optind]; + if (!chp) { + /* GNU coreutils 8.4: + * bare "mktemp" -> "mktemp -t tmp.XXXXXX" + */ + chp = xstrdup("tmp.XXXXXX"); + opts |= OPT_t; + } + if (opts & (OPT_t|OPT_p)) chp = concat_path_file(path, chp); - if (opts & 1) { /* -d */ + if (opts & OPT_d) { if (mkdtemp(chp) == NULL) return EXIT_FAILURE; } else { diff --git a/include/usage.src.h b/include/usage.src.h index ebe80f8e1..c2575b561 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2451,26 +2451,6 @@ INSERT "\nOptions:" \ "\n -L LBL Label" \ -#define mktemp_trivial_usage \ - "[-dt] [-p DIR] [TEMPLATE]" -#define mktemp_full_usage "\n\n" \ - "Create a temporary file with name based on TEMPLATE and print its name.\n" \ - "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" \ - "\nOptions:" \ - "\n -d Make a directory instead of a file" \ -/* "\n -q Fail silently if an error occurs" - we ignore it */ \ - "\n -t Generate a path rooted in temporary directory" \ - "\n -p DIR Use DIR as a temporary directory (implies -t)" \ - "\n" \ - "\nFor -t or -p, directory is chosen as follows:" \ - "\n$TMPDIR if set, else -p DIR, else /tmp" \ - -#define mktemp_example_usage \ - "$ mktemp /tmp/temp.XXXXXX\n" \ - "/tmp/temp.mWiLjM\n" \ - "$ ls -la /tmp/temp.mWiLjM\n" \ - "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" - #define more_trivial_usage \ "[FILE]..." #define more_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From dc50676cce35cdba3ecba3870c3f752408d6db70 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 12 Feb 2011 22:26:57 -0800 Subject: Move stpcpy replacement function into libbb Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- include/platform.h | 8 ++++++++ libbb/platform.c | 11 +++++++++++ runit/runsv.c | 24 +++++++----------------- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/include/platform.h b/include/platform.h index 00ebe563b..e390e58e2 100644 --- a/include/platform.h +++ b/include/platform.h @@ -18,6 +18,7 @@ #define HAVE_PTSNAME_R 1 #define HAVE_SETBIT 1 #define HAVE_SIGHANDLER_T 1 +#define HAVE_STPCPY 1 #define HAVE_STRCASESTR 1 #define HAVE_STRCHRNUL 1 #define HAVE_STRSEP 1 @@ -356,6 +357,8 @@ typedef unsigned smalluint; # define ADJ_TICK MOD_CLKB # endif +# undef HAVE_STPCPY + #else # define bb_setpgrp() setpgrp() @@ -376,6 +379,7 @@ typedef unsigned smalluint; # undef HAVE_MEMRCHR # undef HAVE_MKDTEMP # undef HAVE_SETBIT +# undef HAVE_STPCPY # undef HAVE_STRCASESTR # undef HAVE_STRCHRNUL # undef HAVE_STRSEP @@ -413,6 +417,10 @@ extern char *mkdtemp(char *template) FAST_FUNC; typedef void (*sighandler_t)(int); #endif +#ifndef HAVE_STPCPY +extern char *stpcpy(char *p, const char *to_add) FAST_FUNC; +#endif + #ifndef HAVE_STRCASESTR extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; #endif diff --git a/libbb/platform.c b/libbb/platform.c index ccde2bf02..fe7ce1567 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -134,3 +134,14 @@ char* FAST_FUNC strsep(char **stringp, const char *delim) return start; } #endif + +#ifndef HAVE_STPCPY +char* FAST_FUNC stpcpy(char *p, const char *to_add) +{ + while ((*p = *to_add) != '\0') { + p++; + to_add++; + } + return p; +} +#endif diff --git a/runit/runsv.c b/runit/runsv.c index ebb031837..e76572daa 100644 --- a/runit/runsv.c +++ b/runit/runsv.c @@ -139,16 +139,6 @@ static void s_term(int sig_no UNUSED_PARAM) write(selfpipe.wr, "", 1); /* XXX */ } -/* libbb candidate */ -static char *bb_stpcpy(char *p, const char *to_add) -{ - while ((*p = *to_add) != '\0') { - p++; - to_add++; - } - return p; -} - static int open_trunc_or_warn(const char *name) { /* Why O_NDELAY? */ @@ -192,26 +182,26 @@ static void update_status(struct svdir *s) char *p = stat_buf; switch (s->state) { case S_DOWN: - p = bb_stpcpy(p, "down"); + p = stpcpy(p, "down"); break; case S_RUN: - p = bb_stpcpy(p, "run"); + p = stpcpy(p, "run"); break; case S_FINISH: - p = bb_stpcpy(p, "finish"); + p = stpcpy(p, "finish"); break; } if (s->ctrl & C_PAUSE) - p = bb_stpcpy(p, ", paused"); + p = stpcpy(p, ", paused"); if (s->ctrl & C_TERM) - p = bb_stpcpy(p, ", got TERM"); + p = stpcpy(p, ", got TERM"); if (s->state != S_DOWN) switch (s->sd_want) { case W_DOWN: - p = bb_stpcpy(p, ", want down"); + p = stpcpy(p, ", want down"); break; case W_EXIT: - p = bb_stpcpy(p, ", want exit"); + p = stpcpy(p, ", want exit"); break; } *p++ = '\n'; -- cgit v1.2.3-55-g6feb From 48a5219f39a7fcb8b9670d20439a3ab89c2b9bac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Feb 2011 03:52:16 +0100 Subject: reverted LINHIB0001 swap signature addition see: https://bugs.launchpad.net/ubuntu/+source/util-linux/+bug/683605 Signed-off-by: Denys Vlasenko --- util-linux/volume_id/linux_swap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/util-linux/volume_id/linux_swap.c b/util-linux/volume_id/linux_swap.c index 62d588522..1ee534ab0 100644 --- a/util-linux/volume_id/linux_swap.c +++ b/util-linux/volume_id/linux_swap.c @@ -55,7 +55,6 @@ int FAST_FUNC volume_id_probe_linux_swap(struct volume_id *id /*,uint64_t off*/) if (memcmp(buf, "SWAPSPACE2", 10) == 0 || memcmp(buf, "S1SUSPEND", 9) == 0 || memcmp(buf, "S2SUSPEND", 9) == 0 - || memcmp(buf, "LINHIB0001", 10) == 0 || memcmp(buf, "ULSUSPEND", 9) == 0 ) { sw = volume_id_get_buffer(id, off, sizeof(struct swap_header_v1_2)); -- cgit v1.2.3-55-g6feb From 713e6d78e1cb567848805e8dd0c9c0cadbfa787a Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Mon, 14 Feb 2011 04:50:30 +0100 Subject: udhcpc: use more correct, and more importantly, more understandable BPF code Signed-off-by: Vladislav Grishenko Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpc.c | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 7e5ab61fd..d97a404fa 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -714,22 +714,25 @@ static int udhcp_raw_socket(int ifindex) * * TODO: make conditional? */ -#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68) static const struct sock_filter filter_instr[] = { - /* check for udp */ + /* load 9th byte (protocol) */ BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0), /* L5, L1, is UDP? */ - /* ugly check for arp on ethernet-like and IPv4 */ - BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4), /* L3, L4 */ - /* skip IP header */ - BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */ - /* check udp source and destination ports */ - BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */ - /* returns */ - BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ), /* L3: pass */ - BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */ + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), }; static const struct sock_fprog filter_prog = { .len = sizeof(filter_instr) / sizeof(filter_instr[0]), @@ -742,18 +745,19 @@ static int udhcp_raw_socket(int ifindex) fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); log1("Got raw socket fd %d", fd); //log2? - if (SERVER_PORT == 67 && CLIENT_PORT == 68) { - /* Use only if standard ports are in use */ + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IP); + sock.sll_ifindex = ifindex; + xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); + + if (CLIENT_PORT == 68) { + /* Use only if standard port is in use */ /* Ignoring error (kernel may lack support for this) */ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) >= 0) log1("Attached filter to raw socket fd %d", fd); // log? } - sock.sll_family = AF_PACKET; - sock.sll_protocol = htons(ETH_P_IP); - sock.sll_ifindex = ifindex; - xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); log1("Created raw socket"); return fd; -- cgit v1.2.3-55-g6feb From b9348440b0491b479457b304754bca4840286f74 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Feb 2011 15:42:18 +0100 Subject: echo: fix ENOSPC detection and some iffy code in \NNN handling function old new delta echo_main 330 302 -28 Signed-off-by: Denys Vlasenko --- coreutils/echo.c | 112 ++++++++++++++++----------------- testsuite/echo/echo-prints-dash | 1 + testsuite/echo/echo-prints-non-opts | 1 + testsuite/echo/echo-prints-slash_00041 | 3 + testsuite/echo/echo-prints-slash_0041 | 3 + testsuite/echo/echo-prints-slash_041 | 3 + testsuite/echo/echo-prints-slash_41 | 3 + 7 files changed, 70 insertions(+), 56 deletions(-) create mode 100644 testsuite/echo/echo-prints-dash create mode 100644 testsuite/echo/echo-prints-non-opts create mode 100644 testsuite/echo/echo-prints-slash_00041 create mode 100644 testsuite/echo/echo-prints-slash_0041 create mode 100644 testsuite/echo/echo-prints-slash_041 create mode 100644 testsuite/echo/echo-prints-slash_41 diff --git a/coreutils/echo.c b/coreutils/echo.c index 5fa3d10c5..42c3f9ed8 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -50,7 +50,6 @@ int echo_main(int argc UNUSED_PARAM, char **argv) char *out; char *buffer; unsigned buflen; - int r; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = '\\', @@ -59,40 +58,40 @@ int echo_main(int argc UNUSED_PARAM, char **argv) argv++; #else - const char *p; char nflag = 1; char eflag = 0; while ((arg = *++argv) != NULL) { - if (!arg || arg[0] != '-') - break; + char n, e; + + if (arg[0] != '-') + break; /* not an option arg, echo it */ /* If it appears that we are handling options, then make sure * that all of the options specified are actually valid. * Otherwise, the string should just be echoed. */ - p = arg + 1; - if (!*p) /* A single '-', so echo it. */ - break; - + arg++; + n = nflag; + e = eflag; do { - if (!strrchr("neE", *p)) + if (*arg == 'n') + n = 0; + else if (*arg == 'e') + e = '\\'; + else if (*arg != 'E') { + /* "-ccc" arg with one of c's invalid, echo it */ + /* arg consisting from just "-" also handled here */ goto just_echo; - } while (*++p); - - /* All of the options in this arg are valid, so handle them. */ - p = arg + 1; - do { - if (*p == 'n') - nflag = 0; - if (*p == 'e') - eflag = '\\'; - } while (*++p); + } + } while (*++arg); + nflag = n; + eflag = e; } just_echo: #endif - buflen = 1; + buflen = 0; pp = argv; while ((arg = *pp) != NULL) { buflen += strlen(arg) + 1; @@ -106,29 +105,32 @@ int echo_main(int argc UNUSED_PARAM, char **argv) if (!eflag) { /* optimization for very common case */ out = stpcpy(out, arg); - } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + } else + while ((c = *arg++) != '\0') { + if (c == eflag) { + /* This is an "\x" sequence */ + if (*arg == 'c') { - /* '\c' means cancel newline and + /* "\c" means cancel newline and * ignore all subsequent chars. */ goto do_write; } -#if !ENABLE_FEATURE_FANCY_ECHO - /* SUSv3 specifies that octal escapes must begin with '0'. */ - if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */ -#endif - { - /* Since SUSv3 mandates a first digit of 0, 4-digit octals - * of the form \0### are accepted. */ - if (*arg == '0') { - /* NB: don't turn "...\0" into "...\" */ - if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) { - arg++; - } + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0') { + if ((unsigned char)(arg[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + arg++; } - /* bb_process_escape_sequence handles NUL correctly - * ("...\" case). */ - c = bb_process_escape_sequence(&arg); + } + /* bb_process_escape_sequence handles NUL correctly + * ("...\" case). */ + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. ~30 bytes win */ + const char *z = arg; + c = bb_process_escape_sequence(&z); + arg = z; } } *out++ = c; @@ -144,16 +146,18 @@ int echo_main(int argc UNUSED_PARAM, char **argv) } do_write: - r = full_write(STDOUT_FILENO, buffer, out - buffer); + /* Careful to error out on partial writes too (think ENOSPC!) */ + errno = 0; + /*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer); free(buffer); - if (r < 0) { + if (/*WRONG:r < 0*/ errno) { bb_perror_msg(bb_msg_write_error); return 1; } return 0; } -/*- +/* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -239,7 +243,7 @@ int echo_main(int argc, char **argv) goto just_echo; do { - if (!strrchr("neE", *p)) + if (!strchr("neE", *p)) goto just_echo; } while (*++p); @@ -265,27 +269,23 @@ int echo_main(int argc, char **argv) /* optimization for very common case */ p += strlen(arg); } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + if (c == eflag) { + /* This is an "\x" sequence */ + if (*arg == 'c') { - /* '\c' means cancel newline and + /* "\c" means cancel newline and * ignore all subsequent chars. */ cur_io->iov_len = p - (char*)cur_io->iov_base; cur_io++; goto ret; } -#if !ENABLE_FEATURE_FANCY_ECHO - /* SUSv3 specifies that octal escapes must begin with '0'. */ - if ( (((unsigned char)*arg) - '1') >= 7) -#endif - { - /* Since SUSv3 mandates a first digit of 0, 4-digit octals - * of the form \0### are accepted. */ - if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { - arg++; - } - /* bb_process_escape_sequence can handle nul correctly */ - c = bb_process_escape_sequence( (void*) &arg); + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) { + arg++; } + /* bb_process_escape_sequence can handle nul correctly */ + c = bb_process_escape_sequence( (void*) &arg); } *p++ = c; } diff --git a/testsuite/echo/echo-prints-dash b/testsuite/echo/echo-prints-dash new file mode 100644 index 000000000..ddcdbadf7 --- /dev/null +++ b/testsuite/echo/echo-prints-dash @@ -0,0 +1 @@ +test "`busybox echo - | od -t x1 | head -n 1`" = "0000000 2d 0a" diff --git a/testsuite/echo/echo-prints-non-opts b/testsuite/echo/echo-prints-non-opts new file mode 100644 index 000000000..c7d1e201a --- /dev/null +++ b/testsuite/echo/echo-prints-non-opts @@ -0,0 +1 @@ +test "`busybox echo -neEZ | od -t x1 | head -n 1`" = "0000000 2d 6e 65 45 5a 0a" diff --git a/testsuite/echo/echo-prints-slash_00041 b/testsuite/echo/echo-prints-slash_00041 new file mode 100644 index 000000000..9cffabde0 --- /dev/null +++ b/testsuite/echo/echo-prints-slash_00041 @@ -0,0 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + +test "`busybox echo -ne '\00041z' | od -t x1 | head -n 1`" = "0000000 04 31 7a" diff --git a/testsuite/echo/echo-prints-slash_0041 b/testsuite/echo/echo-prints-slash_0041 new file mode 100644 index 000000000..b07429dfd --- /dev/null +++ b/testsuite/echo/echo-prints-slash_0041 @@ -0,0 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + +test "`busybox echo -ne '\0041z' | od -t x1 | head -n 1`" = "0000000 21 7a" diff --git a/testsuite/echo/echo-prints-slash_041 b/testsuite/echo/echo-prints-slash_041 new file mode 100644 index 000000000..1d70cec92 --- /dev/null +++ b/testsuite/echo/echo-prints-slash_041 @@ -0,0 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + +test "`busybox echo -ne '\041z' | od -t x1 | head -n 1`" = "0000000 21 7a" diff --git a/testsuite/echo/echo-prints-slash_41 b/testsuite/echo/echo-prints-slash_41 new file mode 100644 index 000000000..6d8999b4e --- /dev/null +++ b/testsuite/echo/echo-prints-slash_41 @@ -0,0 +1,3 @@ +# FEATURE: CONFIG_FEATURE_FANCY_ECHO + +test "`busybox echo -ne '\41z' | od -t x1 | head -n 1`" = "0000000 21 7a" -- cgit v1.2.3-55-g6feb From 7c6f2468ccc849c9f8401ee97a3d894d8f483773 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 14 Feb 2011 17:17:10 +0100 Subject: hush: do not print killer signal's name for SIGPIPE Signed-off-by: Denys Vlasenko --- shell/ash.c | 1 + shell/hush.c | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index aaf21cd6f..cccd6dd79 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3892,6 +3892,7 @@ sprint_status(char *s, int status, int sigonly) #endif } st &= 0x7f; +//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata col = fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { col += fmtstr(s + col, 16, " (core dumped)"); diff --git a/shell/hush.c b/shell/hush.c index 00ef361cd..4d9e5f8c7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6504,13 +6504,15 @@ static int checkjobs(struct pipe *fg_pipe) fg_pipe->alive_cmds--; ex = WEXITSTATUS(status); /* bash prints killer signal's name for *last* - * process in pipe (prints just newline for SIGINT). + * process in pipe (prints just newline for SIGINT/SIGPIPE). * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) */ if (WIFSIGNALED(status)) { int sig = WTERMSIG(status); if (i == fg_pipe->num_cmds-1) - printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); + /* TODO: use strsignal() instead for bash compat? but that's bloat... */ + printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); + /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? * Maybe we need to use sig | 128? */ ex = sig + 128; -- cgit v1.2.3-55-g6feb From 57b4909db92ab403cc955e6cef4ea2b8318586b6 Mon Sep 17 00:00:00 2001 From: Pere Orga Date: Mon, 14 Feb 2011 23:56:07 +0100 Subject: wget: fix SEGV with multiple urls and redirection Signed-off-by: Pere Orga Signed-off-by: Denys Vlasenko --- networking/wget.c | 1 + 1 file changed, 1 insertion(+) diff --git a/networking/wget.c b/networking/wget.c index 6c015dccc..cb169aba3 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -805,6 +805,7 @@ However, in real world it was observed that some web servers parse_url(str, &target); if (!use_proxy) { free(server.allocated); + server.allocated = NULL; server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ -- cgit v1.2.3-55-g6feb From 2384a357f41a92421e1e68fdd3a1afda7922a8ea Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Feb 2011 00:58:36 +0100 Subject: wget: make "wget -O FILE URL1 URL2" concatenate output Also fixes a few cases where URL1's data (like start pos) was leaking into URL2 function old new delta wget_main 2303 2321 +18 progress_meter 140 152 +12 retrieve_file_data 397 396 -1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 30/-1) Total: 29 bytes Signed-off-by: Denys Vlasenko --- networking/wget.c | 66 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index cb169aba3..6c9a51211 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -44,6 +44,8 @@ struct globals { #if ENABLE_FEATURE_WGET_TIMEOUT unsigned timeout_seconds; #endif + int output_fd; + int o_flags; smallint chunked; /* chunked transfer encoding */ smallint got_clen; /* got content-length: from server */ /* Local downloads do benefit from big buffer. @@ -90,8 +92,11 @@ static void progress_meter(int flag) if (flag == PROGRESS_START) bb_progress_init(&G.pmt, G.curfile); - bb_progress_update(&G.pmt, G.beg_range, G.transferred, - G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); + bb_progress_update(&G.pmt, + G.beg_range, + G.transferred, + (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len + ); if (flag == PROGRESS_END) { bb_progress_free(&G.pmt); @@ -430,7 +435,7 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ return sfp; } -static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) +static void NOINLINE retrieve_file_data(FILE *dfp) { #if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT # if ENABLE_FEATURE_WGET_TIMEOUT @@ -516,7 +521,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) break; /* EOF, not error */ } - xwrite(output_fd, G.wget_buf, n); + xwrite(G.output_fd, G.wget_buf, n); #if ENABLE_FEATURE_WGET_STATUSBAR G.transferred += n; @@ -546,7 +551,8 @@ static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) } /* Draw full bar and free its resources */ - G.chunked = 0; /* makes it show 100% even for chunked download */ + G.chunked = 0; /* makes it show 100% even for chunked download */ + G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ progress_meter(PROGRESS_END); } @@ -554,7 +560,6 @@ static int download_one_url(const char *url) { bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; - int output_fd; len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ @@ -574,11 +579,9 @@ static int download_one_url(const char *url) use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); - if (proxy && proxy[0]) { + use_proxy = (proxy && proxy[0]); + if (use_proxy) parse_url(proxy, &server); - } else { - use_proxy = 0; - } } if (!use_proxy) { server.port = target.port; @@ -594,7 +597,6 @@ static int download_one_url(const char *url) strip_ipv6_scope_id(target.host); /* If there was no -O FILE, guess output filename */ - output_fd = -1; fname_out_alloc = NULL; if (!(option_mask32 & WGET_OPT_OUTNAME)) { G.fname_out = bb_get_last_path_component_nostrip(target.path); @@ -604,22 +606,17 @@ static int download_one_url(const char *url) /* -P DIR is considered only if there was no -O FILE */ if (G.dir_prefix) G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); - } else { - if (LONE_DASH(G.fname_out)) { - /* -O - */ - output_fd = 1; - option_mask32 &= ~WGET_OPT_CONTINUE; - } } #if ENABLE_FEATURE_WGET_STATUSBAR G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif /* Determine where to start transfer */ + G.beg_range = 0; if (option_mask32 & WGET_OPT_CONTINUE) { - output_fd = open(G.fname_out, O_WRONLY); - if (output_fd >= 0) { - G.beg_range = xlseek(output_fd, 0, SEEK_END); + G.output_fd = open(G.fname_out, O_WRONLY); + if (G.output_fd >= 0) { + G.beg_range = xlseek(G.output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. * We are not sure it exists on remote side */ @@ -634,7 +631,9 @@ static int download_one_url(const char *url) free(s); } establish_session: - G.chunked = G.got_clen = 0; + /*G.content_len = 0; - redundant, got_clen = 0 is enough */ + G.got_clen = 0; + G.chunked = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session @@ -833,15 +832,13 @@ However, in real world it was observed that some web servers free(lsa); if (!(option_mask32 & WGET_OPT_SPIDER)) { - if (output_fd < 0) { - int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; - /* compat with wget: -O FILE can overwrite */ - if (option_mask32 & WGET_OPT_OUTNAME) - o_flags = O_WRONLY | O_CREAT | O_TRUNC; - output_fd = xopen(G.fname_out, o_flags); + if (G.output_fd < 0) + G.output_fd = xopen(G.fname_out, G.o_flags); + retrieve_file_data(dfp); + if (!(option_mask32 & WGET_OPT_OUTNAME)) { + xclose(G.output_fd); + G.output_fd = -1; } - retrieve_file_data(dfp, output_fd); - xclose(output_fd); } if (dfp != sfp) { @@ -929,6 +926,17 @@ int wget_main(int argc UNUSED_PARAM, char **argv) } #endif + G.output_fd = -1; + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; + if (G.fname_out) { /* -O FILE ? */ + if (LONE_DASH(G.fname_out)) { /* -O - ? */ + G.output_fd = 1; + option_mask32 &= ~WGET_OPT_CONTINUE; + } + /* compat with wget: -O FILE can overwrite */ + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC; + } + exitcode = 0; while (*argv) exitcode |= download_one_url(*argv++); -- cgit v1.2.3-55-g6feb From 12f44ea18344f66e03e61e621a6c0fd2d36f7595 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Mon, 14 Feb 2011 19:50:30 +0200 Subject: modinfo: show firmware and depends fields Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- modutils/modinfo.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 731fc0553..cc501825c 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -23,9 +23,9 @@ enum { - OPT_TAGS = (1 << 6) - 1, - OPT_F = (1 << 6), /* field name */ - OPT_0 = (1 << 7), /* \0 as separator */ + OPT_TAGS = (1 << 8) - 1, + OPT_F = (1 << 8), /* field name */ + OPT_0 = (1 << 9), /* \0 as separator */ }; struct modinfo_env { @@ -53,6 +53,8 @@ static void modinfo(const char *path, const char *version, "license", "vermagic", "parm", + "firmware", + "depends", }; size_t len; int j, length; -- cgit v1.2.3-55-g6feb From df7f2008c2a3a54437d2678b8d53eddaf136eb89 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Feb 2011 01:45:14 +0100 Subject: modinfo: trivial optimizations Signed-off-by: Denys Vlasenko --- modutils/modinfo.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/modutils/modinfo.c b/modutils/modinfo.c index cc501825c..db134bd00 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -44,7 +44,7 @@ static int display(const char *data, const char *pattern, int flag) } static void modinfo(const char *path, const char *version, - struct modinfo_env *env) + const struct modinfo_env *env) { static const char *const shortcuts[] = { "filename", @@ -82,11 +82,13 @@ static void modinfo(const char *path, const char *version, if (field) tags |= OPT_F; for (j = 1; (1< Date: Tue, 15 Feb 2011 02:17:31 +0100 Subject: modprobe: fix "modprobe -l name-with-dash" Signed-off-by: Denys Vlasenko --- modutils/modprobe.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 0d28da7ea..7ae459826 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -530,10 +530,14 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) xchdir(G.uts.release); if (opt & OPT_LIST_ONLY) { + int i; char name[MODULE_NAME_LEN]; char *colon, *tokens[2]; parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); + for (i = 0; argv[i]; i++) + replace(argv[i], '-', '_'); + while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { colon = last_char_is(tokens[0], ':'); if (!colon) @@ -543,7 +547,6 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) puts(tokens[0]); else { - int i; for (i = 0; argv[i]; i++) { if (fnmatch(argv[i], name, 0) == 0) { puts(tokens[0]); -- cgit v1.2.3-55-g6feb From 26b80e8fe36510c8ec97ae07d9e16e53de32a4af Mon Sep 17 00:00:00 2001 From: Gilles Espinasse Date: Sun, 13 Feb 2011 22:54:37 +0100 Subject: Add the help text for 'position independent executable' code build Signed-off-by: Gilles Espinasse Signed-off-by: Denys Vlasenko --- Config.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Config.in b/Config.in index b49181732..3361e7381 100644 --- a/Config.in +++ b/Config.in @@ -466,7 +466,10 @@ config PIE default n depends on !STATIC help - (TODO: what is it and why/when is it useful?) + Hardened code option. PIE binaries are loaded at a different + address at each invocation. This has some overhead, + particularly on x86-32 which is short on registers. + Most people will leave this set to 'N'. config NOMMU -- cgit v1.2.3-55-g6feb From 28556b95febc77ebdd2d2f2e0be4a0157dcaf735 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Feb 2011 11:03:53 +0100 Subject: wget: check for final write errors for -O FILE too Signed-off-by: Denys Vlasenko --- networking/wget.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/networking/wget.c b/networking/wget.c index 6c9a51211..ad2bfa4b5 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -941,5 +941,8 @@ int wget_main(int argc UNUSED_PARAM, char **argv) while (*argv) exitcode |= download_one_url(*argv++); + if (G.output_fd >= 0) + xclose(G.output_fd); + return exitcode; } -- cgit v1.2.3-55-g6feb From 4fdb67cc65e93967448bb28e4cb810ad5648bfea Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 15 Feb 2011 18:35:54 +0100 Subject: echo: fix SEGV when run with no args Signed-off-by: Denys Vlasenko --- coreutils/echo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coreutils/echo.c b/coreutils/echo.c index 42c3f9ed8..72e18c161 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -97,7 +97,7 @@ int echo_main(int argc UNUSED_PARAM, char **argv) buflen += strlen(arg) + 1; pp++; } - out = buffer = xmalloc(buflen); + out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */ while ((arg = *argv) != NULL) { int c; -- cgit v1.2.3-55-g6feb From 582716733895946b2729acdf18a32532567b973a Mon Sep 17 00:00:00 2001 From: Vladislav Grishenko Date: Wed, 16 Feb 2011 13:31:30 +0100 Subject: udhcpd: optional IP selection based on MAC hash function old new delta find_free_or_expired_nip 153 225 +72 Signed-off-by: Vladislav Grishenko Signed-off-by: Denys Vlasenko --- networking/udhcp/Config.src | 18 ++++++++++++++++-- networking/udhcp/leases.c | 40 ++++++++++++++++++++++++++++++++++------ 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index dcd493f13..750a53a32 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -39,7 +39,21 @@ config FEATURE_UDHCPD_WRITE_LEASES_EARLY If selected, udhcpd will write a new file with leases every time a new lease has been accepted, thus eliminating the need to send SIGUSR1 for the initial writing or updating. Any timed - rewriting remains undisturbed + rewriting remains undisturbed. + +config FEATURE_UDHCPD_BASE_IP_ON_MAC + bool "Select IP address based on client MAC" + default n + depends on UDHCPD + help + If selected, udhcpd will base its selection of IP address to offer + on the client's hardware address. Otherwise udhcpd uses the next + consecutive free address. + + This reduces the frequency of IP address changes for clients + which let their lease expire, and makes consecutive DHCPOFFERS + for the same client to (almost always) contain the same + IP address. config DHCPD_LEASES_FILE string "Absolute path to lease file" @@ -72,7 +86,7 @@ config FEATURE_UDHCPC_ARPING config FEATURE_UDHCP_PORT bool "Enable '-P port' option for udhcpd and udhcpc" - default y + default n depends on UDHCPD || UDHCPC help At the cost of ~300 bytes, enables -P port option. diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c index 7aeb37bae..c5b60b108 100644 --- a/networking/udhcp/leases.c +++ b/networking/udhcp/leases.c @@ -137,21 +137,42 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) uint32_t addr; struct dyn_lease *oldest_lease = NULL; - addr = server_config.start_ip; /* addr is in host order here */ - for (; addr <= server_config.end_ip; addr++) { +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + uint32_t stop; + unsigned i, hash; + + /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good + * dispersal even with similarly-valued "strings". + */ + hash = 0; + for (i = 0; i < 6; i++) + hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; + + /* pick a seed based on hwaddr then iterate until we find a free address. */ + addr = server_config.start_ip + + (hash % (1 + server_config.end_ip - server_config.start_ip)); + stop = addr; +#else + addr = server_config.start_ip; +#define stop (server_config.end_ip + 1) +#endif + do { uint32_t nip; struct dyn_lease *lease; /* ie, 192.168.55.0 */ if ((addr & 0xff) == 0) - continue; + goto next_addr; /* ie, 192.168.55.255 */ if ((addr & 0xff) == 0xff) - continue; + goto next_addr; nip = htonl(addr); + /* skip our own address */ + if (nip == server_config.server_nip) + goto next_addr; /* is this a static lease addr? */ if (is_nip_reserved(server_config.static_leases, nip)) - continue; + goto next_addr; lease = find_lease_by_nip(nip); if (!lease) { @@ -162,7 +183,14 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) if (!oldest_lease || lease->expires < oldest_lease->expires) oldest_lease = lease; } - } + + next_addr: + addr++; +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + if (addr > server_config.end_ip) + addr = server_config.start_ip; +#endif + } while (addr != stop); if (oldest_lease && is_expired_lease(oldest_lease) -- cgit v1.2.3-55-g6feb From 5369563bf9b9b5406714a65f9199aaa0b6b53fef Mon Sep 17 00:00:00 2001 From: Pere Orga Date: Wed, 16 Feb 2011 20:09:36 +0100 Subject: wget: reduce bloat Signed-off-by: Pere Orga Signed-off-by: Denys Vlasenko --- networking/wget.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/networking/wget.c b/networking/wget.c index ad2bfa4b5..9d50437d8 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -556,7 +556,7 @@ static void NOINLINE retrieve_file_data(FILE *dfp) progress_meter(PROGRESS_END); } -static int download_one_url(const char *url) +static void download_one_url(const char *url) { bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; @@ -853,8 +853,6 @@ However, in real world it was observed that some web servers free(server.allocated); free(target.allocated); free(fname_out_alloc); - - return EXIT_SUCCESS; } int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -885,7 +883,6 @@ int wget_main(int argc UNUSED_PARAM, char **argv) ; #endif - int exitcode; #if ENABLE_FEATURE_WGET_LONG_OPTIONS llist_t *headers_llist = NULL; #endif @@ -937,12 +934,11 @@ int wget_main(int argc UNUSED_PARAM, char **argv) G.o_flags = O_WRONLY | O_CREAT | O_TRUNC; } - exitcode = 0; while (*argv) - exitcode |= download_one_url(*argv++); + download_one_url(*argv++); if (G.output_fd >= 0) xclose(G.output_fd); - return exitcode; + return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From f303bdd918e762f492068f3127b2f7fdac94bd28 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sun, 20 Feb 2011 04:15:43 +0100 Subject: blockdev: add --getsz to replace --getsize function old new delta blockdev_main 255 273 +18 bdcommands 160 176 +16 packed_usage 28142 28107 -35 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 34/-35) Total: -1 bytes Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- util-linux/blockdev.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/util-linux/blockdev.c b/util-linux/blockdev.c index c2fcaee88..4aed02982 100644 --- a/util-linux/blockdev.c +++ b/util-linux/blockdev.c @@ -26,7 +26,8 @@ //usage: "\n --getss Get sector size" //usage: "\n --getbsz Get block size" //usage: "\n --setbsz BYTES Set block size" -//usage: "\n --getsize Get device size in 512-byte sectors" +//usage: "\n --getsz Get device size in 512-byte sectors" +/*//usage: "\n --getsize Get device size in sectors (deprecated)"*/ //usage: "\n --getsize64 Get device size in bytes" //usage: "\n --flushbufs Flush buffers" //usage: "\n --rereadpt Reread partition table" @@ -45,6 +46,7 @@ enum { FL_USRARG = 4, /* argument is provided by user */ FL_NORESULT = 8, + FL_SCALE512 = 16, }; struct bdc { @@ -85,6 +87,11 @@ static const struct bdc bdcommands[] = { .name = "setbsz", .flags = ARG_INT + FL_NORESULT + FL_USRARG, .argval = 0, + },{ + .ioc = BLKGETSIZE64, + .name = "getsz", + .flags = ARG_U64 + FL_SCALE512, + .argval = -1, },{ .ioc = BLKGETSIZE, .name = "getsize", @@ -123,7 +130,7 @@ static const struct bdc *find_cmd(const char *s) } int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int blockdev_main(int argc, char **argv) +int blockdev_main(int argc UNUSED_PARAM, char **argv) { const struct bdc *bdcmd; int fd; @@ -134,18 +141,20 @@ int blockdev_main(int argc, char **argv) uint64_t u64; } ioctl_val_on_stack; - if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */ + argv++; + if (!argv[0] || !argv[1]) /* must have at least 2 args */ bb_show_usage(); - bdcmd = find_cmd(*++argv); + bdcmd = find_cmd(*argv); u64 = (int)bdcmd->argval; if (bdcmd->flags & FL_USRARG) u64 = xatoi_positive(*++argv); - if (!*++argv || argv[1]) + argv++; + if (!argv[0] || argv[1]) bb_show_usage(); - fd = xopen(*argv, O_RDONLY); + fd = xopen(argv[0], O_RDONLY); ioctl_val_on_stack.u64 = u64; #if BB_BIG_ENDIAN @@ -173,6 +182,9 @@ int blockdev_main(int argc, char **argv) /* Fetch it into register(s) */ u64 = ioctl_val_on_stack.u64; + if (bdcmd->flags & FL_SCALE512) + u64 >>= 9; + /* Zero- or one-extend the value if needed, then print */ switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) { case ARG_INT: -- cgit v1.2.3-55-g6feb From 55988aed472d9cd362f9a50f4999b5e47ca33abe Mon Sep 17 00:00:00 2001 From: Bernd Jendrissek Date: Sun, 20 Feb 2011 05:50:04 +0100 Subject: fix "make install" Signed-off-by: Bernd Jendrissek Signed-off-by: Denys Vlasenko --- applets/busybox.mkll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applets/busybox.mkll b/applets/busybox.mkll index 6d61f7e82..68dbf2162 100755 --- a/applets/busybox.mkll +++ b/applets/busybox.mkll @@ -14,7 +14,7 @@ CONFIG_H=${1:-include/autoconf.h} APPLETS_H=${2:-include/applets.h} $HOSTCC -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H | awk '/^[ \t]*LINK/{ - dir=substr($2,8) + dir=substr($2,7) gsub("_","/",dir) if(dir=="/ROOT") dir="" file=$3 -- cgit v1.2.3-55-g6feb From b12553faa8991e11c11f70a81f1d9d44078c7645 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Feb 2011 03:22:20 +0100 Subject: ash: fix ash-signals/signal8 testcase failure function old new delta killcmd 109 224 +115 kill_main 882 910 +28 changepath 194 195 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 144/0) Total: 144 bytes Signed-off-by: Denys Vlasenko --- procps/kill.c | 25 ++++++++++++-- shell/ash.c | 58 +++++++++++++++++++++++++------- shell/ash_test/ash-signals/sigint1.right | 1 + shell/ash_test/ash-signals/sigint1.tests | 41 ++++++++++++++++++++++ shell/hush_test/hush-misc/sigint1.right | 1 + shell/hush_test/hush-misc/sigint1.tests | 41 ++++++++++++++++++++++ 6 files changed, 152 insertions(+), 15 deletions(-) create mode 100644 shell/ash_test/ash-signals/sigint1.right create mode 100755 shell/ash_test/ash-signals/sigint1.tests create mode 100644 shell/hush_test/hush-misc/sigint1.right create mode 100755 shell/hush_test/hush-misc/sigint1.tests diff --git a/procps/kill.c b/procps/kill.c index b51d44a70..39538016e 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -206,9 +206,27 @@ int kill_main(int argc, char **argv) /* Looks like they want to do a kill. Do that */ while (arg) { - /* Support shell 'space' trick */ - if (arg[0] == ' ') - arg++; +#if ENABLE_ASH || ENABLE_HUSH + /* + * We need to support shell's "hack formats" of + * " -PRGP_ID" (yes, with a leading space) + * and " PID1 PID2 PID3" (with degenerate case "") + */ + while (*arg != '\0') { + char *end; + if (*arg == ' ') + arg++; + pid = bb_strtoi(arg, &end, 10); + if (errno && (errno != EINVAL || *end != ' ')) { + bb_error_msg("invalid number '%s'", arg); + errors++; + } else if (kill(pid, signo) != 0) { + bb_perror_msg("can't kill pid %d", (int)pid); + errors++; + } + arg = end; /* can only point to ' ' or '\0' now */ + } +#else pid = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); @@ -217,6 +235,7 @@ int kill_main(int argc, char **argv) bb_perror_msg("can't kill pid %d", (int)pid); errors++; } +#endif arg = *++argv; } return errors; diff --git a/shell/ash.c b/shell/ash.c index cccd6dd79..98d2c7c29 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -3783,18 +3783,51 @@ setjobctl(int on) static int FAST_FUNC killcmd(int argc, char **argv) { - int i = 1; if (argv[1] && strcmp(argv[1], "-l") != 0) { + int i = 1; do { if (argv[i][0] == '%') { - struct job *jp = getjob(argv[i], 0); - unsigned pid = jp->ps[0].ps_pid; - /* Enough space for ' -NNN' */ - argv[i] = alloca(sizeof(int)*3 + 3); - /* kill_main has matching code to expect - * leading space. Needed to not confuse - * negative pids with "kill -SIGNAL_NO" syntax */ - sprintf(argv[i], " -%u", pid); + /* + * "kill %N" - job kill + * Converting to pgrp / pid kill + */ + struct job *jp; + char *dst; + int j, n; + + jp = getjob(argv[i], 0); + /* + * In jobs started under job control, we signal + * entire process group by kill -PGRP_ID. + * This happens, f.e., in interactive shell. + * + * Otherwise, we signal each child via + * kill PID1 PID2 PID3. + * Testcases: + * sh -c 'sleep 1|sleep 1 & kill %1' + * sh -c 'true|sleep 2 & sleep 1; kill %1' + * sh -c 'true|sleep 1 & sleep 2; kill %1' + */ + n = jp->nprocs; /* can't be 0 (I hope) */ + if (jp->jobctl) + n = 1; + dst = alloca(n * sizeof(int)*4); + argv[i] = dst; + for (j = 0; j < n; j++) { + struct procstat *ps = &jp->ps[j]; + /* Skip non-running and not-stopped members + * (i.e. dead members) of the job + */ + if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) + continue; + /* + * kill_main has matching code to expect + * leading space. Needed to not confuse + * negative pids with "kill -SIGNAL_NO" syntax + */ + dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); + } + *dst = '\0'; } } while (argv[++i]); } @@ -4227,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) break; job = job->prev_job; } - } else + } else { job = getjob(*argv, 0); + } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) blocking_wait_with_raise_on_sig(); @@ -4724,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode) #if JOBS /* do job control only in root shell */ doing_jobctl = 0; - if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { + if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { pid_t pgrp; if (jp->nprocs == 0) @@ -4750,7 +4784,7 @@ forkchild(struct job *jp, union node *n, int mode) ash_msg_and_raise_error("can't open '%s'", bb_dev_null); } } - if (!oldlvl) { + if (oldlvl == 0) { if (iflag) { /* why if iflag only? */ setsignal(SIGINT); setsignal(SIGTERM); diff --git a/shell/ash_test/ash-signals/sigint1.right b/shell/ash_test/ash-signals/sigint1.right new file mode 100644 index 000000000..a9094b056 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests new file mode 100755 index 000000000..20e45d940 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (This is truly necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# we don't send SIGINT _to_ the_ child_...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed diff --git a/shell/hush_test/hush-misc/sigint1.right b/shell/hush_test/hush-misc/sigint1.right new file mode 100644 index 000000000..a9094b056 --- /dev/null +++ b/shell/hush_test/hush-misc/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/shell/hush_test/hush-misc/sigint1.tests b/shell/hush_test/hush-misc/sigint1.tests new file mode 100755 index 000000000..20e45d940 --- /dev/null +++ b/shell/hush_test/hush-misc/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (This is truly necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# we don't send SIGINT _to_ the_ child_...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed -- cgit v1.2.3-55-g6feb From bac0a25f72cdf59f34638aa3fd95bb14b103c286 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Feb 2011 03:47:50 +0100 Subject: slightly better wording in comments Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-signals/sigint1.tests | 4 ++-- shell/hush_test/hush-misc/sigint1.tests | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests index 20e45d940..3d483d32a 100755 --- a/shell/ash_test/ash-signals/sigint1.tests +++ b/shell/ash_test/ash-signals/sigint1.tests @@ -3,9 +3,9 @@ (sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & # We create a child which exits with 0 even on SIGINT -# (This is truly necessary only if SIGINT is generated by ^C, +# (The complex command is necessary only if SIGINT is generated by ^C, # in this testcase even bare "sleep 2" would do because -# we don't send SIGINT _to_ the_ child_...) +# in the testcase we don't send SIGINT *to the child*...) $THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' # In one second, we (main shell) get SIGINT here. diff --git a/shell/hush_test/hush-misc/sigint1.tests b/shell/hush_test/hush-misc/sigint1.tests index 20e45d940..3d483d32a 100755 --- a/shell/hush_test/hush-misc/sigint1.tests +++ b/shell/hush_test/hush-misc/sigint1.tests @@ -3,9 +3,9 @@ (sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & # We create a child which exits with 0 even on SIGINT -# (This is truly necessary only if SIGINT is generated by ^C, +# (The complex command is necessary only if SIGINT is generated by ^C, # in this testcase even bare "sleep 2" would do because -# we don't send SIGINT _to_ the_ child_...) +# in the testcase we don't send SIGINT *to the child*...) $THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' # In one second, we (main shell) get SIGINT here. -- cgit v1.2.3-55-g6feb From 3bb235c3b50ca072e8bcfc20d5030f5460439c07 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 23 Feb 2011 01:20:44 +0100 Subject: iproute: fix parsing and matching of of "short" IP addrs like 10/8 function old new delta print_route 1613 1813 +200 get_addr_1 209 258 +49 get_prefix 393 356 -37 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 249/-37) Total: 212 bytes Signed-off-by: Denys Vlasenko --- networking/libiproute/iproute.c | 18 +++++++- networking/libiproute/libnetlink.c | 2 +- networking/libiproute/utils.c | 86 ++++++++++++++++++++++++-------------- networking/libiproute/utils.h | 6 +-- 4 files changed, 74 insertions(+), 38 deletions(-) diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index 393a376ac..f8a67d9ee 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -82,7 +82,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, { struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; @@ -159,8 +159,21 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, } memset(tb, 0, sizeof(tb)); + memset(&src, 0, sizeof(src)); + memset(&dst, 0, sizeof(dst)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + if (tb[RTA_SRC]) { + src.bitlen = r->rtm_src_len; + src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen); + } + if (tb[RTA_DST]) { + dst.bitlen = r->rtm_dst_len; + dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen); + } + if (G_filter.rdst.family && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen) ) { @@ -426,7 +439,8 @@ IF_FEATURE_IP_RULE(ARG_table,) NEXT_ARG(); } if ((**argv < '0' || **argv > '9') - && rtnl_rtntype_a2n(&type, *argv) == 0) { + && rtnl_rtntype_a2n(&type, *argv) == 0 + ) { NEXT_ARG(); req.r.rtm_type = type; ok |= type_ok; diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index 547013ff6..c7533a4a7 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -393,7 +393,7 @@ void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, in if (rta->rta_type <= max) { tb[rta->rta_type] = rta; } - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) { bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index d32db8de5..d0fe30605 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c @@ -83,20 +83,43 @@ int get_addr_1(inet_prefix *addr, char *name, int family) return 0; } - addr->family = AF_INET; if (family != AF_UNSPEC && family != AF_INET) return -1; + + /* Try to parse it as IPv4 */ + addr->family = AF_INET; +#if 0 /* Doesn't handle e.g. "10.10", for example, "ip r l root 10.10/16" */ if (inet_pton(AF_INET, name, addr->data) <= 0) return -1; +#else + { + unsigned i = 0; + unsigned n = 0; + const char *cp = name - 1; + while (*++cp) { + if ((unsigned char)(*cp - '0') <= 9) { + n = 10 * n + (unsigned char)(*cp - '0'); + if (n >= 256) + return -1; + ((uint8_t*)addr->data)[i] = n; + continue; + } + if (*cp == '.' && ++i <= 3) { + n = 0; + continue; + } + return -1; + } + } +#endif addr->bytelen = 4; addr->bitlen = -1; + return 0; } -static int get_prefix_1(inet_prefix *dst, char *arg, int family) +static void get_prefix_1(inet_prefix *dst, char *arg, int family) { - int err; - unsigned plen; char *slash; memset(dst, 0, sizeof(*dst)); @@ -108,48 +131,50 @@ static int get_prefix_1(inet_prefix *dst, char *arg, int family) dst->family = family; /*dst->bytelen = 0; - done by memset */ /*dst->bitlen = 0;*/ - return 0; + return; } slash = strchr(arg, '/'); if (slash) *slash = '\0'; - err = get_addr_1(dst, arg, family); - if (err == 0) { + + if (get_addr_1(dst, arg, family) == 0) { dst->bitlen = (dst->family == AF_INET6) ? 128 : 32; if (slash) { + unsigned plen; inet_prefix netmask_pfx; netmask_pfx.family = AF_UNSPEC; plen = bb_strtou(slash + 1, NULL, 0); if ((errno || plen > dst->bitlen) - && (get_addr_1(&netmask_pfx, slash + 1, family))) - err = -1; - else if (netmask_pfx.family == AF_INET) { + && get_addr_1(&netmask_pfx, slash + 1, family) != 0 + ) { + goto bad; + } + if (netmask_pfx.family == AF_INET) { /* fill in prefix length of dotted quad */ uint32_t mask = ntohl(netmask_pfx.data[0]); uint32_t host = ~mask; /* a valid netmask must be 2^n - 1 */ - if (!(host & (host + 1))) { - for (plen = 0; mask; mask <<= 1) - ++plen; - if (plen <= dst->bitlen) { - dst->bitlen = plen; - /* dst->flags |= PREFIXLEN_SPECIFIED; */ - } else - err = -1; - } else - err = -1; - } else { - /* plain prefix */ - dst->bitlen = plen; + if (host & (host + 1)) + goto bad; + + for (plen = 0; mask; mask <<= 1) + ++plen; + if (plen > dst->bitlen) + goto bad; + /* dst->flags |= PREFIXLEN_SPECIFIED; */ } + dst->bitlen = plen; } } + if (slash) *slash = '/'; - return err; + return; + bad: + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); } int get_addr(inet_prefix *dst, char *arg, int family) @@ -163,15 +188,12 @@ int get_addr(inet_prefix *dst, char *arg, int family) return 0; } -int get_prefix(inet_prefix *dst, char *arg, int family) +void get_prefix(inet_prefix *dst, char *arg, int family) { if (family == AF_PACKET) { bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix"); } - if (get_prefix_1(dst, arg, family)) { - bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); - } - return 0; + get_prefix_1(dst, arg, family); } uint32_t get_addr32(char *name) @@ -204,10 +226,10 @@ void duparg2(const char *key, const char *arg) bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); } -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) { - uint32_t *a1 = a->data; - uint32_t *a2 = b->data; + const uint32_t *a1 = a->data; + const uint32_t *a2 = b->data; int words = bits >> 5; bits &= 0x1f; diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h index 93c9d25d6..5fb4a862c 100644 --- a/networking/libiproute/utils.h +++ b/networking/libiproute/utils.h @@ -58,9 +58,9 @@ struct ipx_addr { extern uint32_t get_addr32(char *name); extern int get_addr_1(inet_prefix *dst, char *arg, int family); -/*extern int get_prefix_1(inet_prefix *dst, char *arg, int family);*/ +/*extern void get_prefix_1(inet_prefix *dst, char *arg, int family);*/ extern int get_addr(inet_prefix *dst, char *arg, int family); -extern int get_prefix(inet_prefix *dst, char *arg, int family); +extern void get_prefix(inet_prefix *dst, char *arg, int family); extern unsigned get_unsigned(char *arg, const char *errmsg); extern uint32_t get_u32(char *arg, const char *errmsg); @@ -77,7 +77,7 @@ extern const char *format_host(int af, int len, void *addr, char *buf, int bufle void invarg(const char *, const char *) NORETURN; void duparg(const char *, const char *) NORETURN; void duparg2(const char *, const char *) NORETURN; -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits); const char *dnet_ntop(int af, const void *addr, char *str, size_t len); int dnet_pton(int af, const char *src, void *addr); -- cgit v1.2.3-55-g6feb From 945fd173e9888185d68fecfb060fdfff98900ac4 Mon Sep 17 00:00:00 2001 From: Roman Borisov Date: Fri, 25 Feb 2011 14:50:39 +0300 Subject: mount: fix wrong long option namess Fixed the --make-shared, --make-rshared, ... etc. (--make-*) options in the mount command. Now parse_mount_options() may reasonably process such options. Fixed: http://lists.busybox.net/pipermail/busybox/2011-January/074511.html Signed-off-by: Roman Borisov Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index 0f213bb30..bc5285052 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -241,14 +241,14 @@ static const char mount_option_str[] = "union\0" "bind\0" "move\0" - "shared\0" - "slave\0" - "private\0" - "unbindable\0" - "rshared\0" - "rslave\0" - "rprivate\0" - "runbindable\0" + "make-shared\0" + "make-slave\0" + "make-private\0" + "make-unbindable\0" + "make-rshared\0" + "make-rslave\0" + "make-rprivate\0" + "make-runbindable\0" ) // Always understood. -- cgit v1.2.3-55-g6feb From 301fe50ca2576291a427de46ca6ed64d4949713e Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 21 Feb 2011 17:52:13 +0100 Subject: mount: ignore unknown mount options when remounting NFS mounts Don't fail on unknown nfs mount options. The kernel automatically adds a few mount options that we don't currently handle, like: sec=null|sys|krb5.. mountaddr= mountproto=tcp|udp local_lock=none|all|flock|posix Which causes a simple mount -o remount,rw to fail. Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/util-linux/mount.c b/util-linux/mount.c index bc5285052..0baa74c7c 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1129,6 +1129,9 @@ static NOINLINE int nfsmount(struct mntent *mp, long vfsflags, char *filteropts) continue; case 20: // "addr" - ignore continue; + case -1: // unknown + if (vfsflags & MS_REMOUNT) + continue; } val = xatoi_positive(opteq); -- cgit v1.2.3-55-g6feb From da4441c44f6efccb6f7b7588404d9c6bfb7b6af8 Mon Sep 17 00:00:00 2001 From: Stefan Seyfried Date: Mon, 21 Feb 2011 17:29:59 +0100 Subject: fix libiproute compile with kernel headers < 2.6.17 Signed-off-by: Stefan Seyfried Signed-off-by: Denys Vlasenko --- networking/libiproute/ipaddress.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 397a8ee34..b3748e8c5 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -162,6 +162,8 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } #endif +/* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */ +#ifdef IFF_DORMANT if (tb[IFLA_OPERSTATE]) { static const char operstate_labels[] ALIGN1 = "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0" @@ -169,6 +171,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("state %s ", nth_string(operstate_labels, *(uint8_t *)RTA_DATA(tb[IFLA_OPERSTATE]))); } +#endif if (G_filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); -- cgit v1.2.3-55-g6feb