Mercurial > hg > dhcpcd
changeset 5304:04f26d9f1885 draft
privsep: Don't wait for the process to finish when stopping it
Instead, wait on receipt of SIGCHLD so we're not blocked.
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Thu, 04 Jun 2020 12:15:20 +0100 |
| parents | 873d4c26c32a |
| children | 2f87bbd4ac93 |
| files | src/dhcpcd.c src/privsep-root.c src/privsep.c |
| diffstat | 3 files changed, 27 insertions(+), 49 deletions(-) [+] |
line wrap: on
line diff
--- a/src/dhcpcd.c Thu Jun 04 11:30:20 2020 +0100 +++ b/src/dhcpcd.c Thu Jun 04 12:15:20 2020 +0100 @@ -87,6 +87,7 @@ SIGHUP, SIGUSR1, SIGUSR2, + SIGCHLD, }; const size_t dhcpcd_signals_len = __arraycount(dhcpcd_signals); @@ -1399,7 +1400,7 @@ unsigned long long opts; int exit_code; - if (ctx->options & DHCPCD_FORKED) { + if (sig != SIGCHLD && ctx->options & DHCPCD_FORKED) { pid_t pid = pidfile_read(ctx->pidfile); if (pid == -1) { if (errno != ENOENT) @@ -1445,6 +1446,10 @@ if (logopen(ctx->logfile) == -1) logerr(__func__); return; + case SIGCHLD: + while (waitpid(-1, NULL, WNOHANG) > 0) + ; + return; default: logerrx("received signal %d but don't know what to do with it", sig); @@ -2215,7 +2220,6 @@ } break; default: - waitpid(pid, &i, 0); ctx.options |= DHCPCD_FORKED; /* A lie */ ctx.fork_fd = sigpipe[0]; close(sigpipe[1]);
--- a/src/privsep-root.c Thu Jun 04 11:30:20 2020 +0100 +++ b/src/privsep-root.c Thu Jun 04 12:15:20 2020 +0100 @@ -686,6 +686,13 @@ if (sig == SIGINT) return; + /* Reap children */ + if (sig == SIGCHLD) { + while (waitpid(-1, NULL, WNOHANG) > 0) + ; + return; + } + logerrx("process %d unexpectedly terminating on signal %d", getpid(), sig); if (ctx->ps_root_pid == getpid()) {
--- a/src/privsep.c Thu Jun 04 11:30:20 2020 +0100 +++ b/src/privsep.c Thu Jun 04 12:15:20 2020 +0100 @@ -291,61 +291,28 @@ int ps_dostop(struct dhcpcd_ctx *ctx, pid_t *pid, int *fd) { - int status; + int err = 0; #ifdef PRIVSEP_DEBUG logdebugx("%s: pid %d fd %d", __func__, *pid, *fd); #endif - if (*pid == 0) - return 0; - if (*fd == -1) - goto wait; - - eloop_event_delete(ctx->eloop, *fd); - if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1 && - errno != ECONNRESET) - logerr(__func__); - if (shutdown(*fd, SHUT_RDWR) == -1 && errno != ENOTCONN) - logerr(__func__); - close(*fd); - *fd = -1; - -wait: - status = 0; - -#ifdef HAVE_CAPSICUM - unsigned int cap_mode = 0; - int cap_err = cap_getmode(&cap_mode); - if (cap_err == -1) { - if (errno != ENOSYS) - logerr("%s: cap_getmode", __func__); - } else if (cap_mode != 0) - goto nowait; -#endif - - /* Wait for the process to finish */ - while (waitpid(*pid, &status, 0) == -1) { - if (errno != EINTR) { - logerr("%s: waitpid", __func__); - status = 0; - break; + if (*fd != -1) { + eloop_event_delete(ctx->eloop, *fd); + if (ps_sendcmd(ctx, *fd, PS_STOP, 0, NULL, 0) == -1 || + shutdown(*fd, SHUT_RDWR) == -1) + { + logerr(__func__); + err = -1; } -#ifdef PRIVSEP_DEBUG - else - logerr("%s: waitpid ", __func__); -#endif + close(*fd); + *fd = -1; } -#ifdef HAVE_CAPSICUM -nowait: -#endif + + /* Don't wait for the process as it may not respond to the shutdown + * request. We'll reap the process on receipt of SIGCHLD. */ *pid = 0; - -#ifdef PRIVSEP_DEBUG - logdebugx("%s: status %d", __func__, status); -#endif - - return status; + return err; } int
