diff options
author | Ron Yorston <rmy@pobox.com> | 2018-12-13 15:01:44 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2018-12-13 15:34:54 +0000 |
commit | c17f7130a77698ba440525919a20d08b26333dd3 (patch) | |
tree | 52bfd64c7af0816d990303c591cc6c03ec5b7b97 | |
parent | 68ddd4ec3c1275c66e01172498055817cbb10f04 (diff) | |
download | busybox-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.c | 100 |
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) | |||
4453 | static pid_t | 4453 | static pid_t |
4454 | waitpid_child(int *status, int wait_flags) | 4454 | waitpid_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) |