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 --- libbb/vfork_daemon_rexec.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'libbb/vfork_daemon_rexec.c') 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(); -- 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/vfork_daemon_rexec.c') 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 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/vfork_daemon_rexec.c') 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 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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/vfork_daemon_rexec.c') 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