summaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
authorDenys Vlasenko2011-02-21 03:22:20 +0100
committerDenys Vlasenko2011-02-21 03:22:20 +0100
commitb12553faa8991e11c11f70a81f1d9d44078c7645 (patch)
tree4154d5308a9bad6bb46e2014cb6cc997dc9a92cd /shell/ash.c
parent55988aed472d9cd362f9a50f4999b5e47ca33abe (diff)
downloadbusybox-b12553faa8991e11c11f70a81f1d9d44078c7645.zip
busybox-b12553faa8991e11c11f70a81f1d9d44078c7645.tar.gz
ash: fix ash-signals/signal8 testcase failure
function old new delta killcmd 109 224 +115 kill_main 882 910 +28 changepath 194 195 +1 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 144/0) Total: 144 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c58
1 files changed, 46 insertions, 12 deletions
diff --git a/shell/ash.c b/shell/ash.c
index cccd6dd..98d2c7c 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -3783,18 +3783,51 @@ setjobctl(int on)
static int FAST_FUNC
killcmd(int argc, char **argv)
{
- int i = 1;
if (argv[1] && strcmp(argv[1], "-l") != 0) {
+ int i = 1;
do {
if (argv[i][0] == '%') {
- struct job *jp = getjob(argv[i], 0);
- unsigned pid = jp->ps[0].ps_pid;
- /* Enough space for ' -NNN<nul>' */
- argv[i] = alloca(sizeof(int)*3 + 3);
- /* kill_main has matching code to expect
- * leading space. Needed to not confuse
- * negative pids with "kill -SIGNAL_NO" syntax */
- sprintf(argv[i], " -%u", pid);
+ /*
+ * "kill %N" - job kill
+ * Converting to pgrp / pid kill
+ */
+ struct job *jp;
+ char *dst;
+ int j, n;
+
+ jp = getjob(argv[i], 0);
+ /*
+ * 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 = jp->nprocs; /* can't be 0 (I hope) */
+ if (jp->jobctl)
+ n = 1;
+ dst = alloca(n * sizeof(int)*4);
+ argv[i] = dst;
+ for (j = 0; j < n; j++) {
+ struct procstat *ps = &jp->ps[j];
+ /* Skip non-running and not-stopped members
+ * (i.e. dead members) of the job
+ */
+ if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status))
+ continue;
+ /*
+ * kill_main has matching code to expect
+ * leading space. Needed to not confuse
+ * negative pids with "kill -SIGNAL_NO" syntax
+ */
+ dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid);
+ }
+ *dst = '\0';
}
} while (argv[++i]);
}
@@ -4227,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
break;
job = job->prev_job;
}
- } else
+ } else {
job = getjob(*argv, 0);
+ }
/* loop until process terminated or stopped */
while (job->state == JOBRUNNING)
blocking_wait_with_raise_on_sig();
@@ -4724,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode)
#if JOBS
/* do job control only in root shell */
doing_jobctl = 0;
- if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
+ if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
pid_t pgrp;
if (jp->nprocs == 0)
@@ -4750,7 +4784,7 @@ forkchild(struct job *jp, union node *n, int mode)
ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
}
}
- if (!oldlvl) {
+ if (oldlvl == 0) {
if (iflag) { /* why if iflag only? */
setsignal(SIGINT);
setsignal(SIGTERM);