From 1125d7d6801940a5218b74c8fd46f1eaa2e4de39 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 8 Jan 2017 17:19:38 +0100 Subject: [PATCH] hush: kill builtin and kill %jobspec support Also made it and printf, type and wait builtins optional. function old new delta builtin_kill - 323 +323 bltins1 336 348 +12 builtin_type 114 116 +2 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 337/0) Total: 337 bytes Signed-off-by: Denys Vlasenko --- coreutils/Kbuild.src | 5 +- procps/Kbuild.src | 2 + procps/kill.c | 4 +- shell/hush.c | 134 +++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 138 insertions(+), 7 deletions(-) diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index d9a448781..9ac6b9e78 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src @@ -15,11 +15,14 @@ lib-$(CONFIG_LESS) += cat.o # less too lib-$(CONFIG_CRONTAB) += cat.o # crontab -l lib-$(CONFIG_ADDUSER) += chown.o # used by adduser lib-$(CONFIG_ADDGROUP) += chown.o # used by adduser +lib-$(CONFIG_FTPD) += ls.o # used by ftpd + lib-$(CONFIG_ASH) += echo.o # used by ash lib-$(CONFIG_SH_IS_ASH) += echo.o # used by ash lib-$(CONFIG_BASH_IS_ASH) += echo.o # used by ash lib-$(CONFIG_HUSH) += echo.o # used by hush lib-$(CONFIG_SH_IS_HUSH) += echo.o # used by hush lib-$(CONFIG_BASH_IS_HUSH) += echo.o # used by hush -lib-$(CONFIG_FTPD) += ls.o # used by ftpd + lib-$(CONFIG_ASH_BUILTIN_PRINTF) += printf.o +lib-$(CONFIG_HUSH_PRINTF) += printf.o diff --git a/procps/Kbuild.src b/procps/Kbuild.src index e7adc7340..82f37f0df 100644 --- a/procps/Kbuild.src +++ b/procps/Kbuild.src @@ -11,3 +11,5 @@ INSERT lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash lib-$(CONFIG_SH_IS_ASH) += kill.o # used for built-in kill by ash lib-$(CONFIG_BASH_IS_ASH) += kill.o # used for built-in kill by ash + +lib-$(CONFIG_HUSH_KILL) += kill.o # used for built-in kill by hush diff --git a/procps/kill.c b/procps/kill.c index 36cd22f37..579c8e53c 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -285,8 +285,8 @@ int kill_main(int argc UNUSED_PARAM, char **argv) /* Looks like they want to do a kill. Do that */ while (arg) { -#if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH \ - || ENABLE_HUSH || ENABLE_SH_IS_HUSH || ENABLE_BASH_IS_HUSH +#if ENABLE_ASH || ENABLE_SH_IS_ASH || ENABLE_BASH_IS_ASH \ + || ENABLE_HUSH_KILL /* * We need to support shell's "hack formats" of * " -PRGP_ID" (yes, with a leading space) diff --git a/shell/hush.c b/shell/hush.c index 58132ef17..9aafb4d25 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -44,12 +44,12 @@ * special variables (done: PWD, PPID, RANDOM) * tilde expansion * aliases - * kill %jobspec * follow IFS rules more precisely, including update semantics * builtins mandated by standards we don't support: * [un]alias, command, fc, getopts, newgrp, readonly, times * make complex ${var%...} constructs support optional * make here documents optional + * make trap, read, ulimit builtins optional * * Bash compat TODO: * redirection of stdout+stderr: &> and >& @@ -117,6 +117,34 @@ //config: help //config: Enable help builtin in hush. Code size + ~1 kbyte. //config: +//config:config HUSH_PRINTF +//config: bool "printf builtin" +//config: default y +//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH +//config: help +//config: Enable printf builtin in hush. +//config: +//config:config HUSH_KILL +//config: bool "kill builtin (for kill %jobspec)" +//config: default y +//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH +//config: help +//config: Enable kill builtin in hush. +//config: +//config:config HUSH_WAIT +//config: bool "wait builtin" +//config: default y +//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH +//config: help +//config: Enable wait builtin in hush. +//config: +//config:config HUSH_TYPE +//config: bool "type builtin" +//config: default y +//config: depends on HUSH || SH_IS_HUSH || BASH_IS_HUSH +//config: help +//config: Enable type builtin in hush. +//config: //config:config HUSH_INTERACTIVE //config: bool "Interactive mode" //config: default y @@ -860,7 +888,7 @@ static int builtin_local(char **argv) FAST_FUNC; #if HUSH_DEBUG static int builtin_memleak(char **argv) FAST_FUNC; #endif -#if ENABLE_PRINTF +#if ENABLE_HUSH_PRINTF static int builtin_printf(char **argv) FAST_FUNC; #endif static int builtin_pwd(char **argv) FAST_FUNC; @@ -870,11 +898,18 @@ static int builtin_shift(char **argv) FAST_FUNC; static int builtin_source(char **argv) FAST_FUNC; static int builtin_test(char **argv) FAST_FUNC; static int builtin_trap(char **argv) FAST_FUNC; +#if ENABLE_HUSH_TYPE static int builtin_type(char **argv) FAST_FUNC; +#endif static int builtin_true(char **argv) FAST_FUNC; static int builtin_umask(char **argv) FAST_FUNC; static int builtin_unset(char **argv) FAST_FUNC; +#if ENABLE_HUSH_KILL +static int builtin_kill(char **argv) FAST_FUNC; +#endif +#if ENABLE_HUSH_WAIT static int builtin_wait(char **argv) FAST_FUNC; +#endif #if ENABLE_HUSH_LOOPS static int builtin_break(char **argv) FAST_FUNC; static int builtin_continue(char **argv) FAST_FUNC; @@ -929,6 +964,9 @@ static const struct built_in_command bltins1[] = { #if ENABLE_HUSH_JOB BLTIN("jobs" , builtin_jobs , "List jobs"), #endif +#if ENABLE_HUSH_KILL + BLTIN("kill" , builtin_kill , "Send signals to processes"), +#endif #if ENABLE_HUSH_LOCAL BLTIN("local" , builtin_local , "Set local variables"), #endif @@ -946,18 +984,22 @@ static const struct built_in_command bltins1[] = { #endif BLTIN("trap" , builtin_trap , "Trap signals"), BLTIN("true" , builtin_true , NULL), +#if ENABLE_HUSH_TYPE BLTIN("type" , builtin_type , "Show command type"), +#endif BLTIN("ulimit" , shell_builtin_ulimit , "Control resource limits"), BLTIN("umask" , builtin_umask , "Set file creation mask"), BLTIN("unset" , builtin_unset , "Unset variables"), +#if ENABLE_HUSH_WAIT BLTIN("wait" , builtin_wait , "Wait for process"), +#endif }; /* For now, echo and test are unconditionally enabled. * Maybe make it configurable? */ static const struct built_in_command bltins2[] = { BLTIN("[" , builtin_test , NULL), BLTIN("echo" , builtin_echo , NULL), -#if ENABLE_PRINTF +#if ENABLE_HUSH_PRINTF BLTIN("printf" , builtin_printf , NULL), #endif BLTIN("pwd" , builtin_pwd , NULL), @@ -8689,7 +8731,7 @@ static int FAST_FUNC builtin_echo(char **argv) return run_applet_main(argv, echo_main); } -#if ENABLE_PRINTF +#if ENABLE_HUSH_PRINTF static int FAST_FUNC builtin_printf(char **argv) { return run_applet_main(argv, printf_main); @@ -9227,6 +9269,7 @@ static int FAST_FUNC builtin_trap(char **argv) goto process_sig_list; } +#if ENABLE_HUSH_TYPE /* http://www.opengroup.org/onlinepubs/9699919799/utilities/type.html */ static int FAST_FUNC builtin_type(char **argv) { @@ -9259,6 +9302,7 @@ static int FAST_FUNC builtin_type(char **argv) return ret; } +#endif #if ENABLE_HUSH_JOB static struct pipe *parse_jobspec(const char *str) @@ -9526,6 +9570,87 @@ static int FAST_FUNC builtin_umask(char **argv) return !rc; /* rc != 0 - success */ } +#if ENABLE_HUSH_KILL +static int FAST_FUNC builtin_kill(char **argv) +{ + int ret = 0; + + argv = skip_dash_dash(argv); + if (argv[0] && strcmp(argv[0], "-l") != 0) { + int i = 0; + + do { + struct pipe *pi; + char *dst; + int j, n; + + if (argv[i][0] != '%') + continue; + /* + * "kill %N" - job kill + * Converting to pgrp / pid kill + */ + pi = parse_jobspec(argv[i]); + if (!pi) { + /* Eat bad jobspec */ + j = i; + do { + j++; + argv[j - 1] = argv[j]; + } while (argv[j]); + ret = 1; + i--; + continue; + } + /* + * In jobs started under job control, we signal + * entire process group by kill -PGRP_ID. + * This happens, f.e., in interactive shell. + * + * Otherwise, we signal each child via + * kill PID1 PID2 PID3. + * Testcases: + * sh -c 'sleep 1|sleep 1 & kill %1' + * sh -c 'true|sleep 2 & sleep 1; kill %1' + * sh -c 'true|sleep 1 & sleep 2; kill %1' + */ + n = pi->num_cmds; + if (ENABLE_HUSH_JOB && G_interactive_fd) + n = 1; + dst = alloca(n * sizeof(int)*4); + argv[i] = dst; +#if ENABLE_HUSH_JOB + if (G_interactive_fd) + dst += sprintf(dst, " -%u", (int)pi->pgrp); + else +#endif + for (j = 0; j < n; j++) { + struct command *cmd = &pi->cmds[j]; + /* Skip exited members of the job */ + if (cmd->pid == 0) + continue; + /* + * kill_main has matching code to expect + * leading space. Needed to not confuse + * negative pids with "kill -SIGNAL_NO" syntax + */ + dst += sprintf(dst, " %u", (int)cmd->pid); + } + *dst = '\0'; + } while (argv[++i]); + } + + if (argv[0] || ret == 0) { + argv--; + argv[0] = (char*)"kill"; /* why? think about "kill -- PID" */ + /* kill_main also handles "killall" etc, so it does look at argv[0]! */ + ret = run_applet_main(argv, kill_main); + } + return ret; +} +#endif + +#if ENABLE_HUSH_WAIT /* http://www.opengroup.org/onlinepubs/9699919799/utilities/wait.html */ #if !ENABLE_HUSH_JOB # define wait_for_child_or_signal(pipe,pid) wait_for_child_or_signal(pid) @@ -9686,6 +9811,7 @@ static int FAST_FUNC builtin_wait(char **argv) return ret; } +#endif #if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min) -- 2.25.1