From 95f7953f2c46c7b9c799250aa8dc6eb10cc5c726 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 14:26:33 +0200 Subject: do not use `a' quoting style in comments Signed-off-by: Denys Vlasenko --- libbb/change_identity.c | 2 +- libbb/correct_password.c | 2 +- libbb/dump.c | 2 +- libbb/progress.c | 2 +- libbb/pw_encrypt_des.c | 2 +- libbb/run_shell.c | 2 +- libbb/setup_environment.c | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) (limited to 'libbb') diff --git a/libbb/change_identity.c b/libbb/change_identity.c index d48d86326..431f72c8c 100644 --- a/libbb/change_identity.c +++ b/libbb/change_identity.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/correct_password.c b/libbb/correct_password.c index f4635a5bc..51928f68d 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/dump.c b/libbb/dump.c index 211a1ed9e..e23b71294 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -828,7 +828,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/libbb/progress.c b/libbb/progress.c index 3c2f01667..64e6529ac 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -25,7 +25,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE diff --git a/libbb/pw_encrypt_des.c b/libbb/pw_encrypt_des.c index c8e02ddff..19a9ab15b 100644 --- a/libbb/pw_encrypt_des.c +++ b/libbb/pw_encrypt_des.c @@ -24,7 +24,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE diff --git a/libbb/run_shell.c b/libbb/run_shell.c index b6b9360e8..3bb58bb6f 100644 --- a/libbb/run_shell.c +++ b/libbb/run_shell.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c index 4258656fe..91b6d94db 100644 --- a/libbb/setup_environment.c +++ b/libbb/setup_environment.c @@ -15,7 +15,7 @@ * may be used to endorse or promote products derived from this software * without specific prior written permission. * - * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ``AS IS'' AND + * THIS SOFTWARE IS PROVIDED BY JULIE HAUGH AND CONTRIBUTORS ''AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JULIE HAUGH OR CONTRIBUTORS BE LIABLE -- cgit v1.2.3-55-g6feb From 84ea60ed65f6ea6fd3b2170e44bbff5de410a78b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 2 Aug 2017 17:27:28 +0200 Subject: line editing: make read_line_input() not take timeout param It's almost always -1. function old new delta read_line_input 3902 3912 +10 new_line_input_t 24 31 +7 pgetc 583 585 +2 save_command_ps_at_cur_history 80 78 -2 read_line 76 74 -2 fgetc_interactive 246 244 -2 addLines 84 82 -2 doCommands 2226 2222 -4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/5 up/down: 19/-12) Total: 7 bytes Signed-off-by: Denys Vlasenko --- editors/ed.c | 6 +++--- include/libbb.h | 11 ++++++----- libbb/lineedit.c | 23 ++++++++++++++++------- shell/ash.c | 5 +++-- shell/hush.c | 3 +-- util-linux/fdisk.c | 2 +- 6 files changed, 30 insertions(+), 20 deletions(-) (limited to 'libbb') diff --git a/editors/ed.c b/editors/ed.c index 7f21ded92..05797692c 100644 --- a/editors/ed.c +++ b/editors/ed.c @@ -360,7 +360,7 @@ static void addLines(int num) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); + len = read_line_input(NULL, "", buf, sizeof(buf)); if (len <= 0) { /* Previously, ctrl-C was exiting to shell. * Now we exit to ed prompt. Is in important? */ @@ -789,7 +789,7 @@ static void doCommands(void) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); + len = read_line_input(NULL, ": ", buf, sizeof(buf)); if (len <= 0) return; while (len && isspace(buf[--len])) @@ -892,7 +892,7 @@ static void doCommands(void) } if (!dirty) return; - len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); + len = read_line_input(NULL, "Really quit? ", buf, 16); /* read error/EOF - no way to continue */ if (len < 0) return; diff --git a/include/libbb.h b/include/libbb.h index 9aba71949..46180c5aa 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1639,9 +1639,9 @@ enum { * buffer[0] is used as a counter of buffered chars and must be 0 * on first call. * timeout: - * -2: do not poll for input; - * -1: poll(-1) (i.e. block); - * >=0: poll for TIMEOUT milliseconds, return -1/EAGAIN on timeout + * -2: do not poll(-1) for input - read() it, return on EAGAIN at once + * -1: poll(-1) (i.e. block even on NONBLOCKed fd) + * >=0: poll() for TIMEOUT milliseconds, return -1/EAGAIN on timeout */ int64_t read_key(int fd, char *buffer, int timeout) FAST_FUNC; void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; @@ -1657,6 +1657,7 @@ unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # endif typedef struct line_input_t { int flags; + int timeout; const char *path_lookup; # if MAX_HISTORY int cnt_history; @@ -1692,7 +1693,7 @@ line_input_t *new_line_input_t(int flags) FAST_FUNC; * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; +int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) FAST_FUNC; void show_history(const line_input_t *st) FAST_FUNC; # if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT void save_history(line_input_t *st); @@ -1700,7 +1701,7 @@ void save_history(line_input_t *st); #else #define MAX_HISTORY 0 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; -#define read_line_input(state, prompt, command, maxsize, timeout) \ +#define read_line_input(state, prompt, command, maxsize) \ read_line_input(prompt, command, maxsize) #endif diff --git a/libbb/lineedit.c b/libbb/lineedit.c index e5721b063..0106093a1 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1267,6 +1267,7 @@ line_input_t* FAST_FUNC new_line_input_t(int flags) { line_input_t *n = xzalloc(sizeof(*n)); n->flags = flags; + n->timeout = -1; #if MAX_HISTORY > 0 n->max_history = MAX_HISTORY; #endif @@ -2130,7 +2131,7 @@ enum { * Backspace deletes last matched char. * Control keys exit search and return to normal editing (at current history line). */ -static int32_t reverse_i_search(void) +static int32_t reverse_i_search(int timeout) { char match_buf[128]; /* for user input */ char read_key_buffer[KEYCODE_BUFFER_SIZE]; @@ -2152,8 +2153,8 @@ static int32_t reverse_i_search(void) int h; unsigned match_buf_len = strlen(match_buf); -//FIXME: correct timeout? - ic = lineedit_read_key(read_key_buffer, -1); +//FIXME: correct timeout? (i.e. count it down?) + ic = lineedit_read_key(read_key_buffer, timeout); switch (ic) { case CTRL('R'): /* searching for the next match */ @@ -2256,9 +2257,10 @@ static int32_t reverse_i_search(void) * (in both cases the cursor remains on the input line, '\n' is not printed) * >0 length of input string, including terminating '\n' */ -int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) +int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize) { int len; + int timeout; #if ENABLE_FEATURE_TAB_COMPLETION smallint lastWasTab = 0; #endif @@ -2297,8 +2299,15 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman maxsize = MAX_LINELEN; S.maxsize = maxsize; - /* With zero flags, no other fields are ever used */ - state = st ? st : (line_input_t*) &const_int_0; + timeout = -1; + /* Make state->flags == 0 if st is NULL. + * With zeroed flags, no other fields are ever referenced. + */ + state = (line_input_t*) &const_int_0; + if (st) { + state = st; + timeout = st->timeout; + } #if MAX_HISTORY > 0 # if ENABLE_FEATURE_EDITING_SAVEHISTORY if (state->hist_file) @@ -2510,7 +2519,7 @@ int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *comman } #if ENABLE_FEATURE_REVERSE_SEARCH case CTRL('R'): - ic = ic_raw = reverse_i_search(); + ic = ic_raw = reverse_i_search(timeout); goto again; #endif diff --git a/shell/ash.c b/shell/ash.c index 78baa9aac..b285e3d33 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -10185,8 +10185,8 @@ preadfd(void) if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { - int timeout = -1; # if ENABLE_ASH_IDLE_TIMEOUT + int timeout = -1; if (iflag) { const char *tmout_var = lookupvar("TMOUT"); if (tmout_var) { @@ -10195,12 +10195,13 @@ preadfd(void) timeout = -1; } } + line_input_state->timeout = timeout; # endif # if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); # endif reinit_unicode_for_ash(); - nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); + nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ); if (nr == 0) { /* ^C pressed, "convert" to SIGINT */ write(STDOUT_FILENO, "^C", 2); diff --git a/shell/hush.c b/shell/hush.c index 93ed0bc0b..6fa4e1630 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2411,8 +2411,7 @@ static int get_user_input(struct in_str *i) /* buglet: SIGINT will not make new prompt to appear _at once_, * only after . (^C works immediately) */ r = read_line_input(G.line_input_state, prompt_str, - G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, - /*timeout*/ -1 + G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1 ); /* read_line_input intercepts ^C, "convert" it to SIGINT */ if (r == 0) diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index e00f85864..4828c0a51 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -644,7 +644,7 @@ read_line(const char *prompt) { int sz; - sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer), /*timeout*/ -1); + sz = read_line_input(NULL, prompt, line_buffer, sizeof(line_buffer)); if (sz <= 0) exit(EXIT_SUCCESS); /* Ctrl-D or Ctrl-C */ -- cgit v1.2.3-55-g6feb From 39194f030918b87eeb3e11e94cfa05f575fb47b4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:00:01 +0200 Subject: new NOFORKs: pwdx,kill[all5],ttysize,realpath,readlink NOEXECs: date,resize function old new delta run_nofork_applet 258 280 +22 readlink_main 112 123 +11 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 33/0) Total: 33 bytes Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 140 +++++++++++++++++++++++---------------------- console-tools/resize.c | 2 +- coreutils/date.c | 21 ++++--- coreutils/readlink.c | 7 +-- coreutils/realpath.c | 3 +- docs/nofork_noexec.txt | 2 +- libbb/bb_pwd.c | 3 +- libbb/vfork_daemon_rexec.c | 6 +- miscutils/ttysize.c | 2 +- procps/kill.c | 10 ++-- procps/pwdx.c | 3 +- 11 files changed, 106 insertions(+), 93 deletions(-) (limited to 'libbb') diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 02eba46e8..7073611a4 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -1,11 +1,10 @@ Why an applet can't be NOFORK or NOEXEC? Why can't be NOFORK: -daemon: runs indefinitely interactive: may wait for user input, ^C has to work spawner: "tool PROG ARGS" which changes program's environment - must fork changes state: e.g. environment, signal handlers -runner: sometimes may run for long time, and/or works with network: +runner: sometimes may run for long(ish) time, and/or works with network: ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) "runners" can become eligible after hush is taught ^C to interrupt NOFORKs! @@ -15,9 +14,12 @@ suid: runs under different uid - must fork+exec Why shouldn't be NOFORK/NOEXEC: complex: no immediately obvious reason why NOFORK wouldn't work, - but does some non-obvoius operations (example: fuser, lsof, losetup). - for NOFORK, nested xmallocs (typical in complex code) is a problem. + but does some non-obvoius operations (example: fuser, lsof, losetup); + nested xmallocs (typical in complex code) is a problem for NOFORK rare: not used often enough to bother optimizing (example: poweroff) +longterm: often runs for a long time (many seconds), execing would make + memory footprint smaller +daemon: runs indefinitely [ - NOFORK [[ - NOFORK @@ -31,7 +33,7 @@ arch - NOFORK arp arping - runner ash - interactive -awk - noexec, runner +awk - noexec. runner base64 - runner basename - NOFORK beep @@ -44,63 +46,63 @@ bunzip2 - runner busybox bzcat - runner bzip2 - runner -cal +cal - runner: cal -n9999 cat - runner chat chattr - runner -chgrp - noexec, runner -chmod - noexec, runner -chown - noexec, runner +chgrp - noexec. runner +chmod - noexec. runner +chown - noexec. runner chpasswd - runner (list of "user:password"s from stdin) chpst - spawner chroot - spawner chrt - spawner chvt -cksum - noexec, runner +cksum - noexec. runner clear - NOFORK cmp - runner comm - runner conspy - interactive -cp - noexec, runner +cp - noexec. runner cpio - runner crond - daemon crontab cryptpw cttyhack - spawner -cut - noexec, runner -date +cut - noexec. runner +date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) dc - runner (eats stdin if no params) -dd - noexec, runner +dd - noexec. runner deallocvt delgroup deluser depmod -devmem -df +devmem - runner, complex (access to device memory may hang) +df - complex (nested allocs) dhcprelay - daemon diff - runner dirname - NOFORK -dmesg +dmesg - runner dnsd - daemon -dnsdomainname -dos2unix - noexec, runner +dnsdomainname - DNS resolution may trigger, need ^C +dos2unix - noexec. runner dpkg - runner -du +du - runner dumpkmap dumpleases echo - NOFORK ed - interactive egrep - runner eject -env - noexec, changes state (env) +env - noexec. changes state (env) envdir - spawner envuidgid - spawner expand - runner -expr +expr - complex (nested allocs) factor - runner (eats stdin if no params) fakeidentd - daemon false - NOFORK -fatattr +fatattr - complex (xopen+xioctl can leak fd) fbset fbsplash - runner, interactive fdflush @@ -108,15 +110,15 @@ fdformat - runner fdisk - interactive fgconsole fgrep - runner -find - noexec, runner +find - noexec. runner findfs - suid flash_eraseall flash_lock flash_unlock flashcp flock -fold - noexec, runner -free +fold - noexec. runner +free - nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk fsck - interactive fsck.minix @@ -134,12 +136,12 @@ groups - noexec gunzip - runner gzip - runner halt - rare -hd - noexec, runner +hd - noexec. runner hdparm - complex, rare -head - noexec, runner -hexdump - noexec, runner +head - noexec. runner +hexdump - noexec. runner hostid - NOFORK -hostname +hostname - DNS resolution may trigger, need ^C httpd - daemon hush - interactive hwclock @@ -169,11 +171,11 @@ iproute iprule iptunnel kbd_mode -kill -killall -killall5 +kill - NOFORK +killall - NOFORK +killall5 - NOFORK klogd - daemon -last +last - runner (I've got 1300 lines of output when tried it) less - interactive link - NOFORK linux32 - spawner @@ -189,7 +191,7 @@ losetup - complex lpd - daemon lpq - runner lpr - runner -ls - noexec, runner +ls - noexec. runner lsattr lsmod lsof - complex @@ -203,7 +205,7 @@ lzopcat - runner makedevs makemime - runner man - spawner, interactive -md5sum - noexec, runner +md5sum - noexec. runner mdev - daemon mesg microcom - interactive, complex @@ -225,11 +227,11 @@ mount - suid mountpoint mpstat mt -mv +mv - runner (can be noexec?) nameif nbd-client nc - runner -netstat +netstat - runner with -c nice - spawner nl - runner nmeter - runner @@ -240,40 +242,40 @@ od - runner openvt - spawner partprobe passwd - suid -paste - noexec, runner +paste - noexec. runner patch -pgrep -pidof +pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) +pidof - nofork candidate(uses find_pid_by_name, is that ok?) ping - suid, runner ping6 - suid, runner pipe_progress pivot_root -pkill +pkill - nofork candidate(xregcomp, procps_scan - are they ok?) pmap popmaildir - runner poweroff - rare -powertop - interactive +powertop - interactive, longterm printenv - NOFORK printf - NOFORK ps pscan pstree pwd - NOFORK -pwdx +pwdx - NOFORK raidautorun rdate rdev -readlink +readlink - NOFORK readprofile -realpath +realpath - NOFORK reboot - rare reformime - runner remove-shell -renice +renice - nofork candidate(uses getpwnam, is that ok?) reset - spawner (execs "stty") -resize +resize - noexec. changes state (signal handlers) rev - runner -rm - noexec, rm -i interactive +rm - noexec. rm -i interactive rmdir - NOFORK rmmod route @@ -289,7 +291,7 @@ script scriptreplay sed - runner sendmail - runner -seq - noexec, runner +seq - noexec. runner setarch - spawner setconsole setfont @@ -300,22 +302,22 @@ setserial setsid - spawner setuidgid sh - interactive -sha1sum - noexec, runner -sha256sum - noexec, runner -sha3sum - noexec, runner -sha512sum - noexec, runner +sha1sum - noexec. runner +sha256sum - noexec. runner +sha3sum - noexec. runner +sha512sum - noexec. runner showkey - interactive shred - runner -shuf - noexec, runner +shuf - noexec. runner slattach sleep - runner smemcap - runner softlimit - spawner -sort - noexec, runner +sort - noexec. runner split - runner ssl_client - network start-stop-daemon -stat +stat - nofork candidate(needs fewer allocs) strings - runner stty su - suid, spawner @@ -326,11 +328,11 @@ svc svlogd - daemon swapoff - rare swapon - rare -switch_root - spawner, rare, change state +switch_root - spawner, rare, changes state sync - NOFORK sysctl syslogd - daemon -tac - noexec, runner +tac - noexec. runner tail - runner tar - runner taskset - spawner @@ -341,9 +343,9 @@ telnetd - daemon test - NOFORK tftp - runner tftpd - daemon -time - spawner, change state (signals) -timeout - spawner, change state (signals) -top - interactive +time - spawner, changes state (signals) +timeout - spawner, changes state (signals) +top - interactive, longterm touch - NOFORK tr - runner traceroute - suid, runner @@ -351,7 +353,7 @@ traceroute6 - suid, runner true - NOFORK truncate - NOFORK tty - NOFORK -ttysize +ttysize - NOFORK tunctl tune2fs ubiattach @@ -370,14 +372,14 @@ uname - NOFORK uncompress - runner unexpand - runner uniq - runner -unix2dos - noexec, runner +unix2dos - noexec. runner unlink - NOFORK unlzma - runner unlzop - runner unxz - runner unzip - runner -uptime -users +uptime - nofork candidate(is getutxent ok?) +users - nofork candidate(is getutxent ok?) usleep - NOFORK uudecode - runner uuencode - runner @@ -395,10 +397,10 @@ which - NOFORK who whoami - NOFORK whois -xargs - noexec, spawner -xxd - noexec, runner +xargs - noexec. spawner +xxd - noexec. runner xz - runner xzcat - runner -yes - noexec, runner +yes - noexec. runner zcat - runner zcip - daemon diff --git a/console-tools/resize.c b/console-tools/resize.c index 62928a01e..97866673a 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -23,7 +23,7 @@ //config: E.g.: //config: COLUMNS=80;LINES=44;export COLUMNS LINES; -//applet:IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_RESIZE(APPLET_NOEXEC(resize, resize, BB_DIR_USR_BIN, BB_SUID_DROP, resize)) //kbuild:lib-$(CONFIG_RESIZE) += resize.o diff --git a/coreutils/date.c b/coreutils/date.c index 2c6e1d4df..89b281646 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -58,7 +58,7 @@ //config: the same format. With it on, 'date DATE' additionally supports //config: MMDDhhmm[[YY]YY][.ss] format. -//applet:IF_DATE(APPLET(date, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_DATE(APPLET_NOEXEC(date, date, BB_DIR_BIN, BB_SUID_DROP, date)) //kbuild:lib-$(CONFIG_DATE) += date.o @@ -152,12 +152,6 @@ enum { OPT_HINT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ }; -static void maybe_set_utc(int opt) -{ - if (opt & OPT_UTC) - putenv((char*)"TZ=UTC0"); -} - #if ENABLE_LONG_OPTS static const char date_longopts[] ALIGN1 = "rfc-822\0" No_argument "R" @@ -170,6 +164,19 @@ static const char date_longopts[] ALIGN1 = ; #endif +/* We are a NOEXEC applet. + * Obstacles to NOFORK: + * - we change env + * - xasprintf result not freed + * - after xasprintf we use other xfuncs + */ + +static void maybe_set_utc(int opt) +{ + if (opt & OPT_UTC) + putenv((char*)"TZ=UTC0"); +} + int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int date_main(int argc UNUSED_PARAM, char **argv) { diff --git a/coreutils/readlink.c b/coreutils/readlink.c index 9690290e3..7f8d6b239 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c @@ -20,7 +20,7 @@ //config: help //config: Enable the readlink option (-f). -//applet:IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_READLINK(APPLET_NOFORK(readlink, readlink, BB_DIR_USR_BIN, BB_SUID_DROP, readlink)) //kbuild:lib-$(CONFIG_READLINK) += readlink.o @@ -85,6 +85,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) if (!(opt & 4)) /* not -v */ logmode = LOGMODE_NONE; + /* NOFORK: only one alloc is allowed; must free */ if (opt & 1) { /* -f */ buf = xmalloc_realpath(fname); } else { @@ -94,9 +95,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) if (!buf) return EXIT_FAILURE; printf((opt & 2) ? "%s" : "%s\n", buf); - - if (ENABLE_FEATURE_CLEAN_UP) - free(buf); + free(buf); fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 6a61c3dc8..f9c630135 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c @@ -13,7 +13,7 @@ //config: Return the canonicalized absolute pathname. //config: This isn't provided by GNU shellutils, but where else does it belong. -//applet:IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_REALPATH(APPLET_NOFORK(realpath, realpath, BB_DIR_USR_BIN, BB_SUID_DROP, realpath)) //kbuild:lib-$(CONFIG_REALPATH) += realpath.o @@ -36,6 +36,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv) } do { + /* NOFORK: only one alloc is allowed; must free */ char *resolved_path = xmalloc_realpath(*argv); if (resolved_path != NULL) { puts(resolved_path); diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index 0ad4e6e60..cfb02145a 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -98,7 +98,7 @@ It itself calls run_nofork_applet(), if argv[0] turned out to be a name of a NOFORK applet. run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, -applet_name. Thus, for example, caller does not need to worry about +logmode, applet_name. Thus, for example, caller does not need to worry about option_mask32 getting trashed. diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c index 4829b723a..dca0a150b 100644 --- a/libbb/bb_pwd.c +++ b/libbb/bb_pwd.c @@ -31,9 +31,9 @@ struct group* FAST_FUNC xgetgrnam(const char *name) return gr; } - struct passwd* FAST_FUNC xgetpwuid(uid_t uid) { + /* Note: used in nofork applets (whoami), be careful not to leak anything */ struct passwd *pw = getpwuid(uid); if (!pw) bb_error_msg_and_die("unknown uid %u", (unsigned)uid); @@ -50,6 +50,7 @@ struct group* FAST_FUNC xgetgrgid(gid_t gid) char* FAST_FUNC xuid2uname(uid_t uid) { + /* Note: used in nofork applets (whoami), be careful not to leak anything */ struct passwd *pw = xgetpwuid(uid); return pw->pw_name; } diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 576534ee5..487ecb0e4 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -92,6 +92,7 @@ struct nofork_save_area { void (*die_func)(void); const char *applet_name; uint32_t option_mask32; + smallint logmode; uint8_t xfunc_error_retval; }; static void save_nofork_data(struct nofork_save_area *save) @@ -100,6 +101,7 @@ static void save_nofork_data(struct nofork_save_area *save) save->die_func = die_func; save->applet_name = applet_name; save->option_mask32 = option_mask32; + save->logmode = logmode; save->xfunc_error_retval = xfunc_error_retval; } static void restore_nofork_data(struct nofork_save_area *save) @@ -108,6 +110,7 @@ static void restore_nofork_data(struct nofork_save_area *save) die_func = save->die_func; applet_name = save->applet_name; option_mask32 = save->option_mask32; + logmode = save->logmode; xfunc_error_retval = save->xfunc_error_retval; } @@ -118,8 +121,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) save_nofork_data(&old); + logmode = LOGMODE_STDIO; xfunc_error_retval = EXIT_FAILURE; - /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. */ @@ -146,7 +149,6 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) /* Restoring some globals */ restore_nofork_data(&old); - /* Other globals can be simply reset to defaults */ GETOPT_RESET(); diff --git a/miscutils/ttysize.c b/miscutils/ttysize.c index 7f6a84308..2c2d4ec33 100644 --- a/miscutils/ttysize.c +++ b/miscutils/ttysize.c @@ -18,7 +18,7 @@ //config: error, but returns default 80x24. //config: Usage in shell scripts: width=`ttysize w`. -//applet:IF_TTYSIZE(APPLET(ttysize, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_TTYSIZE(APPLET_NOFORK(ttysize, ttysize, BB_DIR_USR_BIN, BB_SUID_DROP, ttysize)) //kbuild:lib-$(CONFIG_TTYSIZE) += ttysize.o diff --git a/procps/kill.c b/procps/kill.c index 09beefb2d..0ddae2f70 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -32,10 +32,10 @@ //config: in its own session, so it won't kill the shell that is running //config: the script it was called from. -//applet:IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) -// APPLET_ODDNAME:name main location suid_type help -//applet:IF_KILLALL( APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) -//applet:IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) +//applet:IF_KILL( APPLET_NOFORK(kill, kill, BB_DIR_BIN, BB_SUID_DROP, kill)) +// APPLET_NOFORK:name main location suid_type help +//applet:IF_KILLALL( APPLET_NOFORK(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) +//applet:IF_KILLALL5(APPLET_NOFORK(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) //kbuild:lib-$(CONFIG_KILL) += kill.o //kbuild:lib-$(CONFIG_KILLALL) += kill.o @@ -87,7 +87,7 @@ * + we can't use xfunc here * + we can't use applet_name * + we can't use bb_show_usage - * (Above doesn't apply for killall[5] cases) + * (doesn't apply for killall[5], still should be careful b/c NOFORK) * * kill %n gets translated into kill ' -' by shell (note space!) * This is needed to avoid collision with kill -9 ... syntax diff --git a/procps/pwdx.c b/procps/pwdx.c index dac238950..84802bbcd 100644 --- a/procps/pwdx.c +++ b/procps/pwdx.c @@ -14,7 +14,7 @@ //config: help //config: Report current working directory of a process -//applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_PWDX(APPLET_NOFORK(pwdx, pwdx, BB_DIR_USR_BIN, BB_SUID_DROP, pwdx)) //kbuild:lib-$(CONFIG_PWDX) += pwdx.o @@ -50,6 +50,7 @@ int pwdx_main(int argc UNUSED_PARAM, char **argv) sprintf(buf, "/proc/%u/cwd", pid); + /* NOFORK: only one alloc is allowed; must free */ s = xmalloc_readlink(buf); // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); -- cgit v1.2.3-55-g6feb From 19c9f31af17f2c34e93c9c322b5c546ffbcda6ad Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 3 Aug 2017 19:52:47 +0200 Subject: nofork: fix a bug uncovered by hush testsuite (forgotten fflush) function old new delta run_nofork_applet 280 287 +7 Signed-off-by: Denys Vlasenko --- libbb/vfork_daemon_rexec.c | 2 ++ shell/hush_test/run-all | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 487ecb0e4..98512bb00 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -143,6 +143,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) applet_name = tmp_argv[0]; /* Finally we can call NOFORK applet's main() */ rc = applet_main[applet_no](argc, tmp_argv); + /* Important for shells: `which CMD` was failing */ + fflush_all(); } else { /* xfunc died in NOFORK applet */ } diff --git a/shell/hush_test/run-all b/shell/hush_test/run-all index 1dd0edc39..3fbc7c531 100755 --- a/shell/hush_test/run-all +++ b/shell/hush_test/run-all @@ -80,7 +80,7 @@ do_test() case $? in 0) echo " ok";; 77) echo " skip (feature disabled)";; - *) echo " fail"; tret=1;; + *) echo " fail ($?)"; tret=1;; esac done exit ${tret} -- cgit v1.2.3-55-g6feb From 727948e585cb133c32c8d42570e5524c58190307 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:23:42 +0200 Subject: getopt32: factor out code to treat all args as options Working towards making getopt32() xmalloc-free function old new delta make_all_argv_opts - 58 +58 top_main 914 912 -2 getopt32 1517 1458 -59 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/2 up/down: 58/-61) Total: -3 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 +++- libbb/Kbuild.src | 1 - libbb/getopt32.c | 31 ++++++------------------------- libbb/getopt_allopts.c | 27 +++++++++++++++++++++++++++ procps/ps.c | 5 +++-- procps/top.c | 5 ++--- 6 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 libbb/getopt_allopts.c (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 46180c5aa..bb27c59a1 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1183,7 +1183,9 @@ extern const char *opt_complementary; extern const char *applet_long_options; #endif extern uint32_t option_mask32; -extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* For top, ps. Some argv[i] are replaced by malloced "-opt" strings */ +void make_all_argv_opts(char **argv) FAST_FUNC; /* BSD-derived getopt() functions require that optind be set to 1 in * order to reset getopt() state. This used to be generally accepted * way of resetting getopt(). However, glibc's getopt() diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 458973f17..73201a6bd 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -40,7 +40,6 @@ lib-y += full_write.o lib-y += get_console.o lib-y += get_last_path_component.o lib-y += get_line_from_file.o -lib-y += getopt32.o lib-y += getpty.o lib-y += get_volsize.o lib-y += herror_msg.o diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 80f4cc060..129840cea 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -6,12 +6,13 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG # include #endif #include "libbb.h" +//kbuild:lib-y += getopt32.o + /* Documentation uint32_t @@ -170,21 +171,6 @@ const char *opt_complementary Special characters: - "-" A group consisting of just a dash forces all arguments - to be treated as options, even if they have no leading dashes. - Next char in this case can't be a digit (0-9), use ':' or end of line. - Example: - - opt_complementary = "-:w-x:x-w"; // "-w-x:x-w" would also work, - getopt32(argv, "wx"); // but is less readable - - This makes it possible to use options without a dash (./program w x) - as well as with a dash (./program -x). - - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. - "--" A double dash at the beginning of opt_complementary means the argv[1] string should always be treated as options, even if it isn't prefixed with a "-". This is useful for special syntax in applets @@ -373,8 +359,7 @@ getopt32(char **argv, const char *applet_opts, ...) int max_arg = -1; #define SHOW_USAGE_IF_ERROR 1 -#define ALL_ARGV_IS_OPTS 2 -#define FIRST_ARGV_IS_OPT 4 +#define FIRST_ARGV_IS_OPT 2 int spec_flgs = 0; @@ -486,8 +471,7 @@ getopt32(char **argv, const char *applet_opts, ...) if (c == '-') { spec_flgs |= FIRST_ARGV_IS_OPT; s++; - } else - spec_flgs |= ALL_ARGV_IS_OPTS; + } } else { min_arg = c - '0'; s++; @@ -551,9 +535,9 @@ getopt32(char **argv, const char *applet_opts, ...) opt_complementary = NULL; va_end(p); - if (spec_flgs & (FIRST_ARGV_IS_OPT | ALL_ARGV_IS_OPTS)) { + if (spec_flgs & FIRST_ARGV_IS_OPT) { pargv = argv + 1; - while (*pargv) { + if (*pargv) { if (pargv[0][0] != '-' && pargv[0][0] != '\0') { /* Can't use alloca: opts with params will * return pointers to stack! @@ -563,9 +547,6 @@ getopt32(char **argv, const char *applet_opts, ...) strcpy(pp + 1, *pargv); *pargv = pp; } - if (!(spec_flgs & ALL_ARGV_IS_OPTS)) - break; - pargv++; } } diff --git a/libbb/getopt_allopts.c b/libbb/getopt_allopts.c new file mode 100644 index 000000000..a67d2b70e --- /dev/null +++ b/libbb/getopt_allopts.c @@ -0,0 +1,27 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" + +//kbuild:lib-y += getopt_allopts.o + +void FAST_FUNC make_all_argv_opts(char **argv) +{ + /* Note: we skip argv[0] */ + while (*++argv) { + char *p; + + if (argv[0][0] == '-') + continue; + /* Neither top nor ps care if "" arg turns into "-" */ + /*if (argv[0][0] == '\0') + continue;*/ + p = xmalloc(strlen(*argv) + 2); + *p = '-'; + strcpy(p + 1, *argv); + *argv = p; + } +} diff --git a/procps/ps.c b/procps/ps.c index eb1946d27..081479b33 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -715,7 +715,8 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) # if ENABLE_FEATURE_PS_WIDE /* -w is a bit complicated */ int w_count = 0; - opt_complementary = "-:ww"; + make_all_argv_opts(argv); + opt_complementary = "ww"; opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") "w", &w_count); /* if w is given once, GNU ps sets the width to 132, @@ -731,7 +732,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } # else /* -w is not supported, only -Z and/or -T */ - opt_complementary = "-"; + make_all_argv_opts(argv); opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); # endif diff --git a/procps/top.c b/procps/top.c index 015d1ab74..1bc432fc9 100644 --- a/procps/top.c +++ b/procps/top.c @@ -1110,15 +1110,14 @@ int top_main(int argc UNUSED_PARAM, char **argv) #endif /* all args are options; -n NUM */ - opt_complementary = "-"; /* options can be specified w/o dash */ + make_all_argv_opts(argv); /* options can be specified w/o dash */ col = getopt32(argv, "d:n:b"IF_FEATURE_TOPMEM("m"), &str_interval, &str_iterations); #if ENABLE_FEATURE_TOPMEM if (col & OPT_m) /* -m (busybox specific) */ scan_mask = TOPMEM_MASK; #endif if (col & OPT_d) { - /* work around for "-d 1" -> "-d -1" done by getopt32 - * (opt_complementary == "-" does this) */ + /* work around for "-d 1" -> "-d -1" done by make_all_argv_opts() */ if (str_interval[0] == '-') str_interval++; /* Need to limit it to not overflow poll timeout */ -- cgit v1.2.3-55-g6feb From dd5a40246b91bd5d3d165998e6ac3cc4f7083f63 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 16:46:17 +0200 Subject: getopt32: move support for "always treat first arg as option" to users (tar/ar) Now getopt() never leaks (and never performs) any xmalloc's. function old new delta ar_main 522 556 +34 tar_main 986 1014 +28 getopt32 1458 1350 -108 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 62/-108) Total: -46 bytes Signed-off-by: Denys Vlasenko --- archival/ar.c | 6 ++++-- archival/tar.c | 4 +++- libbb/getopt32.c | 36 +++--------------------------------- 3 files changed, 10 insertions(+), 36 deletions(-) (limited to 'libbb') diff --git a/archival/ar.c b/archival/ar.c index 2886d155b..46c10aad4 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -240,10 +240,12 @@ int ar_main(int argc UNUSED_PARAM, char **argv) archive_handle = init_handle(); - /* --: prepend '-' to the first argument if required */ + /* prepend '-' to the first argument if required */ + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') + argv[1] = xasprintf("-%s", argv[1]); /* -1: at least one param is reqd */ /* one of p,t,x[,r] is required */ - opt_complementary = "--:-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); + opt_complementary = "-1:p:t:x"IF_FEATURE_AR_CREATE(":r"); opt = getopt32(argv, "voc""ptx"IF_FEATURE_AR_CREATE("r")); argv += optind; diff --git a/archival/tar.c b/archival/tar.c index 280ded4e1..f62b33005 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -966,7 +966,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; /* Prepend '-' to the first argument if required */ - opt_complementary = "--:" // first arg is options + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') + argv[1] = xasprintf("-%s", argv[1]); + opt_complementary = "tt:vv:" // count -t,-v #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // --exclude=PATTERN is a list diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 129840cea..513415894 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -171,16 +171,6 @@ const char *opt_complementary Special characters: - "--" A double dash at the beginning of opt_complementary means the - argv[1] string should always be treated as options, even if it isn't - prefixed with a "-". This is useful for special syntax in applets - such as "ar" and "tar": - tar xvf foo.tar - - NB: getopt32() will leak a small amount of memory if you use - this option! Do not use it if there is a possibility of recursive - getopt32() calls. - "-N" A dash as the first char in a opt_complementary group followed by a single digit (0-9) means that at least N non-option arguments must be present on the command line @@ -337,6 +327,8 @@ const char *applet_long_options; uint32_t option_mask32; +/* Please keep getopt32 free from xmalloc */ + uint32_t FAST_FUNC getopt32(char **argv, const char *applet_opts, ...) { @@ -354,12 +346,10 @@ getopt32(char **argv, const char *applet_opts, ...) struct option *long_options = (struct option *) &bb_null_long_options; #endif unsigned trigger; - char **pargv; int min_arg = 0; int max_arg = -1; #define SHOW_USAGE_IF_ERROR 1 -#define FIRST_ARGV_IS_OPT 2 int spec_flgs = 0; @@ -467,12 +457,7 @@ getopt32(char **argv, const char *applet_opts, ...) continue; } if (*s == '-') { - if (c < '0' || c > '9') { - if (c == '-') { - spec_flgs |= FIRST_ARGV_IS_OPT; - s++; - } - } else { + if (c >= '0' && c <= '9') { min_arg = c - '0'; s++; } @@ -535,21 +520,6 @@ getopt32(char **argv, const char *applet_opts, ...) opt_complementary = NULL; va_end(p); - if (spec_flgs & FIRST_ARGV_IS_OPT) { - pargv = argv + 1; - if (*pargv) { - if (pargv[0][0] != '-' && pargv[0][0] != '\0') { - /* Can't use alloca: opts with params will - * return pointers to stack! - * NB: we leak these allocations... */ - char *pp = xmalloc(strlen(*pargv) + 2); - *pp = '-'; - strcpy(pp + 1, *pargv); - *pargv = pp; - } - } - } - /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. * run_nofork_applet() does this, but we might end up here -- cgit v1.2.3-55-g6feb From b182e9ad6011909fdb76358431d23d195febaf54 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 4 Aug 2017 23:04:17 +0200 Subject: libbb: use _exit, not exit, in bb_daemonize_or_rexec() By the time we reach exit in parent, child already exited or execed. We should not re-run libc cleanup code. While at it, introduce bb_daemon_helper() and add a few comments. Signed-off-by: Denys Vlasenko --- console-tools/openvt.c | 4 ++-- debianutils/start_stop_daemon.c | 13 +++++++------ include/libbb.h | 1 + libbb/vfork_daemon_rexec.c | 10 ++++++++-- loginutils/login.c | 4 ++-- printutils/lpd.c | 5 ++--- 6 files changed, 22 insertions(+), 15 deletions(-) (limited to 'libbb') diff --git a/console-tools/openvt.c b/console-tools/openvt.c index f3db28367..423122fe9 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -99,7 +99,7 @@ static int find_free_vtno(void) /*xfunc_error_retval = 3; - do we need compat? */ if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0) bb_perror_msg_and_die("can't find open VT"); -// Not really needed, grep for DAEMON_ONLY_SANITIZE +// Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS // if (fd > 2) // close(fd); return vtno; @@ -155,7 +155,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv) /* Grab new VT */ sprintf(vtname, VC_FORMAT, vtno); /* (Try to) clean up stray open fds above fd 2 */ - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS | DAEMON_ONLY_SANITIZE, NULL); + bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); close(STDIN_FILENO); /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */ xopen(vtname, O_RDWR); diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 9d60b2c7f..07c104baa 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -516,6 +516,11 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else + /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do + * without: SSD is not itself a daemon, it _execs_ a daemon. + * The usual NOMMU problem of "child can't run indefinitely, + * it must exec" does not bite us: we exec anyway. + */ pid_t pid = xvfork(); if (pid != 0) { /* parent */ @@ -525,12 +530,8 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) } /* Child */ setsid(); /* detach from controlling tty */ - /* Redirect stdio to /dev/null, close extra FDs. - * We do not actually daemonize because of DAEMON_ONLY_SANITIZE */ - bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO - + DAEMON_CLOSE_EXTRA_FDS - + DAEMON_ONLY_SANITIZE, - NULL /* argv, unused */ ); + /* Redirect stdio to /dev/null, close extra FDs */ + bb_daemon_helper(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); #endif } if (opt & OPT_MAKEPID) { diff --git a/include/libbb.h b/include/libbb.h index bb27c59a1..6a2a2d640 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1169,6 +1169,7 @@ enum { #endif void bb_daemonize_or_rexec(int flags, char **argv) FAST_FUNC; void bb_sanitize_stdio(void) FAST_FUNC; +#define bb_daemon_helper(arg) bb_daemonize_or_rexec((arg) | DAEMON_ONLY_SANITIZE, NULL) /* Clear dangerous stuff, set PATH. Return 1 if was run by different user. */ int sanitize_env_if_suid(void) FAST_FUNC; diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 98512bb00..f84e678b5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -209,6 +209,9 @@ pid_t FAST_FUNC fork_or_rexec(char **argv) /* Maybe we are already re-execed and come here again? */ if (re_execed) return 0; + + /* fflush_all(); ? - so far all callers had no buffered output to flush */ + pid = xvfork(); if (pid) /* parent */ return pid; @@ -245,8 +248,11 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) fd = dup(fd); /* have 0,1,2 open at least to /dev/null */ if (!(flags & DAEMON_ONLY_SANITIZE)) { + + /* fflush_all(); - add it in fork_or_rexec() if necessary */ + if (fork_or_rexec(argv)) - exit(EXIT_SUCCESS); /* parent */ + _exit(EXIT_SUCCESS); /* parent */ /* if daemonizing, detach from stdio & ctty */ setsid(); dup2(fd, 0); @@ -258,7 +264,7 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) * Prevent this: stop being a session leader. */ if (fork_or_rexec(argv)) - exit(EXIT_SUCCESS); /* parent */ + _exit(EXIT_SUCCESS); /* parent */ } } while (fd > 2) { diff --git a/loginutils/login.c b/loginutils/login.c index 381468d81..fcdb9592c 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -350,8 +350,8 @@ int login_main(int argc UNUSED_PARAM, char **argv) /* Mandatory paranoia for suid applet: * ensure that fd# 0,1,2 are opened (at least to /dev/null) * and any extra open fd's are closed. - * (The name of the function is misleading. Not daemonizing here.) */ - bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); + */ + bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); username[0] = '\0'; opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); diff --git a/printutils/lpd.c b/printutils/lpd.c index 3fdba5d2b..662d3a224 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -198,9 +198,8 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) q = p; // next line } // helper should not talk over network. - // this call reopens stdio fds to "/dev/null" - // (no daemonization is done) - bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); + // this call reopens stdio fds to "/dev/null". + bb_daemon_helper(DAEMON_DEVNULL_STDIO); BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From 9cf89cdf84fb20154088145980b676d2b28fc55d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 13:45:22 +0200 Subject: sysctl: fix file parsing, do not require -w for VAR=VAL function old new delta sysctl_act_on_setting - 451 +451 sysctl_main 222 282 +60 packed_usage 31744 31793 +49 config_read 604 639 +35 sysctl_act_recursive 612 163 -449 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/1 up/down: 595/-449) Total: 146 bytes Signed-off-by: Denys Vlasenko --- libbb/parse_config.c | 10 +++++----- procps/sysctl.c | 51 +++++++++++++++++++++++++++++++++------------------ testsuite/mdev.tests | 4 ++-- testsuite/parse.tests | 44 +++++++++++++++++++++++++++++++++++++------- 4 files changed, 77 insertions(+), 32 deletions(-) (limited to 'libbb') diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 307ae2cd2..da7482c6d 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -201,10 +201,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const /* Combine remaining arguments? */ if ((t != (ntokens-1)) || !(flags & PARSE_GREEDY)) { /* Vanilla token, find next delimiter */ - line += strcspn(line, delims[0] ? delims : delims + 1); + line += strcspn(line, (delims[0] && (flags & PARSE_EOL_COMMENTS)) ? delims : delims + 1); } else { /* Combining, find comment char if any */ - line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); + line = strchrnul(line, (flags & PARSE_EOL_COMMENTS) ? delims[0] : '\0'); /* Trim any extra delimiters from the end */ if (flags & PARSE_TRIM) { @@ -214,10 +214,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const } /* Token not terminated? */ - if (*line == delims[0]) - *line = '\0'; + if ((flags & PARSE_EOL_COMMENTS) && *line == delims[0]) + *line = '\0'; /* ends with comment char: this line is done */ else if (*line != '\0') - *line++ = '\0'; + *line++ = '\0'; /* token is done, continue parsing line */ #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { diff --git a/procps/sysctl.c b/procps/sysctl.c index b17f5e896..619f4f1e4 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -21,17 +21,17 @@ //kbuild:lib-$(CONFIG_BB_SYSCTL) += sysctl.o //usage:#define sysctl_trivial_usage -//usage: "[OPTIONS] [KEY[=VALUE]]..." +//usage: "-p [-enq] [FILE...] / [-enqaw] [KEY[=VALUE]]..." //usage:#define sysctl_full_usage "\n\n" //usage: "Show/set kernel parameters\n" +//usage: "\n -p Set values from FILEs (default /etc/sysctl.conf)" //usage: "\n -e Don't warn about unknown keys" //usage: "\n -n Don't show key names" +//usage: "\n -q Quiet" //usage: "\n -a Show all values" /* Same as -a, no need to show it */ /* //usage: "\n -A Show all values in table form" */ //usage: "\n -w Set values" -//usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)" -//usage: "\n -q Set values silently" //usage: //usage:#define sysctl_example_usage //usage: "sysctl [-n] [-e] variable...\n" @@ -48,7 +48,7 @@ enum { FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ FLAG_SHOW_ALL = 1 << 3, FLAG_PRELOAD_FILE = 1 << 4, -/* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */ + /* NB: procps 3.2.8 does not require -w for KEY=VAL to work, it only rejects non-KEY=VAL form */ FLAG_WRITE = 1 << 5, FLAG_QUIET = 1 << 6, }; @@ -104,6 +104,7 @@ static int sysctl_act_on_setting(char *setting) int fd, retval = EXIT_SUCCESS; char *cptr, *outname; char *value = value; /* for compiler */ + bool writing = (option_mask32 & FLAG_WRITE); outname = xstrdup(setting); @@ -114,8 +115,10 @@ static int sysctl_act_on_setting(char *setting) cptr++; } - if (option_mask32 & FLAG_WRITE) { - cptr = strchr(setting, '='); + cptr = strchr(setting, '='); + if (cptr) + writing = 1; + if (writing) { if (cptr == NULL) { bb_error_msg("error: '%s' must be of the form name=value", outname); @@ -147,7 +150,7 @@ static int sysctl_act_on_setting(char *setting) break; default: bb_perror_msg("error %sing key '%s'", - option_mask32 & FLAG_WRITE ? + writing ? "sett" : "read", outname); break; @@ -156,7 +159,7 @@ static int sysctl_act_on_setting(char *setting) goto end; } - if (option_mask32 & FLAG_WRITE) { + if (writing) { //TODO: procps 3.2.7 writes "value\n", note trailing "\n" xwrite_str(fd, value); close(fd); @@ -238,22 +241,27 @@ static int sysctl_handle_preload_file(const char *filename) { char *token[2]; parser_t *parser; + int parse_flags; parser = config_open(filename); /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); - /* xchroot("/proc/sys") - if you are paranoid */ //TODO: ';' is comment char too -//TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value -// (but _whitespace_ from ends should be trimmed first (and we do it right)) -//TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") -// can it be fixed by removing PARSE_COLLAPSE bit? - while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { +//TODO: #comment is also comment, not strictly 1st char only + parse_flags = 0; + parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one + parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters + parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line + parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found + parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char + while (config_read(parser, token, 2, 2, "#=", parse_flags)) { char *tp; + trim(token[0]); + trim(token[1]); sysctl_dots_to_slashes(token[0]); tp = xasprintf("%s=%s", token[0], token[1]); - sysctl_act_recursive(tp); + sysctl_act_on_setting(tp); free(tp); } if (ENABLE_FEATURE_CLEAN_UP) @@ -273,12 +281,19 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) option_mask32 = opt; if (opt & FLAG_PRELOAD_FILE) { + int cur_dir_fd; option_mask32 |= FLAG_WRITE; - /* xchdir("/proc/sys") is inside */ - return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); + if (!*argv) + *--argv = (char*)"/etc/sysctl.conf"; + cur_dir_fd = xopen(".", O_RDONLY | O_DIRECTORY); + do { + /* xchdir("/proc/sys") is inside */ + sysctl_handle_preload_file(*argv); + xfchdir(cur_dir_fd); /* files can be relative, must restore cwd */ + } while (*++argv); + return 0; /* procps-ng 3.3.10 does not flag parse errors */ } xchdir("/proc/sys"); - /* xchroot("/proc/sys") - if you are paranoid */ if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { return sysctl_act_recursive("."); } diff --git a/testsuite/mdev.tests b/testsuite/mdev.tests index 8515aff31..8e53ec564 100755 --- a/testsuite/mdev.tests +++ b/testsuite/mdev.tests @@ -168,7 +168,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 @echo @echo TEST" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH ASH_ECHO +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH ASH_ECHO testing "mdev command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS" \ @@ -183,7 +183,7 @@ SKIP= # continuing to use directory structure from prev test rm -rf mdev.testdir/dev/* echo "sda 0:0 644 =block/ @echo @echo TEST:\$MDEV" >mdev.testdir/etc/mdev.conf -optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME FEATURE_SH_IS_ASH +optional STATIC FEATURE_MDEV_CONF FEATURE_MDEV_RENAME FEATURE_MDEV_EXEC FEATURE_LS_RECURSIVE FEATURE_LS_TIMESTAMPS FEATURE_LS_USERNAME SH_IS_ASH testing "mdev move and command" \ "env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1; ls -lnR mdev.testdir/dev | $FILTER_LS2" \ diff --git a/testsuite/parse.tests b/testsuite/parse.tests index 904e1a17a..2cbed6f31 100755 --- a/testsuite/parse.tests +++ b/testsuite/parse.tests @@ -5,13 +5,13 @@ . ./testing.sh -COLLAPSE=$(( 0x00010000)) -TRIM=$(( 0x00020000)) -GREEDY=$(( 0x00040000)) -MIN_DIE=$(( 0x00100000)) -KEEP_COPY=$((0x00200000)) -ESCAPE=$(( 0x00400000)) -NORMAL=$(( COLLAPSE | TRIM | GREEDY)) +COLLAPSE=$(( 0x00010000)) +TRIM=$(( 0x00020000)) +GREEDY=$(( 0x00040000)) +MIN_DIE=$(( 0x00100000)) +KEEP_COPY=$(( 0x00200000)) +EOL_COMMENTS=$((0x00400000)) +NORMAL=$(( COLLAPSE | TRIM | GREEDY | EOL_COMMENTS)) # testing "description" "command" "result" "infile" "stdin" @@ -27,6 +27,34 @@ testing "parse notrim" \ "-" \ " sda 0:0 644 @echo @echo TEST \n" +testing "parse comments" \ + "parse -n 4 -m 3 -f $((NORMAL - EOL_COMMENTS)) -" \ + "[sda][0:0][644][@echo @echo TEST #this is not eaten]\n" \ + "-" \ + "\ +# sda 0:0 644 @echo @echo TEST - this gets eaten + sda 0:0 644 @echo @echo TEST #this is not eaten +" + +testing "parse bad comment" \ + "parse -n 2 -m 2 -d '#=' -f $((GREEDY)) - 2>&1" \ + "\ +[var][val] +parse: bad line 3: 1 tokens found, 2 needed +[ #this][ok] +[ #this][=ok] +[ #this][=ok=ok=ok=] +" \ + "-" \ + "\ +# this gets eaten +var=val + #this causes error msg + #this=ok + #this==ok + #this==ok=ok=ok= +" + FILE=__parse cat >$FILE <$FILE.res < Date: Sat, 5 Aug 2017 17:50:35 +0200 Subject: libbb: make trim() return pointer to terminating NUL function old new delta trim 80 90 +10 angle_address 56 50 -6 sysctl_main 282 273 -9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/3 up/down: +10/-15) Total: -5 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/trim.c | 12 ++++++++++-- mailutils/sendmail.c | 5 ++--- miscutils/lsscsi.c | 3 +-- procps/sysctl.c | 12 ++++++++---- 5 files changed, 22 insertions(+), 12 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 6a2a2d640..6077f64c9 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -347,7 +347,7 @@ unsigned long long monotonic_ms(void) FAST_FUNC; unsigned monotonic_sec(void) FAST_FUNC; extern void chomp(char *s) FAST_FUNC; -extern void trim(char *s) FAST_FUNC; +extern char *trim(char *s) FAST_FUNC; extern char *skip_whitespace(const char *) FAST_FUNC; extern char *skip_non_whitespace(const char *) FAST_FUNC; extern char *skip_dev_pfx(const char *tty_name) FAST_FUNC; diff --git a/libbb/trim.c b/libbb/trim.c index 16cb4fbb0..e47fec74e 100644 --- a/libbb/trim.c +++ b/libbb/trim.c @@ -10,9 +10,10 @@ #include "libbb.h" -void FAST_FUNC trim(char *s) +char* FAST_FUNC trim(char *s) { size_t len = strlen(s); + size_t old = len; /* trim trailing whitespace */ while (len && isspace(s[len-1])) @@ -26,5 +27,12 @@ void FAST_FUNC trim(char *s) memmove(s, nws, len); } } - s[len] = '\0'; + + s += len; + /* If it was a "const char*" which does not need trimming, + * avoid superfluous store */ + if (old != len) + *s = '\0'; + + return s; } diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 346de2712..65895f0ec 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -166,9 +166,8 @@ static char *angle_address(char *str) { char *s, *e; - trim(str); - e = last_char_is(str, '>'); - if (e) { + e = trim(str); + if (e != str && e[-1] == '>') { s = strrchr(str, '<'); if (s) { *e = '\0'; diff --git a/miscutils/lsscsi.c b/miscutils/lsscsi.c index b69ff1eef..c86630e31 100644 --- a/miscutils/lsscsi.c +++ b/miscutils/lsscsi.c @@ -37,9 +37,8 @@ static char *get_line(const char *filename, char *buf, unsigned *bufsize_p) if (sz < 0) sz = 0; buf[sz] = '\0'; - trim(buf); - sz = strlen(buf) + 1; + sz = (trim(buf) - buf) + 1; bufsize -= sz; buf += sz; buf[0] = '\0'; diff --git a/procps/sysctl.c b/procps/sysctl.c index 619f4f1e4..ef1a1b99f 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -257,12 +257,16 @@ static int sysctl_handle_preload_file(const char *filename) parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char while (config_read(parser, token, 2, 2, "#=", parse_flags)) { char *tp; - trim(token[0]); + trim(token[1]); + tp = trim(token[0]); sysctl_dots_to_slashes(token[0]); - tp = xasprintf("%s=%s", token[0], token[1]); - sysctl_act_on_setting(tp); - free(tp); + /* ^^^converted in-place. tp still points to NUL */ + /* now, add "=TOKEN1" */ + *tp++ = '='; + overlapping_strcpy(tp, token[1]); + + sysctl_act_on_setting(token[0]); } if (ENABLE_FEATURE_CLEAN_UP) config_close(parser); -- cgit v1.2.3-55-g6feb From 50db1f29bf96c2ae4dbb96763793a9592d99cf02 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 5 Aug 2017 18:20:34 +0200 Subject: sysctl: recognize ";comment" and "#comment" lines function old new delta config_read 639 699 +60 Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++++ libbb/parse_config.c | 12 ++++++++++-- procps/sysctl.c | 7 ++++--- 3 files changed, 19 insertions(+), 5 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 6077f64c9..51e8f27a5 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1403,6 +1403,11 @@ enum { // keep a copy of current line PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char + PARSE_ALT_COMMENTS = 0x00800000, // delim[0] and delim[1] are two different allowed comment chars + // (so far, delim[0] will only work as comment char for full-line comment) + // (IOW: it works as if PARSE_EOL_COMMENTS is not set. sysctl applet is okay with this) + PARSE_WS_COMMENTS = 0x01000000, // comments are recognized even if there is whitespace before + // ("line start>#comment" is also comment, not only "line start>#comment") // NORMAL is: // * remove leading and trailing delimiters and collapse // multiple delimiters into one diff --git a/libbb/parse_config.c b/libbb/parse_config.c index da7482c6d..eaf69d97f 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -161,13 +161,18 @@ mintokens > 0 make config_read() print error message if less than mintokens #undef config_read int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) { - char *line; + char *line, *p; int ntokens, mintokens; int t; + char alt_comment_ch; if (!parser) return 0; + alt_comment_ch = '\0'; + if (flags & PARSE_ALT_COMMENTS) + alt_comment_ch = *delims++; + ntokens = (uint8_t)flags; mintokens = (uint8_t)(flags >> 8); @@ -184,7 +189,10 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const if (flags & PARSE_TRIM) line += strspn(line, delims + 1); - if (line[0] == '\0' || line[0] == delims[0]) + p = line; + if (flags & PARSE_WS_COMMENTS) + p = skip_whitespace(p); + if (p[0] == '\0' || p[0] == delims[0] || p[0] == alt_comment_ch) goto again; if (flags & PARSE_KEEP_COPY) { diff --git a/procps/sysctl.c b/procps/sysctl.c index ef1a1b99f..a42a91247 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -247,15 +247,16 @@ static int sysctl_handle_preload_file(const char *filename) /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); -//TODO: ';' is comment char too -//TODO: #comment is also comment, not strictly 1st char only parse_flags = 0; parse_flags &= ~PARSE_COLLAPSE; // NO (var==val is not var=val) - treat consecutive delimiters as one parse_flags &= ~PARSE_TRIM; // NO - trim leading and trailing delimiters parse_flags |= PARSE_GREEDY; // YES - last token takes entire remainder of the line parse_flags &= ~PARSE_MIN_DIE; // NO - die if < min tokens found parse_flags &= ~PARSE_EOL_COMMENTS; // NO (only first char) - comments are recognized even if not first char - while (config_read(parser, token, 2, 2, "#=", parse_flags)) { + parse_flags |= PARSE_ALT_COMMENTS;// YES - two comment chars: ';' and '#' + /* #comment is also comment, not strictly 1st char only */ + parse_flags |= PARSE_WS_COMMENTS; // YES - comments are recognized even if there is whitespace before + while (config_read(parser, token, 2, 2, ";#=", parse_flags)) { char *tp; trim(token[1]); -- cgit v1.2.3-55-g6feb From 32b60cc0db90e517399ca9fa73a8ac1140db810d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 12:17:46 +0200 Subject: kbd_mode: try harder to find console device if -C TTY is not given Was (under X): $ ./busybox_old kbd_mode kbd_mode: ioctl 0x4b44 failed: Inappropriate ioctl for device Now: $ ./busybox kbd_mode The keyboard is in off mode function old new delta kbd_mode_main 166 174 +8 packed_usage 31782 31764 -18 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/1 up/down: 8/-18) Total: -10 bytes text data bss dec hex filename 915757 485 6880 923122 e15f2 busybox_old 915747 485 6880 923112 e15e8 busybox_unstripped Signed-off-by: Denys Vlasenko --- console-tools/kbd_mode.c | 22 ++++++++++++++-------- libbb/get_console.c | 1 - 2 files changed, 14 insertions(+), 9 deletions(-) (limited to 'libbb') diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index da31af28d..b0b594614 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -22,7 +22,7 @@ //usage:#define kbd_mode_trivial_usage //usage: "[-a|k|s|u] [-C TTY]" //usage:#define kbd_mode_full_usage "\n\n" -//usage: "Report or set the keyboard mode\n" +//usage: "Report or set VT console keyboard mode\n" //usage: "\n -a Default (ASCII)" //usage: "\n -k Medium-raw (keycode)" //usage: "\n -s Raw (scancode)" @@ -43,15 +43,20 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) }; int fd; unsigned opt; -//TODO? kbd-2.0.3 without -C tries in sequence: -//fd#0, /dev/tty, /dev/tty0. -//Also, it checks KDGKBTYPE before doing KDGKBMODE -//maybe we can use get_console_fd_or_die()? - const char *tty_name = CURRENT_TTY; + const char *tty_name; opt = getopt32(argv, "sakuC:", &tty_name); - fd = xopen_nonblocking(tty_name); - opt &= 0xf; /* clear -C bit, see (*) */ + if (opt & 0x10) { + opt &= 0xf; /* clear -C bit, see (*) */ + fd = xopen_nonblocking(tty_name); + } else { + /* kbd-2.0.3 tries in sequence: + * fd#0, /dev/tty, /dev/tty0. + * get_console_fd_or_die: /dev/console, /dev/tty0, /dev/tty. + * kbd-2.0.3 checks KDGKBTYPE, get_console_fd_or_die checks too. + */ + fd = get_console_fd_or_die(); + } if (!opt) { /* print current setting */ const char *mode = "unknown"; @@ -79,6 +84,7 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) * #define K_OFF 0x04 * (looks like "-ak" together would cause the same effect as -u) */ + opt &= 0xf; /* clear -C bit */ opt = opt & UNICODE ? 3 : opt >> 1; /* double cast prevents warnings about widening conversion */ xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); diff --git a/libbb/get_console.c b/libbb/get_console.c index 9b6407bd0..96b339ca7 100644 --- a/libbb/get_console.c +++ b/libbb/get_console.c @@ -64,7 +64,6 @@ int FAST_FUNC get_console_fd_or_die(void) } bb_error_msg_and_die("can't open console"); - /*return fd; - total failure */ } /* From */ -- cgit v1.2.3-55-g6feb From 2262746e2b798361a9c293e02f76cb4f06b7b100 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 6 Aug 2017 17:14:09 +0200 Subject: slattach: code shrink, better --help text function old new delta tcsetattr_serial_or_warn - 34 +34 static.int_N_SLIP - 4 +4 restore_state_and_exit 123 117 -6 packed_usage 31774 31747 -27 set_termios_state_or_warn 42 - -42 slattach_main 673 624 -49 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 0/3 up/down: 38/-124) Total: -86 bytes Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 6 +- libbb/xfuncs.c | 2 +- networking/slattach.c | 167 +++++++++++++++++++------------------------------- 3 files changed, 68 insertions(+), 107 deletions(-) (limited to 'libbb') diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 9b33afc32..3bd82aa60 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -78,7 +78,7 @@ conspy - interactive, longterm cp - noexec. runner cpio - runner crond - daemon -crontab 0 leaks: open+xasprintf +crontab - longterm (runs $EDITOR), leaks: open+xasprintf cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin cttyhack - noexec. spawner cut - noexec. runner @@ -311,7 +311,7 @@ setkeycodes setlogcons setpriv - spawner, changes state, let's play safe and not be noexec setserial -setsid - spawner, uses fork_or_rexec() [not audted to work in noexec], let's play safe and not be noexec +setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec setuidgid - noexec. spawner sha1sum - noexec. runner sha256sum - noexec. runner @@ -320,7 +320,7 @@ sha512sum - noexec. runner showkey - interactive, longterm shred - runner shuf - noexec. runner -slattach +slattach - longterm (may sleep forever), uses bb_common_bufsiz1 sleep - runner, longterm smemcap - runner softlimit - noexec. spawner diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 98d3531d6..1b3a1667b 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -313,7 +313,7 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) { -//TODO: lineedit, microcom and less might be adapted to use this too: +//TODO: lineedit, microcom, slattach, less might be adapted to use this too: // grep for "tcsetattr" struct termios newterm; diff --git a/networking/slattach.c b/networking/slattach.c index 71b5bf427..d4659a314 100644 --- a/networking/slattach.c +++ b/networking/slattach.c @@ -17,23 +17,23 @@ //config: default y //config: select PLATFORM_LINUX //config: help -//config: slattach is a small utility to attach network interfaces to serial -//config: lines. +//config: slattach configures serial line as SLIP network interface. //applet:IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) +/* shouldn't be NOEXEC: may sleep indefinitely */ //kbuild:lib-$(CONFIG_SLATTACH) += slattach.o //usage:#define slattach_trivial_usage -//usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" +//usage: "[-ehmLF] [-c SCRIPT] [-s BAUD] [-p PROTOCOL] SERIAL_DEVICE" //usage:#define slattach_full_usage "\n\n" -//usage: "Attach network interface(s) to serial line(s)\n" -//usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" -//usage: "\n -s SPD Set line speed" -//usage: "\n -e Exit after initializing device" -//usage: "\n -h Exit when the carrier is lost" -//usage: "\n -c PROG Run PROG when the line is hung up" -//usage: "\n -m Do NOT initialize the line in raw 8 bits mode" +//usage: "Configure serial line as SLIP network interface\n" +//usage: "\n -p PROT Protocol: slip, cslip (default), slip6, clisp6, adaptive" +//usage: "\n -s BAUD Line speed" +//usage: "\n -e Exit after initialization" +//usage: "\n -h Exit if carrier is lost (else never exits)" +//usage: "\n -c PROG Run PROG on carrier loss" +//usage: "\n -m Do NOT set raw 8bit mode" //usage: "\n -L Enable 3-wire operation" //usage: "\n -F Disable RTS/CTS flow control" @@ -42,103 +42,53 @@ #include "libiproute/utils.h" /* invarg_1_to_2() */ struct globals { - int handle; int saved_disc; struct termios saved_state; } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) -#define handle (G.handle ) -#define saved_disc (G.saved_disc ) -#define saved_state (G.saved_state ) #define INIT_G() do { setup_common_bufsiz(); } while (0) +#define serial_fd 3 -/* - * Save tty state and line discipline - * - * It is fine here to bail out on errors, since we haven modified anything yet - */ -static void save_state(void) -{ - /* Save line status */ - if (tcgetattr(handle, &saved_state) < 0) - bb_perror_msg_and_die("get state"); - - /* Save line discipline */ - xioctl(handle, TIOCGETD, &saved_disc); -} - -static int set_termios_state_or_warn(struct termios *state) +static int tcsetattr_serial_or_warn(struct termios *state) { int ret; - ret = tcsetattr(handle, TCSANOW, state); - if (ret < 0) { - bb_perror_msg("set state"); + ret = tcsetattr(serial_fd, TCSANOW, state); + if (ret != 0) { + bb_perror_msg("tcsetattr"); return 1; /* used as exitcode */ } - return 0; + return ret; /* 0 */ } -/* - * Restore state and line discipline for ALL managed ttys - * - * Restoring ALL managed ttys is the only way to have a single - * hangup delay. - * - * Go on after errors: we want to restore as many controlled ttys - * as possible. - */ static void restore_state_and_exit(int exitcode) NORETURN; static void restore_state_and_exit(int exitcode) { struct termios state; /* Restore line discipline */ - if (ioctl_or_warn(handle, TIOCSETD, &saved_disc) < 0) { + if (ioctl_or_warn(serial_fd, TIOCSETD, &G.saved_disc)) { exitcode = 1; } /* Hangup */ - memcpy(&state, &saved_state, sizeof(state)); + memcpy(&state, &G.saved_state, sizeof(state)); cfsetispeed(&state, B0); cfsetospeed(&state, B0); - if (set_termios_state_or_warn(&state)) - exitcode = 1; + exitcode |= tcsetattr_serial_or_warn(&state); sleep(1); /* Restore line status */ - if (set_termios_state_or_warn(&saved_state)) + if (tcsetattr_serial_or_warn(&G.saved_state)) exit(EXIT_FAILURE); + if (ENABLE_FEATURE_CLEAN_UP) - close(handle); + close(serial_fd); exit(exitcode); } -/* - * Set tty state, line discipline and encapsulation - */ -static void set_state(struct termios *state, int encap) -{ - int disc; - - /* Set line status */ - if (set_termios_state_or_warn(state)) - goto bad; - /* Set line discliple (N_SLIP always) */ - disc = N_SLIP; - if (ioctl_or_warn(handle, TIOCSETD, &disc) < 0) { - goto bad; - } - - /* Set encapsulation (SLIP, CSLIP, etc) */ - if (ioctl_or_warn(handle, SIOCSIFENCAP, &encap) < 0) { - bad: - restore_state_and_exit(EXIT_FAILURE); - } -} - static void sig_handler(int signo UNUSED_PARAM) { restore_state_and_exit(EXIT_SUCCESS); @@ -155,13 +105,14 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) "cslip6\0" /* 3 */ "adaptive\0" /* 8 */ ; + static const int int_N_SLIP = N_SLIP; - int i, encap, opt; + int encap, opt, fd; struct termios state; const char *proto = "cslip"; const char *extcmd; /* Command to execute after hangup */ const char *baud_str; - int baud_code = -1; /* Line baud rate (system code) */ + int baud_code = baud_code; /* for compiler */ enum { OPT_p_proto = 1 << 0, @@ -177,15 +128,12 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) INIT_G(); /* Parse command line options */ + opt_complementary = "=1"; opt = getopt32(argv, "p:s:c:ehmLF", &proto, &baud_str, &extcmd); /*argc -= optind;*/ argv += optind; - if (!*argv) - bb_show_usage(); - encap = index_in_strings(proto_names, proto); - if (encap < 0) invarg_1_to_2(proto, "protocol"); if (encap > 3) @@ -198,6 +146,22 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) invarg_1_to_2(baud_str, "baud rate"); } + /* Open tty */ + fd = open(*argv, O_RDWR | O_NDELAY); + if (fd < 0) { + char *buf = concat_path_file("/dev", *argv); + fd = xopen(buf, O_RDWR | O_NDELAY); + /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ + free(buf); + } + xmove_fd(fd, serial_fd); + + /* Save current tty state */ + if (tcgetattr(serial_fd, &G.saved_state) != 0) + bb_perror_msg_and_die("tcgetattr"); + /* Save line discipline */ + xioctl(serial_fd, TIOCGETD, &G.saved_disc); + /* Trap signals in order to restore tty states upon exit */ if (!(opt & OPT_e_quit)) { bb_signals(0 @@ -208,43 +172,37 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) , sig_handler); } - /* Open tty */ - handle = open(*argv, O_RDWR | O_NDELAY); - if (handle < 0) { - char *buf = concat_path_file("/dev", *argv); - handle = xopen(buf, O_RDWR | O_NDELAY); - /* maybe if (ENABLE_FEATURE_CLEAN_UP) ?? */ - free(buf); - } - - /* Save current tty state */ - save_state(); - /* Configure tty */ - memcpy(&state, &saved_state, sizeof(state)); + memcpy(&state, &G.saved_state, sizeof(state)); if (!(opt & OPT_m_nonraw)) { /* raw not suppressed */ memset(&state.c_cc, 0, sizeof(state.c_cc)); state.c_cc[VMIN] = 1; state.c_iflag = IGNBRK | IGNPAR; - state.c_oflag = 0; - state.c_lflag = 0; + /*state.c_oflag = 0;*/ + /*state.c_lflag = 0;*/ state.c_cflag = CS8 | HUPCL | CREAD | ((opt & OPT_L_local) ? CLOCAL : 0) | ((opt & OPT_F_noflow) ? 0 : CRTSCTS); - cfsetispeed(&state, cfgetispeed(&saved_state)); - cfsetospeed(&state, cfgetospeed(&saved_state)); + cfsetispeed(&state, cfgetispeed(&G.saved_state)); + cfsetospeed(&state, cfgetospeed(&G.saved_state)); } - if (opt & OPT_s_baud) { cfsetispeed(&state, baud_code); cfsetospeed(&state, baud_code); } - - set_state(&state, encap); + /* Set line status */ + if (tcsetattr_serial_or_warn(&state)) + goto bad; + /* Set line disclipline (N_SLIP always) */ + if (ioctl_or_warn(serial_fd, TIOCSETD, (void*)&int_N_SLIP)) + goto bad; + /* Set encapsulation (SLIP, CSLIP, etc) */ + if (ioctl_or_warn(serial_fd, SIOCSIFENCAP, &encap)) + goto bad; /* Exit now if option -e was passed */ if (opt & OPT_e_quit) - return 0; + return EXIT_SUCCESS; /* If we're not requested to watch, just keep descriptor open * until we are killed */ @@ -254,17 +212,20 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) /* Watch line for hangup */ while (1) { - if (ioctl(handle, TIOCMGET, &i) < 0 || !(i & TIOCM_CAR)) - goto no_carrier; + int modem_stat; + if (ioctl(serial_fd, TIOCMGET, &modem_stat)) + break; + if (!(modem_stat & TIOCM_CAR)) + break; sleep(15); } - no_carrier: - /* Execute command on hangup */ if (opt & OPT_c_extcmd) system(extcmd); /* Restore states and exit */ restore_state_and_exit(EXIT_SUCCESS); + bad: + restore_state_and_exit(EXIT_FAILURE); } -- cgit v1.2.3-55-g6feb From 798b94518e61ced3f7be7766727705df4859878c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 16:00:25 +0200 Subject: ubi tools: ubiupdatevol supports "-" input and actually respects -s SIZE Decided to not make any flash applets NOEXEC. Minor robustifications here and there. Better error messages. Save on strings: function old new delta ubi_tools_main 1235 1288 +53 ubi_get_volid_by_name 125 133 +8 ubirename_main 198 204 +6 get_num_from_file 90 94 +4 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 71/0) Total: 71 bytes text data bss dec hex filename 915696 485 6880 923061 e15b5 busybox_old 915670 485 6880 923035 e159b busybox_unstripped Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 22 +++++++-------- libbb/ubi.c | 1 + miscutils/flash_eraseall.c | 1 + miscutils/flash_lock_unlock.c | 1 + miscutils/flashcp.c | 1 + miscutils/ubi_tools.c | 63 ++++++++++++++++++++++++++----------------- miscutils/ubirename.c | 6 ++++- 7 files changed, 59 insertions(+), 36 deletions(-) (limited to 'libbb') diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index d54c206fe..981a10192 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -123,10 +123,10 @@ fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) find - noexec. runner findfs - suid -flash_eraseall -flash_lock -flash_unlock -flashcp - needs ^C. flash writing may be slow, better to free memory by execing +flash_eraseall - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flash_lock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flash_unlock - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +flashcp - needs ^C. could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner free - nofork candidate(struct globals, needs to close /proc/meminfo fd) @@ -366,13 +366,13 @@ tty - NOFORK ttysize - NOFORK tunctl - noexec tune2fs - noexec. leaks: open+xfunc -ubiattach -ubidetach -ubimkvol -ubirename -ubirmvol -ubirsvol -ubiupdatevol +ubiattach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubidetach - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubimkvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirename - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirmvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubirsvol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) +ubiupdatevol - could be noexec, but I feel flash ops are risky (prone to hw/fw/sw bugs) udhcpc - daemon udhcpd - daemon udpsvd - daemon diff --git a/libbb/ubi.c b/libbb/ubi.c index 34595d797..a90016acf 100644 --- a/libbb/ubi.c +++ b/libbb/ubi.c @@ -35,6 +35,7 @@ int FAST_FUNC ubi_get_volid_by_name(unsigned ubi_devnum, const char *vol_name) if (open_read_close(fname, buf, sizeof(buf)) <= 0) continue; + buf[UBI_MAX_VOLUME_NAME] = '\0'; strchrnul(buf, '\n')[0] = '\0'; if (strcmp(vol_name, buf) == 0) return i; diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index af9ebea24..3ddd9dd99 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -17,6 +17,7 @@ //config: This utility is used to erase the whole MTD device. //applet:IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASH_ERASEALL) += flash_eraseall.o diff --git a/miscutils/flash_lock_unlock.c b/miscutils/flash_lock_unlock.c index 374eed5f6..6f2c049f4 100644 --- a/miscutils/flash_lock_unlock.c +++ b/miscutils/flash_lock_unlock.c @@ -20,6 +20,7 @@ // APPLET_ODDNAME:name main location suid_type help //applet:IF_FLASH_LOCK( APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) //applet:IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASH_LOCK) += flash_lock_unlock.o //kbuild:lib-$(CONFIG_FLASH_UNLOCK) += flash_lock_unlock.o diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c index d4ac62df4..c10b96ee8 100644 --- a/miscutils/flashcp.c +++ b/miscutils/flashcp.c @@ -14,6 +14,7 @@ //config: This utility is used to copy images into a MTD device. //applet:IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_FLASHCP) += flashcp.o diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c index 494718ccf..123551e94 100644 --- a/miscutils/ubi_tools.c +++ b/miscutils/ubi_tools.c @@ -52,6 +52,7 @@ //applet:IF_UBIRMVOL( APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) //applet:IF_UBIRSVOL( APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) //applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o //kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o @@ -83,16 +84,16 @@ #define do_rsvol (ENABLE_UBIRSVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 's')) #define do_update (ENABLE_UBIUPDATEVOL && (UBI_APPLET_CNT == 1 || applet_name[4] == 'p')) -static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg) +static unsigned get_num_from_file(const char *path, unsigned max) { char buf[sizeof(long long)*3]; unsigned long long num; if (open_read_close(path, buf, sizeof(buf)) < 0) - bb_perror_msg_and_die(errmsg, path); + bb_perror_msg_and_die("can't open '%s'", path); /* It can be \n terminated, xatoull won't work well */ if (sscanf(buf, "%llu", &num) != 1 || num > max) - bb_error_msg_and_die(errmsg, path); + bb_error_msg_and_die("number in '%s' is malformed or too large", path); return num; } @@ -226,10 +227,10 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num); strcpy(p, "avail_eraseblocks"); - leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'"); + leb_avail = get_num_from_file(path, UINT_MAX); strcpy(p, "eraseblock_size"); - leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'"); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); size_bytes = leb_avail * (unsigned long long)leb_size; //if (size_bytes <= 0) @@ -241,16 +242,19 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) if (!(opts & OPTION_N)) bb_error_msg_and_die("name not specified"); + /* the structure is memset(0) above */ mkvol_req.vol_id = vol_id; mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; if ((opts & OPTION_t) && type[0] == 's') mkvol_req.vol_type = UBI_STATIC_VOLUME; mkvol_req.alignment = alignment; mkvol_req.bytes = size_bytes; /* signed int64_t */ - strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME); - mkvol_req.name_len = strlen(vol_name); + /* strnlen avoids overflow of 16-bit field (paranoia) */ + mkvol_req.name_len = strnlen(vol_name, UBI_MAX_VOLUME_NAME+1); if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME) bb_error_msg_and_die("volume name too long: '%s'", vol_name); + /* this is safe: .name[] is UBI_MAX_VOLUME_NAME+1 bytes */ + strcpy(mkvol_req.name, vol_name); xioctl(fd, UBI_IOCMKVOL, &mkvol_req); } else @@ -315,38 +319,49 @@ int ubi_tools_main(int argc UNUSED_PARAM, char **argv) else { unsigned ubinum, volnum; unsigned leb_size; - ssize_t len; - char *input_data; + char *buf; /* Assume that device is in normal format. */ /* Removes need for scanning sysfs tree as full libubi does. */ if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) - bb_error_msg_and_die("wrong format of UBI device name"); + bb_error_msg_and_die("UBI device name '%s' is not /dev/ubiN_M", ubi_ctrl); sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); - leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'"); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK); - if (!(opts & OPTION_t)) { - if (!*argv) - bb_show_usage(); + if (!*argv) + bb_show_usage(); + if (NOT_LONE_DASH(*argv)) /* mtd-utils supports "-" as stdin */ xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); - if (!(opts & OPTION_s)) { - struct stat st; - xfstat(STDIN_FILENO, &st, *argv); - size_bytes = st.st_size; - } + + if (!(opts & OPTION_s)) { + struct stat st; + xfstat(STDIN_FILENO, &st, *argv); + size_bytes = st.st_size; } bytes64 = size_bytes; /* this ioctl expects signed int64_t* parameter */ xioctl(fd, UBI_IOCVOLUP, &bytes64); - input_data = xmalloc(leb_size); - while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) { - xwrite(fd, input_data, len); + /* can't use bb_copyfd_exact_size(): copy in blocks of exactly leb_size */ + buf = xmalloc(leb_size); + while (size_bytes != 0) { + int len = full_read(STDIN_FILENO, buf, leb_size); + if (len <= 0) { + if (len < 0) + bb_perror_msg_and_die("read error from '%s'", *argv); + break; + } + if ((unsigned)len > size_bytes) { + /* for this case: "ubiupdatevol -s 1024000 $UBIDEV /dev/urandom" */ + len = size_bytes; + } + xwrite(fd, buf, len); + size_bytes -= len; } - if (len < 0) - bb_perror_msg_and_die("UBI volume update failed"); + if (ENABLE_FEATURE_CLEAN_UP) + free(buf); } } diff --git a/miscutils/ubirename.c b/miscutils/ubirename.c index 786c4b9fa..ecc8fe137 100644 --- a/miscutils/ubirename.c +++ b/miscutils/ubirename.c @@ -14,6 +14,7 @@ //config: Utility to rename UBI volumes //applet:IF_UBIRENAME(APPLET(ubirename, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if flash operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_UBIRENAME) += ubirename.o @@ -80,9 +81,12 @@ int ubirename_main(int argc, char **argv) argv += 2; while (argv[0]) { rnvol->ents[n].vol_id = ubi_get_volid_by_name(ubi_devnum, argv[0]); - rnvol->ents[n].name_len = strlen(argv[1]); + + /* strnlen avoids overflow of 16-bit field (paranoia) */ + rnvol->ents[n].name_len = strnlen(argv[1], sizeof(rnvol->ents[n].name)); if (rnvol->ents[n].name_len >= sizeof(rnvol->ents[n].name)) bb_error_msg_and_die("new name '%s' is too long", argv[1]); + strcpy(rnvol->ents[n].name, argv[1]); n++; argv += 2; -- cgit v1.2.3-55-g6feb From 248a67fb75a0d2c98f4f9935b7bb9e11382b2c78 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:18:09 +0200 Subject: free,stat: make NOEXEC pkill/pgrep/pidof uncovered another quirk: what about noexec's _process names_? Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 18 ++++++++++-------- coreutils/stat.c | 2 +- libbb/vfork_daemon_rexec.c | 2 ++ procps/free.c | 7 +++++-- procps/pgrep.c | 6 +++++- procps/pidof.c | 4 ++++ shell/ash.c | 2 ++ shell/hush.c | 2 ++ 8 files changed, 31 insertions(+), 12 deletions(-) (limited to 'libbb') diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 70f38d867..8ec3bdbe6 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -16,6 +16,8 @@ leak categories. Why can't be NOEXEC: suid: runs under different uid - must fork+exec +if it's important that /proc/PID/cmdline and comm are correct. + ("pkill sh" killing itself before it kills real "sh" is no fun) Why shouldn't be NOFORK/NOEXEC: rare: not started often enough to bother optimizing (example: poweroff) @@ -131,7 +133,7 @@ flash_unlock - hardware flashcp - hardware flock - spawner, changes state (file locks), let's play safe and not be noexec fold - noexec. runner -free - nofork candidate(struct globals, needs to close /proc/meminfo fd) +free - noexec. nofork candidate(struct globals, needs to close /proc/meminfo fd) freeramdisk - leaks: open+ioctl_or_perror_and_die fsck - interactive, longterm fsck.minix - needs ^C @@ -172,7 +174,7 @@ inotifyd - daemon insmod - noexec install - runner ionice - noexec. spawner -iostat - runner +iostat - longterm: "iostat 1" runs indefinitely ip - noexec candidate ipaddr - noexec candidate ipcalc - noexec candidate @@ -244,7 +246,7 @@ mv - noexec candidate, runner nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die nbd-client - noexec nc - runner -netstat - runner with -c +netstat - longterm with -c (continuous listing) nice - noexec. spawner nl - runner nmeter - longterm @@ -257,13 +259,13 @@ partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) passwd - suid paste - noexec. runner patch - needs ^C -pgrep - nofork candidate(xregcomp, procps_scan - are they ok?) -pidof - nofork candidate(uses find_pid_by_name, is that ok?) +pgrep - must fork+exec to get correct /proc/PID/cmdline and comm field +pidof - must fork+exec to get correct /proc/PID/cmdline and comm field ping - suid, longterm ping6 - suid, longterm pipe_progress - longterm pivot_root - NOFORK -pkill - nofork candidate(xregcomp, procps_scan - are they ok?) +pkill - must fork+exec to get correct /proc/PID/cmdline and comm field pmap - noexec candidate, leaks: open+xstrdup popmaildir - runner poweroff - rare @@ -329,7 +331,7 @@ sort - noexec. runner split - runner ssl_client - longterm start-stop-daemon - not noexec: uses bb_common_bufsiz1 -stat - nofork candidate(needs fewer allocs) +stat - noexec. nofork candidate(needs fewer allocs) strings - runner stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd su - suid, spawner @@ -338,7 +340,7 @@ sum - runner sv - noexec. needs ^C (uses usleep(420000)) svc - noexec. needs ^C (uses usleep(420000)) svlogd - daemon -swapoff - rare +swapoff - longterm: may cause memory pressure, execing is beneficial swapon - rare switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode sync - NOFORK diff --git a/coreutils/stat.c b/coreutils/stat.c index 3b85808b5..4e926a908 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -36,7 +36,7 @@ //config: Without this, stat will not support the '-f' option to display //config: information about filesystem status. -//applet:IF_STAT(APPLET(stat, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_STAT(APPLET_NOEXEC(stat, stat, BB_DIR_BIN, BB_SUID_DROP, stat)) //kbuild:lib-$(CONFIG_STAT) += stat.o diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index f84e678b5..50ecea762 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -175,6 +175,8 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) /* reset some state and run without execing */ /* msg_eol = "\n"; - no caller needs this reinited yet */ diff --git a/procps/free.c b/procps/free.c index 618664e08..b57e4a322 100644 --- a/procps/free.c +++ b/procps/free.c @@ -15,7 +15,7 @@ //config: memory in the system, as well as the buffers used by the kernel. //config: The shared memory column should be ignored; it is obsolete. -//applet:IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_FREE(APPLET_NOEXEC(free, free, BB_DIR_USR_BIN, BB_SUID_DROP, free)) //kbuild:lib-$(CONFIG_FREE) += free.o @@ -47,7 +47,10 @@ struct globals { #endif } FIX_ALIASING; #define G (*(struct globals*)bb_common_bufsiz1) -#define INIT_G() do { setup_common_bufsiz(); } while (0) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* NB: noexec applet - globals not zeroed */ \ +} while (0) static unsigned long long scale(unsigned long d) diff --git a/procps/pgrep.c b/procps/pgrep.c index a3ca9e295..a16a6e959 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c @@ -18,9 +18,13 @@ //config: help //config: Send signals to processes by name. -//applet:IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_PGREP(APPLET_ODDNAME(pgrep, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pgrep)) // APPLET_ODDNAME:name main location suid_type help //applet:IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) +/* can't be noexec: can find _itself_ under wrong name, since after fork only, + * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), + * but cmdline? + */ //kbuild:lib-$(CONFIG_PGREP) += pgrep.o //kbuild:lib-$(CONFIG_PKILL) += pgrep.o diff --git a/procps/pidof.c b/procps/pidof.c index 41247a02c..98d7949f8 100644 --- a/procps/pidof.c +++ b/procps/pidof.c @@ -30,6 +30,10 @@ //config: of the pidof, in other words the calling shell or shell script. //applet:IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) +/* can't be noexec: can find _itself_ under wrong name, since after fork only, + * /proc/PID/cmdline and comm are wrong! Can fix comm (prctl(PR_SET_NAME)), + * but cmdline? + */ //kbuild:lib-$(CONFIG_PIDOF) += pidof.o diff --git a/shell/ash.c b/shell/ash.c index e8f3ed26b..0a323e957 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,6 +7803,8 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) run_applet_no_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ diff --git a/shell/hush.c b/shell/hush.c index bb80f422c..b4fe7146b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7387,6 +7387,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); +//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From f2cf1cc716216308a8a6d07e3afab23be07a6b02 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:45:33 +0200 Subject: noexec: set comm field for noexecs function old new delta set_task_comm - 18 +18 tryexec 152 159 +7 pseudo_exec_argv 321 328 +7 main 106 97 -9 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/2 up/down: 34/-13) Total: 23 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++++ libbb/appletlib.c | 13 ++++++++++--- libbb/vfork_daemon_rexec.c | 7 +++++-- shell/ash.c | 5 ++++- shell/hush.c | 5 ++++- 5 files changed, 28 insertions(+), 7 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 51e8f27a5..e4a19ac04 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1116,6 +1116,11 @@ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; extern int find_applet_by_name(const char *name) FAST_FUNC; extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #endif +#if defined(__linux__) +void set_task_comm(const char *comm) FAST_FUNC; +#else +# define set_task_comm(name) ((void)0) +#endif /* Helpers for daemonization. * diff --git a/libbb/appletlib.c b/libbb/appletlib.c index fa28d433b..ce259446b 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -911,6 +911,14 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) } # endif +#if defined(__linux__) && (NUM_APPLETS > 1) +void FAST_FUNC set_task_comm(const char *comm) +{ + /* okay if too long (truncates) */ + prctl(PR_SET_NAME, (long)comm, 0, 0, 0); +} +#endif + # if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) { @@ -1064,15 +1072,14 @@ int main(int argc UNUSED_PARAM, char **argv) applet_name++; applet_name = bb_basename(applet_name); -# if defined(__linux__) /* If we are a result of execv("/proc/self/exe"), fix ugly comm of "exe" */ if (ENABLE_FEATURE_SH_STANDALONE || ENABLE_FEATURE_PREFER_APPLETS || !BB_MMU ) { - prctl(PR_SET_NAME, (long)applet_name, 0, 0, 0); + if (NUM_APPLETS > 1) + set_task_comm(applet_name); } -# endif parse_config_file(); /* ...maybe, if FEATURE_SUID_CONFIG */ run_applet_and_exit(applet_name, argv); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 50ecea762..546cc9e36 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -175,8 +175,6 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) /* reset some state and run without execing */ /* msg_eol = "\n"; - no caller needs this reinited yet */ @@ -185,6 +183,11 @@ int FAST_FUNC spawn_and_wait(char **argv) * init, or a NOFORK applet. But none of those call us * as of yet (and that should probably always stay true). */ +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); /* xfunc_error_retval and applet_name are init by: */ run_applet_no_and_exit(a, argv[0], argv); } diff --git a/shell/ash.c b/shell/ash.c index 0a323e957..507d15c90 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,8 +7803,11 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); run_applet_no_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ diff --git a/shell/hush.c b/shell/hush.c index b4fe7146b..021c1f0ff 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7387,8 +7387,11 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); -//TODO: prctl(PR_SET_NAME, (long)argv[0], 0, 0, 0);? [think pidof, pgrep, pkill] +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(argv[0]); run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From c9c1ccc4ed7e7525a2e3c07d855c7a27c3534430 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 18:59:35 +0200 Subject: noexec: do GETOPT_RESET() before entering APPLET_main() hush -c 'yes | head -1' was not happy. function old new delta tryexec 159 169 +10 pseudo_exec_argv 328 338 +10 Signed-off-by: Denys Vlasenko --- libbb/vfork_daemon_rexec.c | 1 + shell/ash.c | 1 + shell/hush.c | 3 ++- 3 files changed, 4 insertions(+), 1 deletion(-) (limited to 'libbb') diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 546cc9e36..9d3cb9d54 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -176,6 +176,7 @@ int FAST_FUNC spawn_and_wait(char **argv) /* child */ /* reset some state and run without execing */ + GETOPT_RESET(); /* msg_eol = "\n"; - no caller needs this reinited yet */ logmode = LOGMODE_STDIO; diff --git a/shell/ash.c b/shell/ash.c index 507d15c90..bedd27b0d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,6 +7803,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); + GETOPT_RESET(); //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! diff --git a/shell/hush.c b/shell/hush.c index 021c1f0ff..b890107a2 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7386,12 +7386,13 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, //FIXME: should also close saved redir fds /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); - debug_printf_exec("running applet '%s'\n", argv[0]); + GETOPT_RESET(); //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) set_task_comm(argv[0]); + debug_printf_exec("running applet '%s'\n", argv[0]); run_applet_no_and_exit(a, argv[0], argv); } # endif -- cgit v1.2.3-55-g6feb From 80e8e3cc0542ac6242d49eaf223146dcbf2fa0da Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 7 Aug 2017 19:24:57 +0200 Subject: noexec: consolidate code function old new delta run_noexec_applet_and_exit - 61 +61 find_applet_by_name 128 124 -4 run_applet_no_and_exit 441 434 -7 tryexec 169 152 -17 pseudo_exec_argv 338 321 -17 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/6 up/down: 61/-48) Total: 13 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++-- libbb/appletlib.c | 2 -- libbb/vfork_daemon_rexec.c | 37 +++++++++++++++++++++---------------- shell/ash.c | 8 +------- shell/hush.c | 8 +------- 5 files changed, 26 insertions(+), 34 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index e4a19ac04..3f3e033fe 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1112,9 +1112,10 @@ int wait_for_exitstatus(pid_t pid) FAST_FUNC; int spawn_and_wait(char **argv) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; +void run_noexec_applet_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #ifndef BUILD_INDIVIDUAL -extern int find_applet_by_name(const char *name) FAST_FUNC; -extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; +int find_applet_by_name(const char *name) FAST_FUNC; +void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #endif #if defined(__linux__) void set_task_comm(const char *comm) FAST_FUNC; diff --git a/libbb/appletlib.c b/libbb/appletlib.c index ce259446b..5b84920a4 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -924,8 +924,6 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar { int argc = string_array_len(argv); - /* Reinit some shared global data */ - xfunc_error_retval = EXIT_FAILURE; /* * We do not use argv[0]: do not want to repeat massaging of * "-/sbin/halt" -> "halt", for example. diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 9d3cb9d54..a349459f0 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -158,6 +158,26 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) } #endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) +void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) +{ + /* reset some state and run without execing */ + /* msg_eol = "\n"; - no caller needs this reinited yet */ + logmode = LOGMODE_STDIO; + xfunc_error_retval = EXIT_FAILURE; + die_func = NULL; + GETOPT_RESET(); + +//TODO: think pidof, pgrep, pkill! +//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), +//but one from procps-ng-3.3.10 needs more! +//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) + set_task_comm(name); + /* xfunc_error_retval and applet_name are init by: */ + run_applet_no_and_exit(a, name, argv); +} +#endif + int FAST_FUNC spawn_and_wait(char **argv) { int rc; @@ -175,22 +195,7 @@ int FAST_FUNC spawn_and_wait(char **argv) return wait4pid(rc); /* child */ - /* reset some state and run without execing */ - GETOPT_RESET(); - - /* msg_eol = "\n"; - no caller needs this reinited yet */ - logmode = LOGMODE_STDIO; - /* die_func = NULL; - needed if the caller is a shell, - * init, or a NOFORK applet. But none of those call us - * as of yet (and that should probably always stay true). - */ -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); - /* xfunc_error_retval and applet_name are init by: */ - run_applet_no_and_exit(a, argv[0], argv); + run_noexec_applet_and_exit(a, argv[0], argv); } # endif } diff --git a/shell/ash.c b/shell/ash.c index bedd27b0d..6dc1cfef7 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7803,13 +7803,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) const char *cmd, char **argv, c while (*envp) putenv(*envp++); popredir(/*drop:*/ 1); - GETOPT_RESET(); -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); - run_applet_no_and_exit(applet_no, cmd, argv); + run_noexec_applet_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ execve(bb_busybox_exec_path, argv, envp); diff --git a/shell/hush.c b/shell/hush.c index b890107a2..8dc531657 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7386,14 +7386,8 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, //FIXME: should also close saved redir fds /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); - GETOPT_RESET(); -//TODO: think pidof, pgrep, pkill! -//set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), -//but one from procps-ng-3.3.10 needs more! -//Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) - set_task_comm(argv[0]); debug_printf_exec("running applet '%s'\n", argv[0]); - run_applet_no_and_exit(a, argv[0], argv); + run_noexec_applet_and_exit(a, argv[0], argv); } # endif /* Re-exec ourselves */ -- cgit v1.2.3-55-g6feb From 8858a9864e1d56cfc121755d613d1292727d15f3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 01:21:49 +0200 Subject: libbb: rearrange NOFORK/NOEXEC code, logic is not changed Signed-off-by: Denys Vlasenko --- NOFORK_NOEXEC.lst | 4 +- libbb/vfork_daemon_rexec.c | 125 +++++++++++++++++++++++++-------------------- 2 files changed, 71 insertions(+), 58 deletions(-) (limited to 'libbb') diff --git a/NOFORK_NOEXEC.lst b/NOFORK_NOEXEC.lst index 98e1bffdf..bfb76a12e 100644 --- a/NOFORK_NOEXEC.lst +++ b/NOFORK_NOEXEC.lst @@ -124,7 +124,7 @@ fatattr - noexec. leaks: open+xioctl, complex fbset - hardware, leaks: open+xfunc fbsplash - runner, longterm fdflush - hardware, leaks: open+ioctl_or_perror_and_die -fdformat - hardware, needs ^C (floppy may be unresponsive), longterm +fdformat - hardware, longterm fdisk - interactive, longterm fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) @@ -413,7 +413,7 @@ wget - longterm which - NOFORK who - noexec. nofork candidate(is getutxent ok?) whoami - NOFORK -whois - needs ^C +whois - talks to network xargs - noexec. spawner xxd - noexec. runner xz - runner diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index a349459f0..c96cd61a5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -14,61 +14,12 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "busybox.h" /* uses applet tables */ #include "NUM_APPLETS.h" -/* This does a fork/exec in one call, using vfork(). Returns PID of new child, - * -1 for failure. Runs argv[0], searching path if that has no / in it. */ -pid_t FAST_FUNC spawn(char **argv) -{ - /* Compiler should not optimize stores here */ - volatile int failed; - pid_t pid; - - fflush_all(); - - /* Be nice to nommu machines. */ - failed = 0; - pid = vfork(); - if (pid < 0) /* error */ - return pid; - if (!pid) { /* child */ - /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ - BB_EXECVP(argv[0], argv); - - /* We are (maybe) sharing a stack with blocked parent, - * let parent know we failed and then exit to unblock parent - * (but don't run atexit() stuff, which would screw up parent.) - */ - failed = errno; - /* mount, for example, does not want the message */ - /*bb_perror_msg("can't execute '%s'", argv[0]);*/ - _exit(111); - } - /* parent */ - /* Unfortunately, this is not reliable: according to standards - * vfork() can be equivalent to fork() and we won't see value - * of 'failed'. - * Interested party can wait on pid and learn exit code. - * If 111 - then it (most probably) failed to exec */ - if (failed) { - safe_waitpid(pid, NULL, 0); /* prevent zombie */ - errno = failed; - return -1; - } - return pid; -} - -/* Die with an error message if we can't spawn a child process. */ -pid_t FAST_FUNC xspawn(char **argv) -{ - pid_t pid = spawn(argv); - if (pid < 0) - bb_simple_perror_msg_and_die(*argv); - return pid; -} - +/* + * NOFORK support + */ #if ENABLE_FEATURE_PREFER_APPLETS \ || ENABLE_FEATURE_SH_NOFORK static jmp_buf die_jmp; @@ -127,10 +78,10 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) * reset the libc getopt() function, which keeps internal state. */ GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; - argc = 1; - while (argv[argc]) - argc++; + argc = string_array_len(argv); /* If xfunc "dies" in NOFORK applet, die_func longjmp's here instead */ die_func = jump; @@ -153,11 +104,16 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } #endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +/* + * NOEXEC support + */ #if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) { @@ -167,17 +123,74 @@ void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) xfunc_error_retval = EXIT_FAILURE; die_func = NULL; GETOPT_RESET(); +//? applet_long_options = NULL; +//? opt_complementary = NULL; //TODO: think pidof, pgrep, pkill! //set_task_comm() makes our pidof find NOEXECs (e.g. "yes >/dev/null"), //but one from procps-ng-3.3.10 needs more! //Rewrite /proc/PID/cmdline? (need to save argv0 and length at init for this to work!) set_task_comm(name); - /* xfunc_error_retval and applet_name are init by: */ + /* applet_name is set by this function: */ run_applet_no_and_exit(a, name, argv); } #endif +/* + * Higher-level code, hiding optional NOFORK/NOEXEC trickery. + */ + +/* This does a fork/exec in one call, using vfork(). Returns PID of new child, + * -1 for failure. Runs argv[0], searching path if that has no / in it. */ +pid_t FAST_FUNC spawn(char **argv) +{ + /* Compiler should not optimize stores here */ + volatile int failed; + pid_t pid; + + fflush_all(); + + /* Be nice to nommu machines. */ + failed = 0; + pid = vfork(); + if (pid < 0) /* error */ + return pid; + if (!pid) { /* child */ + /* This macro is ok - it doesn't do NOEXEC/NOFORK tricks */ + BB_EXECVP(argv[0], argv); + + /* We are (maybe) sharing a stack with blocked parent, + * let parent know we failed and then exit to unblock parent + * (but don't run atexit() stuff, which would screw up parent.) + */ + failed = errno; + /* mount, for example, does not want the message */ + /*bb_perror_msg("can't execute '%s'", argv[0]);*/ + _exit(111); + } + /* parent */ + /* Unfortunately, this is not reliable: according to standards + * vfork() can be equivalent to fork() and we won't see value + * of 'failed'. + * Interested party can wait on pid and learn exit code. + * If 111 - then it (most probably) failed to exec */ + if (failed) { + safe_waitpid(pid, NULL, 0); /* prevent zombie */ + errno = failed; + return -1; + } + return pid; +} + +/* Die with an error message if we can't spawn a child process. */ +pid_t FAST_FUNC xspawn(char **argv) +{ + pid_t pid = spawn(argv); + if (pid < 0) + bb_simple_perror_msg_and_die(*argv); + return pid; +} + int FAST_FUNC spawn_and_wait(char **argv) { int rc; -- cgit v1.2.3-55-g6feb From ddd1ee44436c2ec7e0125ca128c9a148bea8a2c0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 14:09:23 +0200 Subject: libbb: simplify NOFORK/NOEXEC defines, move set_task_comm to libbb Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 16 ---------------- libbb/vfork_daemon_rexec.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 25 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 5b84920a4..cbca7ef17 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -34,14 +34,6 @@ # include /* for mallopt */ #endif -#include -#ifndef PR_SET_NAME -#define PR_SET_NAME 15 -#endif -#ifndef PR_GET_NAME -#define PR_GET_NAME 16 -#endif - /* Declare _main() */ #define PROTOTYPES #include "applets.h" @@ -911,14 +903,6 @@ int busybox_main(int argc UNUSED_PARAM, char **argv) } # endif -#if defined(__linux__) && (NUM_APPLETS > 1) -void FAST_FUNC set_task_comm(const char *comm) -{ - /* okay if too long (truncates) */ - prctl(PR_SET_NAME, (long)comm, 0, 0, 0); -} -#endif - # if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) { diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index c96cd61a5..e55847f93 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -14,14 +14,32 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +#include +#ifndef PR_SET_NAME +#define PR_SET_NAME 15 +#endif +#ifndef PR_GET_NAME +#define PR_GET_NAME 16 +#endif + #include "busybox.h" /* uses applet tables */ #include "NUM_APPLETS.h" +#define NOFORK_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_NOFORK)) +#define NOEXEC_SUPPORT ((NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE)) + +#if defined(__linux__) && (NUM_APPLETS > 1) +void FAST_FUNC set_task_comm(const char *comm) +{ + /* okay if too long (truncates) */ + prctl(PR_SET_NAME, (long)comm, 0, 0, 0); +} +#endif + /* - * NOFORK support + * NOFORK/NOEXEC support */ -#if ENABLE_FEATURE_PREFER_APPLETS \ - || ENABLE_FEATURE_SH_NOFORK +#if NOFORK_SUPPORT static jmp_buf die_jmp; static void jump(void) { @@ -109,12 +127,9 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } -#endif /* FEATURE_PREFER_APPLETS || FEATURE_SH_NOFORK */ +#endif -/* - * NOEXEC support - */ -#if (NUM_APPLETS > 1) && (ENABLE_FEATURE_PREFER_APPLETS || ENABLE_FEATURE_SH_STANDALONE) +#if NOEXEC_SUPPORT void FAST_FUNC run_noexec_applet_and_exit(int a, const char *name, char **argv) { /* reset some state and run without execing */ @@ -212,7 +227,7 @@ int FAST_FUNC spawn_and_wait(char **argv) } # endif } -#endif /* FEATURE_PREFER_APPLETS */ +#endif rc = spawn(argv); return wait4pid(rc); } -- cgit v1.2.3-55-g6feb From 036585a911a5fe6c2cd77b808dd9150500f37272 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 8 Aug 2017 16:38:18 +0200 Subject: getopt32: remove applet_long_options FEATURE_GETOPT_LONG made dependent on LONG_OPTS. The folloving options are removed, now LONG_OPTS enables long options for affected applets: FEATURE_ENV_LONG_OPTIONS FEATURE_EXPAND_LONG_OPTIONS FEATURE_UNEXPAND_LONG_OPTIONS FEATURE_MKDIR_LONG_OPTIONS FEATURE_MV_LONG_OPTIONS FEATURE_RMDIR_LONG_OPTIONS FEATURE_ADDGROUP_LONG_OPTIONS FEATURE_ADDUSER_LONG_OPTIONS FEATURE_HWCLOCK_LONG_OPTIONS FEATURE_NSENTER_LONG_OPTS FEATURE_CHCON_LONG_OPTIONS FEATURE_RUNCON_LONG_OPTIONS They either had a small number of long options, or their long options are essential. Example: upstream addgroup and adduser have ONLY longopts, we should probably go further and get rid of non-standard short options. To this end, make addgroup and adduser "select LONG_OPTS". We had this breakage caused by us even in our own package! #if ENABLE_LONG_OPTS || !ENABLE_ADDGROUP /* We try to use --gid, not -g, because "standard" addgroup * has no short option -g, it has only long --gid. */ argv[1] = (char*)"--gid"; #else /* Breaks if system in fact does NOT use busybox addgroup */ argv[1] = (char*)"-g"; #endif xargs: its lone longopt no longer depends on DESKTOP, only on LONG_OPTS. hwclock TODO: get rid of incompatible -t, -l aliases to --systz, --localtime Shorten help texts by omitting long option when short opt alternative exists. Reduction of size comes from the fact that store of an immediate (an address of longopts) to a fixed address (global variable) is a longer insn than pushing that immediate or passing it in a register. This effect is CPU-agnostic. function old new delta getopt32 1350 22 -1328 vgetopt32 - 1318 +1318 getopt32long - 24 +24 tftpd_main 562 567 +5 scan_recursive 376 380 +4 collect_cpu 545 546 +1 date_main 1096 1095 -1 hostname_main 262 259 -3 uname_main 259 255 -4 setpriv_main 362 358 -4 rmdir_main 191 187 -4 mv_main 562 558 -4 ipcalc_main 548 544 -4 ifenslave_main 641 637 -4 gzip_main 192 188 -4 gunzip_main 77 73 -4 fsfreeze_main 81 77 -4 flock_main 318 314 -4 deluser_main 337 333 -4 cp_main 374 370 -4 chown_main 175 171 -4 applet_long_options 4 - -4 xargs_main 894 889 -5 wget_main 2540 2535 -5 udhcpc_main 2767 2762 -5 touch_main 436 431 -5 tar_main 1014 1009 -5 start_stop_daemon_main 1033 1028 -5 sed_main 682 677 -5 script_main 1082 1077 -5 run_parts_main 330 325 -5 rtcwake_main 459 454 -5 od_main 2169 2164 -5 nl_main 201 196 -5 modprobe_main 773 768 -5 mkdir_main 160 155 -5 ls_main 568 563 -5 install_main 773 768 -5 hwclock_main 411 406 -5 getopt_main 622 617 -5 fstrim_main 256 251 -5 env_main 198 193 -5 dumpleases_main 635 630 -5 dpkg_main 3991 3986 -5 diff_main 1355 1350 -5 cryptpw_main 233 228 -5 cpio_main 593 588 -5 conspy_main 1135 1130 -5 chpasswd_main 313 308 -5 adduser_main 887 882 -5 addgroup_main 416 411 -5 ftpgetput_main 351 345 -6 get_terminal_width_height 242 234 -8 expand_main 690 680 -10 static.expand_longopts 18 - -18 static.unexpand_longopts 27 - -27 mkdir_longopts 28 - -28 env_longopts 30 - -30 static.ifenslave_longopts 34 - -34 mv_longopts 46 - -46 static.rmdir_longopts 48 - -48 packed_usage 31739 31687 -52 ------------------------------------------------------------------------------ (add/remove: 2/8 grow/shrink: 3/49 up/down: 1352/-1840) Total: -488 bytes text data bss dec hex filename 915681 485 6880 923046 e15a6 busybox_old 915428 485 6876 922789 e14a5 busybox_unstripped Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 5 +-- archival/cpio.c | 7 ++-- archival/dpkg.c | 3 +- archival/gzip.c | 7 ++-- archival/tar.c | 11 ++++--- coreutils/chown.c | 7 ++-- coreutils/cp.c | 7 ++-- coreutils/date.c | 5 ++- coreutils/env.c | 21 +++--------- coreutils/expand.c | 53 +++++++----------------------- coreutils/install.c | 18 +++++++---- coreutils/ls.c | 3 +- coreutils/mkdir.c | 33 +++++++------------ coreutils/mv.c | 38 +++++++--------------- coreutils/nl.c | 5 ++- coreutils/nproc.c | 1 - coreutils/od_bloaty.c | 7 ++-- coreutils/rmdir.c | 27 ++++------------ coreutils/touch.c | 13 +++++--- coreutils/uname.c | 3 +- debianutils/run_parts.c | 14 ++++---- debianutils/start_stop_daemon.c | 12 ++++--- editors/diff.c | 10 +++--- editors/patch_bbox.c | 3 +- editors/sed.c | 8 ++--- findutils/xargs.c | 9 ++---- include/libbb.h | 25 +++++++++------ libbb/getopt32.c | 71 ++++++++++++++++++++++++++--------------- libbb/vfork_daemon_rexec.c | 17 +++++----- loginutils/addgroup.c | 14 ++------ loginutils/adduser.c | 25 +++------------ loginutils/chpasswd.c | 3 +- loginutils/cryptpw.c | 4 +-- loginutils/deluser.c | 5 ++- miscutils/conspy.c | 4 +-- miscutils/nandwrite.c | 8 ++--- modutils/modprobe.c | 3 +- networking/ftpgetput.c | 10 +++--- networking/hostname.c | 12 +++---- networking/ifenslave.c | 14 +++----- networking/ipcalc.c | 10 +++--- networking/udhcp/d6_dhcpc.c | 4 +-- networking/udhcp/dhcpc.c | 4 +-- networking/udhcp/dumpleases.c | 3 +- networking/wget.c | 9 ++++-- selinux/chcon.c | 41 +++++++----------------- selinux/runcon.c | 22 ++----------- util-linux/flock.c | 3 +- util-linux/fsfreeze.c | 9 +++--- util-linux/fstrim.c | 3 +- util-linux/getopt.c | 22 ++----------- util-linux/hwclock.c | 28 ++++++++-------- util-linux/nsenter.c | 35 ++++---------------- util-linux/rtcwake.c | 4 +-- util-linux/script.c | 4 +-- util-linux/setpriv.c | 9 ++++-- util-linux/unshare.c | 3 +- 57 files changed, 299 insertions(+), 459 deletions(-) (limited to 'libbb') diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 9b9fdc87b..20ab893da 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -389,9 +389,10 @@ int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { #if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS - applet_long_options = gunzip_longopts; -#endif + getopt32long(argv, "cfkvqdtn", gunzip_longopts); +#else getopt32(argv, "cfkvqdtn"); +#endif argv += optind; /* If called as zcat... diff --git a/archival/cpio.c b/archival/cpio.c index 38bab8257..f2165be3a 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -360,9 +360,8 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) char *cpio_owner; IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) unsigned opt; - #if ENABLE_LONG_OPTS - applet_long_options = + const char *long_opts = "extract\0" No_argument "i" "list\0" No_argument "t" #if ENABLE_FEATURE_CPIO_O @@ -390,9 +389,9 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* -L makes sense only with -o or -p */ #if !ENABLE_FEATURE_CPIO_O - opt = getopt32(argv, OPTION_STR, &cpio_filename, &cpio_owner); + opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner); #else - opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), + opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts, &cpio_filename, &cpio_owner, &cpio_fmt); #endif argv += optind; diff --git a/archival/dpkg.c b/archival/dpkg.c index 90ad8766c..852e0cac2 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -1766,8 +1766,7 @@ int dpkg_main(int argc UNUSED_PARAM, char **argv) INIT_G(); - IF_LONG_OPTS(applet_long_options = dpkg_longopts); - opt = getopt32(argv, "CilPruF:", &str_f); + opt = getopt32long(argv, "CilPruF:", dpkg_longopts, &str_f); argv += optind; //if (opt & OPT_configure) ... // -C if (opt & OPT_force) { // -F (--force in official dpkg) diff --git a/archival/gzip.c b/archival/gzip.c index 4cf34ac28..9c53895e9 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -2216,11 +2216,12 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) + sizeof(struct globals)); -#if ENABLE_FEATURE_GZIP_LONG_OPTIONS - applet_long_options = gzip_longopts; -#endif /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ +#if ENABLE_FEATURE_GZIP_LONG_OPTIONS + opt = getopt32long(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789", gzip_longopts); +#else opt = getopt32(argv, "cfkv" IF_FEATURE_GZIP_DECOMPRESS("dt") "qn123456789"); +#endif #if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ if (opt & 0x30) // -d and/or -t return gunzip_main(argc, argv); diff --git a/archival/tar.c b/archival/tar.c index f62b33005..44ab246c0 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -940,6 +940,11 @@ static const char tar_longopts[] ALIGN1 = "exclude\0" Required_argument "\xff" # endif ; +# define GETOPT32 getopt32long +# define LONGOPTS ,tar_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -980,9 +985,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) ":\xf9+" // --strip-components=NUM #endif ; -#if ENABLE_FEATURE_TAR_LONG_OPTIONS - applet_long_options = tar_longopts; -#endif #if ENABLE_DESKTOP /* Lie to buildroot when it starts asking stupid questions. */ if (argv[1] && strcmp(argv[1], "--version") == 0) { @@ -1019,7 +1021,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) } } #endif - opt = getopt32(argv, + opt = GETOPT32(argv, "txC:f:Oopvk" IF_FEATURE_TAR_CREATE( "ch" ) IF_FEATURE_SEAMLESS_BZ2( "j" ) @@ -1030,6 +1032,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_SEAMLESS_Z( "Z" ) IF_FEATURE_TAR_NOPRESERVE_TIME("m") IF_FEATURE_TAR_LONG_OPTIONS("\xf9:") // --strip-components + LONGOPTS , &base_dir // -C dir , &tar_filename // -f filename IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T diff --git a/coreutils/chown.c b/coreutils/chown.c index 1bfc725cc..0c77529ec 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c @@ -127,11 +127,12 @@ int chown_main(int argc UNUSED_PARAM, char **argv) int opt, flags; struct param_t param; -#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS - applet_long_options = chown_longopts; -#endif opt_complementary = "-2"; +#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS + opt = getopt32long(argv, OPT_STR, chown_longopts); +#else opt = getopt32(argv, OPT_STR); +#endif argv += optind; /* This matches coreutils behavior (almost - see below) */ diff --git a/coreutils/cp.c b/coreutils/cp.c index 092e39583..fe408950a 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -81,7 +81,7 @@ int cp_main(int argc, char **argv) // -a = -pdR opt_complementary = "-2:l--s:s--l:Pd:rRd:Rd:apdR"; #if ENABLE_FEATURE_CP_LONG_OPTIONS - applet_long_options = + flags = getopt32long(argv, FILEUTILS_CP_OPTSTR, "archive\0" No_argument "a" "force\0" No_argument "f" "interactive\0" No_argument "i" @@ -94,9 +94,10 @@ int cp_main(int argc, char **argv) "update\0" No_argument "u" "remove-destination\0" No_argument "\xff" "parents\0" No_argument "\xfe" - ; -#endif + ); +#else flags = getopt32(argv, FILEUTILS_CP_OPTSTR); +#endif /* Options of cp from GNU coreutils 6.10: * -a, --archive * -f, --force diff --git a/coreutils/date.c b/coreutils/date.c index 5a4ad5fe5..33f210434 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -194,9 +194,8 @@ int date_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "d--s:s--d" IF_FEATURE_DATE_ISOFMT(":R--I:I--R"); - IF_LONG_OPTS(applet_long_options = date_longopts;) - opt = getopt32(argv, "Rs:ud:r:" - IF_FEATURE_DATE_ISOFMT("I::D:"), + opt = getopt32long(argv, "Rs:ud:r:" + IF_FEATURE_DATE_ISOFMT("I::D:"), date_longopts, &date_str, &date_str, &filename IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt)); argv += optind; diff --git a/coreutils/env.c b/coreutils/env.c index 3242446f5..20453e871 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -30,11 +30,6 @@ //config: env is used to set an environment variable and run //config: a command; without options it displays the current //config: environment. -//config: -//config:config FEATURE_ENV_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on ENV && LONG_OPTS //applet:IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) @@ -53,23 +48,17 @@ #include "libbb.h" -#if ENABLE_FEATURE_ENV_LONG_OPTIONS -static const char env_longopts[] ALIGN1 = - "ignore-environment\0" No_argument "i" - "unset\0" Required_argument "u" - ; -#endif - int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int env_main(int argc UNUSED_PARAM, char **argv) { unsigned opts; llist_t *unset_env = NULL; -#if ENABLE_FEATURE_ENV_LONG_OPTIONS - applet_long_options = env_longopts; -#endif - opts = getopt32(argv, "+iu:+", &unset_env); + opts = getopt32long(argv, "+iu:+", + "ignore-environment\0" No_argument "i" + "unset\0" Required_argument "u" + , &unset_env + ); argv += optind; if (argv[0] && LONE_DASH(argv[0])) { opts |= 1; diff --git a/coreutils/expand.c b/coreutils/expand.c index 64f2a539d..fa3ff18f4 100644 --- a/coreutils/expand.c +++ b/coreutils/expand.c @@ -26,21 +26,11 @@ //config: help //config: By default, convert all tabs to spaces. //config: -//config:config FEATURE_EXPAND_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on EXPAND && LONG_OPTS -//config: //config:config UNEXPAND //config: bool "unexpand (6 kb)" //config: default y //config: help //config: By default, convert only leading sequences of blanks to tabs. -//config: -//config:config FEATURE_UNEXPAND_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on UNEXPAND && LONG_OPTS //applet:IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) // APPLET_ODDNAME:name main location suid_type help @@ -53,29 +43,16 @@ //usage: "[-i] [-t N] [FILE]..." //usage:#define expand_full_usage "\n\n" //usage: "Convert tabs to spaces, writing to stdout\n" -//usage: IF_FEATURE_EXPAND_LONG_OPTIONS( -//usage: "\n -i,--initial Don't convert tabs after non blanks" -//usage: "\n -t,--tabs N Tabstops every N chars" -//usage: ) -//usage: IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( //usage: "\n -i Don't convert tabs after non blanks" //usage: "\n -t Tabstops every N chars" -//usage: ) //usage:#define unexpand_trivial_usage //usage: "[-fa][-t N] [FILE]..." //usage:#define unexpand_full_usage "\n\n" //usage: "Convert spaces to tabs, writing to stdout\n" -//usage: IF_FEATURE_UNEXPAND_LONG_OPTIONS( -//usage: "\n -a,--all Convert all blanks" -//usage: "\n -f,--first-only Convert only leading blanks" -//usage: "\n -t,--tabs N Tabstops every N chars" -//usage: ) -//usage: IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( //usage: "\n -a Convert all blanks" //usage: "\n -f Convert only leading blanks" //usage: "\n -t N Tabstops every N chars" -//usage: ) #include "libbb.h" #include "unicode.h" @@ -188,31 +165,23 @@ int expand_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int exit_status = EXIT_SUCCESS; -#if ENABLE_FEATURE_EXPAND_LONG_OPTIONS - static const char expand_longopts[] ALIGN1 = - /* name, has_arg, val */ - "initial\0" No_argument "i" - "tabs\0" Required_argument "t" - ; -#endif -#if ENABLE_FEATURE_UNEXPAND_LONG_OPTIONS - static const char unexpand_longopts[] ALIGN1 = - /* name, has_arg, val */ - "first-only\0" No_argument "i" - "tabs\0" Required_argument "t" - "all\0" No_argument "a" - ; -#endif init_unicode(); if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { - IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts); - opt = getopt32(argv, "it:", &opt_t); + opt = getopt32long(argv, "it:", + "initial\0" No_argument "i" + "tabs\0" Required_argument "t" + , &opt_t + ); } else { - IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts); /* -t NUM sets also -a */ opt_complementary = "ta"; - opt = getopt32(argv, "ft:a", &opt_t); + opt = getopt32long(argv, "ft:a", + "first-only\0" No_argument "i" + "tabs\0" Required_argument "t" + "all\0" No_argument "a" + , &opt_t + ); /* -f --first-only is the default */ if (!(opt & OPT_ALL)) opt |= OPT_INITIAL; } diff --git a/coreutils/install.c b/coreutils/install.c index a1342bb13..c01750f81 100644 --- a/coreutils/install.c +++ b/coreutils/install.c @@ -55,12 +55,17 @@ static const char install_longopts[] ALIGN1 = "target-directory\0" Required_argument "t" /* autofs build insists of using -b --suffix=.orig */ /* TODO? (short option for --suffix is -S) */ -#if ENABLE_SELINUX +# if ENABLE_SELINUX "context\0" Required_argument "Z" "preserve_context\0" No_argument "\xff" "preserve-context\0" No_argument "\xff" -#endif +# endif ; +# define GETOPT32 getopt32long +# define LONGOPTS install_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif @@ -135,15 +140,14 @@ int install_main(int argc, char **argv) #endif }; -#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS - applet_long_options = install_longopts; -#endif opt_complementary = "t--d:d--t:s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); /* -c exists for backwards compatibility, it's needed */ /* -b is ignored ("make a backup of each existing destination file") */ - opts = getopt32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"), + opts = GETOPT32(argv, "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:"), + LONGOPTS &gid_str, &mode_str, &uid_str, &last - IF_SELINUX(, &scontext)); + IF_SELINUX(, &scontext) + ); argc -= optind; argv += optind; diff --git a/coreutils/ls.c b/coreutils/ls.c index 0fe0345b3..0834cdc63 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -1093,7 +1093,6 @@ int ls_main(int argc UNUSED_PARAM, char **argv) #endif /* process options */ - IF_LONG_OPTS(applet_long_options = ls_longopts;) opt_complementary = /* -n and -g imply -l */ "nl:gl" @@ -1111,7 +1110,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ /* -w NUM: */ IF_FEATURE_LS_WIDTH(":w+"); - opt = getopt32(argv, ls_options + opt = getopt32long(argv, ls_options, ls_longopts IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) IF_FEATURE_LS_COLOR(, &color_opt) ); diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index 22851187c..986353dc6 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -18,11 +18,6 @@ //config: default y //config: help //config: mkdir is used to create directories with the specified names. -//config: -//config:config FEATURE_MKDIR_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on MKDIR && LONG_OPTS //applet:IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) @@ -53,19 +48,6 @@ /* This is a NOFORK applet. Be very careful! */ -#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS -static const char mkdir_longopts[] ALIGN1 = - "mode\0" Required_argument "m" - "parents\0" No_argument "p" -#if ENABLE_SELINUX - "context\0" Required_argument "Z" -#endif -#if ENABLE_FEATURE_VERBOSE - "verbose\0" No_argument "v" -#endif - ; -#endif - int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mkdir_main(int argc UNUSED_PARAM, char **argv) { @@ -78,10 +60,17 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) security_context_t scontext; #endif -#if ENABLE_FEATURE_MKDIR_LONG_OPTIONS - applet_long_options = mkdir_longopts; -#endif - opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); + opt = getopt32long(argv, "m:pv" IF_SELINUX("Z:"), + "mode\0" Required_argument "m" + "parents\0" No_argument "p" +# if ENABLE_SELINUX + "context\0" Required_argument "Z" +# endif +# if ENABLE_FEATURE_VERBOSE + "verbose\0" No_argument "v" +# endif + , &smode IF_SELINUX(,&scontext) + ); if (opt & 1) { mode_t mmode = bb_parse_mode(smode, 0777); if (mmode == (mode_t)-1) { diff --git a/coreutils/mv.c b/coreutils/mv.c index 147dd3bb2..7f6e9fef5 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -16,11 +16,6 @@ //config: default y //config: help //config: mv is used to move or rename files or directories. -//config: -//config:config FEATURE_MV_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on MV && LONG_OPTS //applet:IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) @@ -41,23 +36,6 @@ #include "libbb.h" #include "libcoreutils/coreutils.h" -#if ENABLE_FEATURE_MV_LONG_OPTIONS -static const char mv_longopts[] ALIGN1 = - "interactive\0" No_argument "i" - "force\0" No_argument "f" - "no-clobber\0" No_argument "n" - IF_FEATURE_VERBOSE( - "verbose\0" No_argument "v" - ) - ; -#endif - -#define OPT_FORCE (1 << 0) -#define OPT_INTERACTIVE (1 << 1) -#define OPT_NOCLOBBER (1 << 2) -#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) - - int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) { @@ -69,15 +47,23 @@ int mv_main(int argc, char **argv) int status = 0; int copy_flag = 0; -#if ENABLE_FEATURE_MV_LONG_OPTIONS - applet_long_options = mv_longopts; -#endif +#define OPT_FORCE (1 << 0) +#define OPT_INTERACTIVE (1 << 1) +#define OPT_NOCLOBBER (1 << 2) +#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) /* Need at least two arguments. * If more than one of -f, -i, -n is specified , only the final one * takes effect (it unsets previous options). */ opt_complementary = "-2:f-in:i-fn:n-fi"; - flags = getopt32(argv, "finv"); + flags = getopt32long(argv, "finv", + "interactive\0" No_argument "i" + "force\0" No_argument "f" + "no-clobber\0" No_argument "n" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + ); argc -= optind; argv += optind; last = argv[argc - 1]; diff --git a/coreutils/nl.c b/coreutils/nl.c index 93e78c490..c2f8b1042 100644 --- a/coreutils/nl.c +++ b/coreutils/nl.c @@ -57,14 +57,13 @@ int nl_main(int argc UNUSED_PARAM, char **argv) "starting-line-number\0"Required_argument "v" "number-width\0" Required_argument "w" ; - - applet_long_options = nl_longopts; #endif ns.width = 6; ns.start = 1; ns.inc = 1; ns.sep = "\t"; - getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); + getopt32long(argv, "pw:+s:v:+i:+b:", nl_longopts, + &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); ns.all = (opt_b[0] == 'a'); ns.nonempty = (opt_b[0] == 't'); ns.empty_str = xasprintf("%*s\n", ns.width + (int)strlen(ns.sep), ""); diff --git a/coreutils/nproc.c b/coreutils/nproc.c index 0ae55e70a..336b176ca 100644 --- a/coreutils/nproc.c +++ b/coreutils/nproc.c @@ -28,7 +28,6 @@ int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) unsigned long mask[1024]; unsigned i, count = 0; - //applet_long_options = ...; //getopt32(argv, ""); //if --all, count /sys/devices/system/cpu/cpuN dirs, else: diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index fa0196ca4..f19875c42 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -61,8 +61,8 @@ enum { OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, }; -#define OD_GETOPT32() getopt32(argv, \ - "A:N:abcdfhij:lot:*vxsS:w:+:", \ +#define OD_GETOPT32() getopt32long(argv, \ + "A:N:abcdfhij:lot:*vxsS:w:+:", od_longopts, \ /* -w with optional param */ \ /* -S was -s and also had optional parameter */ \ /* but in coreutils 6.3 it was renamed and now has */ \ @@ -1213,9 +1213,6 @@ int od_main(int argc UNUSED_PARAM, char **argv) address_pad_len_char = '7'; /* Parse command line */ -#if ENABLE_LONG_OPTS - applet_long_options = od_longopts; -#endif opt = OD_GETOPT32(); argv += optind; if (opt & OPT_A) { diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c index c04ce78f8..955740494 100644 --- a/coreutils/rmdir.c +++ b/coreutils/rmdir.c @@ -11,14 +11,6 @@ //config: default y //config: help //config: rmdir is used to remove empty directories. -//config: -//config:config FEATURE_RMDIR_LONG_OPTIONS -//config: bool "Enable long options" -//config: default y -//config: depends on RMDIR && LONG_OPTS -//config: help -//config: Support long options for the rmdir applet, including -//config: --ignore-fail-on-non-empty for compatibility with GNU rmdir. //applet:IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) @@ -31,12 +23,9 @@ //usage: "[OPTIONS] DIRECTORY..." //usage:#define rmdir_full_usage "\n\n" //usage: "Remove DIRECTORY if it is empty\n" -//usage: IF_FEATURE_RMDIR_LONG_OPTIONS( -//usage: "\n -p|--parents Include parents" -//usage: "\n --ignore-fail-on-non-empty" -//usage: ) -//usage: IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( //usage: "\n -p Include parents" +//usage: IF_LONG_OPTS( +//usage: "\n --ignore-fail-on-non-empty" //usage: ) //usage: //usage:#define rmdir_example_usage @@ -49,7 +38,7 @@ #define PARENTS (1 << 0) #define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) -#define IGNORE_NON_EMPTY (1 << 2) +#define IGNORE_NON_EMPTY ((1 << 2) * ENABLE_LONG_OPTS) int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rmdir_main(int argc UNUSED_PARAM, char **argv) @@ -58,8 +47,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) int flags; char *path; -#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS - static const char rmdir_longopts[] ALIGN1 = + flags = getopt32long(argv, "pv", "parents\0" No_argument "p" /* Debian etch: many packages fail to be purged or installed * because they desperately want this option: */ @@ -67,10 +55,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_VERBOSE( "verbose\0" No_argument "v" ) - ; - applet_long_options = rmdir_longopts; -#endif - flags = getopt32(argv, "pv"); + ); argv += optind; if (!*argv) { @@ -86,7 +71,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) } if (rmdir(path) < 0) { -#if ENABLE_FEATURE_RMDIR_LONG_OPTIONS +#if ENABLE_LONG_OPTS if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) break; #endif diff --git a/coreutils/touch.c b/coreutils/touch.c index 11b40d427..857761578 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -103,6 +103,11 @@ int touch_main(int argc UNUSED_PARAM, char **argv) "date\0" Required_argument "d" IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; +# define GETOPT32 getopt32long +# define LONGOPTS ,touch_longopts +# else +# define GETOPT32 getopt32 +# define LONGOPTS # endif char *reference_file = NULL; char *date_str = NULL; @@ -112,17 +117,17 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # define reference_file NULL # define date_str NULL # define timebuf ((struct timeval*)NULL) +# define GETOPT32 getopt32 +# define LONGOPTS #endif -#if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS - applet_long_options = touch_longopts; -#endif /* -d and -t both set time. In coreutils, * accepted data format differs a bit between -d and -t. * We accept the same formats for both */ - opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") + opts = GETOPT32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") IF_FEATURE_TOUCH_NODEREF("h") /*ignored:*/ "fma" + LONGOPTS IF_FEATURE_TOUCH_SUSV3(, &reference_file) IF_FEATURE_TOUCH_SUSV3(, &date_str) IF_FEATURE_TOUCH_SUSV3(, &date_str) diff --git a/coreutils/uname.c b/coreutils/uname.c index be9a3f90d..bb2d1fe8d 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c @@ -147,8 +147,7 @@ int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) "operating-system\0" No_argument "o" ; # endif - IF_LONG_OPTS(applet_long_options = uname_longopts); - toprint = getopt32(argv, options); + toprint = getopt32long(argv, options, uname_longopts); if (argv[optind]) { /* coreutils-6.9 compat */ bb_show_usage(); } diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index c6a90a486..b770383c4 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -159,10 +159,15 @@ static const char runparts_longopts[] ALIGN1 = "reverse\0" No_argument "\xf0" "test\0" No_argument "\xf1" "exit-on-error\0" No_argument "\xf2" -#if ENABLE_FEATURE_RUN_PARTS_FANCY +# if ENABLE_FEATURE_RUN_PARTS_FANCY "list\0" No_argument "\xf3" -#endif +# endif ; +# define GETOPT32 getopt32long +# define LONGOPTS ,runparts_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -175,12 +180,9 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) INIT_G(); -#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS - applet_long_options = runparts_longopts; -#endif /* We require exactly one argument: the directory name */ opt_complementary = "=1"; - getopt32(argv, "a:*u:", &arg_list, &umask_p); + GETOPT32(argv, "a:*u:" LONGOPTS, &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 9effdc80b..45c277a53 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -426,6 +426,11 @@ static const char start_stop_daemon_longopts[] ALIGN1 = "retry\0" Required_argument "R" # endif ; +# define GETOPT32 getopt32long +# define LONGOPTS start_stop_daemon_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -446,10 +451,6 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) INIT_G(); -#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS - applet_long_options = start_stop_daemon_longopts; -#endif - /* -K or -S is required; they are mutually exclusive */ /* -p is required if -m is given */ /* -xpun (at least one) is required if -K is given */ @@ -457,8 +458,9 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* -q turns off -v */ opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa" IF_FEATURE_START_STOP_DAEMON_FANCY("q-v"); - opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:" + opt = GETOPT32(argv, "KSbqtma:n:s:u:c:x:p:" IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"), + LONGOPTS &startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) /* We accept and ignore -R / --retry */ diff --git a/editors/diff.c b/editors/diff.c index 03c13908e..d90ac8f94 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -967,6 +967,11 @@ static const char diff_longopts[] ALIGN1 = "starting-file\0" Required_argument "S" "minimal\0" No_argument "d" ; +# define GETOPT32 getopt32long +# define LONGOPTS ,diff_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS #endif int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -980,10 +985,7 @@ int diff_main(int argc UNUSED_PARAM, char **argv) /* exactly 2 params; collect multiple -L