From 020abc8856f94d6e355f4daa972ac75fb05ae113 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 14 Jan 2020 17:05:48 +0100 Subject: udhcpd: mangle hostnames starting with dash ("-option") function old new delta add_lease 316 328 +12 Signed-off-by: Denys Vlasenko --- networking/udhcp/dhcpd.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 3e08ec011..9d6604943 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -192,6 +192,8 @@ static struct dyn_lease *add_lease( * but merely make dumpleases output safe for shells to use. * We accept "0-9A-Za-z._-", all other chars turn to dots. */ + if (*p == '-') + *p = '.'; /* defeat "-option" attacks too */ while (*p) { if (!isalnum(*p) && *p != '-' && *p != '_') *p = '.'; -- cgit v1.2.3-55-g6feb From eb7f9acda147543079f261753a11d2afa340fc5e Mon Sep 17 00:00:00 2001 From: Peter Korsgaard Date: Mon, 27 Jan 2020 15:36:41 +0100 Subject: syslogd: add config option to include milliseconds in timestamps For some use cases, having logs with more than 1 second accuracy can be helpful. Add an option to include milliseconds when adding a timestamp in HH:MM:SS.mmm format, similar to syslog-ng with fraq_digits(3) or journalctl -o short-precise. For simplicity, abuse the remaining space in the buffer used by ctime to add the millieconds (overwriting year). function old new delta timestamp_and_log 401 448 +47 Signed-off-by: Peter Korsgaard Signed-off-by: Denys Vlasenko --- sysklogd/syslogd.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 0e226124a..ab50f4a28 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -64,6 +64,14 @@ //config: help //config: Supports restricted syslogd config. See docs/syslog.conf.txt //config: +//config:config FEATURE_SYSLOGD_PRECISE_TIMESTAMPS +//config: bool "Include milliseconds in timestamps" +//config: default n +//config: depends on SYSLOGD +//config: help +//config: Includes milliseconds (HH:MM:SS.mmm) in timestamp when +//config: timestamps are added. +//config: //config:config FEATURE_SYSLOGD_READ_BUFFER_SIZE //config: int "Read buffer size in bytes" //config: default 256 @@ -276,7 +284,7 @@ struct globals { /* ...then copy to parsebuf, escaping control chars */ /* (can grow x2 max) */ char parsebuf[MAX_READ*2]; - /* ...then sprintf into printbuf, adding timestamp (15 chars), + /* ...then sprintf into printbuf, adding timestamp (15 or 19 chars), * host (64), fac.prio (20) to the message */ /* (growth by: 15 + 64 + 20 + delims = ~110) */ char printbuf[MAX_READ*2 + 128]; @@ -832,12 +840,24 @@ static void timestamp_and_log(int pri, char *msg, int len) msg += 16; } +#if ENABLE_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS + if (!timestamp) { + struct timeval tv; + gettimeofday(&tv, NULL); + now = tv.tv_sec; + timestamp = ctime(&now) + 4; /* skip day of week */ + /* overwrite year by milliseconds, zero terminate */ + sprintf(timestamp + 15, ".%03u", (unsigned)tv.tv_usec / 1000u); + } else { + timestamp[15] = '\0'; + } +#else if (!timestamp) { time(&now); timestamp = ctime(&now) + 4; /* skip day of week */ } - timestamp[15] = '\0'; +#endif if (option_mask32 & OPT_kmsg) { log_to_kmsg(pri, msg); -- cgit v1.2.3-55-g6feb From b0c711e64f868fcab0711d8d0f86aaaa4ed93158 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 23 Jan 2020 11:26:08 +0000 Subject: ash: improve expandstr() The dash maintainer recently posted a fix for issues with expanding PS1. These had already been fixed differently in BusyBox ash. Borrow a couple of improvements: - Use a single call to setjmp() to trap errors in both readtoken1() and expandarg(). - In case of error set the prompt to the literal value of PS1 rather than the half-digested nonsense in stackblock() which might include ugly control characters. function old new delta expandstr 353 300 -53 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 4b5eafa7c..d6040f47e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13098,29 +13098,27 @@ expandstr(const char *ps, int syntax_type) volatile int saveint; struct jmploc *volatile savehandler = exception_handler; struct jmploc jmploc; + const char *volatile result; + int err; /* XXX Fix (char *) cast. */ setinputstring((char *)ps); saveprompt = doprompt; doprompt = 0; + result = ps; + + SAVE_INT(saveint); + err = setjmp(jmploc.loc); + if (err) + goto out; /* readtoken1() might die horribly. * Try a prompt with syntactically wrong command: * PS1='$(date "+%H:%M:%S) > ' */ - SAVE_INT(saveint); - if (setjmp(jmploc.loc) == 0) { - exception_handler = &jmploc; - readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); - } - exception_handler = savehandler; - RESTORE_INT(saveint); - - doprompt = saveprompt; - - /* Try: PS1='`xxx(`' */ - unwindfiles(file_stop); + exception_handler = &jmploc; + readtoken1(pgetc(), syntax_type, FAKEEOFMARK, 0); n.narg.type = NARG; n.narg.next = NULL; @@ -13130,17 +13128,20 @@ expandstr(const char *ps, int syntax_type) /* expandarg() might fail too: * PS1='$((123+))' */ - SAVE_INT(saveint); - if (setjmp(jmploc.loc) == 0) { - exception_handler = &jmploc; - expandarg(&n, NULL, EXP_QUOTED); - } else if (exception_type == EXEXIT) { - exitshell(); - } + expandarg(&n, NULL, EXP_QUOTED); + result = stackblock(); + +out: exception_handler = savehandler; + if (err && exception_type != EXERROR) + longjmp(exception_handler->loc, 1); RESTORE_INT(saveint); - return stackblock(); + doprompt = saveprompt; + /* Try: PS1='`xxx(`' */ + unwindfiles(file_stop); + + return result; } static inline int -- cgit v1.2.3-55-g6feb From 16bcd504a32e6a7bf2015ffb241133f9ead6100b Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Thu, 23 Jan 2020 15:31:19 +0000 Subject: vi: fixes to string search in colon commands, closes 10321 Handling of string searches in colon commands (e.g ':/pat1/,/pat2/cmd') differ from standard vi: - As reported in bug 10321 such searches can't be repeated using the 'n' command. This is because the last search pattern isn't updated. - The search also can't be repeated using the command '://' because an empty search pattern doesn't imply the use of the last search pattern. - Such searches should start on the line after the current line, otherwise '://' never moves to the next occurrence of the pattern. This can also affect other cases where line ranges are specified using search patterns. Fix these various issues. function old new delta get_one_address 325 342 +17 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- editors/vi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 51dfc1209..1dd0b6fb6 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2251,7 +2251,6 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present int st; char *q; IF_FEATURE_VI_YANKMARK(char c;) - IF_FEATURE_VI_SEARCH(char *pat;) *addr = -1; // assume no addr if (*p == '.') { // the current line @@ -2276,16 +2275,20 @@ static char *get_one_address(char *p, int *addr) // get colon addr, if present #endif #if ENABLE_FEATURE_VI_SEARCH else if (*p == '/') { // a search pattern - q = strchrnul(++p, '/'); - pat = xstrndup(p, q - p); // save copy of pattern + q = strchrnul(p + 1, '/'); + if (p + 1 != q) { + // save copy of new pattern + free(last_search_pattern); + last_search_pattern = xstrndup(p, q - p); + } p = q; if (*p == '/') p++; - q = char_search(dot, pat, (FORWARD << 1) | FULL); + q = char_search(next_line(dot), last_search_pattern + 1, + (FORWARD << 1) | FULL); if (q != NULL) { *addr = count_lines(text, q); } - free(pat); } #endif else if (*p == '$') { // the last line in file -- cgit v1.2.3-55-g6feb From 1ff7002b1d229c678fdffebec602fb4c54439a31 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 24 Jan 2020 13:16:45 +0000 Subject: xargs: fix handling of quoted arguments, closes 11441 As reported in bug 11441 when presented with a large number of quoted arguments xargs can return 'argument line too long': seq 10000 29999 | sed -e 's/^/"/' -e 's/$/"/' | busybox xargs echo This happens because the variant of process_stdin() which handles quoted arguments doesn't preserve state between calls. If the allowed number of characters is exceeded part way through a quoted argument the next call to process_stdin() incorrectly treats the terminating quote as a starting quote, thus quoting all of the argument separators. function old new delta process_stdin 274 303 +29 xargs_main 731 745 +14 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 43/0) Total: 43 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- findutils/xargs.c | 27 ++++++++++++++++++--------- testsuite/xargs.tests | 9 +++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/findutils/xargs.c b/findutils/xargs.c index 726315803..4fb306bb8 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -114,17 +114,28 @@ struct globals { int max_procs; #endif smalluint xargs_exitcode; +#if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES +#define NORM 0 +#define QUOTE 1 +#define BACKSLASH 2 +#define SPACE 4 + smalluint process_stdin__state; + char process_stdin__q; +#endif } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) #define INIT_G() do { \ setup_common_bufsiz(); \ - G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ + IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ + IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ + /* Even zero values are set because we are NOEXEC applet */ \ + G.eof_str = NULL; \ G.idx = 0; \ IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.running_procs = 0;) \ IF_FEATURE_XARGS_SUPPORT_PARALLEL(G.max_procs = 1;) \ G.xargs_exitcode = 0; \ - IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.repl_str = "{}";) \ - IF_FEATURE_XARGS_SUPPORT_REPL_STR(G.eol_ch = '\n';) \ + IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__state = NORM;) \ + IF_FEATURE_XARGS_SUPPORT_QUOTES(G.process_stdin__q = '\0';) \ } while (0) @@ -257,12 +268,8 @@ static void store_param(char *s) #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) { -#define NORM 0 -#define QUOTE 1 -#define BACKSLASH 2 -#define SPACE 4 - char q = '\0'; /* quote char */ - char state = NORM; +#define q G.process_stdin__q +#define state G.process_stdin__state char *s = buf; /* start of the word */ char *p = s + strlen(buf); /* end of the word */ @@ -339,6 +346,8 @@ static char* FAST_FUNC process_stdin(int n_max_chars, int n_max_arg, char *buf) /* store_param(NULL) - caller will do it */ dbg_msg("return:'%s'", s); return s; +#undef q +#undef state } #else /* The variant does not support single quotes, double quotes or backslash */ diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests index 2d0a201b7..855b33bc2 100755 --- a/testsuite/xargs.tests +++ b/testsuite/xargs.tests @@ -41,4 +41,13 @@ testing "xargs -sNUM test 2" \ "echo 1 2 3 4 5 6 7 8 9 0\n""echo 1 2 3 4 5 6 7 8 9\n""echo 1 00\n" \ "" "2 3 4 5 6 7 8 9 0 2 3 4 5 6 7 8 9 00\n" +# see that we don't get "argument line too long", +# but do see the last word, 99999, instead +optional FEATURE_XARGS_SUPPORT_QUOTES +testing "xargs argument line too long" \ + "seq 10000 99999 | sed -e 's/^/\"/' -e 's/$/\"/' | xargs echo | grep -o 99999; echo \$?" \ + "99999\n0\n" \ + "" "" +SKIP= + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 9e2a5668fd38db169d9d91b13089a99df4c9bd37 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Tue, 21 Jan 2020 16:01:58 +0000 Subject: ash,hush: allow builtins to be tab-completed, closes 7532 function old new delta complete_cmd_dir_file 678 830 +152 get_builtin_name - 35 +35 optschanged 125 132 +7 hush_main 1069 1076 +7 save_command_ps_at_cur_history 76 78 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 4/0 up/down: 203/0) Total: 203 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- include/libbb.h | 13 +++++++++++++ libbb/lineedit.c | 17 ++++++++++++++--- shell/ash.c | 19 ++++++++++++++++++- shell/hush.c | 17 +++++++++++++++++ 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 05a560977..392c0443d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1818,10 +1818,19 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # else # define MAX_HISTORY 0 # endif +typedef const char *get_exe_name_t(int i) FAST_FUNC; typedef struct line_input_t { int flags; int timeout; const char *path_lookup; +# if ENABLE_FEATURE_TAB_COMPLETION \ +&& (ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH \ +|| ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH \ +) + /* function to fetch additional application-specific names to match */ + get_exe_name_t *get_exe_name; +# define EDITING_HAS_get_exe_name 1 +# endif # if MAX_HISTORY int cnt_history; int cur_history; @@ -1868,6 +1877,10 @@ int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; read_line_input(prompt, command, maxsize) #endif +#ifndef EDITING_HAS_get_exe_name +# define EDITING_HAS_get_exe_name 0 +#endif + #ifndef COMM_LEN # ifdef TASK_COMM_LEN diff --git a/libbb/lineedit.c b/libbb/lineedit.c index b1ec52b88..de236dea0 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -813,18 +813,29 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) } pf_len = strlen(pfind); -# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 if (type == FIND_EXE_ONLY && !dirbuf) { +# if ENABLE_FEATURE_SH_STANDALONE && NUM_APPLETS != 1 const char *p = applet_names; - while (*p) { if (strncmp(pfind, p, pf_len) == 0) add_match(xstrdup(p)); while (*p++ != '\0') continue; } - } # endif +# if EDITING_HAS_get_exe_name + if (state->get_exe_name) { + i = 0; + for (;;) { + const char *b = state->get_exe_name(i++); + if (!b) + break; + if (strncmp(pfind, b, pf_len) == 0) + add_match(xstrdup(b)); + } + } +# endif + } for (i = 0; i < npaths; i++) { DIR *dir; diff --git a/shell/ash.c b/shell/ash.c index d6040f47e..fb4028219 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -9523,6 +9523,11 @@ evalpipe(union node *n, int flags) return status; } +/* setinteractive needs this forward reference */ +#if EDITING_HAS_get_exe_name +static const char *get_builtin_name(int i) FAST_FUNC; +#endif + /* * Controls whether the shell is interactive or not. */ @@ -9554,8 +9559,12 @@ setinteractive(int on) } #endif #if ENABLE_FEATURE_EDITING - if (!line_input_state) + if (!line_input_state) { line_input_state = new_line_input_t(FOR_SHELL | WITH_PATH_LOOKUP); +# if EDITING_HAS_get_exe_name + line_input_state->get_exe_name = get_builtin_name; +# endif + } #endif } } @@ -10023,6 +10032,14 @@ find_builtin(const char *name) return bp; } +#if EDITING_HAS_get_exe_name +static const char * FAST_FUNC +get_builtin_name(int i) +{ + return /*i >= 0 &&*/ i < ARRAY_SIZE(builtintab) ? builtintab[i].name + 1 : NULL; +} +#endif + /* * Execute a simple command. */ diff --git a/shell/hush.c b/shell/hush.c index 97202b953..6e44d4e11 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7889,6 +7889,20 @@ static const struct built_in_command *find_builtin(const char *name) return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); } +#if EDITING_HAS_get_exe_name +static const char * FAST_FUNC get_builtin_name(int i) +{ + if (/*i >= 0 && */ i < ARRAY_SIZE(bltins1)) { + return bltins1[i].b_cmd; + } + i -= ARRAY_SIZE(bltins1); + if (i < ARRAY_SIZE(bltins2)) { + return bltins2[i].b_cmd; + } + return NULL; +} +#endif + static void remove_nested_vars(void) { struct variable *cur; @@ -10268,6 +10282,9 @@ int hush_main(int argc, char **argv) # if ENABLE_FEATURE_EDITING G.line_input_state = new_line_input_t(FOR_SHELL); +# if EDITING_HAS_get_exe_name + G.line_input_state->get_exe_name = get_builtin_name; +# endif # endif # if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0 { -- cgit v1.2.3-55-g6feb From bd8b05ba1b0901bbd6a913dfd5186ac7c8beffed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 2 Feb 2020 23:28:55 +0100 Subject: awk: fix more "length" cases, closes 12486 function old new delta next_token 808 831 +23 Signed-off-by: Denys Vlasenko --- editors/awk.c | 22 ++++++++++++++++++---- testsuite/awk.tests | 23 ++++++++++++++++++++++- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index f19990901..70df2fdb4 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -272,7 +272,8 @@ typedef struct tsplitter_s { /* if previous token class is CONCAT1 and next is CONCAT2, concatenation */ /* operator is inserted between them */ #define TC_CONCAT1 (TC_VARIABLE | TC_ARRTERM | TC_SEQTERM \ - | TC_STRING | TC_NUMBER | TC_UOPPOST) + | TC_STRING | TC_NUMBER | TC_UOPPOST \ + | TC_LENGTH) #define TC_CONCAT2 (TC_OPERAND | TC_UOPPRE) #define OF_RES1 0x010000 @@ -1070,8 +1071,10 @@ static uint32_t next_token(uint32_t expected) const uint32_t *ti; if (t_rollback) { + debug_printf_parse("%s: using rolled-back token\n", __func__); t_rollback = FALSE; } else if (concat_inserted) { + debug_printf_parse("%s: using concat-inserted token\n", __func__); concat_inserted = FALSE; t_tclass = save_tclass; t_info = save_info; @@ -1200,7 +1203,11 @@ static uint32_t next_token(uint32_t expected) goto readnext; /* insert concatenation operator when needed */ - if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP)) { + debug_printf_parse("%s: %x %x %x concat_inserted?\n", __func__, + (ltclass & TC_CONCAT1), (tc & TC_CONCAT2), (expected & TC_BINOP)); + if ((ltclass & TC_CONCAT1) && (tc & TC_CONCAT2) && (expected & TC_BINOP) + && !(ltclass == TC_LENGTH && tc == TC_SEQSTART) /* but not for "length(..." */ + ) { concat_inserted = TRUE; save_tclass = tc; save_info = t_info; @@ -1208,6 +1215,7 @@ static uint32_t next_token(uint32_t expected) t_info = OC_CONCAT | SS | P(35); } + debug_printf_parse("%s: t_tclass=tc=%x\n", __func__, t_tclass); t_tclass = tc; } ltclass = t_tclass; @@ -1218,6 +1226,7 @@ static uint32_t next_token(uint32_t expected) EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); } + debug_printf_parse("%s: returning, ltclass:%x t_double:%f\n", __func__, ltclass, t_double); return ltclass; #undef concat_inserted #undef save_tclass @@ -1282,7 +1291,7 @@ static node *parse_expr(uint32_t iexp) glptr = NULL; } else if (tc & (TC_BINOP | TC_UOPPOST)) { - debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); + debug_printf_parse("%s: TC_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); /* for binary and postfix-unary operators, jump back over * previous operators with higher priority */ vn = cn; @@ -1387,7 +1396,12 @@ static node *parse_expr(uint32_t iexp) case TC_LENGTH: debug_printf_parse("%s: TC_LENGTH\n", __func__); - next_token(TC_SEQSTART | TC_OPTERM | TC_GRPTERM); + next_token(TC_SEQSTART /* length(...) */ + | TC_OPTERM /* length; (or newline)*/ + | TC_GRPTERM /* length } */ + | TC_BINOPX /* length NUM */ + | TC_COMMA /* print length, 1 */ + ); rollback_token(); if (t_tclass & TC_SEQSTART) { /* It was a "(" token. Handle just like TC_BUILTIN */ diff --git a/testsuite/awk.tests b/testsuite/awk.tests index a7a533ba0..b5008290f 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -85,7 +85,8 @@ testing "awk floating const with leading zeroes" \ "" "\n" # long field seps requiring regex -testing "awk long field sep" "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ +testing "awk long field sep" \ + "awk -F-- '{ print NF, length(\$NF), \$NF }'" \ "2 0 \n3 0 \n4 0 \n5 0 \n" \ "" \ "a--\na--b--\na--b--c--\na--b--c--d--" @@ -317,6 +318,26 @@ testing "awk length()" \ "3\n3\n3\n3\n" \ "" "qwe" +testing "awk print length, 1" \ + "awk '{ print length, 1 }'" \ + "0 1\n" \ + "" "\n" + +testing "awk print length 1" \ + "awk '{ print length 1 }'" \ + "01\n" \ + "" "\n" + +testing "awk length == 0" \ + "awk 'length == 0 { print \"foo\" }'" \ + "foo\n" \ + "" "\n" + +testing "awk if (length == 0)" \ + "awk '{ if (length == 0) { print \"bar\" } }'" \ + "bar\n" \ + "" "\n" + testing "awk -f and ARGC" \ "awk -f - input" \ "re\n2\n" \ -- cgit v1.2.3-55-g6feb From 260bd21169843fc00ee294a5f75da9e53cb2bc14 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Feb 2020 12:58:46 +0100 Subject: tftpd: show requested file name in open error message function old new delta tftp_protocol 1902 1949 +47 Signed-off-by: Denys Vlasenko --- networking/tftp.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/networking/tftp.c b/networking/tftp.c index 04bfe844f..e74186884 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -402,9 +402,17 @@ static int tftp_protocol( /* Open file (must be after changing user) */ local_fd = open(local_file, open_mode, 0666); if (local_fd < 0) { + /* sanitize name, it came from untrusted remote side */ + unsigned char *p = (void *) local_file; + while (*p) { + if (*p < ' ') + *p = '?'; + p++; + } + bb_perror_msg("can't open '%s'", local_file); G_error_pkt_reason = ERR_NOFILE; strcpy(G_error_pkt_str, "can't open file"); - goto send_err_pkt; + goto send_err_pkt_nomsg; } /* gcc 4.3.1 would NOT optimize it out as it should! */ #if ENABLE_FEATURE_TFTP_BLOCKSIZE @@ -721,7 +729,7 @@ static int tftp_protocol( * must never resend the current DATA packet on receipt * of a duplicate ACK". * DATA pkts are resent ONLY on timeout. - * Thus "goto send_again" will ba a bad mistake above. + * Thus "goto send_again" will be a bad mistake above. * See: * http://en.wikipedia.org/wiki/Sorcerer's_Apprentice_Syndrome */ @@ -740,6 +748,7 @@ static int tftp_protocol( send_err_pkt: if (G_error_pkt_str[0]) bb_simple_error_msg(G_error_pkt_str); + send_err_pkt_nomsg: G.error_pkt[1] = TFTP_ERROR; xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), &peer_lsa->u.sa, peer_lsa->len); -- cgit v1.2.3-55-g6feb From 779df9f228789034ef23f856f855147bdb729958 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Feb 2020 13:01:43 +0100 Subject: tftp: code shrink function old new delta tftp_protocol 1949 1947 -2 Signed-off-by: Denys Vlasenko --- networking/tftp.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/networking/tftp.c b/networking/tftp.c index e74186884..4d608a6fb 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -459,16 +459,14 @@ static int tftp_protocol( } /* add filename and mode */ /* fill in packet if the filename fits into xbuf */ - len = strlen(remote_file) + 1; - if (2 + len + sizeof("octet") >= io_bufsize) { + len = strlen(remote_file); + if (len + 3 + sizeof("octet") >= io_bufsize) { bb_simple_error_msg("remote filename is too long"); goto ret; } - strcpy(cp, remote_file); - cp += len; + cp = stpcpy(cp, remote_file) + 1; /* add "mode" part of the packet */ - strcpy(cp, "octet"); - cp += sizeof("octet"); + cp = stpcpy(cp, "octet"); # if ENABLE_FEATURE_TFTP_BLOCKSIZE if (blksize == TFTP_BLKSIZE_DEFAULT && !want_transfer_size) @@ -757,7 +755,6 @@ static int tftp_protocol( } #if ENABLE_TFTP - int tftp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tftp_main(int argc UNUSED_PARAM, char **argv) { @@ -873,7 +870,6 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) } return result; } - #endif /* ENABLE_TFTP */ #if ENABLE_TFTPD @@ -1010,7 +1006,6 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) strcpy(G_error_pkt_str, error_msg); goto do_proto; } - #endif /* ENABLE_TFTPD */ #endif /* ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT */ -- cgit v1.2.3-55-g6feb From 0c4e5977dfc32b54e452cd88a9cf14afde29c89d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Feb 2020 15:03:12 +0100 Subject: tftp: fix thinko in code shrink Signed-off-by: Denys Vlasenko --- networking/tftp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/tftp.c b/networking/tftp.c index 4d608a6fb..043747d0d 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -466,7 +466,7 @@ static int tftp_protocol( } cp = stpcpy(cp, remote_file) + 1; /* add "mode" part of the packet */ - cp = stpcpy(cp, "octet"); + cp = stpcpy(cp, "octet") + 1; # if ENABLE_FEATURE_TFTP_BLOCKSIZE if (blksize == TFTP_BLKSIZE_DEFAULT && !want_transfer_size) -- cgit v1.2.3-55-g6feb From adc540f0dbcd640b37f39364aa4a1c6857a96a96 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Feb 2020 15:27:23 +0100 Subject: tftp: on download, open local file only when first bit of data arrived No reason to potentially clobber existing file before absolutely necessary. function old new delta tftp_protocol 1947 2020 +73 tftp_main 393 376 -17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 73/-17) Total: 56 bytes Signed-off-by: Denys Vlasenko --- networking/tftp.c | 61 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 28 deletions(-) diff --git a/networking/tftp.c b/networking/tftp.c index 043747d0d..60fdff232 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -319,7 +319,7 @@ static int tftp_protocol( uint16_t opcode; uint16_t block_nr; uint16_t recv_blk; - int open_mode, local_fd; + int local_fd = -1; int retries, waittime_ms; int io_bufsize = blksize + 4; char *cp; @@ -354,19 +354,6 @@ static int tftp_protocol( } } - /* Prepare open mode */ - if (CMD_PUT(option_mask32)) { - open_mode = O_RDONLY; - } else { - open_mode = O_WRONLY | O_TRUNC | O_CREAT; -#if ENABLE_TFTPD - if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) { - /* tftpd without -c */ - open_mode = O_WRONLY | O_TRUNC; - } -#endif - } - /* Examples of network traffic. * Note two cases when ACKs with block# of 0 are sent. * @@ -400,6 +387,14 @@ static int tftp_protocol( if (!ENABLE_TFTP || our_lsa) { /* tftpd */ /* Open file (must be after changing user) */ + int open_mode = O_RDONLY; + if (CMD_GET(option_mask32)) { + open_mode = O_WRONLY | O_TRUNC | O_CREAT; + if ((option_mask32 & (TFTPD_OPT+TFTPD_OPT_c)) == TFTPD_OPT) { + /* tftpd without -c */ + open_mode = O_WRONLY | O_TRUNC; + } + } local_fd = open(local_file, open_mode, 0666); if (local_fd < 0) { /* sanitize name, it came from untrusted remote side */ @@ -414,6 +409,7 @@ static int tftp_protocol( strcpy(G_error_pkt_str, "can't open file"); goto send_err_pkt_nomsg; } + /* gcc 4.3.1 would NOT optimize it out as it should! */ #if ENABLE_FEATURE_TFTP_BLOCKSIZE if (blksize != TFTP_BLKSIZE_DEFAULT || want_transfer_size) { @@ -432,10 +428,11 @@ static int tftp_protocol( block_nr = 0; } } else { /* tftp */ - /* Open file (must be after changing user) */ - local_fd = CMD_GET(option_mask32) ? STDOUT_FILENO : STDIN_FILENO; - if (NOT_LONE_DASH(local_file)) - local_fd = xopen(local_file, open_mode); + if (CMD_PUT(option_mask32)) { + local_fd = STDIN_FILENO; + if (local_file) + local_fd = xopen(local_file, O_RDONLY); + } /* Removing #if, or using if() statement instead of #if may lead to * "warning: null argument where non-null required": */ #if ENABLE_TFTP @@ -491,7 +488,7 @@ static int tftp_protocol( } if (want_transfer_size) { /* add "tsize", , size, (see RFC2349) */ - /* if tftp and downloading, we send "0" (since we opened local_fd with O_TRUNC) + /* if tftp and downloading, we send "0" (local_fd is not open yet) * and this makes server to send "tsize" option with the size */ /* if tftp and uploading, we send file size (maybe dont, to not confuse old servers???) */ /* if tftpd and downloading, we are answering to client's request */ @@ -500,7 +497,8 @@ static int tftp_protocol( strcpy(cp, "tsize"); cp += sizeof("tsize"); st.st_size = 0; - fstat(local_fd, &st); + if (local_fd >= 0) + fstat(local_fd, &st); cp += sprintf(cp, "%"OFF_FMT"u", (off_t)st.st_size) + 1; # if ENABLE_FEATURE_TFTP_PROGRESS_BAR /* Save for progress bar. If 0 (tftp downloading), @@ -690,7 +688,13 @@ static int tftp_protocol( if (CMD_GET(option_mask32) && (opcode == TFTP_DATA)) { if (recv_blk == block_nr) { - int sz = full_write(local_fd, &rbuf[4], len - 4); + int sz; + if (local_fd == -1) { + local_fd = STDOUT_FILENO; + if (local_file) + local_fd = xopen(local_file, O_WRONLY | O_TRUNC | O_CREAT); + } + sz = full_write(local_fd, &rbuf[4], len - 4); if (sz != len - 4) { strcpy(G_error_pkt_str, bb_msg_write_error); G_error_pkt_reason = ERR_WRITE; @@ -739,7 +743,9 @@ static int tftp_protocol( free(xbuf); free(rbuf); } - return finished == 0; /* returns 1 on failure */ + if (!finished) + goto err; + return EXIT_SUCCESS; send_read_err_pkt: strcpy(G_error_pkt_str, bb_msg_read_error); @@ -750,6 +756,9 @@ static int tftp_protocol( G.error_pkt[1] = TFTP_ERROR; xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), &peer_lsa->u.sa, peer_lsa->len); + err: + if (local_fd >= 0 && CMD_GET(option_mask32) && local_file) + unlink(local_file); return EXIT_FAILURE; #undef remote_file } @@ -767,7 +776,6 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) # endif int result; int port; - IF_GETPUT(int opt;) INIT_G(); @@ -808,7 +816,7 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) } } - IF_GETPUT(opt =) getopt32(argv, "^" + getopt32(argv, "^" IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p") "l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:") IF_FEATURE_TFTP_HPA_COMPAT("m:") @@ -859,15 +867,12 @@ int tftp_main(int argc UNUSED_PARAM, char **argv) # endif result = tftp_protocol( NULL /*our_lsa*/, peer_lsa, - local_file, remote_file + (LONE_DASH(local_file) ? NULL : local_file), remote_file IF_FEATURE_TFTP_BLOCKSIZE(, 1 /* want_transfer_size */) IF_FEATURE_TFTP_BLOCKSIZE(, blksize) ); tftp_progress_done(); - if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) { - unlink(local_file); - } return result; } #endif /* ENABLE_TFTP */ -- cgit v1.2.3-55-g6feb From a6e48dead331c3c19e070992d2d571e74a1d9a8d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Feb 2020 13:57:41 +0100 Subject: fdisk: add HFS / HFS+ partition type Signed-off-by: Denys Vlasenko --- util-linux/fdisk.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index e58cb0fd1..f568fe92c 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -344,6 +344,7 @@ static const char *const i386_sys_types[] = { "\xa8" "Darwin UFS", "\xa9" "NetBSD", "\xab" "Darwin boot", + "\xaf" "HFS / HFS+", "\xb7" "BSDI fs", "\xb8" "BSDI swap", "\xbe" "Solaris boot", @@ -390,15 +391,12 @@ static const char *const i386_sys_types[] = { "\xc6" "DRDOS/sec (FAT-16)", "\xc7" "Syrinx", "\xda" "Non-FS data", - "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or - Concurrent DOS or CTOS */ + "\xdb" "CP/M / CTOS / ...",/* CP/M or Concurrent CP/M or Concurrent DOS or CTOS */ "\xde" "Dell Utility", /* Dell PowerEdge Server utilities */ "\xdf" "BootIt", /* BootIt EMBRM */ - "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT - extended partition */ + "\xe1" "DOS access", /* DOS access or SpeedStor 12-bit FAT extended partition */ "\xe3" "DOS R/O", /* DOS R/O or SpeedStor */ - "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended - partition < 1024 cyl. */ + "\xe4" "SpeedStor", /* SpeedStor 16-bit FAT extended partition <1024 cyl. */ "\xf1" "SpeedStor", "\xf4" "SpeedStor", /* SpeedStor large partition */ "\xfe" "LANstep", /* SpeedStor >1024 cyl. or LANstep */ -- cgit v1.2.3-55-g6feb