git: d2d180fb7736 - main - syslogd: Watch for dead pipe processes
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 27 Nov 2024 22:27:15 UTC
The branch main has been updated by jfree: URL: https://cgit.FreeBSD.org/src/commit/?id=d2d180fb77362eb1381ada9edefe4332be776bf2 commit d2d180fb77362eb1381ada9edefe4332be776bf2 Author: Jake Freeland <jfree@FreeBSD.org> AuthorDate: 2024-11-27 22:26:02 +0000 Commit: Jake Freeland <jfree@FreeBSD.org> CommitDate: 2024-11-27 22:26:02 +0000 syslogd: Watch for dead pipe processes For each new pipe process, add its process descriptor into the kqueue with the EVFILT_PROCDESC filter and NOTE_EXIT event. When the pipe process exits, the main kqueue loop will catch this, logging exit errors and cleaning up the pipe process' filed node. Reviewed by: markj Differential Revision: https://reviews.freebsd.org/D41477 --- usr.sbin/syslogd/syslogd.c | 95 ++++++++++++++++++++++++++++++++++++++-------- usr.sbin/syslogd/syslogd.h | 1 + 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/usr.sbin/syslogd/syslogd.c b/usr.sbin/syslogd/syslogd.c index 901a90ef3e35..8cc0534e509d 100644 --- a/usr.sbin/syslogd/syslogd.c +++ b/usr.sbin/syslogd/syslogd.c @@ -316,6 +316,7 @@ static bool KeepKernFac; /* Keep remotely logged kernel facility */ static bool needdofsync = true; /* Are any file(s) waiting to be fsynced? */ static struct pidfh *pfh; static bool RFC3164OutputFormat = true; /* Use legacy format by default. */ +static int kq; /* kqueue(2) descriptor. */ struct iovlist; @@ -324,7 +325,7 @@ static void addpeer(const char *, const char *, mode_t); static void addsock(const char *, const char *, mode_t); static nvlist_t *cfline(const char *, const char *, const char *, const char *); static const char *cvthname(struct sockaddr *); -static void deadq_enter(int); +static struct deadq_entry *deadq_enter(int); static void deadq_remove(struct deadq_entry *); static int decode(const char *, const CODE *); static void die(int) __dead2; @@ -336,6 +337,7 @@ static void fprintlog_successive(struct filed *, int); static void init(bool); static void logmsg(int, const struct logtime *, const char *, const char *, const char *, const char *, const char *, const char *, int); +static void log_deadchild(int, int, const struct filed *); static void markit(void); static struct socklist *socksetup(struct addrinfo *, const char *, mode_t); static int socklist_recv_file(struct socklist *); @@ -373,9 +375,21 @@ close_filed(struct filed *f) f->f_type = F_UNUSED; break; case F_PIPE: - if (f->f_procdesc >= 0) { - deadq_enter(f->f_procdesc); + if (f->f_procdesc != -1) { + /* + * Close the procdesc, killing the underlying + * process (if it is still alive). + */ + (void)close(f->f_procdesc); f->f_procdesc = -1; + /* + * The pipe process is guaranteed to be dead now, + * so remove it from the deadq. + */ + if (f->f_dq != NULL) { + deadq_remove(f->f_dq); + f->f_dq = NULL; + } } break; default: @@ -487,7 +501,7 @@ main(int argc, char *argv[]) struct kevent ev; struct socklist *sl; pid_t spid; - int ch, kq, ppipe_w = -1, s; + int ch, ppipe_w = -1, s; char *p; bool bflag = false, pflag = false, Sflag = false; @@ -789,6 +803,12 @@ main(int argc, char *argv[]) break; } break; + case EVFILT_PROCDESC: + if ((ev.fflags & NOTE_EXIT) != 0) { + log_deadchild(ev.ident, ev.data, ev.udata); + close_filed(ev.udata); + } + break; } } } @@ -1828,6 +1848,7 @@ fprintlog_write(struct filed *f, struct iovlist *il, int flags) dprintf(" %s\n", f->f_pname); iovlist_append(il, "\n"); if (f->f_procdesc == -1) { + struct kevent ev; struct filed *f_in_list; size_t i = 0; @@ -1842,10 +1863,16 @@ fprintlog_write(struct filed *f, struct iovlist *il, int flags) logerror(f->f_pname); break; } + EV_SET(&ev, f->f_procdesc, EVFILT_PROCDESC, EV_ADD, + NOTE_EXIT, 0, f); + if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) { + logerror("failed to add procdesc kevent"); + exit(1); + } } if (writev(f->f_file, il->iov, il->iovcnt) < 0) { logerror(f->f_pname); - close_filed(f); + f->f_dq = deadq_enter(f->f_procdesc); } break; @@ -2216,7 +2243,7 @@ die(int signo) /* flush any pending output */ if (f->f_prevcount) fprintlog_successive(f, 0); - /* close our end of the pipe */ + /* terminate existing pipe processes */ if (f->f_type == F_PIPE) close_filed(f); } @@ -2464,7 +2491,23 @@ closelogfiles(void) case F_FORW: case F_CONSOLE: case F_TTY: + close_filed(f); + break; case F_PIPE: + if (f->f_procdesc != -1) { + struct kevent ev; + /* + * This filed is going to be freed. + * Delete procdesc kevents that reference it. + */ + EV_SET(&ev, f->f_procdesc, EVFILT_PROCDESC, + EV_DELETE, NOTE_EXIT, 0, f); + if (kevent(kq, &ev, 1, NULL, 0, NULL) == -1) { + logerror("failed to delete procdesc" + "kevent"); + exit(1); + } + } close_filed(f); break; default: @@ -3127,15 +3170,11 @@ markit(void) case 0: /* Already signalled once, try harder now. */ (void)pdkill(dq->dq_procdesc, SIGKILL); - (void)deadq_remove(dq); break; case 1: - if (pdkill(dq->dq_procdesc, SIGTERM) != 0) - (void)deadq_remove(dq); - else - dq->dq_timeout--; - break; + (void)pdkill(dq->dq_procdesc, SIGTERM); + /* FALLTHROUGH. */ default: dq->dq_timeout--; } @@ -3552,13 +3591,13 @@ p_open(const char *prog, int *rpd) return (pfd[1]); } -static void +static struct deadq_entry * deadq_enter(int pd) { struct deadq_entry *dq; if (pd == -1) - return; + return (NULL); dq = malloc(sizeof(*dq)); if (dq == NULL) { @@ -3569,16 +3608,42 @@ deadq_enter(int pd) dq->dq_procdesc = pd; dq->dq_timeout = DQ_TIMO_INIT; TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries); + return (dq); } static void deadq_remove(struct deadq_entry *dq) { TAILQ_REMOVE(&deadq_head, dq, dq_entries); - close(dq->dq_procdesc); free(dq); } +static void +log_deadchild(int pd, int status, const struct filed *f) +{ + pid_t pid; + int code; + char buf[256]; + const char *reason; + + errno = 0; /* Keep strerror() stuff out of logerror messages. */ + if (WIFSIGNALED(status)) { + reason = "due to signal"; + code = WTERMSIG(status); + } else { + reason = "with status"; + code = WEXITSTATUS(status); + if (code == 0) + return; + } + if (pdgetpid(pd, &pid) == -1) + err(1, "pdgetpid"); + (void)snprintf(buf, sizeof(buf), + "Logging subprocess %d (%s) exited %s %d.", + pid, f->f_pname, reason, code); + logerror(buf); +} + static struct socklist * socksetup(struct addrinfo *ai, const char *name, mode_t mode) { diff --git a/usr.sbin/syslogd/syslogd.h b/usr.sbin/syslogd/syslogd.h index 2d74c4d0ebbb..b6f83ceb6d8d 100644 --- a/usr.sbin/syslogd/syslogd.h +++ b/usr.sbin/syslogd/syslogd.h @@ -161,6 +161,7 @@ struct filed { struct { char f_pname[MAXPATHLEN]; int f_procdesc; + struct deadq_entry *f_dq; }; /* F_PIPE */ };