Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/syslogd/syslogd.c
Show First 20 Lines • Show All 240 Lines • ▼ Show 20 Lines | struct { | ||||
char f_hname[MAXHOSTNAMELEN]; | char f_hname[MAXHOSTNAMELEN]; | ||||
struct addrinfo *f_addr; | struct addrinfo *f_addr; | ||||
} f_forw; /* forwarding address */ | } f_forw; /* forwarding address */ | ||||
char f_fname[MAXPATHLEN]; | char f_fname[MAXPATHLEN]; | ||||
struct { | struct { | ||||
char f_pname[MAXPATHLEN]; | char f_pname[MAXPATHLEN]; | ||||
pid_t f_pid; | pid_t f_pid; | ||||
int f_pending; | |||||
int f_tries; | |||||
} f_pipe; | } f_pipe; | ||||
} f_un; | } f_un; | ||||
#define fu_uname f_un.f_uname | #define fu_uname f_un.f_uname | ||||
#define fu_forw_hname f_un.f_forw.f_hname | #define fu_forw_hname f_un.f_forw.f_hname | ||||
#define fu_forw_addr f_un.f_forw.f_addr | #define fu_forw_addr f_un.f_forw.f_addr | ||||
#define fu_fname f_un.f_fname | #define fu_fname f_un.f_fname | ||||
#define fu_pipe_pname f_un.f_pipe.f_pname | #define fu_pipe_pname f_un.f_pipe.f_pname | ||||
#define fu_pipe_pid f_un.f_pipe.f_pid | #define fu_pipe_pid f_un.f_pipe.f_pid | ||||
#define fu_pipe_pending f_un.f_pipe.f_pending | |||||
#define fu_pipe_tries f_un.f_pipe.f_tries | |||||
char f_prevline[MAXSVLINE]; /* last message logged */ | char f_prevline[MAXSVLINE]; /* last message logged */ | ||||
struct logtime f_lasttime; /* time of last occurrence */ | struct logtime f_lasttime; /* time of last occurrence */ | ||||
int f_prevpri; /* pri of f_prevline */ | int f_prevpri; /* pri of f_prevline */ | ||||
size_t f_prevlen; /* length of f_prevline */ | size_t f_prevlen; /* length of f_prevline */ | ||||
int f_prevcount; /* repetition cnt of prevline */ | int f_prevcount; /* repetition cnt of prevline */ | ||||
u_int f_repeatcount; /* number of "repeated" msgs */ | u_int f_repeatcount; /* number of "repeated" msgs */ | ||||
int f_flags; /* file-specific flags */ | int f_flags; /* file-specific flags */ | ||||
#define FFLAG_SYNC 0x01 | #define FFLAG_SYNC 0x01 | ||||
#define FFLAG_NEEDSYNC 0x02 | #define FFLAG_NEEDSYNC 0x02 | ||||
}; | }; | ||||
/* | /* | ||||
* Queue of about-to-be dead processes we should watch out for. | * Queue of about-to-be dead processes we should watch out for. | ||||
*/ | */ | ||||
struct deadq_entry { | struct deadq_entry { | ||||
pid_t dq_pid; | pid_t dq_pid; | ||||
int dq_timeout; | int dq_timeout; | ||||
int *dq_pendingp; | |||||
TAILQ_ENTRY(deadq_entry) dq_entries; | TAILQ_ENTRY(deadq_entry) dq_entries; | ||||
}; | }; | ||||
static TAILQ_HEAD(, deadq_entry) deadq_head = | static TAILQ_HEAD(, deadq_entry) deadq_head = | ||||
TAILQ_HEAD_INITIALIZER(deadq_head); | TAILQ_HEAD_INITIALIZER(deadq_head); | ||||
/* | /* | ||||
* The timeout to apply to processes waiting on the dead queue. Unit | * The timeout to apply to processes waiting on the dead queue. Unit | ||||
* of measure is `mark intervals', i.e. 20 minutes by default. | * of measure is `mark intervals', i.e. 20 minutes by default. | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | |||||
static int LogFacPri; /* Put facility and priority in log message: */ | static int LogFacPri; /* Put facility and priority in log message: */ | ||||
/* 0=no, 1=numeric, 2=names */ | /* 0=no, 1=numeric, 2=names */ | ||||
static int KeepKernFac; /* Keep remotely logged kernel facility */ | static int KeepKernFac; /* Keep remotely logged kernel facility */ | ||||
static int needdofsync = 0; /* Are any file(s) waiting to be fsynced? */ | static int needdofsync = 0; /* Are any file(s) waiting to be fsynced? */ | ||||
static struct pidfh *pfh; | static struct pidfh *pfh; | ||||
static int sigpipe[2]; /* Pipe to catch a signal during select(). */ | static int sigpipe[2]; /* Pipe to catch a signal during select(). */ | ||||
static bool RFC3164OutputFormat = true; /* Use legacy format by default. */ | static bool RFC3164OutputFormat = true; /* Use legacy format by default. */ | ||||
static int MaxDeadProcesses; /* Maximum dead processes for a filed */ | |||||
static int MaxSpawnTries; /* Maximum attempts per timer interval */ | |||||
static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild; | static volatile sig_atomic_t MarkSet, WantDie, WantInitialize, WantReapchild; | ||||
struct iovlist; | struct iovlist; | ||||
static int allowaddr(char *); | static int allowaddr(char *); | ||||
static int addfile(struct filed *); | static int addfile(struct filed *); | ||||
static int addpeer(struct peer *); | static int addpeer(struct peer *); | ||||
static int addsock(struct addrinfo *, struct socklist *); | static int addsock(struct addrinfo *, struct socklist *); | ||||
static struct filed *cfline(const char *, const char *, const char *); | static struct filed *cfline(const char *, const char *, const char *); | ||||
static const char *cvthname(struct sockaddr *); | static const char *cvthname(struct sockaddr *); | ||||
static void deadq_enter(pid_t, const char *); | static void deadq_enter(pid_t, const char *, int *); | ||||
static int deadq_remove(struct deadq_entry *); | static int deadq_remove(struct deadq_entry *); | ||||
static int deadq_removebypid(pid_t); | static int 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 dodie(int); | static void dodie(int); | ||||
static void dofsync(void); | static void dofsync(void); | ||||
static void domark(int); | static void domark(int); | ||||
static void fprintlog_first(struct filed *, const char *, const char *, | static void fprintlog_first(struct filed *, const char *, const char *, | ||||
▲ Show 20 Lines • Show All 113 Lines • ▼ Show 20 Lines | main(int argc, char *argv[]) | ||||
struct peer *pe; | struct peer *pe; | ||||
struct socklist *sl; | struct socklist *sl; | ||||
pid_t ppid = 1, spid; | pid_t ppid = 1, spid; | ||||
char *p; | char *p; | ||||
if (madvise(NULL, 0, MADV_PROTECT) != 0) | if (madvise(NULL, 0, MADV_PROTECT) != 0) | ||||
dprintf("madvise() failed: %s\n", strerror(errno)); | dprintf("madvise() failed: %s\n", strerror(errno)); | ||||
while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:m:nNoO:p:P:sS:Tuv")) | while ((ch = getopt(argc, argv, "468Aa:b:cCdf:FHkl:m:M:nNoO:p:P:sS:Tuv")) | ||||
!= -1) | != -1) | ||||
switch (ch) { | switch (ch) { | ||||
#ifdef INET | #ifdef INET | ||||
case '4': | case '4': | ||||
family = PF_INET; | family = PF_INET; | ||||
break; | break; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
▲ Show 20 Lines • Show All 99 Lines • ▼ Show 20 Lines | case 'S': | ||||
.pe_name = name, | .pe_name = name, | ||||
.pe_mode = mode | .pe_mode = mode | ||||
}); | }); | ||||
break; | break; | ||||
} | } | ||||
case 'm': /* mark interval */ | case 'm': /* mark interval */ | ||||
MarkInterval = atoi(optarg) * 60; | MarkInterval = atoi(optarg) * 60; | ||||
break; | break; | ||||
case 'M': | |||||
MaxSpawnTries = atoi(optarg); | |||||
if ((p = strchr(optarg, ':'))) | |||||
MaxDeadProcesses = atoi(p + 1); | |||||
break; | |||||
case 'N': | case 'N': | ||||
NoBind = 1; | NoBind = 1; | ||||
SecureMode = 1; | SecureMode = 1; | ||||
break; | break; | ||||
case 'n': | case 'n': | ||||
resolve = 0; | resolve = 0; | ||||
break; | break; | ||||
case 'O': | case 'O': | ||||
▲ Show 20 Lines • Show All 1,005 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
fprintlog_write(struct filed *f, struct iovlist *il, int flags) | fprintlog_write(struct filed *f, struct iovlist *il, int flags) | ||||
{ | { | ||||
struct msghdr msghdr; | struct msghdr msghdr; | ||||
struct addrinfo *r; | struct addrinfo *r; | ||||
struct socklist *sl; | struct socklist *sl; | ||||
const char *msgret; | const char *msgret; | ||||
ssize_t lsent; | ssize_t lsent; | ||||
bool canspawn; | |||||
switch (f->f_type) { | switch (f->f_type) { | ||||
case F_FORW: | case F_FORW: | ||||
/* Truncate messages to RFC 5426 recommended size. */ | /* Truncate messages to RFC 5426 recommended size. */ | ||||
dprintf(" %s", f->fu_forw_hname); | dprintf(" %s", f->fu_forw_hname); | ||||
switch (f->fu_forw_addr->ai_family) { | switch (f->fu_forw_addr->ai_family) { | ||||
#ifdef INET | #ifdef INET | ||||
case AF_INET: | case AF_INET: | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | if (writev(f->f_file, il->iov, il->iovcnt) < 0) { | ||||
f->f_flags |= FFLAG_NEEDSYNC; | f->f_flags |= FFLAG_NEEDSYNC; | ||||
needdofsync = 1; | needdofsync = 1; | ||||
} | } | ||||
break; | break; | ||||
case F_PIPE: | case F_PIPE: | ||||
dprintf(" %s\n", f->fu_pipe_pname); | dprintf(" %s\n", f->fu_pipe_pname); | ||||
iovlist_append(il, "\n"); | iovlist_append(il, "\n"); | ||||
canspawn = (MaxDeadProcesses <= 0 || | |||||
f->fu_pipe_pending < MaxDeadProcesses) && | |||||
(MaxSpawnTries <= 0 || | |||||
f->fu_pipe_tries < MaxSpawnTries); | |||||
if (f->fu_pipe_pid == 0) { | if (f->fu_pipe_pid == 0) { | ||||
if (!canspawn) | |||||
break; | |||||
dprintf("spawning: %s (pending: %d, tries: %d)\n", | |||||
f->fu_pipe_pname, | |||||
f->fu_pipe_pending, f->fu_pipe_tries); | |||||
f->fu_pipe_tries++; | |||||
if ((f->f_file = p_open(f->fu_pipe_pname, | if ((f->f_file = p_open(f->fu_pipe_pname, | ||||
&f->fu_pipe_pid)) < 0) { | &f->fu_pipe_pid)) < 0) { | ||||
logerror(f->fu_pipe_pname); | logerror(f->fu_pipe_pname); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (writev(f->f_file, il->iov, il->iovcnt) < 0) { | if (writev(f->f_file, il->iov, il->iovcnt) < 0) { | ||||
int e = errno; | int e = errno; | ||||
if (e == EWOULDBLOCK && !canspawn) | |||||
deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname); | /* Not much point in disposing of this process, | ||||
* we can't spawn another one. */ | |||||
break; | |||||
deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname, | |||||
&f->fu_pipe_pending); | |||||
close_filed(f); | close_filed(f); | ||||
errno = e; | errno = e; | ||||
logerror(f->fu_pipe_pname); | logerror(f->fu_pipe_pname); | ||||
} | } | ||||
break; | break; | ||||
case F_CONSOLE: | case F_CONSOLE: | ||||
if (flags & IGN_CONS) { | if (flags & IGN_CONS) { | ||||
▲ Show 20 Lines • Show All 577 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
int i; | int i; | ||||
FILE *cf; | FILE *cf; | ||||
struct filed *f; | struct filed *f; | ||||
char *p; | char *p; | ||||
char oldLocalHostName[MAXHOSTNAMELEN]; | char oldLocalHostName[MAXHOSTNAMELEN]; | ||||
char hostMsg[2*MAXHOSTNAMELEN+40]; | char hostMsg[2*MAXHOSTNAMELEN+40]; | ||||
char bootfileMsg[LINE_MAX]; | char bootfileMsg[LINE_MAX]; | ||||
struct deadq_entry *dq; | |||||
dprintf("init\n"); | dprintf("init\n"); | ||||
WantInitialize = 0; | WantInitialize = 0; | ||||
/* | /* | ||||
* Load hostname (may have changed). | * Load hostname (may have changed). | ||||
*/ | */ | ||||
if (signo != 0) | if (signo != 0) | ||||
Show All 40 Lines | STAILQ_FOREACH(f, &fhead, next) { | ||||
switch (f->f_type) { | switch (f->f_type) { | ||||
case F_FILE: | case F_FILE: | ||||
case F_FORW: | case F_FORW: | ||||
case F_CONSOLE: | case F_CONSOLE: | ||||
case F_TTY: | case F_TTY: | ||||
close_filed(f); | close_filed(f); | ||||
break; | break; | ||||
case F_PIPE: | case F_PIPE: | ||||
deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname); | deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname, | ||||
&f->fu_pipe_pending); | |||||
close_filed(f); | close_filed(f); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* Disconnect the deadq entries from the filed objects about to be | |||||
* deallocated. */ | |||||
TAILQ_FOREACH(dq, &deadq_head, dq_entries) | |||||
dq->dq_pendingp = NULL; | |||||
while(!STAILQ_EMPTY(&fhead)) { | while(!STAILQ_EMPTY(&fhead)) { | ||||
f = STAILQ_FIRST(&fhead); | f = STAILQ_FIRST(&fhead); | ||||
STAILQ_REMOVE_HEAD(&fhead, next); | STAILQ_REMOVE_HEAD(&fhead, next); | ||||
free(f->f_program); | free(f->f_program); | ||||
free(f->f_host); | free(f->f_host); | ||||
free(f); | free(f); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 339 Lines • ▼ Show 20 Lines | case '/': | ||||
} else { | } else { | ||||
(void)strlcpy(f->fu_fname, p, sizeof(f->fu_fname)); | (void)strlcpy(f->fu_fname, p, sizeof(f->fu_fname)); | ||||
f->f_type = F_FILE; | f->f_type = F_FILE; | ||||
} | } | ||||
break; | break; | ||||
case '|': | case '|': | ||||
f->fu_pipe_pid = 0; | f->fu_pipe_pid = 0; | ||||
f->fu_pipe_pending = 0; | |||||
f->fu_pipe_tries = 0; | |||||
(void)strlcpy(f->fu_pipe_pname, p + 1, | (void)strlcpy(f->fu_pipe_pname, p + 1, | ||||
sizeof(f->fu_pipe_pname)); | sizeof(f->fu_pipe_pname)); | ||||
f->f_type = F_PIPE; | f->f_type = F_PIPE; | ||||
break; | break; | ||||
case '*': | case '*': | ||||
f->f_type = F_WALL; | f->f_type = F_WALL; | ||||
break; | break; | ||||
▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | markit(void) | ||||
STAILQ_FOREACH(f, &fhead, next) { | STAILQ_FOREACH(f, &fhead, next) { | ||||
if (f->f_prevcount && now >= REPEATTIME(f)) { | if (f->f_prevcount && now >= REPEATTIME(f)) { | ||||
dprintf("flush %s: repeated %d times, %d sec.\n", | dprintf("flush %s: repeated %d times, %d sec.\n", | ||||
TypeNames[f->f_type], f->f_prevcount, | TypeNames[f->f_type], f->f_prevcount, | ||||
repeatinterval[f->f_repeatcount]); | repeatinterval[f->f_repeatcount]); | ||||
fprintlog_successive(f, 0); | fprintlog_successive(f, 0); | ||||
BACKOFF(f); | BACKOFF(f); | ||||
} | } | ||||
if (f->f_type == F_PIPE) | |||||
/* Allow to try spawning the program again. */ | |||||
f->fu_pipe_tries = 0; | |||||
} | } | ||||
/* 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 (kill(dq->dq_pid, SIGKILL) != 0) | if (kill(dq->dq_pid, SIGKILL) != 0) | ||||
▲ Show 20 Lines • Show All 455 Lines • ▼ Show 20 Lines | (void)snprintf(errmsg, sizeof errmsg, | ||||
(int)pid); | (int)pid); | ||||
logerror(errmsg); | logerror(errmsg); | ||||
} | } | ||||
*rpid = pid; | *rpid = pid; | ||||
return (pfd[1]); | return (pfd[1]); | ||||
} | } | ||||
static void | static void | ||||
deadq_enter(pid_t pid, const char *name) | deadq_enter(pid_t pid, const char *name, int *pendingp) | ||||
{ | { | ||||
struct deadq_entry *dq; | struct deadq_entry *dq; | ||||
int status; | int status; | ||||
if (pid == 0) | if (pid == 0) | ||||
return; | return; | ||||
/* | /* | ||||
* Be paranoid, if we can't signal the process, don't enter it | * Be paranoid, if we can't signal the process, don't enter it | ||||
* into the dead queue (perhaps it's already dead). If possible, | * into the dead queue (perhaps it's already dead). If possible, | ||||
* we try to fetch and log the child's status. | * we try to fetch and log the child's status. | ||||
*/ | */ | ||||
if (kill(pid, 0) != 0) { | if (kill(pid, 0) != 0) { | ||||
if (waitpid(pid, &status, WNOHANG) > 0) | if (waitpid(pid, &status, WNOHANG) > 0) | ||||
log_deadchild(pid, status, name); | log_deadchild(pid, status, name); | ||||
return; | return; | ||||
} | } | ||||
dq = malloc(sizeof(*dq)); | dq = malloc(sizeof(*dq)); | ||||
if (dq == NULL) { | if (dq == NULL) { | ||||
logerror("malloc"); | logerror("malloc"); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
*dq = (struct deadq_entry){ | *dq = (struct deadq_entry){ | ||||
.dq_pid = pid, | .dq_pid = pid, | ||||
.dq_timeout = DQ_TIMO_INIT | .dq_timeout = DQ_TIMO_INIT, | ||||
.dq_pendingp = pendingp | |||||
}; | }; | ||||
if (dq->dq_pendingp) | |||||
(*dq->dq_pendingp)++; | |||||
TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries); | TAILQ_INSERT_TAIL(&deadq_head, dq, dq_entries); | ||||
} | } | ||||
static int | static int | ||||
deadq_remove(struct deadq_entry *dq) | deadq_remove(struct deadq_entry *dq) | ||||
{ | { | ||||
if (dq != NULL) { | if (dq != NULL) { | ||||
if (dq->dq_pendingp) | |||||
(*dq->dq_pendingp)--; | |||||
TAILQ_REMOVE(&deadq_head, dq, dq_entries); | TAILQ_REMOVE(&deadq_head, dq, dq_entries); | ||||
free(dq); | free(dq); | ||||
return (1); | return (1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 211 Lines • Show Last 20 Lines |