Changeset View
Standalone View
usr.sbin/syslogd/syslogd.c
Show First 20 Lines • Show All 435 Lines • ▼ Show 20 Lines | |||||
static bool allowaddr(char *); | static bool allowaddr(char *); | ||||
static void addpeer(const char *, const char *, mode_t); | static void addpeer(const char *, const char *, mode_t); | ||||
static void addsock(const char *, const char *, mode_t); | static void addsock(const char *, const char *, mode_t); | ||||
static void cfline(const char *, const char *, const char *, const char *); | static void cfline(const char *, const char *, const char *, const char *); | ||||
static const char *cvthname(struct sockaddr *); | static const char *cvthname(struct sockaddr *); | ||||
static void deadq_enter(int); | static void deadq_enter(int); | ||||
static void deadq_remove(struct deadq_entry *); | static void deadq_remove(struct deadq_entry *); | ||||
static bool deadq_removebypid(pid_t); | |||||
static int decode(const char *, const CODE *); | static int decode(const char *, const CODE *); | ||||
static void die(int) __dead2; | static void die(int) __dead2; | ||||
static void dofsync(void); | static void dofsync(void); | ||||
static void fprintlog_first(struct filed *, const char *, const char *, | static void fprintlog_first(struct filed *, const char *, const char *, | ||||
const char *, const char *, const char *, const char *, int); | const char *, const char *, const char *, const char *, int); | ||||
static void fprintlog_write(struct filed *, struct iovlist *, int); | static void fprintlog_write(struct filed *, struct iovlist *, int); | ||||
static void fprintlog_successive(struct filed *, int); | static void fprintlog_successive(struct filed *, int); | ||||
static void init(bool); | static void init(bool); | ||||
static void logerror(const char *); | static void logerror(const char *); | ||||
static void logmsg(int, const struct logtime *, const char *, const char *, | static void logmsg(int, const struct logtime *, const char *, const char *, | ||||
const char *, const char *, const char *, const char *, int); | const char *, const char *, const char *, const char *, int); | ||||
static void log_deadchild(pid_t, int, const char *); | |||||
static void markit(void); | static void markit(void); | ||||
static struct socklist *socksetup(struct addrinfo *, const char *, mode_t); | static struct socklist *socksetup(struct addrinfo *, const char *, mode_t); | ||||
static int socklist_recv_file(struct socklist *); | static int socklist_recv_file(struct socklist *); | ||||
static int socklist_recv_sock(struct socklist *); | static int socklist_recv_sock(struct socklist *); | ||||
static int skip_message(const char *, const char *, int); | static int skip_message(const char *, const char *, int); | ||||
static int evaluate_prop_filter(const struct prop_filter *filter, | static int evaluate_prop_filter(const struct prop_filter *filter, | ||||
const char *value); | const char *value); | ||||
static int prop_filter_compile(struct prop_filter *pfilter, | static int prop_filter_compile(struct prop_filter *pfilter, | ||||
char *filterstr); | char *filterstr); | ||||
static void parsemsg(const char *, char *); | static void parsemsg(const char *, char *); | ||||
static void printsys(char *); | static void printsys(char *); | ||||
static int p_open(const char *, pid_t *); | static int p_open(const char *, pid_t *); | ||||
static void reapchild(int); | |||||
static const char *ttymsg_check(struct iovec *, int, char *, int); | static const char *ttymsg_check(struct iovec *, int, char *, int); | ||||
static void usage(void); | static void usage(void); | ||||
static bool validate(struct sockaddr *, const char *); | static bool validate(struct sockaddr *, const char *); | ||||
static void unmapped(struct sockaddr *); | static void unmapped(struct sockaddr *); | ||||
static void wallmsg(struct filed *, struct iovec *, const int iovlen); | static void wallmsg(struct filed *, struct iovec *, const int iovlen); | ||||
static int waitdaemon(int); | static int waitdaemon(int); | ||||
static void timedout(int); | static void timedout(int); | ||||
static void increase_rcvbuf(int); | static void increase_rcvbuf(int); | ||||
▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | addfile(int fd) | ||||
sl->sl_socket = fd; | sl->sl_socket = fd; | ||||
sl->sl_recv = socklist_recv_file; | sl->sl_recv = socklist_recv_file; | ||||
STAILQ_INSERT_TAIL(&shead, sl, next); | STAILQ_INSERT_TAIL(&shead, sl, next); | ||||
} | } | ||||
int | int | ||||
main(int argc, char *argv[]) | main(int argc, char *argv[]) | ||||
{ | { | ||||
struct sigaction act = { }; | |||||
sigset_t sigset = { }; | sigset_t sigset = { }; | ||||
struct kevent ev; | struct kevent ev; | ||||
struct socklist *sl; | struct socklist *sl; | ||||
pid_t ppid = -1, spid; | pid_t ppid = -1, spid; | ||||
int ch, kq, s; | int ch, kq, s; | ||||
char *p; | char *p; | ||||
bool bflag = false, pflag = false, Sflag = false; | bool bflag = false, pflag = false, Sflag = false; | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (sigprocmask(SIG_BLOCK, &sigset, NULL) != 0) { | if (sigprocmask(SIG_BLOCK, &sigset, NULL) != 0) { | ||||
warn("failed to apply signal mask"); | warn("failed to apply signal mask"); | ||||
pidfile_remove(pfh); | pidfile_remove(pfh); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
(void)alarm(TIMERINTVL); | (void)alarm(TIMERINTVL); | ||||
/* Do not create zombie processes. */ | |||||
markj: A comment explaining how syslogd handles children would be better. | |||||
act.sa_flags = SA_NOCLDWAIT; | |||||
if (sigaction(SIGCHLD, &act, NULL) == -1) { | |||||
warn("failed to apply signal handler"); | |||||
pidfile_remove(pfh); | |||||
exit(1); | |||||
} | |||||
/* tuck my process id away */ | /* tuck my process id away */ | ||||
pidfile_write(pfh); | pidfile_write(pfh); | ||||
dprintf("off & running....\n"); | dprintf("off & running....\n"); | ||||
init(false); | init(false); | ||||
for (;;) { | for (;;) { | ||||
if (needdofsync) { | if (needdofsync) { | ||||
dofsync(); | dofsync(); | ||||
Show All 22 Lines | case EVFILT_SIGNAL: | ||||
case SIGQUIT: | case SIGQUIT: | ||||
case SIGTERM: | case SIGTERM: | ||||
if (ev.ident == SIGTERM || Debug) | if (ev.ident == SIGTERM || Debug) | ||||
die(ev.ident); | die(ev.ident); | ||||
break; | break; | ||||
case SIGALRM: | case SIGALRM: | ||||
markit(); | markit(); | ||||
break; | break; | ||||
case SIGCHLD: | |||||
reapchild(ev.ident); | |||||
break; | |||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
static int | static int | ||||
socklist_recv_sock(struct socklist *sl) | socklist_recv_sock(struct socklist *sl) | ||||
▲ Show 20 Lines • Show All 1,353 Lines • ▼ Show 20 Lines | if (stat(device, &sb) < 0) { | ||||
return (errbuf); | return (errbuf); | ||||
} | } | ||||
if ((sb.st_mode & S_IWGRP) == 0) | if ((sb.st_mode & S_IWGRP) == 0) | ||||
/* Messages disabled. */ | /* Messages disabled. */ | ||||
return (NULL); | return (NULL); | ||||
return (ttymsg(iov, iovcnt, line, tmout)); | return (ttymsg(iov, iovcnt, line, tmout)); | ||||
} | } | ||||
static void | |||||
reapchild(int signo __unused) | |||||
{ | |||||
int status; | |||||
pid_t pid, pipe_pid; | |||||
struct filed *f; | |||||
while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) { | |||||
/* First, look if it's a process from the dead queue. */ | |||||
if (deadq_removebypid(pid)) | |||||
continue; | |||||
/* Now, look in list of active processes. */ | |||||
STAILQ_FOREACH(f, &fhead, next) { | |||||
if (f->f_type == F_PIPE) { | |||||
if (pdgetpid(f->fu_pipe_pd, &pipe_pid) == -1) { | |||||
dprintf("Failed to query PID: %s\n", | |||||
strerror(errno)); | |||||
continue; | |||||
} | |||||
if (pipe_pid != pid) | |||||
continue; | |||||
/* Do not enter into deadq. */ | |||||
f->fu_pipe_pd = -1; | |||||
close_filed(f); | |||||
log_deadchild(pid, status, f->fu_pipe_pname); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/* | /* | ||||
* Return a printable representation of a host address. | * Return a printable representation of a host address. | ||||
*/ | */ | ||||
static const char * | static const char * | ||||
cvthname(struct sockaddr *f) | cvthname(struct sockaddr *f) | ||||
{ | { | ||||
int error, hl; | int error, hl; | ||||
static char hname[NI_MAXHOST], ip[NI_MAXHOST]; | static char hname[NI_MAXHOST], ip[NI_MAXHOST]; | ||||
▲ Show 20 Lines • Show All 924 Lines • ▼ Show 20 Lines | STAILQ_FOREACH(f, &fhead, next) { | ||||
} | } | ||||
} | } | ||||
/* Walk the dead queue, and see if we should signal somebody. */ | /* Walk the dead queue, and see if we should signal somebody. */ | ||||
TAILQ_FOREACH_SAFE(dq, &deadq_head, dq_entries, dq0) { | TAILQ_FOREACH_SAFE(dq, &deadq_head, dq_entries, dq0) { | ||||
switch (dq->dq_timeout) { | switch (dq->dq_timeout) { | ||||
case 0: | case 0: | ||||
/* Already signalled once, try harder now. */ | /* Already signalled once, try harder now. */ | ||||
if (pdkill(dq->dq_procdesc, SIGKILL) != 0) | (void)pdkill(dq->dq_procdesc, SIGKILL); | ||||
(void)deadq_remove(dq); | (void)deadq_remove(dq); | ||||
Not Done Inline ActionsNow that there are no zombies, how do you know that it is safe to kill this PID? It might have been recycled. Once you convert to using process descriptors, you can use pdkill() to remove the problem, but that happens later in the patch stack. Or am I missing something? markj: Now that there are no zombies, how do you know that it is safe to kill this PID? It might have… | |||||
Done Inline Actions
What you're describing is correct. The PID will be recycled and then we're sending SIGKILL to an entirely unrelated process. It slipped my mind that the PID would be recycled. I can't think of a simple way of verifying that the given PID is a child of syslogd. jfree: > Now that there are no zombies, how do you know that it is safe to kill this PID? It might… | |||||
Not Done Inline ActionsI think you have to defer the use of SA_NOCLDWAIT until after process descriptors are introduced. markj: I think you have to defer the use of SA_NOCLDWAIT until after process descriptors are… | |||||
break; | break; | ||||
case 1: | case 1: | ||||
/* | |||||
* Timed out on dead queue, send terminate | |||||
* signal. Note that we leave the removal | |||||
* from the dead queue to reapchild(), which | |||||
* will also log the event (unless the process | |||||
* didn't even really exist, in case we simply | |||||
* drop it from the dead queue). | |||||
*/ | |||||
if (pdkill(dq->dq_procdesc, SIGTERM) != 0) | if (pdkill(dq->dq_procdesc, SIGTERM) != 0) | ||||
(void)deadq_remove(dq); | (void)deadq_remove(dq); | ||||
else | else | ||||
dq->dq_timeout--; | dq->dq_timeout--; | ||||
break; | break; | ||||
default: | default: | ||||
dq->dq_timeout--; | dq->dq_timeout--; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 456 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
static void | static void | ||||
deadq_remove(struct deadq_entry *dq) | deadq_remove(struct deadq_entry *dq) | ||||
{ | { | ||||
TAILQ_REMOVE(&deadq_head, dq, dq_entries); | TAILQ_REMOVE(&deadq_head, dq, dq_entries); | ||||
close(dq->dq_procdesc); | close(dq->dq_procdesc); | ||||
free(dq); | free(dq); | ||||
} | |||||
static bool | |||||
deadq_removebypid(pid_t pid) | |||||
{ | |||||
struct deadq_entry *dq; | |||||
pid_t dq_pid; | |||||
TAILQ_FOREACH(dq, &deadq_head, dq_entries) { | |||||
if (pdgetpid(dq->dq_procdesc, &dq_pid) == -1) { | |||||
dprintf("Failed to query PID: %s\n", strerror(errno)); | |||||
continue; | |||||
} | |||||
if (dq_pid == pid) { | |||||
deadq_remove(dq); | |||||
return (true); | |||||
} | |||||
} | |||||
return (false); | |||||
} | |||||
static void | |||||
log_deadchild(pid_t pid, int status, const char *name) | |||||
{ | |||||
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; | |||||
} | |||||
(void)snprintf(buf, sizeof buf, | |||||
"Logging subprocess %d (%s) exited %s %d.", | |||||
pid, name, reason, code); | |||||
logerror(buf); | |||||
} | } | ||||
static struct socklist * | static struct socklist * | ||||
socksetup(struct addrinfo *ai, const char *name, mode_t mode) | socksetup(struct addrinfo *ai, const char *name, mode_t mode) | ||||
{ | { | ||||
struct socklist *sl; | struct socklist *sl; | ||||
int (*sl_recv)(struct socklist *); | int (*sl_recv)(struct socklist *); | ||||
int s, optval = 1; | int s, optval = 1; | ||||
▲ Show 20 Lines • Show All 110 Lines • Show Last 20 Lines |
A comment explaining how syslogd handles children would be better.