aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-12-13 15:01:44 +0000
committerRon Yorston <rmy@pobox.com>2018-12-13 15:34:54 +0000
commitc17f7130a77698ba440525919a20d08b26333dd3 (patch)
tree52bfd64c7af0816d990303c591cc6c03ec5b7b97
parent68ddd4ec3c1275c66e01172498055817cbb10f04 (diff)
downloadbusybox-w32-c17f7130a77698ba440525919a20d08b26333dd3.tar.gz
busybox-w32-c17f7130a77698ba440525919a20d08b26333dd3.tar.bz2
busybox-w32-c17f7130a77698ba440525919a20d08b26333dd3.zip
ash: fix ctrl-c handling for pipelines
There were two flaws in the implementation of ctrl-c handling in waitpid_child(): - processes associated with all jobs were killed; - all processes in a pipeline were killed but only the status of one was updated. As a result of the latter ctrl-c didn't reliably stop a pipeline.
-rw-r--r--shell/ash.c100
1 files changed, 57 insertions, 43 deletions
diff --git a/shell/ash.c b/shell/ash.c
index 2e3b22850..188ec0979 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -4453,12 +4453,14 @@ static BOOL WINAPI ctrl_handler(DWORD dwCtrlType)
4453static pid_t 4453static pid_t
4454waitpid_child(int *status, int wait_flags) 4454waitpid_child(int *status, int wait_flags)
4455{ 4455{
4456 struct job *jb;
4457 struct procstat *ps;
4458 int pid_nr = 0;
4456 pid_t *pidlist; 4459 pid_t *pidlist;
4457 HANDLE *proclist; 4460 HANDLE *proclist;
4458 int pid_nr = 0; 4461 pid_t pid = -1;
4459 pid_t pid;
4460 DWORD win_status, idx; 4462 DWORD win_status, idx;
4461 struct job *jb; 4463 int i, delay;
4462 4464
4463 for (jb = curjob; jb; jb = jb->prev_job) { 4465 for (jb = curjob; jb; jb = jb->prev_job) {
4464 if (jb->state != JOBDONE) 4466 if (jb->state != JOBDONE)
@@ -4474,59 +4476,71 @@ waitpid_child(int *status, int wait_flags)
4474 proclist[0] = hSIGINT; 4476 proclist[0] = hSIGINT;
4475 pid_nr = 1; 4477 pid_nr = 1;
4476 for (jb = curjob; jb; jb = jb->prev_job) { 4478 for (jb = curjob; jb; jb = jb->prev_job) {
4477 struct procstat *ps, *psend;
4478 if (jb->state == JOBDONE) 4479 if (jb->state == JOBDONE)
4479 continue; 4480 continue;
4480 ps = jb->ps; 4481 ps = jb->ps;
4481 psend = ps + jb->nprocs; 4482 for (i = 0; i < jb->nprocs; ++i) {
4482 while (ps < psend) { 4483 if (ps[i].ps_proc) {
4483 if (ps->ps_pid != -1 && ps->ps_proc != NULL) { 4484 pidlist[pid_nr] = ps[i].ps_pid;
4484 pidlist[pid_nr] = ps->ps_pid; 4485 proclist[pid_nr++] = ps[i].ps_proc;
4485 proclist[pid_nr++] = ps->ps_proc;
4486 } 4486 }
4487 ps++;
4488 } 4487 }
4489 } 4488 }
4490 4489
4491 if (pid_nr == 1) { 4490 if (pid_nr == 1)
4492 free(pidlist); 4491 goto done;
4493 free(proclist);
4494 return -1;
4495 }
4496 4492
4497 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE, 4493 idx = WaitForMultipleObjects(pid_nr, proclist, FALSE,
4498 wait_flags&WNOHANG ? 1 : INFINITE); 4494 wait_flags&WNOHANG ? 1 : INFINITE);
4499 if (idx >= pid_nr) { 4495 if (idx < pid_nr) {
4500 free(pidlist); 4496 if (idx == 0) { /* hSIGINT */
4501 free(proclist); 4497 ResetEvent(hSIGINT);
4502 return -1; 4498
4503 } 4499 ps = curjob->ps;
4504 if (!idx) { /* hSIGINT */ 4500 for (i = 0; i < curjob->nprocs; ++i) {
4505 int i; 4501 if (ps[i].ps_proc) {
4506 ResetEvent(hSIGINT); 4502 kill_SIGTERM_by_handle(ps[i].ps_proc, 128+SIGINT);
4507 for (i = 1; i < pid_nr; i++) 4503 pid = ps[i].ps_pid; /* remember last valid pid */
4508 kill_SIGTERM_by_handle(proclist[i], 128+SIGINT); 4504 }
4509 Sleep(200); 4505 }
4510 for (i = 1; i < pid_nr; i++) { 4506
4511 DWORD code; 4507 Sleep(200);
4512 if (GetExitCodeProcess(proclist[i], &code) && 4508 delay = FALSE;
4513 code == STILL_ACTIVE) { 4509 for (i = 0; i < curjob->nprocs; ++i) {
4514 TerminateProcess(proclist[i], 128+SIGINT); 4510 DWORD code;
4515 } 4511 if (ps[i].ps_proc &&
4516 } 4512 GetExitCodeProcess(ps[i].ps_proc, &code) &&
4517 pid = pidlist[1]; 4513 code == STILL_ACTIVE) {
4518 free(pidlist); 4514 TerminateProcess(ps[i].ps_proc, 128+SIGINT);
4519 free(proclist); 4515 delay = TRUE;
4520 *status = 128 + SIGINT; /* terminated by a signal */ 4516 }
4521 if (iflag) 4517 }
4522 write(STDOUT_FILENO, "^C", 2); 4518
4523 return pid; 4519 if (delay)
4520 Sleep(200);
4521 for (i = 0; i < curjob->nprocs; ++i) {
4522 /* mark all pids dead except the one we'll return */
4523 if (ps[i].ps_pid != pid) {
4524 ps[i].ps_status = 128 + SIGINT;
4525 ps[i].ps_pid = -1;
4526 CloseHandle(ps[i].ps_proc);
4527 ps[i].ps_proc = NULL;
4528 }
4529 }
4530
4531 *status = 128 + SIGINT; /* terminated by a signal */
4532 if (iflag)
4533 write(STDOUT_FILENO, "^C", 2);
4534 }
4535 else { /* valid pid index */
4536 GetExitCodeProcess(proclist[idx], &win_status);
4537 *status = (int)win_status << 8;
4538 pid = pidlist[idx];
4539 }
4524 } 4540 }
4525 GetExitCodeProcess(proclist[idx], &win_status); 4541 done:
4526 pid = pidlist[idx];
4527 free(pidlist); 4542 free(pidlist);
4528 free(proclist); 4543 free(proclist);
4529 *status = (int)win_status << 8;
4530 return pid; 4544 return pid;
4531} 4545}
4532#define waitpid(p, s, f) waitpid_child(s, f) 4546#define waitpid(p, s, f) waitpid_child(s, f)