From 8de5b9f88ba9fe2f203abab9ca7d85129c3eb679 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 14:43:29 +0100 Subject: ash : fix double-quoted "\z" handling function old new delta readtoken1 2602 2608 +6 Signed-off-by: Denys Vlasenko --- shell/ash.c | 23 ++++++++++---- shell/ash_test/ash-quoting/bkslash_case1.right | 10 +++++++ shell/ash_test/ash-quoting/bkslash_case1.tests | 38 ++++++++++++++++++++++++ shell/hush_test/hush-quoting/bkslash_case1.right | 10 +++++++ shell/hush_test/hush-quoting/bkslash_case1.tests | 38 ++++++++++++++++++++++++ 5 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 shell/ash_test/ash-quoting/bkslash_case1.right create mode 100755 shell/ash_test/ash-quoting/bkslash_case1.tests create mode 100644 shell/hush_test/hush-quoting/bkslash_case1.right create mode 100755 shell/hush_test/hush-quoting/bkslash_case1.tests diff --git a/shell/ash.c b/shell/ash.c index 4c1b5e409..5e281b5ce 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6146,12 +6146,12 @@ rmescapes(char *str, int flag, int *slash_position) if (*p == '*' || *p == '?' || *p == '[' - || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */ - || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */ - || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */ - || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */ + || *p == '\\' /* case '\' in \\ ) echo ok;; *) echo WRONG;; esac */ + || *p == ']' /* case ']' in [a\]] ) echo ok;; *) echo WRONG;; esac */ + || *p == '-' /* case '-' in [a\-c]) echo ok;; *) echo WRONG;; esac */ + || *p == '!' /* case '!' in [\!] ) echo ok;; *) echo WRONG;; esac */ /* Some libc support [^negate], that's why "^" also needs love */ - || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */ + || *p == '^' /* case '^' in [\^] ) echo ok;; *) echo WRONG;; esac */ ) { *q++ = '\\'; } @@ -11992,13 +11992,24 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) USTPUTC(CTLESC, out); USTPUTC('\\', out); } - /* Backslash is retained if we are in "str" and next char isn't special */ + /* Backslash is retained if we are in "str" + * and next char isn't dquote-special. + */ if (dblquote && c != '\\' && c != '`' && c != '$' && (c != '"' || eofmark != NULL) ) { +//dash survives not doing USTPUTC(CTLESC), but merely by chance: +//Example: "\z" gets encoded as "\z". +//rmescapes() then emits "\", "\z", protecting z from globbing. +//But it's wrong, should protect _both_ from globbing: +//everything in double quotes is not globbed. +//Unlike dash, we have a fix in rmescapes() which emits bare "z" +//for "z" since "z" is not glob-special (else unicode may break), +//and glob would see "\z" and eat "\". Thus: + USTPUTC(CTLESC, out); /* protect '\' from glob */ USTPUTC('\\', out); } USTPUTC(CTLESC, out); diff --git a/shell/ash_test/ash-quoting/bkslash_case1.right b/shell/ash_test/ash-quoting/bkslash_case1.right new file mode 100644 index 000000000..1b52491f7 --- /dev/null +++ b/shell/ash_test/ash-quoting/bkslash_case1.right @@ -0,0 +1,10 @@ +ok1 +ok2 +ok3 +ok4 +ok5 +Ok:0 +ok6 +ok7 +ok8 +Ok:0 diff --git a/shell/ash_test/ash-quoting/bkslash_case1.tests b/shell/ash_test/ash-quoting/bkslash_case1.tests new file mode 100755 index 000000000..d0c359927 --- /dev/null +++ b/shell/ash_test/ash-quoting/bkslash_case1.tests @@ -0,0 +1,38 @@ +# Case argument is globbed, match patterns are not. +# This caught some bugs in the past. + +case z in +\z ) echo ok1 ;; +* ) echo BUG ;; +esac +case \z in +z ) echo ok2 ;; +* ) echo BUG ;; +esac +case \z in +\z ) echo ok3 ;; +* ) echo BUG ;; +esac +case z in +\z ) echo ok4 ;; +* ) echo BUG ;; +esac +case \\z in +\\z ) echo ok5 ;; +* ) echo BUG ;; +esac +echo Ok:$? + +case "\z" in +"\z" ) echo ok6 ;; +* ) echo BUG ;; +esac +case "\\z" in +"\\z" ) echo ok7 ;; +* ) echo BUG ;; +esac +case "\\\z" in +"\\\z") echo ok8 ;; +* ) echo BUG ;; +esac +echo Ok:$? diff --git a/shell/hush_test/hush-quoting/bkslash_case1.right b/shell/hush_test/hush-quoting/bkslash_case1.right new file mode 100644 index 000000000..1b52491f7 --- /dev/null +++ b/shell/hush_test/hush-quoting/bkslash_case1.right @@ -0,0 +1,10 @@ +ok1 +ok2 +ok3 +ok4 +ok5 +Ok:0 +ok6 +ok7 +ok8 +Ok:0 diff --git a/shell/hush_test/hush-quoting/bkslash_case1.tests b/shell/hush_test/hush-quoting/bkslash_case1.tests new file mode 100755 index 000000000..d0c359927 --- /dev/null +++ b/shell/hush_test/hush-quoting/bkslash_case1.tests @@ -0,0 +1,38 @@ +# Case argument is globbed, match patterns are not. +# This caught some bugs in the past. + +case z in +\z ) echo ok1 ;; +* ) echo BUG ;; +esac +case \z in +z ) echo ok2 ;; +* ) echo BUG ;; +esac +case \z in +\z ) echo ok3 ;; +* ) echo BUG ;; +esac +case z in +\z ) echo ok4 ;; +* ) echo BUG ;; +esac +case \\z in +\\z ) echo ok5 ;; +* ) echo BUG ;; +esac +echo Ok:$? + +case "\z" in +"\z" ) echo ok6 ;; +* ) echo BUG ;; +esac +case "\\z" in +"\\z" ) echo ok7 ;; +* ) echo BUG ;; +esac +case "\\\z" in +"\\\z") echo ok8 ;; +* ) echo BUG ;; +esac +echo Ok:$? -- cgit v1.2.3-55-g6feb From aa617ac09703f31e9f80836f8d8f9349b52578ee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 15:30:13 +0100 Subject: hush: simplify process_command_subs() Incidentally, this fixes LINENO bug here: echo "1:${LINENO}" echo "2:`echo; echo`" # was counting lines in the `cmd` output as LINENO++ echo "3:${LINENO}" function old new delta parse_and_run_file 53 71 +18 expand_vars_to_list 1187 1164 -23 setup_file_in_str 25 - -25 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/1 up/down: 18/-48) Total: -30 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 8f1017e3c..e005b0a20 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6614,24 +6614,22 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) static void parse_and_run_string(const char *s) { struct in_str input; + //IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) + setup_string_in_str(&input, s); parse_and_run_stream(&input, '\0'); + //IF_HUSH_LINENO_VAR(G.lineno = sv;) } static void parse_and_run_file(FILE *f) { struct in_str input; -#if ENABLE_HUSH_LINENO_VAR - unsigned sv; + IF_HUSH_LINENO_VAR(unsigned sv = G.lineno;) - sv = G.lineno; - G.lineno = 1; -#endif + IF_HUSH_LINENO_VAR(G.lineno = 1;) setup_file_in_str(&input, f); parse_and_run_stream(&input, ';'); -#if ENABLE_HUSH_LINENO_VAR - G.lineno = sv; -#endif + IF_HUSH_LINENO_VAR(G.lineno = sv;) } #if ENABLE_HUSH_TICK @@ -6744,16 +6742,16 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) static int process_command_subs(o_string *dest, const char *s) { FILE *fp; - struct in_str pipe_str; pid_t pid; int status, ch, eol_cnt; fp = generate_stream_from_string(s, &pid); /* Now send results of command back into original context */ - setup_file_in_str(&pipe_str, fp); eol_cnt = 0; - while ((ch = i_getch(&pipe_str)) != EOF) { + while ((ch = getc(fp)) != EOF) { + if (ch == '\0') + continue; if (ch == '\n') { eol_cnt++; continue; -- cgit v1.2.3-55-g6feb From edccc982e515e63a080a75fb49fd08b946f62cc6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 16:48:52 +0100 Subject: progress meter: add disabled code for a more stable ETA Compiles to ~25 bytes if enabled. Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/progress.c | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/include/libbb.h b/include/libbb.h index 2c34859a2..c02621d94 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1949,6 +1949,7 @@ typedef struct bb_progress_t { unsigned last_update_sec; unsigned last_change_sec; unsigned start_sec; + /*unsigned last_eta;*/ const char *curfile; } bb_progress_t; diff --git a/libbb/progress.c b/libbb/progress.c index f1d980d68..23e974ce7 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -57,6 +57,9 @@ void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) p->last_update_sec = p->start_sec; p->last_change_sec = p->start_sec; p->last_size = 0; +#if 0 + p->last_eta = INT_MAX; +#endif } /* File already had beg_size bytes. @@ -192,6 +195,16 @@ void FAST_FUNC bb_progress_update(bb_progress_t *p, /* if 32bit, can overflow ^^^^^^^^^^, but this would only show bad ETA */ if (eta >= 1000*60*60) eta = 1000*60*60 - 1; +#if 0 + /* To prevent annoying "back-and-forth" estimation jitter, + * if new ETA is larger than the last just by a few seconds, + * disregard it, and show last one. The end result is that + * ETA usually only decreases, unless download slows down a lot. + */ + if ((unsigned)(eta - p->last_eta) < 10) + eta = p->last_eta; + p->last_eta = eta; +#endif secs = eta % 3600; hours = eta / 3600; fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60); -- cgit v1.2.3-55-g6feb From 4892f3a4c77fb5051d64cfc5f9056a7d6ec6cdb2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 18:20:28 +0100 Subject: inetd,mount: add comment with example of flags to build with libtirpc Signed-off-by: Denys Vlasenko --- networking/inetd.c | 6 +++++- util-linux/mount.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/networking/inetd.c b/networking/inetd.c index 6843845fb..ca1a97268 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -246,7 +246,11 @@ #if ENABLE_FEATURE_INETD_RPC # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) # warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support" - /* not #error, since user may be using e.g. libtirpc instead */ + /* not #error, since user may be using e.g. libtirpc instead. + * This might work: + * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc" + * CONFIG_EXTRA_LDLIBS="tirpc" + */ # endif # include # include diff --git a/util-linux/mount.c b/util-linux/mount.c index 4eade0869..fa2e7b114 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -244,7 +244,11 @@ * uclibc faq entry rather than in busybox... */ # if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) # warning "You probably need to build uClibc with UCLIBC_HAS_RPC for NFS support" - /* not #error, since user may be using e.g. libtirpc instead */ + /* not #error, since user may be using e.g. libtirpc instead. + * This might work: + * CONFIG_EXTRA_CFLAGS="-I/usr/include/tirpc" + * CONFIG_EXTRA_LDLIBS="tirpc" + */ # endif # include # include -- cgit v1.2.3-55-g6feb From 7189af847fd8a54a85f08e9bf51cd103f0d87393 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 23:21:33 +0100 Subject: ping: implement -A "adaptive ping" function old new delta common_ping_main 1757 1862 +105 packed_usage 32367 32427 +60 sendping_tail 236 209 -27 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 165/-27) Total: 138 bytes Signed-off-by: Denys Vlasenko --- networking/ping.c | 100 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 60 insertions(+), 40 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index d1d59d545..bf750d032 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -74,6 +74,7 @@ //usage: ) //usage: "\n -c CNT Send only CNT pings" //usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" +//usage: "\n -A Ping as soon as reply is recevied" //usage: "\n -t TTL Set TTL" //usage: "\n -I IFACE/IP Source interface or IP address" //usage: "\n -W SEC Seconds to wait for the first response (default 10)" @@ -90,6 +91,7 @@ //usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" //usage: "\n -c CNT Send only CNT pings" //usage: "\n -s SIZE Send SIZE data bytes in packets (default 56)" +//usage: "\n -A Ping as soon as reply is recevied" //usage: "\n -I IFACE/IP Source interface or IP address" //usage: "\n -q Quiet, only display output at start" //usage: "\n and when finished" @@ -348,20 +350,21 @@ static int common_ping_main(sa_family_t af, char **argv) /* Full(er) version */ /* -c NUM, -t NUM, -w NUM, -W NUM */ -#define OPT_STRING "qvc:+s:t:+w:+W:+I:np:4"IF_PING6("6") +#define OPT_STRING "qvAc:+s:t:+w:+W:+I:np:4"IF_PING6("6") enum { OPT_QUIET = 1 << 0, OPT_VERBOSE = 1 << 1, - OPT_c = 1 << 2, - OPT_s = 1 << 3, - OPT_t = 1 << 4, - OPT_w = 1 << 5, - OPT_W = 1 << 6, - OPT_I = 1 << 7, - /*OPT_n = 1 << 8, - ignored */ - OPT_p = 1 << 9, - OPT_IPV4 = 1 << 10, - OPT_IPV6 = (1 << 11) * ENABLE_PING6, + OPT_A = 1 << 2, + OPT_c = 1 << 3, + OPT_s = 1 << 4, + OPT_t = 1 << 5, + OPT_w = 1 << 6, + OPT_W = 1 << 7, + OPT_I = 1 << 8, + /*OPT_n = 1 << 9, - ignored */ + OPT_p = 1 << 10, + OPT_IPV4 = 1 << 11, + OPT_IPV6 = (1 << 12) * ENABLE_PING6, }; @@ -377,9 +380,8 @@ struct globals { uint8_t pattern; unsigned tmin, tmax; /* in us */ unsigned long long tsum; /* in us, sum of all times */ - unsigned deadline; + unsigned deadline_ms; unsigned timeout; - unsigned total_secs; unsigned sizeof_rcv_packet; char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */ void *snd_packet; /* [datalen + ipv4/ipv6_const] */ @@ -405,9 +407,7 @@ struct globals { #define tmin (G.tmin ) #define tmax (G.tmax ) #define tsum (G.tsum ) -#define deadline (G.deadline ) #define timeout (G.timeout ) -#define total_secs (G.total_secs ) #define hostname (G.hostname ) #define dotted (G.dotted ) #define pingaddr (G.pingaddr ) @@ -455,7 +455,7 @@ static void print_stats_and_exit(int junk UNUSED_PARAM) tmax / 1000, tmax % 1000); } /* if condition is true, exit with 1 -- 'failure' */ - exit(nrecv == 0 || (deadline && nrecv < pingcount)); + exit(nrecv == 0 || (G.deadline_ms && nrecv < pingcount)); } static void sendping_tail(void (*sp)(int), int size_pkt) @@ -467,22 +467,23 @@ static void sendping_tail(void (*sp)(int), int size_pkt) size_pkt += datalen; + if (G.deadline_ms) { + unsigned n = ((unsigned)monotonic_ms()) - G.deadline_ms; + if ((int)n >= 0) + print_stats_and_exit(0); + } + /* sizeof(pingaddr) can be larger than real sa size, but I think * it doesn't matter */ 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); - if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { + if (pingcount == 0 || G.ntransmitted < pingcount) { /* Didn't send all pings yet - schedule next in 1s */ signal(SIGALRM, sp); - if (deadline) { - total_secs += PINGINTERVAL; - if (total_secs >= deadline) - signal(SIGALRM, print_stats_and_exit); - } alarm(PINGINTERVAL); - } else { /* -c NN, and all NN are sent (and no deadline) */ + } else { /* -c NN, and all NN are sent */ /* Wait for the last ping to come back. * -W timeout: wait for a response in seconds. * Affects only timeout in absence of any responses, @@ -632,7 +633,7 @@ static void unpack_tail(int sz, uint32_t *tp, puts(dupmsg); fflush_all(); } -static void unpack4(char *buf, int sz, struct sockaddr_in *from) +static int unpack4(char *buf, int sz, struct sockaddr_in *from) { struct icmp *icmppkt; struct iphdr *iphdr; @@ -640,7 +641,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) /* discard if too short */ if (sz < (datalen + ICMP_MINLEN)) - return; + return 0; /* check IP header */ iphdr = (struct iphdr *) buf; @@ -648,7 +649,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) sz -= hlen; icmppkt = (struct icmp *) (buf + hlen); if (icmppkt->icmp_id != myid) - return; /* not our ping */ + return 0; /* not our ping */ if (icmppkt->icmp_type == ICMP_ECHOREPLY) { uint16_t recv_seq = ntohs(icmppkt->icmp_seq); @@ -659,25 +660,28 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) unpack_tail(sz, tp, inet_ntoa(*(struct in_addr *) &from->sin_addr.s_addr), recv_seq, iphdr->ttl); - } else if (icmppkt->icmp_type != ICMP_ECHO) { + return 1; + } + if (icmppkt->icmp_type != ICMP_ECHO) { bb_error_msg("warning: got ICMP %d (%s)", icmppkt->icmp_type, icmp_type_name(icmppkt->icmp_type)); } + return 0; } #if ENABLE_PING6 -static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) +static int unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) { struct icmp6_hdr *icmppkt; char buf[INET6_ADDRSTRLEN]; /* discard if too short */ if (sz < (datalen + sizeof(struct icmp6_hdr))) - return; + return 0; icmppkt = (struct icmp6_hdr *) packet; if (icmppkt->icmp6_id != myid) - return; /* not our ping */ + return 0; /* not our ping */ if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { uint16_t recv_seq = ntohs(icmppkt->icmp6_seq); @@ -689,11 +693,14 @@ static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimi inet_ntop(AF_INET6, &from->sin6_addr, buf, sizeof(buf)), recv_seq, hoplimit); - } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { + return 1; + } + if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { bb_error_msg("warning: got ICMP %d (%s)", icmppkt->icmp6_type, icmp6_type_name(icmppkt->icmp6_type)); } + return 0; } #endif @@ -726,6 +733,7 @@ static void ping4(len_and_sockaddr *lsa) signal(SIGINT, print_stats_and_exit); /* start the ping's going ... */ + send_ping: sendping4(0); /* listen for replies */ @@ -741,9 +749,12 @@ static void ping4(len_and_sockaddr *lsa) bb_perror_msg("recvfrom"); continue; } - unpack4(G.rcv_packet, c, &from); + c = unpack4(G.rcv_packet, c, &from); if (pingcount && G.nreceived >= pingcount) break; + if (c && (option_mask32 & OPT_A)) { + goto send_ping; + } } } #if ENABLE_PING6 @@ -794,10 +805,6 @@ static void ping6(len_and_sockaddr *lsa) signal(SIGINT, print_stats_and_exit); - /* start the ping's going ... */ - sendping6(0); - - /* listen for replies */ msg.msg_name = &from; msg.msg_namelen = sizeof(from); msg.msg_iov = &iov; @@ -805,12 +812,18 @@ static void ping6(len_and_sockaddr *lsa) msg.msg_control = control_buf; iov.iov_base = G.rcv_packet; iov.iov_len = G.sizeof_rcv_packet; + + /* start the ping's going ... */ + send_ping: + sendping6(0); + + /* listen for replies */ while (1) { int c; struct cmsghdr *mp; int hoplimit = -1; - msg.msg_controllen = sizeof(control_buf); + msg.msg_controllen = sizeof(control_buf); c = recvmsg(pingsock, &msg, 0); if (c < 0) { if (errno != EINTR) @@ -827,9 +840,12 @@ static void ping6(len_and_sockaddr *lsa) move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); } } - unpack6(G.rcv_packet, c, &from, hoplimit); + c = unpack6(G.rcv_packet, c, &from, hoplimit); if (pingcount && G.nreceived >= pingcount) break; + if (c && (option_mask32 & OPT_A)) { + goto send_ping; + } } } #endif @@ -875,7 +891,7 @@ static int common_ping_main(int opt, char **argv) OPT_STRING /* exactly one arg; -v and -q don't mix */ "\0" "=1:q--v:v--q", - &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I, &str_p + &pingcount, &str_s, &opt_ttl, &G.deadline_ms, &timeout, &str_I, &str_p ); if (opt & OPT_s) datalen = xatou16(str_s); // -s @@ -889,6 +905,10 @@ static int common_ping_main(int opt, char **argv) } if (opt & OPT_p) G.pattern = xstrtou_range(str_p, 16, 0, 255); + if (G.deadline_ms) { + unsigned d = G.deadline_ms < INT_MAX/1000 ? G.deadline_ms : INT_MAX/1000; + G.deadline_ms = 1 | ((d * 1000) + monotonic_ms()); + } myid = (uint16_t) getpid(); hostname = argv[optind]; @@ -911,7 +931,7 @@ static int common_ping_main(int opt, char **argv) dotted = xmalloc_sockaddr2dotted_noport(&lsa->u.sa); ping(lsa); - print_stats_and_exit(EXIT_SUCCESS); + print_stats_and_exit(0); /*return EXIT_SUCCESS;*/ } #endif /* FEATURE_FANCY_PING */ -- cgit v1.2.3-55-g6feb From 256adb0f99ab3485b4c9243a76dc0df1738f08b1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Feb 2018 23:53:24 +0100 Subject: ping: don't call monotonic_us twice per sending the ping function old new delta sendping6 80 85 +5 sendping4 106 111 +5 sendping_tail 209 204 -5 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 10/-5) Total: 5 bytes Signed-off-by: Denys Vlasenko --- networking/ping.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/networking/ping.c b/networking/ping.c index bf750d032..8f85d3ec2 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -380,7 +380,8 @@ struct globals { uint8_t pattern; unsigned tmin, tmax; /* in us */ unsigned long long tsum; /* in us, sum of all times */ - unsigned deadline_ms; + unsigned cur_us; /* low word only, we don't need more */ + unsigned deadline_us; unsigned timeout; unsigned sizeof_rcv_packet; char *rcv_packet; /* [datalen + MAXIPLEN + MAXICMPLEN] */ @@ -455,7 +456,7 @@ static void print_stats_and_exit(int junk UNUSED_PARAM) tmax / 1000, tmax % 1000); } /* if condition is true, exit with 1 -- 'failure' */ - exit(nrecv == 0 || (G.deadline_ms && nrecv < pingcount)); + exit(nrecv == 0 || (G.deadline_us && nrecv < pingcount)); } static void sendping_tail(void (*sp)(int), int size_pkt) @@ -467,8 +468,8 @@ static void sendping_tail(void (*sp)(int), int size_pkt) size_pkt += datalen; - if (G.deadline_ms) { - unsigned n = ((unsigned)monotonic_ms()) - G.deadline_ms; + if (G.deadline_us) { + unsigned n = G.cur_us - G.deadline_us; if ((int)n >= 0) print_stats_and_exit(0); } @@ -517,7 +518,7 @@ static void sendping4(int junk UNUSED_PARAM) */ /*if (datalen >= 4)*/ /* No hton: we'll read it back on the same machine */ - *(uint32_t*)&pkt->icmp_dun = monotonic_us(); + *(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us(); pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); @@ -536,7 +537,7 @@ static void sendping6(int junk UNUSED_PARAM) pkt->icmp6_id = myid; /*if (datalen >= 4)*/ - *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); + *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = G.cur_us = monotonic_us(); //TODO? pkt->icmp_cksum = inet_cksum(...); @@ -891,7 +892,7 @@ static int common_ping_main(int opt, char **argv) OPT_STRING /* exactly one arg; -v and -q don't mix */ "\0" "=1:q--v:v--q", - &pingcount, &str_s, &opt_ttl, &G.deadline_ms, &timeout, &str_I, &str_p + &pingcount, &str_s, &opt_ttl, &G.deadline_us, &timeout, &str_I, &str_p ); if (opt & OPT_s) datalen = xatou16(str_s); // -s @@ -905,9 +906,9 @@ static int common_ping_main(int opt, char **argv) } if (opt & OPT_p) G.pattern = xstrtou_range(str_p, 16, 0, 255); - if (G.deadline_ms) { - unsigned d = G.deadline_ms < INT_MAX/1000 ? G.deadline_ms : INT_MAX/1000; - G.deadline_ms = 1 | ((d * 1000) + monotonic_ms()); + if (G.deadline_us) { + unsigned d = G.deadline_us < INT_MAX/1000000 ? G.deadline_us : INT_MAX/1000000; + G.deadline_us = 1 | ((d * 1000000) + monotonic_us()); } myid = (uint16_t) getpid(); -- cgit v1.2.3-55-g6feb From a48eadbc22d3892481826e0b7dc4c7a5d2baad5c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Feb 2018 17:37:41 +0100 Subject: tls: remove redundant floor prevention function old new delta tls_xread_record 499 489 -10 Signed-off-by: Denys Vlasenko --- networking/tls.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/networking/tls.c b/networking/tls.c index da7b6058f..99722cfb4 100644 --- a/networking/tls.c +++ b/networking/tls.c @@ -806,8 +806,6 @@ static int tls_xread_record(tls_state_t *tls, const char *expected) || xhdr->proto_min != TLS_MIN ) { sz = total < target ? total : target; - if (sz > 24) - sz = 24; /* don't flood */ bad_record_die(tls, expected, sz); } dbg("xhdr type:%d ver:%d.%d len:%d\n", -- cgit v1.2.3-55-g6feb From 7398892ac0592999397532ba168376edd402438c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Feb 2018 13:46:34 +0100 Subject: mkfs_ext2, mkfs_vfat: fix warnings in STORE_LE on big-endian platforms "warning: large integer implicitly truncated to unsigned type [-Woverflow]" Signed-off-by: Denys Vlasenko --- util-linux/mkfs_ext2.c | 6 +++--- util-linux/mkfs_vfat.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/util-linux/mkfs_ext2.c b/util-linux/mkfs_ext2.c index 8434dd6ad..f524bc239 100644 --- a/util-linux/mkfs_ext2.c +++ b/util-linux/mkfs_ext2.c @@ -83,11 +83,11 @@ char BUG_wrong_field_size(void); #define STORE_LE(field, value) \ do { \ if (sizeof(field) == 4) \ - field = SWAP_LE32(value); \ + field = SWAP_LE32((uint32_t)(value)); \ else if (sizeof(field) == 2) \ - field = SWAP_LE16(value); \ + field = SWAP_LE16((uint16_t)(value)); \ else if (sizeof(field) == 1) \ - field = (value); \ + field = (uint8_t)(value); \ else \ BUG_wrong_field_size(); \ } while (0) diff --git a/util-linux/mkfs_vfat.c b/util-linux/mkfs_vfat.c index 426854b1e..26a919536 100644 --- a/util-linux/mkfs_vfat.c +++ b/util-linux/mkfs_vfat.c @@ -210,11 +210,11 @@ void BUG_unsupported_field_size(void); #define STORE_LE(field, value) \ do { \ if (sizeof(field) == 4) \ - field = SWAP_LE32(value); \ + field = SWAP_LE32((uint32_t)(value)); \ else if (sizeof(field) == 2) \ - field = SWAP_LE16(value); \ + field = SWAP_LE16((uint16_t)(value)); \ else if (sizeof(field) == 1) \ - field = (value); \ + field = (uint8_t)(value); \ else \ BUG_unsupported_field_size(); \ } while (0) -- cgit v1.2.3-55-g6feb From 95121d98e6da12599246d8e25c3f300e422a06fb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 Feb 2018 15:52:35 +0100 Subject: poweroff: add a config option for people needing VERY early poweroff Signed-off-by: Denys Vlasenko --- init/halt.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/init/halt.c b/init/halt.c index c6c857f08..e6dcb1c67 100644 --- a/init/halt.c +++ b/init/halt.c @@ -24,6 +24,17 @@ //config: help //config: Stop all processes and reboot the system. //config: +//config:config FEATURE_WAIT_FOR_INIT +//config: bool "Before signaling init, make sure it is ready for it" +//config: default y +//config: depends on HALT || POWEROFF || REBOOT +//config: help +//config: In rare cases, poweroff may be commanded by firmware to OS +//config: even before init process exists. On Linux, this spawns +//config: "/sbin/poweroff" very early. This option adds code +//config: which checks that init is ready to receive poweroff +//config: commands. Code size increase of ~80 bytes. +//config: //config:config FEATURE_CALL_TELINIT //config: bool "Call telinit on shutdown and reboot" //config: default y @@ -108,6 +119,47 @@ static void write_wtmp(void) #define write_wtmp() ((void)0) #endif +#if ENABLE_FEATURE_WAIT_FOR_INIT +/* In Linux, "poweroff" may be spawned even before init. + * For example, with ACPI: + * linux/drivers/acpi/bus.c: + * static void sb_notify_work(struct work_struct *dummy) + * orderly_poweroff(true); + * linux/kernel/reboot.c: + * static int run_cmd(const char *cmd) + * ret = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); + * poweroff_cmd[] = "/sbin/poweroff"; + * static int __orderly_poweroff(bool force) + * ret = run_cmd(poweroff_cmd); + * + * We want to make sure init exists and listens to signals. + */ +static int init_was_not_there(void) +{ + enum { initial = 5 }; /* 5 seconds should be plenty for timeout */ + int cnt = initial - 1; + + /* Just existence of PID 1 does not mean it installed + * the handlers already. + */ +#if 0 + while (kill(1, 0) != 0 && --cnt >= 0) + sleep(1); +#endif + /* ... so let's wait for some evidence a usual startup event, + * mounting of /proc, happened. By that time init should be ready + * for signals. + */ + while (access("/proc/meminfo", F_OK) != 0 && --cnt >= 0) + sleep(1); + + /* Does it look like init wasn't there? */ + return (cnt != initial - 1); +} +#else + /* Assume it's always there */ +# define init_was_not_there() 0 +#endif int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int halt_main(int argc UNUSED_PARAM, char **argv) @@ -171,6 +223,8 @@ int halt_main(int argc UNUSED_PARAM, char **argv) if (!ENABLE_FEATURE_CALL_TELINIT) { /* bbox init assumed */ rc = kill(1, signals[which]); + if (init_was_not_there()) + rc = kill(1, signals[which]); } else { /* SysV style init assumed */ /* runlevels: -- cgit v1.2.3-55-g6feb From a84db18fc71d09e801df0ebca048d82e90b32c6a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Feb 2018 15:57:45 +0100 Subject: tar,unzip: postpone creation of symlinks with "suspicious" targets This mostly reverts commit bc9bbeb2b81001e8731cd2ae501c8fccc8d87cc7 "libarchive: do not extract unsafe symlinks unless $EXTRACT_UNSAFE_SYMLINKS=1" Users report that it is somewhat too restrictive. See https://bugs.busybox.net/show_bug.cgi?id=8411 In particular, this interferes with unpacking of busybox-based filesystems with links like "sbin/applet" -> "../bin/busybox". The change is made smaller by deleting ARCHIVE_EXTRACT_QUIET flag - it is unused since 2010, and removing conditionals on it allows commonalizing some error message codes. function old new delta create_or_remember_symlink - 94 +94 create_symlinks_from_list - 64 +64 tar_main 1002 1006 +4 unzip_main 2732 2724 -8 data_extract_all 984 891 -93 unsafe_symlink_target 147 - -147 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 1/2 up/down: 162/-248) Total: -86 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_all.c | 28 ++++---------- archival/libarchive/unsafe_symlink_target.c | 59 +++++++++++++---------------- archival/tar.c | 2 + archival/unzip.c | 25 ++++++------ include/bb_archive.h | 23 ++++++----- testsuite/tar.tests | 10 ++--- 6 files changed, 68 insertions(+), 79 deletions(-) diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index d3a6df5e8..8fa69ffaf 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -107,9 +107,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } } else if (existing_sb.st_mtime >= file_header->mtime) { - if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - && !S_ISDIR(file_header->mode) - ) { + if (!S_ISDIR(file_header->mode)) { bb_error_msg("%s not created: newer or " "same age file exists", dst_name); } @@ -125,7 +123,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) /* Handle hard links separately */ if (hard_link) { res = link(hard_link, dst_name); - if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + if (res != 0) { /* shared message */ bb_perror_msg("can't create %slink '%s' to '%s'", "hard", dst_name, hard_link @@ -165,10 +163,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } case S_IFDIR: res = mkdir(dst_name, file_header->mode); - if ((res == -1) + if ((res != 0) && (errno != EISDIR) /* btw, Linux doesn't return this */ && (errno != EEXIST) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { bb_perror_msg("can't make dir %s", dst_name); } @@ -198,27 +195,16 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) * * Untarring bug.tar would otherwise place evil.py in '/tmp'. */ - if (!unsafe_symlink_target(file_header->link_target)) { - res = symlink(file_header->link_target, dst_name); - if (res != 0 - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { - /* shared message */ - bb_perror_msg("can't create %slink '%s' to '%s'", - "sym", - dst_name, file_header->link_target - ); - } - } + create_or_remember_symlink(&archive_handle->symlink_placeholders, + file_header->link_target, + dst_name); break; case S_IFSOCK: case S_IFBLK: case S_IFCHR: case S_IFIFO: res = mknod(dst_name, file_header->mode, file_header->device); - if ((res == -1) - && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) - ) { + if (res != 0) { bb_perror_msg("can't create node %s", dst_name); } break; diff --git a/archival/libarchive/unsafe_symlink_target.c b/archival/libarchive/unsafe_symlink_target.c index 441ba8b24..8dcafeaa1 100644 --- a/archival/libarchive/unsafe_symlink_target.c +++ b/archival/libarchive/unsafe_symlink_target.c @@ -5,44 +5,37 @@ #include "libbb.h" #include "bb_archive.h" -int FAST_FUNC unsafe_symlink_target(const char *target) +void FAST_FUNC create_or_remember_symlink(llist_t **symlink_placeholders, + const char *target, + const char *linkname) { - const char *dot; - - if (target[0] == '/') { - const char *var; - unsafe: - var = getenv("EXTRACT_UNSAFE_SYMLINKS"); - if (var) { - if (LONE_CHAR(var, '1')) - return 0; /* pretend it's safe */ - return 1; /* "UNSAFE!" */ - } - bb_error_msg("skipping unsafe symlink to '%s' in archive," - " set %s=1 to extract", - target, - "EXTRACT_UNSAFE_SYMLINKS" + if (target[0] == '/' || strstr(target, "..")) { + llist_add_to(symlink_placeholders, + xasprintf("%s%c%s", linkname, '\0', target) + ); + return; + } + if (symlink(target, linkname) != 0) { + /* shared message */ + bb_perror_msg_and_die("can't create %slink '%s' to '%s'", + "sym", linkname, target ); - /* Prevent further messages */ - setenv("EXTRACT_UNSAFE_SYMLINKS", "0", 0); - return 1; /* "UNSAFE!" */ } +} - dot = target; - for (;;) { - dot = strchr(dot, '.'); - if (!dot) - return 0; /* safe target */ +void FAST_FUNC create_symlinks_from_list(llist_t *list) +{ + while (list) { + char *target; - /* Is it a path component starting with ".."? */ - if ((dot[1] == '.') - && (dot == target || dot[-1] == '/') - /* Is it exactly ".."? */ - && (dot[2] == '/' || dot[2] == '\0') - ) { - goto unsafe; + target = list->data + strlen(list->data) + 1; + if (symlink(target, list->data)) { + /* shared message */ + bb_error_msg_and_die("can't create %slink '%s' to '%s'", + "sym", + list->data, target + ); } - /* NB: it can even be trailing ".", should only add 1 */ - dot += 1; + list = list->link; } } diff --git a/archival/tar.c b/archival/tar.c index 9ed3821d5..415ebde0d 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -1244,6 +1244,8 @@ int tar_main(int argc UNUSED_PARAM, char **argv) while (get_header_tar(tar_handle) == EXIT_SUCCESS) bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ + create_symlinks_from_list(tar_handle->symlink_placeholders); + /* Check that every file that should have been extracted was */ while (tar_handle->accept) { if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) diff --git a/archival/unzip.c b/archival/unzip.c index da4b2a544..0d00d8dc9 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -345,7 +345,9 @@ static void unzip_create_leading_dirs(const char *fn) } #if ENABLE_FEATURE_UNZIP_CDF -static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) +static void unzip_extract_symlink(llist_t **symlink_placeholders, + zip_header_t *zip, + const char *dst_fn) { char *target; @@ -370,15 +372,9 @@ static void unzip_extract_symlink(zip_header_t *zip, const char *dst_fn) target[xstate.mem_output_size] = '\0'; #endif } - if (!unsafe_symlink_target(target)) { -//TODO: libbb candidate - if (symlink(target, dst_fn)) { - /* shared message */ - bb_perror_msg_and_die("can't create %slink '%s' to '%s'", - "sym", dst_fn, target - ); - } - } + create_or_remember_symlink(symlink_placeholders, + target, + dst_fn); free(target); } #endif @@ -490,6 +486,9 @@ int unzip_main(int argc, char **argv) llist_t *zaccept = NULL; llist_t *zreject = NULL; char *base_dir = NULL; +#if ENABLE_FEATURE_UNZIP_CDF + llist_t *symlink_placeholders = NULL; +#endif int i; char key_buf[80]; /* must match size used by my_fgets80 */ @@ -954,7 +953,7 @@ int unzip_main(int argc, char **argv) #if ENABLE_FEATURE_UNZIP_CDF if (S_ISLNK(file_mode)) { if (dst_fd != STDOUT_FILENO) /* not -p? */ - unzip_extract_symlink(&zip, dst_fn); + unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn); } else #endif { @@ -990,6 +989,10 @@ int unzip_main(int argc, char **argv) total_entries++; } +#if ENABLE_FEATURE_UNZIP_CDF + create_symlinks_from_list(symlink_placeholders); +#endif + if ((opts & OPT_l) && quiet <= 1) { if (!verbose) { // " Length Date Time Name\n" diff --git a/include/bb_archive.h b/include/bb_archive.h index 8ed20d70e..a5c61e95b 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -64,6 +64,9 @@ typedef struct archive_handle_t { /* Currently processed file's header */ file_header_t *file_header; + /* List of symlink placeholders */ + llist_t *symlink_placeholders; + /* Process the header component, e.g. tar -t */ void FAST_FUNC (*action_header)(const file_header_t *); @@ -119,15 +122,14 @@ typedef struct archive_handle_t { #define ARCHIVE_RESTORE_DATE (1 << 0) #define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) #define ARCHIVE_UNLINK_OLD (1 << 2) -#define ARCHIVE_EXTRACT_QUIET (1 << 3) -#define ARCHIVE_EXTRACT_NEWER (1 << 4) -#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) -#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) -#define ARCHIVE_NUMERIC_OWNER (1 << 7) -#define ARCHIVE_O_TRUNC (1 << 8) -#define ARCHIVE_REMEMBER_NAMES (1 << 9) +#define ARCHIVE_EXTRACT_NEWER (1 << 3) +#define ARCHIVE_DONT_RESTORE_OWNER (1 << 4) +#define ARCHIVE_DONT_RESTORE_PERM (1 << 5) +#define ARCHIVE_NUMERIC_OWNER (1 << 6) +#define ARCHIVE_O_TRUNC (1 << 7) +#define ARCHIVE_REMEMBER_NAMES (1 << 8) #if ENABLE_RPM -#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) +#define ARCHIVE_REPLACE_VIA_RENAME (1 << 9) #endif @@ -197,7 +199,10 @@ void seek_by_jump(int fd, off_t amount) FAST_FUNC; void seek_by_read(int fd, off_t amount) FAST_FUNC; const char *strip_unsafe_prefix(const char *str) FAST_FUNC; -int unsafe_symlink_target(const char *target) FAST_FUNC; +void create_or_remember_symlink(llist_t **symlink_placeholders, + const char *target, + const char *linkname) FAST_FUNC; +void create_symlinks_from_list(llist_t *list) FAST_FUNC; void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; diff --git a/testsuite/tar.tests b/testsuite/tar.tests index b7cd74ca5..1675b07b1 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -279,7 +279,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2 testing "tar does not extract into symlinks" "\ >>/tmp/passwd && uudecode -o input && tar xf input 2>&1 && rm passwd; cat /tmp/passwd; echo \$? " "\ -tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract +tar: can't create symlink 'passwd' to '/tmp/passwd' 0 " \ "" "\ @@ -299,7 +299,7 @@ optional UUDECODE FEATURE_TAR_AUTODETECT FEATURE_SEAMLESS_BZ2 testing "tar -k does not extract into symlinks" "\ >>/tmp/passwd && uudecode -o input && tar xf input -k 2>&1 && rm passwd; cat /tmp/passwd; echo \$? " "\ -tar: skipping unsafe symlink to '/tmp/passwd' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract +tar: can't create symlink 'passwd' to '/tmp/passwd' 0 " \ "" "\ @@ -324,11 +324,11 @@ rm -rf etc usr ' "\ etc/ssl/certs/3b2716e5.0 etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem -tar: skipping unsafe symlink to '/usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract etc/ssl/certs/f80cc7f6.0 usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt 0 etc/ssl/certs/3b2716e5.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem +etc/ssl/certs/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem -> /usr/share/ca-certificates/mozilla/EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.crt etc/ssl/certs/f80cc7f6.0 -> EBG_Elektronik_Sertifika_Hizmet_Sağlayıcısı.pem " \ "" "" @@ -346,9 +346,9 @@ ls symlink/bb_test_evilfile ' "\ anything.txt symlink -tar: skipping unsafe symlink to '/tmp' in archive, set EXTRACT_UNSAFE_SYMLINKS=1 to extract symlink/bb_test_evilfile -0 +tar: can't create symlink 'symlink' to '/tmp' +1 ls: /tmp/bb_test_evilfile: No such file or directory ls: bb_test_evilfile: No such file or directory symlink/bb_test_evilfile -- cgit v1.2.3-55-g6feb From b083e8cc538ba6b27e19da541ca6a0f7ceb7daee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 20 Feb 2018 17:58:19 +0100 Subject: umount: fix "umount -t FSTYPE MNTPOINT" acting as if -a is specified While at it, add -t to --help, and fix comments which say that -t is ignored function old new delta packed_usage 32427 32444 +17 umount_main 558 552 -6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 17/-6) Total: 11 bytes Signed-off-by: Denys Vlasenko --- util-linux/umount.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/util-linux/umount.c b/util-linux/umount.c index b45cd8a6b..e2329f8b3 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -57,6 +57,7 @@ //usage: IF_FEATURE_MOUNT_LOOP( //usage: "\n -d Free loop device if it has been used" //usage: ) +//usage: "\n -t FSTYPE[,...] Unmount only these filesystem type(s)" //usage: //usage:#define umount_example_usage //usage: "$ umount /dev/hdc1\n" @@ -81,8 +82,8 @@ static struct mntent *getmntent_r(FILE* stream, struct mntent* result, } #endif -/* ignored: -c -v -t -i */ -#define OPTION_STRING "fldnra" "cvt:i" +/* ignored: -c -v -i */ +#define OPTION_STRING "fldnrat:" "cvi" #define OPT_FORCE (1 << 0) // Same as MNT_FORCE #define OPT_LAZY (1 << 1) // Same as MNT_DETACH #define OPT_FREELOOP (1 << 2) @@ -143,7 +144,8 @@ int umount_main(int argc UNUSED_PARAM, char **argv) } // If we're not umounting all, we need at least one argument. - if (!(opt & OPT_ALL) && !fstype) { + // Note: "-t FSTYPE" does not imply -a. + if (!(opt & OPT_ALL)) { if (!argv[0]) bb_show_usage(); m = NULL; -- cgit v1.2.3-55-g6feb From 79cda9522ad390f1bdb7ba1025b1c81bbd1613e6 Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Tue, 20 Feb 2018 19:28:02 +0100 Subject: ip link: support "add TYPE vrf", improve --help VRF interfaces have a mandatory table parameter, which needs to be specified using a RTNL attribute. function old new delta do_add_or_delete 1150 1254 +104 packed_usage 32444 32546 +102 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 206/0) Total: 206 bytes Signed-off-by: Jan Luebbe Signed-off-by: Denys Vlasenko --- networking/ip.c | 57 +++++++++++++++++++++++++++++++++++++++--- networking/libiproute/iplink.c | 24 +++++++++++++++++- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/networking/ip.c b/networking/ip.c index 0bc0edc57..665f9bcce 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -155,11 +155,60 @@ //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 //usage:#define iplink_trivial_usage -//usage: "set IFACE [up|down] [arp on|off] | show [IFACE]" -//usage:#define iplink_full_usage "\n\n" -//usage: "iplink set IFACE [up|down] [arp on|off] [multicast on|off] [promisc on|off]\n" -//usage: " [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" +//usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" +//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]" +// * short help shows only "set" command, long help continues (with just one "\n") +// * and shows all other commands: +//usage:#define iplink_full_usage "\n" +//usage: "iplink add [link IFACE] IFACE [address MAC] type TYPE [ARGS]\n" +//usage: "iplink delete IFACE type TYPE [ARGS]\n" +//usage: " TYPE ARGS := vlan VLANARGS | vrf table NUM\n" +//usage: " VLANARGS := id VLANID [protocol 802.1q|802.1ad] [reorder_hdr on|off]\n" +//usage: " [gvrp on|off] [mvrp on|off] [loose_binding on|off]\n" //usage: "iplink show [IFACE]" +//upstream man ip-link: +//===================== +//ip link add [link DEV] [ name ] NAME +// [ txqueuelen PACKETS ] +// [ address LLADDR ] +// [ broadcast LLADDR ] +// [ mtu MTU ] [index IDX ] +// [ numtxqueues QUEUE_COUNT ] +// [ numrxqueues QUEUE_COUNT ] +// type TYPE [ ARGS ] +// ip link delete { DEVICE | dev DEVICE | group DEVGROUP } type TYPE [ ARGS ] +// ip link set { DEVICE | dev DEVICE | group DEVGROUP } [ { up | down } ] +// [ arp { on | off } ] +// [ dynamic { on | off } ] +// [ multicast { on | off } ] +// [ allmulticast { on | off } ] +// [ promisc { on | off } ] +// [ trailers { on | off } ] +// [ txqueuelen PACKETS ] +// [ name NEWNAME ] +// [ address LLADDR ] +// [ broadcast LLADDR ] +// [ mtu MTU ] +// [ netns { PID | NAME } ] +// [ link-netnsid ID ] +// [ alias NAME ] +// [ vf NUM [ mac LLADDR ] +// [ vlan VLANID [ qos VLAN-QOS ] ] +// [ rate TXRATE ] +// [ spoofchk { on | off} ] +// [ query_rss { on | off} ] +// [ state { auto | enable | disable} ] ] +// [ trust { on | off} ] ] +// [ master DEVICE ] +// [ nomaster ] +// [ addrgenmode { eui64 | none | stable_secret | random } ] +// [ protodown { on | off } ] +// ip link show [ DEVICE | group GROUP ] [up] [master DEV] [type TYPE] +// ip link help [ TYPE ] +//TYPE := { vlan | veth | vcan | dummy | ifb | macvlan | macvtap | +// bridge | bond | ipoib | ip6tnl | ipip | sit | vxlan | +// gre | gretap | ip6gre | ip6gretap | vti | nlmon | +// bond_slave | ipvlan | geneve | bridge_slave | vrf } //usage: //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 //usage:#define iproute_trivial_usage diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index f38fba055..312283318 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -525,6 +525,24 @@ static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); } +static void vrf_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) +{ +/* IFLA_VRF_TABLE is an enum, not a define - + * can't test "defined(IFLA_VRF_TABLE)". + */ +#if !defined(IFLA_VRF_MAX) +# define IFLA_VRF_TABLE 1 +#endif + uint32_t table; + + if (strcmp(*argv, "table") != 0) + invarg_1_to_2(*argv, "type vrf"); + + NEXT_ARG(); + table = get_u32(*argv, "table"); + addattr_l(n, size, IFLA_VRF_TABLE, &table, sizeof(table)); +} + #ifndef NLMSG_TAIL #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) @@ -563,6 +581,8 @@ static int do_add_or_delete(char **argv, const unsigned rtm) if (rtm == RTM_NEWLINK) req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; + /* NB: update iplink_full_usage if you extend this code */ + while (*argv) { arg = index_in_substrings(keywords, *argv); if (arg == ARG_type) { @@ -582,7 +602,7 @@ static int do_add_or_delete(char **argv, const unsigned rtm) } else if (arg == ARG_address) { NEXT_ARG(); address_str = *argv; - dbg("address_str:'%s'", name_str); + dbg("address_str:'%s'", address_str); } else { if (arg == ARG_dev) { if (dev_str) @@ -609,6 +629,8 @@ static int do_add_or_delete(char **argv, const unsigned rtm) if (strcmp(type_str, "vlan") == 0) vlan_parse_opt(argv, &req.n, sizeof(req)); + else if (strcmp(type_str, "vrf") == 0) + vrf_parse_opt(argv, &req.n, sizeof(req)); data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; } -- cgit v1.2.3-55-g6feb From e789c3bea18181723c4ae7d761ec30926d182cfb Mon Sep 17 00:00:00 2001 From: Jan Luebbe Date: Wed, 14 Feb 2018 14:05:27 +0100 Subject: iplink: implement support for selecting a master interface Attaching an interface to a VRF is done by setting the interface's master. Besides VRF, this can also be used for bridges. function old new delta set_master - 142 +142 do_iplink 1262 1357 +95 packed_usage 32546 32539 -7 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 237/-7) Total: 230 bytes Signed-off-by: Jan Luebbe Signed-off-by: Denys Vlasenko --- networking/ip.c | 3 ++- networking/libiproute/iplink.c | 38 ++++++++++++++++++++++++++++++++++++++ networking/tcpudp.c | 2 +- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/networking/ip.c b/networking/ip.c index 665f9bcce..accf90759 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -156,7 +156,8 @@ //--------------123456789.123456789.123456789.123456789.123456789.123456789.123456789.123....79 //usage:#define iplink_trivial_usage //usage: /*Usage:iplink*/"set IFACE [up|down] [arp on|off] [multicast on|off]\n" -//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]" +//usage: " [promisc on|off] [mtu NUM] [name NAME] [qlen NUM] [address MAC]\n" +//usage: " [master IFACE | nomaster]\n" // * short help shows only "set" command, long help continues (with just one "\n") // * and shows all other commands: //usage:#define iplink_full_usage "\n" diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 312283318..2aa8b683b 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -127,6 +127,31 @@ static void set_mtu(char *dev, int mtu) close(s); } +/* Exits on error */ +static void set_master(char *dev, int master) +{ + struct rtnl_handle rth; + struct { + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; + } req; + + memset(&req, 0, sizeof(req)); + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_NEWLINK; + req.i.ifi_family = preferred_family; + + xrtnl_open(&rth); + req.i.ifi_index = xll_name_to_index(dev); + //printf("master %i for %i\n", master, req.i.ifi_index); + addattr_l(&req.n, sizeof(req), IFLA_MASTER, &master, 4); + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) + xfunc_die(); +} + /* Exits on error */ static int get_address(char *dev, int *htype) { @@ -200,6 +225,7 @@ static int do_set(char **argv) uint32_t flags = 0; int qlen = -1; int mtu = -1; + int master = -1; char *newaddr = NULL; char *newbrd = NULL; struct ifreq ifr0, ifr1; @@ -209,9 +235,11 @@ static int do_set(char **argv) static const char keywords[] ALIGN1 = "up\0""down\0""name\0""mtu\0""qlen\0""multicast\0" "arp\0""promisc\0""address\0" + "master\0""nomaster\0" "dev\0" /* must be last */; enum { ARG_up = 0, ARG_down, ARG_name, ARG_mtu, ARG_qlen, ARG_multicast, ARG_arp, ARG_promisc, ARG_addr, + ARG_master, ARG_nomaster, ARG_dev }; enum { PARM_on = 0, PARM_off }; smalluint key; @@ -243,6 +271,11 @@ static int do_set(char **argv) } else if (key == ARG_addr) { NEXT_ARG(); newaddr = *argv; + } else if (key == ARG_master) { + NEXT_ARG(); + master = xll_name_to_index(*argv); + } else if (key == ARG_nomaster) { + master = 0; } else if (key >= ARG_dev) { /* ^^^^^^ ">=" here results in "dev IFACE" treated as default */ if (key == ARG_dev) { @@ -427,6 +460,9 @@ static int do_set(char **argv) if (mtu != -1) { set_mtu(dev, mtu); } + if (master != -1) { + set_master(dev, master); + } if (mask) do_chflags(dev, flags, mask); return 0; @@ -673,6 +709,8 @@ int FAST_FUNC do_iplink(char **argv) { static const char keywords[] ALIGN1 = "add\0""delete\0""set\0""show\0""lst\0""list\0"; + + xfunc_error_retval = 2; //TODO: move up to "ip"? Is it the common rule for all "ip" tools? if (*argv) { int key = index_in_substrings(keywords, *argv); if (key < 0) /* invalid argument */ diff --git a/networking/tcpudp.c b/networking/tcpudp.c index d4c69e0f7..2feb63a01 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -318,7 +318,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) sslser = user; client = 0; if ((getuid() == 0) && !(opts & OPT_u)) { - xfunc_exitcode = 100; + xfunc_error_retval = 100; bb_error_msg_and_die(bb_msg_you_must_be_root); } if (opts & OPT_u) -- cgit v1.2.3-55-g6feb From 7d285c78a35b1e745f7c6f27e31d73677ad2943a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 21 Feb 2018 20:08:54 +0100 Subject: sort: fix -s. Closes 10671 function old new delta sort_main 786 862 +76 compare_keys 720 794 +74 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 150/0) Total: 150 bytes Signed-off-by: Denys Vlasenko --- coreutils/sort.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 57 insertions(+), 12 deletions(-) diff --git a/coreutils/sort.c b/coreutils/sort.c index ceea24491..8ffd0cf44 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -62,9 +62,9 @@ //usage: "\n -u Suppress duplicate lines" //usage: IF_FEATURE_SORT_BIG( //usage: "\n -z Lines are terminated by NUL, not newline" -////usage: "\n -m Ignored for GNU compatibility" -////usage: "\n -S BUFSZ Ignored for GNU compatibility" -////usage: "\n -T TMPDIR Ignored for GNU compatibility" +///////: "\n -m Ignored for GNU compatibility" +///////: "\n -S BUFSZ Ignored for GNU compatibility" +///////: "\n -T TMPDIR Ignored for GNU compatibility" //usage: ) //usage: //usage:#define sort_example_usage @@ -117,6 +117,7 @@ enum { FLAG_k = 0x10000, FLAG_t = 0x20000, FLAG_bb = 0x80000000, /* Ignore trailing blanks */ + FLAG_no_tie_break = 0x40000000, }; #if ENABLE_FEATURE_SORT_BIG @@ -340,10 +341,34 @@ static int compare_keys(const void *xarg, const void *yarg) #endif } /* for */ - /* Perform fallback sort if necessary */ - if (!retval && !(option_mask32 & FLAG_s)) { - flags = option_mask32; - retval = strcmp(*(char **)xarg, *(char **)yarg); + if (retval == 0) { + /* So far lines are "the same" */ + + if (option_mask32 & FLAG_s) { + /* "Stable sort": later line is "smaller", + * IOW: do not allow qsort() to swap equal lines. + */ + uint32_t *p32; + uint32_t x32, y32; + char *line; + unsigned len; + + line = *(char**)xarg; + len = (strlen(line) + 4) & (~3u); + p32 = (void*)(line + len); + x32 = *p32; + line = *(char**)yarg; + len = (strlen(line) + 4) & (~3u); + p32 = (void*)(line + len); + y32 = *p32; + + retval = x32 > y32; + } else + if (!(option_mask32 & FLAG_no_tie_break)) { + /* fallback sort */ + flags = option_mask32; + retval = strcmp(*(char **)xarg, *(char **)yarg); + } } if (flags & FLAG_r) @@ -368,7 +393,7 @@ static unsigned str2u(char **str) int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sort_main(int argc UNUSED_PARAM, char **argv) { - char *line, **lines; + char **lines; char *str_ignored, *str_o, *str_t; llist_t *lst_k = NULL; int i; @@ -457,7 +482,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv) * do not continue to next file: */ FILE *fp = xfopen_stdin(*argv); for (;;) { - line = GET_LINE(fp); + char *line = GET_LINE(fp); if (!line) break; lines = xrealloc_vector(lines, 6, linecount); @@ -482,15 +507,35 @@ int sort_main(int argc UNUSED_PARAM, char **argv) return EXIT_SUCCESS; } #endif + + /* For stable sort, store original line position beyond terminating NUL */ + if (option_mask32 & FLAG_s) { + for (i = 0; i < linecount; i++) { + uint32_t *p32; + char *line; + unsigned len; + + line = lines[i]; + len = (strlen(line) + 4) & (~3u); + lines[i] = line = xrealloc(line, len + 4); + p32 = (void*)(line + len); + *p32 = i; + } + /*option_mask32 |= FLAG_no_tie_break;*/ + /* ^^^redundant: if FLAG_s, compare_keys() does no tie break */ + } + /* Perform the actual sort */ qsort(lines, linecount, sizeof(lines[0]), compare_keys); /* Handle -u */ if (option_mask32 & FLAG_u) { int j = 0; - /* coreutils 6.3 drop lines for which only key is the same */ - /* -- disabling last-resort compare... */ - option_mask32 |= FLAG_s; + /* coreutils 6.3 drop lines for which only key is the same + * -- disabling last-resort compare, or else compare_keys() + * will be the same only for completely identical lines. + */ + option_mask32 |= FLAG_no_tie_break; for (i = 1; i < linecount; i++) { if (compare_keys(&lines[j], &lines[i]) == 0) free(lines[i]); -- cgit v1.2.3-55-g6feb From 2af5e3fac394a922bcf7752be25128879405a21a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 21 Feb 2018 20:13:39 +0100 Subject: libbb: compile capability code only if FEATURE_SETPRIV_CAPABILITIES or RUN_INIT Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 ++--- libbb/capability.c | 3 ++- util-linux/switch_root.c | 6 ++++++ 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index c02621d94..f1ab1ca6f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1488,6 +1488,7 @@ extern void run_shell(const char *shell, int loginshell, const char **args) NORE */ const char *get_shell_name(void) FAST_FUNC; +#if ENABLE_FEATURE_SETPRIV_CAPABILITIES || ENABLE_RUN_INIT unsigned cap_name_to_number(const char *cap) FAST_FUNC; void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; void drop_capability(int cap_ordinal) FAST_FUNC; @@ -1499,9 +1500,7 @@ struct caps { \ struct __user_cap_data_struct data[2]; \ } void getcaps(void *caps) FAST_FUNC; - -unsigned cap_name_to_number(const char *name) FAST_FUNC; -void printf_cap(const char *pfx, unsigned cap_no) FAST_FUNC; +#endif #if ENABLE_SELINUX extern void renew_current_security_context(void) FAST_FUNC; diff --git a/libbb/capability.c b/libbb/capability.c index f60062bfc..6587dcbf7 100644 --- a/libbb/capability.c +++ b/libbb/capability.c @@ -3,7 +3,8 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//kbuild:lib-$(CONFIG_PLATFORM_LINUX) += capability.o +//kbuild:lib-$(CONFIG_FEATURE_SETPRIV_CAPABILITIES) += capability.o +//kbuild:lib-$(CONFIG_RUN_INIT) += capability.o #include // #include diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c index 2d1802b79..947dd0cdc 100644 --- a/util-linux/switch_root.c +++ b/util-linux/switch_root.c @@ -39,6 +39,12 @@ #include #if ENABLE_RUN_INIT # include +# ifndef PR_CAPBSET_READ +# define PR_CAPBSET_READ 23 +# endif +# ifndef PR_CAPBSET_DROP +# define PR_CAPBSET_DROP 24 +# endif # include // #include // This header is in libcap, but the functions are in libc. -- cgit v1.2.3-55-g6feb From 427ae18348a908719ff60383b33041bce5e5393e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Feb 2018 10:54:55 +0100 Subject: sort: in -s handling, return 1/-1, not 1/0 compare result function old new delta compare_keys 794 795 +1 Signed-off-by: Denys Vlasenko --- coreutils/sort.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coreutils/sort.c b/coreutils/sort.c index 8ffd0cf44..c24b62681 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -345,7 +345,7 @@ static int compare_keys(const void *xarg, const void *yarg) /* So far lines are "the same" */ if (option_mask32 & FLAG_s) { - /* "Stable sort": later line is "smaller", + /* "Stable sort": later line is "greater than", * IOW: do not allow qsort() to swap equal lines. */ uint32_t *p32; @@ -362,7 +362,8 @@ static int compare_keys(const void *xarg, const void *yarg) p32 = (void*)(line + len); y32 = *p32; - retval = x32 > y32; + /* If x > y, 1, else -1 */ + retval = (x32 > y32) * 2 - 1; } else if (!(option_mask32 & FLAG_no_tie_break)) { /* fallback sort */ -- cgit v1.2.3-55-g6feb From 2709acbbda8a82ccd18abfe191dcb9dd530e4c57 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Feb 2018 11:03:23 +0100 Subject: sort: fix potentially buggy use of OPT_STR This also makes OPT_STR reused: text data bss dec hex filename 930979 481 6852 938312 e5148 busybox_old 930954 481 6852 938287 e512f busybox_unstripped ^^^^^^ Signed-off-by: Denys Vlasenko --- coreutils/sort.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/coreutils/sort.c b/coreutils/sort.c index c24b62681..b39297a26 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -85,16 +85,7 @@ #include "libbb.h" -/* This is a NOEXEC applet. Be very careful! */ - - -/* - sort [-m][-o output][-bdfinru][-t char][-k keydef]... [file...] - sort -c [-bdfinru][-t char][-k keydef][file] -*/ - /* These are sort types */ -#define OPT_STR "ngMucszbrdfimS:T:o:k:*t:" enum { FLAG_n = 1, /* Numeric sort */ FLAG_g = 2, /* Sort using strtod() */ @@ -120,6 +111,15 @@ enum { FLAG_no_tie_break = 0x40000000, }; +static const char sort_opt_str[] ALIGN1 = "^" + "ngMucszbrdfimS:T:o:k:*t:" + "\0" "o--o:t--t"/*-t, -o: at most one of each*/; +/* + * OPT_STR must not be string literal, needs to have stable address: + * code uses "strchr(OPT_STR,c) - OPT_STR" idiom. + */ +#define OPT_STR (sort_opt_str + 1) + #if ENABLE_FEATURE_SORT_BIG static char key_separator; @@ -129,6 +129,10 @@ static struct sort_key { unsigned flags; } *key_list; + +/* This is a NOEXEC applet. Be very careful! */ + + static char *get_key(char *str, struct sort_key *key, int flags) { int start = start; /* for compiler */ @@ -404,9 +408,8 @@ int sort_main(int argc UNUSED_PARAM, char **argv) xfunc_error_retval = 2; /* Parse command line options */ - opts = getopt32(argv, "^" - OPT_STR - "\0" "o--o:t--t"/*-t, -o: at most one of each*/, + opts = getopt32(argv, + sort_opt_str, &str_ignored, &str_ignored, &str_o, &lst_k, &str_t ); /* global b strips leading and trailing spaces */ -- cgit v1.2.3-55-g6feb From 3177626033fa58fcb60e29009936f08f16e6a99c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 22 Feb 2018 12:14:55 +0100 Subject: od: move address_fmt[] from data to globals. 8 less bytes in data section function old new delta od_main 2164 2179 +15 address_fmt 8 - -8 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 1/0 up/down: 15/-8) Total: 7 bytes text data bss dec hex filename 930954 481 6852 938287 e512f busybox_old 930977 473 6852 938302 e513e busybox_unstripped Signed-off-by: Denys Vlasenko --- coreutils/od_bloaty.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index c9bb3b85f..4cae0c529 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -211,7 +211,14 @@ struct globals { bool not_first; bool prev_pair_equal; + + char address_fmt[sizeof("%0n"OFF_FMT"xc")]; } FIX_ALIASING; +/* Corresponds to 'x' above */ +#define address_base_char G.address_fmt[sizeof(G.address_fmt)-3] +/* Corresponds to 'n' above */ +#define address_pad_len_char G.address_fmt[2] + #if !ENABLE_LONG_OPTS enum { G_pseudo_offset = 0 }; #endif @@ -220,6 +227,7 @@ enum { G_pseudo_offset = 0 }; setup_common_bufsiz(); \ BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ G.bytes_per_block = 32; \ + strcpy(G.address_fmt, "%0n"OFF_FMT"xc"); \ } while (0) @@ -844,18 +852,12 @@ format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM) { } -static char address_fmt[] ALIGN1 = "%0n"OFF_FMT"xc"; -/* Corresponds to 'x' above */ -#define address_base_char address_fmt[sizeof(address_fmt)-3] -/* Corresponds to 'n' above */ -#define address_pad_len_char address_fmt[2] - static void format_address_std(off_t address, char c) { /* Corresponds to 'c' */ - address_fmt[sizeof(address_fmt)-2] = c; - printf(address_fmt, address); + G.address_fmt[sizeof(G.address_fmt)-2] = c; + printf(G.address_fmt, address); } #if ENABLE_LONG_OPTS -- cgit v1.2.3-55-g6feb From bf39d97e9d9422537970ed8c3af1b8270bdf0ac0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 23 Feb 2018 16:29:26 +0100 Subject: Fix install with hardlinks and a custom PREFIX. Closes 10801 Trying to install busybox with hardlinks and a custom PREFIX will fail for applets not in the /bin directory, because relative pathnames are used. applets/install.sh is *supposed to* use the absolute pathname for hardlinks but it fails to do so because the wrong check is used in the if statement. While fixing it, shore up other sloppy coding in applets/install.sh Signed-off-by: Denys Vlasenko --- applets/install.sh | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/applets/install.sh b/applets/install.sh index ae99381d7..c75a78e9d 100755 --- a/applets/install.sh +++ b/applets/install.sh @@ -38,7 +38,7 @@ while [ ${#} -gt 0 ]; do shift done -if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then +if [ -n "$DO_INSTALL_LIBS" ] && [ x"$DO_INSTALL_LIBS" != x"n" ]; then # get the target dir for the libs # assume it starts with lib libdir=$($CC -print-file-name=libc.so | \ @@ -58,7 +58,7 @@ if [ -n "$DO_INSTALL_LIBS" ] && [ "$DO_INSTALL_LIBS" != "n" ]; then done fi -if [ "$cleanup" = "1" ] && [ -e "$prefix/bin/busybox" ]; then +if [ x"$cleanup" = x"1" ] && [ -e "$prefix/bin/busybox" ]; then inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'` sub_shell_it=` cd "$prefix" @@ -81,13 +81,13 @@ install -m 755 busybox "$prefix/bin/busybox" || exit 1 for i in $h; do appdir=`dirname "$i"` app=`basename "$i"` - if [ "$noclobber" = "1" ] && [ -e "$prefix/$i" ]; then + if [ x"$noclobber" = x"1" ] && [ -e "$prefix/$i" ]; then echo " $prefix/$i already exists" continue fi mkdir -p "$prefix/$appdir" || exit 1 - if [ "$scriptwrapper" = "y" ]; then - if [ "$swrapall" != "y" ] && [ "$i" = "/bin/sh" ]; then + if [ x"$scriptwrapper" = x"y" ]; then + if [ x"$swrapall" != x"y" ] && [ x"$i" = x"/bin/sh" ]; then ln $linkopts busybox "$prefix/$i" || exit 1 else rm -f "$prefix/$i" @@ -95,17 +95,17 @@ for i in $h; do chmod +x "$prefix/$i" fi echo " $prefix/$i" - elif [ "$binaries" = "y" ]; then + elif [ x"$binaries" = x"y" ]; then # Copy the binary over rather - if [ -e $sharedlib_dir/$app ]; then + if [ -e "$sharedlib_dir/$app" ]; then echo " Copying $sharedlib_dir/$app to $prefix/$i" - cp -pPR $sharedlib_dir/$app $prefix/$i || exit 1 + cp -pPR "$sharedlib_dir/$app" "$prefix/$i" || exit 1 else echo "Error: Could not find $sharedlib_dir/$app" exit 1 fi else - if [ "$2" = "--hardlinks" ]; then + if [ x"$linkopts" = x"-f" ]; then bb_path="$prefix/bin/busybox" else case "$appdir" in -- cgit v1.2.3-55-g6feb From 58cd6e1adef72e0c71c4ab9213196a720c9a926d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 23 Feb 2018 17:00:23 +0100 Subject: df: 4TB+ support on 32 bits arch Reported for Pascal Bellard. function old new delta df_main 1054 1065 +11 Signed-off-by: Denys Vlasenko --- coreutils/df.c | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/coreutils/df.c b/coreutils/df.c index 4076b5fec..1ed09d015 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -91,8 +91,6 @@ static unsigned long kscale(unsigned long b, unsigned long bs) int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int df_main(int argc UNUSED_PARAM, char **argv) { - unsigned long blocks_used; - unsigned blocks_percent_used; unsigned long df_disp_hr = 1024; int status = EXIT_SUCCESS; unsigned opt; @@ -222,20 +220,29 @@ int df_main(int argc UNUSED_PARAM, char **argv) s.f_frsize = s.f_bsize; if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) { + unsigned long long blocks_used; + unsigned long long blocks_total; + unsigned blocks_percent_used; + if (opt & OPT_INODE) { s.f_blocks = s.f_files; s.f_bavail = s.f_bfree = s.f_ffree; s.f_frsize = 1; - if (df_disp_hr) df_disp_hr = 1; } blocks_used = s.f_blocks - s.f_bfree; - blocks_percent_used = 0; - if (blocks_used + s.f_bavail) { - blocks_percent_used = (blocks_used * 100ULL - + (blocks_used + s.f_bavail)/2 - ) / (blocks_used + s.f_bavail); + blocks_total = blocks_used + s.f_bavail; + blocks_percent_used = blocks_total; /* 0% if blocks_total == 0, else... */ + if (blocks_total != 0) { + /* Downscale sizes for narrower division */ + unsigned u; + while (blocks_total >= INT_MAX / 101) { + blocks_total >>= 1; + blocks_used >>= 1; + } + u = (unsigned)blocks_used * 100u + (unsigned)blocks_total / 2; + blocks_percent_used = u / (unsigned)blocks_total; } /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */ -- cgit v1.2.3-55-g6feb From e20a703fd34fa0f3ac17c53d868735a99d794a3e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 23 Feb 2018 17:08:32 +0100 Subject: df: do "rootfs" check sooner function old new delta df_main 1065 1064 -1 Signed-off-by: Denys Vlasenko --- coreutils/df.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/coreutils/df.c b/coreutils/df.c index 1ed09d015..50dccac52 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -206,6 +206,11 @@ int df_main(int argc UNUSED_PARAM, char **argv) } device = mount_entry->mnt_fsname; + + /* GNU coreutils 6.10 skips certain mounts, try to be compatible */ + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) + continue; + mount_point = mount_entry->mnt_dir; fs_type = mount_entry->mnt_type; @@ -245,10 +250,6 @@ int df_main(int argc UNUSED_PARAM, char **argv) blocks_percent_used = u / (unsigned)blocks_total; } - /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */ - if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) - continue; - #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY if (strcmp(device, "/dev/root") == 0) { /* Adjusts device to be the real root device, -- cgit v1.2.3-55-g6feb From 23286900da2f38de6b7f0c8318263eac4ce774d1 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 25 Feb 2018 20:09:54 +0100 Subject: lineedit: allow window size tracking to be disabled function old new delta lineedit_read_key 269 261 -8 win_changed 47 - -47 read_line_input 3884 3821 -63 cmdedit_setwidth 63 - -63 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 0/2 up/down: 0/-181) Total: -181 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- libbb/Config.src | 5 +++++ libbb/lineedit.c | 18 ++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/libbb/Config.src b/libbb/Config.src index 3c1b064b6..fdf8bbb28 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -149,6 +149,11 @@ config FEATURE_EDITING_FANCY_PROMPT Setting this option allows for prompts to use things like \w and \$ and escape codes. +config FEATURE_EDITING_WINCH + bool "Enable automatic tracking of window size changes" + default y + depends on FEATURE_EDITING + config FEATURE_EDITING_ASK_TERMINAL bool "Query cursor position from terminal" default n diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 896bbc88c..678c4d29c 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -151,9 +151,11 @@ struct lineedit_statics { unsigned num_matches; #endif +#if ENABLE_FEATURE_EDITING_WINCH unsigned SIGWINCH_saved; volatile unsigned SIGWINCH_count; volatile smallint ok_to_redraw; +#endif #if ENABLE_FEATURE_EDITING_VI # define DELBUFSIZ 128 @@ -165,8 +167,10 @@ struct lineedit_statics { smallint sent_ESC_br6n; #endif +#if ENABLE_FEATURE_EDITING_WINCH /* Largish struct, keeping it last results in smaller code */ struct sigaction SIGWINCH_handler; +#endif }; /* See lineedit_ptr_hack.c */ @@ -2030,6 +2034,7 @@ static void parse_and_put_prompt(const char *prmt_ptr) } #endif +#if ENABLE_FEATURE_EDITING_WINCH static void cmdedit_setwidth(void) { int new_y; @@ -2054,6 +2059,7 @@ static void win_changed(int nsig UNUSED_PARAM) S.SIGWINCH_count++; } } +#endif static int lineedit_read_key(char *read_key_buffer, int timeout) { @@ -2072,9 +2078,9 @@ static int lineedit_read_key(char *read_key_buffer, int timeout) * * Note: read_key sets errno to 0 on success. */ - S.ok_to_redraw = 1; + IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 1;) ic = read_key(STDIN_FILENO, read_key_buffer, timeout); - S.ok_to_redraw = 0; + IF_FEATURE_EDITING_WINCH(S.ok_to_redraw = 0;) if (errno) { #if ENABLE_UNICODE_SUPPORT if (errno == EAGAIN && unicode_idx != 0) @@ -2408,11 +2414,12 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman parse_and_put_prompt(prompt); ask_terminal(); +#if ENABLE_FEATURE_EDITING_WINCH /* Install window resize handler (NB: after *all* init is complete) */ S.SIGWINCH_handler.sa_handler = win_changed; S.SIGWINCH_handler.sa_flags = SA_RESTART; sigaction(SIGWINCH, &S.SIGWINCH_handler, &S.SIGWINCH_handler); - +#endif read_key_buffer[0] = 0; while (1) { /* @@ -2424,6 +2431,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman * in one place. */ int32_t ic, ic_raw; +#if ENABLE_FEATURE_EDITING_WINCH unsigned count; count = S.SIGWINCH_count; @@ -2431,7 +2439,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman S.SIGWINCH_saved = count; cmdedit_setwidth(); } - +#endif ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); #if ENABLE_FEATURE_REVERSE_SEARCH @@ -2868,8 +2876,10 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman /* restore initial_settings */ tcsetattr_stdin_TCSANOW(&initial_settings); +#if ENABLE_FEATURE_EDITING_WINCH /* restore SIGWINCH handler */ sigaction_set(SIGWINCH, &S.SIGWINCH_handler); +#endif fflush_all(); len = command_len; -- cgit v1.2.3-55-g6feb From 0e0209ac5312fb0a4cf740f59e3564c6549f4d77 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Feb 2018 11:47:51 +0100 Subject: less: accept -R option. Closes 10816 Signed-off-by: Denys Vlasenko --- miscutils/less.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miscutils/less.c b/miscutils/less.c index 97ab1e6f8..51ef2a59d 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -1814,7 +1814,11 @@ int less_main(int argc, char **argv) * -s: condense many empty lines to one * (used by some setups for manpage display) */ - getopt32(argv, "EMmN~I" IF_FEATURE_LESS_TRUNCATE("S") /*ignored:*/"s"); + getopt32(argv, "EMmN~I" + IF_FEATURE_LESS_TRUNCATE("S") + IF_FEATURE_LESS_RAW("R") + /*ignored:*/"s" + ); argv += optind; num_files = argc - optind; files = argv; -- cgit v1.2.3-55-g6feb From d82ea2ba8f9486d338b3aefe161afd4f77ce7a86 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 27 Feb 2018 13:03:44 +0100 Subject: tcpudp: shrink per-host rate-limiting code function old new delta tcpudpsvd_main 1775 1780 +5 ipsvd_perhost_add 108 107 -1 cclen 4 - -4 cc 4 - -4 ipsvd_perhost_init 30 25 -5 ipsvd_perhost_remove 80 44 -36 ------------------------------------------------------------------------------ (add/remove: 0/2 grow/shrink: 1/3 up/down: 5/-50) Total: -45 bytes text data bss dec hex filename 933358 473 6852 940683 e5a8b busybox_old 933326 473 6844 940643 e5a63 busybox_unstripped Signed-off-by: Denys Vlasenko --- networking/tcpudp.c | 7 ++++--- networking/tcpudp_perhost.c | 22 +++++++++------------- networking/tcpudp_perhost.h | 8 ++++---- 3 files changed, 17 insertions(+), 20 deletions(-) diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 2feb63a01..a90e3f80a 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -127,6 +127,7 @@ struct globals { unsigned cur_per_host; unsigned cnum; unsigned cmax; + struct hcc *cc; char **env_cur; char *env_var[1]; /* actually bigger */ } FIX_ALIASING; @@ -229,7 +230,7 @@ static void sig_child_handler(int sig UNUSED_PARAM) while ((pid = wait_any_nohang(&wstat)) > 0) { if (max_per_host) - ipsvd_perhost_remove(pid); + ipsvd_perhost_remove(G.cc, pid); if (cnum) cnum--; if (verbose) @@ -347,7 +348,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) signal(SIGPIPE, SIG_IGN); if (max_per_host) - ipsvd_perhost_init(cmax); + G.cc = ipsvd_perhost_init(cmax); local_port = bb_lookup_port(argv[1], tcp ? "tcp" : "udp", 0); lsa = xhost2sockaddr(argv[0], local_port); @@ -422,7 +423,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) /* Drop connection immediately if cur_per_host > max_per_host * (minimizing load under SYN flood) */ remote_addr = xmalloc_sockaddr2dotted_noport(&remote.u.sa); - cur_per_host = ipsvd_perhost_add(remote_addr, max_per_host, &hccp); + cur_per_host = ipsvd_perhost_add(G.cc, remote_addr, max_per_host, &hccp); if (cur_per_host > max_per_host) { /* ipsvd_perhost_add detected that max is exceeded * (and did not store ip in connection table) */ diff --git a/networking/tcpudp_perhost.c b/networking/tcpudp_perhost.c index 105410883..2643f8d16 100644 --- a/networking/tcpudp_perhost.c +++ b/networking/tcpudp_perhost.c @@ -10,25 +10,21 @@ #include "libbb.h" #include "tcpudp_perhost.h" -static struct hcc *cc; -static unsigned cclen; - -/* to be optimized */ - -void ipsvd_perhost_init(unsigned c) +struct hcc* FAST_FUNC ipsvd_perhost_init(unsigned c) { // free(cc); - cc = xzalloc(c * sizeof(*cc)); - cclen = c; + struct hcc *cc = xzalloc((c + 1) * sizeof(*cc)); + cc[c].pid = -1; /* "end" marker */ + return cc; } -unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp) +unsigned FAST_FUNC ipsvd_perhost_add(struct hcc *cc, char *ip, unsigned maxconn, struct hcc **hccpp) { unsigned i; unsigned conn = 1; int freepos = -1; - for (i = 0; i < cclen; ++i) { + for (i = 0; cc[i].pid >= 0; ++i) { if (!cc[i].ip) { freepos = i; continue; @@ -46,10 +42,10 @@ unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp) return conn; } -void ipsvd_perhost_remove(int pid) +void FAST_FUNC ipsvd_perhost_remove(struct hcc *cc, int pid) { unsigned i; - for (i = 0; i < cclen; ++i) { + for (i = 0; cc[i].pid >= 0; ++i) { if (cc[i].pid == pid) { free(cc[i].ip); cc[i].ip = NULL; @@ -59,7 +55,7 @@ void ipsvd_perhost_remove(int pid) } } -//void ipsvd_perhost_free(void) +//void ipsvd_perhost_free(struct hcc *cc) //{ // free(cc); //} diff --git a/networking/tcpudp_perhost.h b/networking/tcpudp_perhost.h index 3e5757678..3b14d9a57 100644 --- a/networking/tcpudp_perhost.h +++ b/networking/tcpudp_perhost.h @@ -14,7 +14,7 @@ struct hcc { int pid; }; -void ipsvd_perhost_init(unsigned); +struct hcc* FAST_FUNC ipsvd_perhost_init(unsigned); /* Returns number of already opened connects to this ips, including this one. * ip should be a malloc'ed ptr. @@ -22,12 +22,12 @@ void ipsvd_perhost_init(unsigned); * and pointer to table entry if stored in *hccpp * (useful for storing pid later). * Else ip is NOT inserted (you must take care of it - free() etc) */ -unsigned ipsvd_perhost_add(char *ip, unsigned maxconn, struct hcc **hccpp); +unsigned FAST_FUNC ipsvd_perhost_add(struct hcc *cc, char *ip, unsigned maxconn, struct hcc **hccpp); /* Finds and frees element with pid */ -void ipsvd_perhost_remove(int pid); +void FAST_FUNC ipsvd_perhost_remove(struct hcc *cc, int pid); //unsigned ipsvd_perhost_setpid(int pid); -//void ipsvd_perhost_free(void); +//void ipsvd_perhost_free(struct hcc *cc); POP_SAVED_FUNCTION_VISIBILITY -- cgit v1.2.3-55-g6feb From cc222747ae7e264cbe9b1c8a9c253860275db8a9 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 23 Nov 2017 19:49:31 +0200 Subject: libbb: Use return value from is_prefixed_with() add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-5 (-5) Function old new delta skip_dev_pfx 30 25 -5 Total: Before=779966, After=779961, chg -0.00% Signed-off-by: Andy Shevchenko Signed-off-by: Denys Vlasenko --- libbb/skip_whitespace.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libbb/skip_whitespace.c b/libbb/skip_whitespace.c index 4df5d9e4d..37a24d3be 100644 --- a/libbb/skip_whitespace.c +++ b/libbb/skip_whitespace.c @@ -32,7 +32,6 @@ char* FAST_FUNC skip_non_whitespace(const char *s) char* FAST_FUNC skip_dev_pfx(const char *tty_name) { - if (is_prefixed_with(tty_name, "/dev/")) - tty_name += 5; - return (char*)tty_name; + char *unprefixed = is_prefixed_with(tty_name, "/dev/"); + return unprefixed ? unprefixed : (char*)tty_name; } -- cgit v1.2.3-55-g6feb