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>
This commit is contained in:
parent
55988aed47
commit
b12553faa8
@ -206,9 +206,27 @@ int kill_main(int argc, char **argv)
|
|||||||
|
|
||||||
/* Looks like they want to do a kill. Do that */
|
/* Looks like they want to do a kill. Do that */
|
||||||
while (arg) {
|
while (arg) {
|
||||||
/* Support shell 'space' trick */
|
#if ENABLE_ASH || ENABLE_HUSH
|
||||||
if (arg[0] == ' ')
|
/*
|
||||||
arg++;
|
* We need to support shell's "hack formats" of
|
||||||
|
* " -PRGP_ID" (yes, with a leading space)
|
||||||
|
* and " PID1 PID2 PID3" (with degenerate case "")
|
||||||
|
*/
|
||||||
|
while (*arg != '\0') {
|
||||||
|
char *end;
|
||||||
|
if (*arg == ' ')
|
||||||
|
arg++;
|
||||||
|
pid = bb_strtoi(arg, &end, 10);
|
||||||
|
if (errno && (errno != EINVAL || *end != ' ')) {
|
||||||
|
bb_error_msg("invalid number '%s'", arg);
|
||||||
|
errors++;
|
||||||
|
} else if (kill(pid, signo) != 0) {
|
||||||
|
bb_perror_msg("can't kill pid %d", (int)pid);
|
||||||
|
errors++;
|
||||||
|
}
|
||||||
|
arg = end; /* can only point to ' ' or '\0' now */
|
||||||
|
}
|
||||||
|
#else
|
||||||
pid = bb_strtoi(arg, NULL, 10);
|
pid = bb_strtoi(arg, NULL, 10);
|
||||||
if (errno) {
|
if (errno) {
|
||||||
bb_error_msg("invalid number '%s'", arg);
|
bb_error_msg("invalid number '%s'", arg);
|
||||||
@ -217,6 +235,7 @@ int kill_main(int argc, char **argv)
|
|||||||
bb_perror_msg("can't kill pid %d", (int)pid);
|
bb_perror_msg("can't kill pid %d", (int)pid);
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
arg = *++argv;
|
arg = *++argv;
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
|
58
shell/ash.c
58
shell/ash.c
@ -3783,18 +3783,51 @@ setjobctl(int on)
|
|||||||
static int FAST_FUNC
|
static int FAST_FUNC
|
||||||
killcmd(int argc, char **argv)
|
killcmd(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i = 1;
|
|
||||||
if (argv[1] && strcmp(argv[1], "-l") != 0) {
|
if (argv[1] && strcmp(argv[1], "-l") != 0) {
|
||||||
|
int i = 1;
|
||||||
do {
|
do {
|
||||||
if (argv[i][0] == '%') {
|
if (argv[i][0] == '%') {
|
||||||
struct job *jp = getjob(argv[i], 0);
|
/*
|
||||||
unsigned pid = jp->ps[0].ps_pid;
|
* "kill %N" - job kill
|
||||||
/* Enough space for ' -NNN<nul>' */
|
* Converting to pgrp / pid kill
|
||||||
argv[i] = alloca(sizeof(int)*3 + 3);
|
*/
|
||||||
/* kill_main has matching code to expect
|
struct job *jp;
|
||||||
* leading space. Needed to not confuse
|
char *dst;
|
||||||
* negative pids with "kill -SIGNAL_NO" syntax */
|
int j, n;
|
||||||
sprintf(argv[i], " -%u", pid);
|
|
||||||
|
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]);
|
} while (argv[++i]);
|
||||||
}
|
}
|
||||||
@ -4227,8 +4260,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
|
|||||||
break;
|
break;
|
||||||
job = job->prev_job;
|
job = job->prev_job;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
job = getjob(*argv, 0);
|
job = getjob(*argv, 0);
|
||||||
|
}
|
||||||
/* loop until process terminated or stopped */
|
/* loop until process terminated or stopped */
|
||||||
while (job->state == JOBRUNNING)
|
while (job->state == JOBRUNNING)
|
||||||
blocking_wait_with_raise_on_sig();
|
blocking_wait_with_raise_on_sig();
|
||||||
@ -4724,7 +4758,7 @@ forkchild(struct job *jp, union node *n, int mode)
|
|||||||
#if JOBS
|
#if JOBS
|
||||||
/* do job control only in root shell */
|
/* do job control only in root shell */
|
||||||
doing_jobctl = 0;
|
doing_jobctl = 0;
|
||||||
if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) {
|
if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) {
|
||||||
pid_t pgrp;
|
pid_t pgrp;
|
||||||
|
|
||||||
if (jp->nprocs == 0)
|
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);
|
ash_msg_and_raise_error("can't open '%s'", bb_dev_null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!oldlvl) {
|
if (oldlvl == 0) {
|
||||||
if (iflag) { /* why if iflag only? */
|
if (iflag) { /* why if iflag only? */
|
||||||
setsignal(SIGINT);
|
setsignal(SIGINT);
|
||||||
setsignal(SIGTERM);
|
setsignal(SIGTERM);
|
||||||
|
1
shell/ash_test/ash-signals/sigint1.right
Normal file
1
shell/ash_test/ash-signals/sigint1.right
Normal file
@ -0,0 +1 @@
|
|||||||
|
Sending SIGINT to main shell PID
|
41
shell/ash_test/ash-signals/sigint1.tests
Executable file
41
shell/ash_test/ash-signals/sigint1.tests
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
# What should happen if non-interactive shell gets SIGINT?
|
||||||
|
|
||||||
|
(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) &
|
||||||
|
|
||||||
|
# We create a child which exits with 0 even on SIGINT
|
||||||
|
# (This is truly necessary only if SIGINT is generated by ^C,
|
||||||
|
# in this testcase even bare "sleep 2" would do because
|
||||||
|
# we don't send SIGINT _to_ the_ child_...)
|
||||||
|
$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2'
|
||||||
|
|
||||||
|
# In one second, we (main shell) get SIGINT here.
|
||||||
|
# The question is whether we should, or should not, exit.
|
||||||
|
|
||||||
|
# bash will not stop here. It will execute next command(s).
|
||||||
|
|
||||||
|
# The rationale for this is described here:
|
||||||
|
# http://www.cons.org/cracauer/sigint.html
|
||||||
|
#
|
||||||
|
# Basically, bash will not exit on SIGINT immediately if it waits
|
||||||
|
# for a child. It will wait for the child to exit.
|
||||||
|
# If child exits NOT by dying on SIGINT, then bash will not exit.
|
||||||
|
#
|
||||||
|
# The idea is that the following script:
|
||||||
|
# | emacs file.txt
|
||||||
|
# | more cmds
|
||||||
|
# User may use ^C to interrupt editor's ops like search. But then
|
||||||
|
# emacs exits normally. User expects that script doesn't stop.
|
||||||
|
#
|
||||||
|
# This is a nice idea, but detecting "did process really exit
|
||||||
|
# with SIGINT?" is racy. Consider:
|
||||||
|
# | bash -c 'while true; do /bin/true; done'
|
||||||
|
# When ^C is pressed while bash waits for /bin/true to exit,
|
||||||
|
# it may happen that /bin/true exits with exitcode 0 before
|
||||||
|
# ^C is delivered to it as SIGINT. bash will see SIGINT, then
|
||||||
|
# it will see that child exited with 0, and bash will NOT EXIT.
|
||||||
|
|
||||||
|
# Therefore we do not implement bash behavior.
|
||||||
|
# I'd say that emacs need to put itself into a separate pgrp
|
||||||
|
# to isolate shell from getting stray SIGINTs from ^C.
|
||||||
|
|
||||||
|
echo Next command after SIGINT was executed
|
1
shell/hush_test/hush-misc/sigint1.right
Normal file
1
shell/hush_test/hush-misc/sigint1.right
Normal file
@ -0,0 +1 @@
|
|||||||
|
Sending SIGINT to main shell PID
|
41
shell/hush_test/hush-misc/sigint1.tests
Executable file
41
shell/hush_test/hush-misc/sigint1.tests
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
# What should happen if non-interactive shell gets SIGINT?
|
||||||
|
|
||||||
|
(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) &
|
||||||
|
|
||||||
|
# We create a child which exits with 0 even on SIGINT
|
||||||
|
# (This is truly necessary only if SIGINT is generated by ^C,
|
||||||
|
# in this testcase even bare "sleep 2" would do because
|
||||||
|
# we don't send SIGINT _to_ the_ child_...)
|
||||||
|
$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2'
|
||||||
|
|
||||||
|
# In one second, we (main shell) get SIGINT here.
|
||||||
|
# The question is whether we should, or should not, exit.
|
||||||
|
|
||||||
|
# bash will not stop here. It will execute next command(s).
|
||||||
|
|
||||||
|
# The rationale for this is described here:
|
||||||
|
# http://www.cons.org/cracauer/sigint.html
|
||||||
|
#
|
||||||
|
# Basically, bash will not exit on SIGINT immediately if it waits
|
||||||
|
# for a child. It will wait for the child to exit.
|
||||||
|
# If child exits NOT by dying on SIGINT, then bash will not exit.
|
||||||
|
#
|
||||||
|
# The idea is that the following script:
|
||||||
|
# | emacs file.txt
|
||||||
|
# | more cmds
|
||||||
|
# User may use ^C to interrupt editor's ops like search. But then
|
||||||
|
# emacs exits normally. User expects that script doesn't stop.
|
||||||
|
#
|
||||||
|
# This is a nice idea, but detecting "did process really exit
|
||||||
|
# with SIGINT?" is racy. Consider:
|
||||||
|
# | bash -c 'while true; do /bin/true; done'
|
||||||
|
# When ^C is pressed while bash waits for /bin/true to exit,
|
||||||
|
# it may happen that /bin/true exits with exitcode 0 before
|
||||||
|
# ^C is delivered to it as SIGINT. bash will see SIGINT, then
|
||||||
|
# it will see that child exited with 0, and bash will NOT EXIT.
|
||||||
|
|
||||||
|
# Therefore we do not implement bash behavior.
|
||||||
|
# I'd say that emacs need to put itself into a separate pgrp
|
||||||
|
# to isolate shell from getting stray SIGINTs from ^C.
|
||||||
|
|
||||||
|
echo Next command after SIGINT was executed
|
Loading…
Reference in New Issue
Block a user