libbb: fix '--help' handling in FEATURE_SH_NOFORK=y

Most BusyBox applets respond to the '--help' option by printing
a usage message.  This is normally handled by busybox_main() so
applet main routines don't have support for '--help'.

In standalone shell mode with FEATURE_SH_NOFORK enabled nofork
applets are invoked directly, bypassing busybox_main().  This
results in inconsistent handling of '--help':

- applets which call getopt() report "unrecognized option '--help'"
  and print help anyway;

- realpath says "--help: No such file or directory" and doesn't
  print help;

- usleep says "invalid number '--help'" and doesn't print help.

Avoid inconsistency by checking for '--help' in run_nofork_applet().

Bug found by Ron Yorston.

function                                             old     new   delta
show_usage_if_dash_dash_help                           -      70     +70
run_nofork_applet                                    347     362     +15
run_applet_no_and_exit                               432     365     -67
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 1/1 up/down: 85/-67)             Total: 18 bytes

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2021-02-18 23:30:24 +01:00
parent 33745b1fc8
commit 6bdfbc4cb5
3 changed files with 25 additions and 10 deletions

View File

@ -1219,6 +1219,7 @@ void run_noexec_applet_and_exit(int a, const char *name, char **argv) NORETURN F
int find_applet_by_name(const char *name) 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; void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC;
#endif #endif
void show_usage_if_dash_dash_help(int applet_no, char **argv) FAST_FUNC;
#if defined(__linux__) #if defined(__linux__)
void set_task_comm(const char *comm) FAST_FUNC; void set_task_comm(const char *comm) FAST_FUNC;
#else #else

View File

@ -905,16 +905,8 @@ int busybox_main(int argc UNUSED_PARAM, char **argv)
# endif # endif
# if NUM_APPLETS > 0 # if NUM_APPLETS > 0
void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) void FAST_FUNC show_usage_if_dash_dash_help(int applet_no, char **argv)
{ {
int argc = string_array_len(argv);
/*
* We do not use argv[0]: do not want to repeat massaging of
* "-/sbin/halt" -> "halt", for example.
*/
applet_name = name;
/* Special case. POSIX says "test --help" /* Special case. POSIX says "test --help"
* should be no different from e.g. "test --foo". * should be no different from e.g. "test --foo".
* Thus for "test", we skip --help check. * Thus for "test", we skip --help check.
@ -931,15 +923,32 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **ar
&& applet_no != APPLET_NO_false && applet_no != APPLET_NO_false
# endif # endif
) { ) {
if (argc == 2 && strcmp(argv[1], "--help") == 0) { if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) {
/* Make "foo --help" exit with 0: */ /* Make "foo --help" exit with 0: */
xfunc_error_retval = 0; xfunc_error_retval = 0;
bb_show_usage(); bb_show_usage();
} }
} }
}
void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv)
{
int argc;
/*
* We do not use argv[0]: do not want to repeat massaging of
* "-/sbin/halt" -> "halt", for example.
*/
applet_name = name;
show_usage_if_dash_dash_help(applet_no, argv);
if (ENABLE_FEATURE_SUID) if (ENABLE_FEATURE_SUID)
check_suid(applet_no); check_suid(applet_no);
argc = string_array_len(argv);
xfunc_error_retval = applet_main[applet_no](argc, argv); xfunc_error_retval = applet_main[applet_no](argc, argv);
/* Note: applet_main() may also not return (die on a xfunc or such) */ /* Note: applet_main() may also not return (die on a xfunc or such) */
xfunc_die(); xfunc_die();
} }

View File

@ -109,8 +109,13 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv)
char *tmp_argv[argc+1]; char *tmp_argv[argc+1];
memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0]));
applet_name = tmp_argv[0]; applet_name = tmp_argv[0];
/* longjmp's (instead of returning) if --help is seen */
show_usage_if_dash_dash_help(applet_no, argv);
/* Finally we can call NOFORK applet's main() */ /* Finally we can call NOFORK applet's main() */
rc = applet_main[applet_no](argc, tmp_argv); rc = applet_main[applet_no](argc, tmp_argv);
/* Important for shells: `which CMD` was failing */ /* Important for shells: `which CMD` was failing */
fflush_all(); fflush_all();
} else { } else {