Index: usr.sbin/syslogd/syslogd.c =================================================================== --- usr.sbin/syslogd/syslogd.c +++ usr.sbin/syslogd/syslogd.c @@ -246,6 +246,8 @@ struct { char f_pname[MAXPATHLEN]; pid_t f_pid; + int f_pending; + int f_tries; } f_pipe; } f_un; #define fu_uname f_un.f_uname @@ -254,6 +256,8 @@ #define fu_fname f_un.f_fname #define fu_pipe_pname f_un.f_pipe.f_pname #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 */ struct logtime f_lasttime; /* time of last occurrence */ int f_prevpri; /* pri of f_prevline */ @@ -271,6 +275,7 @@ struct deadq_entry { pid_t dq_pid; int dq_timeout; + int *dq_pendingp; TAILQ_ENTRY(deadq_entry) dq_entries; }; static TAILQ_HEAD(, deadq_entry) deadq_head = @@ -373,6 +378,9 @@ static int sigpipe[2]; /* Pipe to catch a signal during select(). */ 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; struct iovlist; @@ -383,7 +391,7 @@ static int addsock(struct addrinfo *, struct socklist *); static struct filed *cfline(const char *, const char *, const char *); 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_removebypid(pid_t); static int decode(const char *, const CODE *); @@ -513,7 +521,7 @@ if (madvise(NULL, 0, MADV_PROTECT) != 0) 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) switch (ch) { #ifdef INET @@ -629,6 +637,11 @@ case 'm': /* mark interval */ MarkInterval = atoi(optarg) * 60; break; + case 'M': + MaxSpawnTries = atoi(optarg); + if ((p = strchr(optarg, ':'))) + MaxDeadProcesses = atoi(p + 1); + break; case 'N': NoBind = 1; SecureMode = 1; @@ -1650,6 +1663,7 @@ struct socklist *sl; const char *msgret; ssize_t lsent; + bool canspawn; switch (f->f_type) { case F_FORW: @@ -1748,7 +1762,17 @@ case F_PIPE: dprintf(" %s\n", f->fu_pipe_pname); 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 (!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, &f->fu_pipe_pid)) < 0) { logerror(f->fu_pipe_pname); @@ -1757,8 +1781,12 @@ } if (writev(f->f_file, il->iov, il->iovcnt) < 0) { int e = errno; - - deadq_enter(f->fu_pipe_pid, f->fu_pipe_pname); + if (e == EWOULDBLOCK && !canspawn) + /* 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); errno = e; logerror(f->fu_pipe_pname); @@ -2352,6 +2380,7 @@ char oldLocalHostName[MAXHOSTNAMELEN]; char hostMsg[2*MAXHOSTNAMELEN+40]; char bootfileMsg[LINE_MAX]; + struct deadq_entry *dq; dprintf("init\n"); WantInitialize = 0; @@ -2408,11 +2437,16 @@ close_filed(f); break; 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); 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)) { f = STAILQ_FIRST(&fhead); STAILQ_REMOVE_HEAD(&fhead, next); @@ -2768,6 +2802,8 @@ case '|': f->fu_pipe_pid = 0; + f->fu_pipe_pending = 0; + f->fu_pipe_tries = 0; (void)strlcpy(f->fu_pipe_pname, p + 1, sizeof(f->fu_pipe_pname)); f->f_type = F_PIPE; @@ -2845,6 +2881,9 @@ fprintlog_successive(f, 0); 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. */ @@ -3316,7 +3355,7 @@ } static void -deadq_enter(pid_t pid, const char *name) +deadq_enter(pid_t pid, const char *name, int *pendingp) { struct deadq_entry *dq; int status; @@ -3341,8 +3380,11 @@ } *dq = (struct deadq_entry){ .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); } @@ -3350,6 +3392,8 @@ deadq_remove(struct deadq_entry *dq) { if (dq != NULL) { + if (dq->dq_pendingp) + (*dq->dq_pendingp)--; TAILQ_REMOVE(&deadq_head, dq, dq_entries); free(dq); return (1);