syslogd.c revision 69175
1140308Scognet/* 2140308Scognet * Copyright (c) 1983, 1988, 1993, 1994 3140308Scognet * The Regents of the University of California. All rights reserved. 4140308Scognet * 5140308Scognet * Redistribution and use in source and binary forms, with or without 6140308Scognet * modification, are permitted provided that the following conditions 7140308Scognet * are met: 8140308Scognet * 1. Redistributions of source code must retain the above copyright 9140308Scognet * notice, this list of conditions and the following disclaimer. 10140308Scognet * 2. Redistributions in binary form must reproduce the above copyright 11140308Scognet * notice, this list of conditions and the following disclaimer in the 12140308Scognet * documentation and/or other materials provided with the distribution. 13140308Scognet * 3. All advertising materials mentioning features or use of this software 14140308Scognet * must display the following acknowledgement: 15140308Scognet * This product includes software developed by the University of 16140308Scognet * California, Berkeley and its contributors. 17140308Scognet * 4. Neither the name of the University nor the names of its contributors 18140308Scognet * may be used to endorse or promote products derived from this software 19140308Scognet * without specific prior written permission. 20140308Scognet * 21140308Scognet * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22140308Scognet * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23140308Scognet * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24140308Scognet * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25140308Scognet * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26140308Scognet * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27140308Scognet * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28140308Scognet * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29140308Scognet * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30140308Scognet * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31140308Scognet * SUCH DAMAGE. 32140308Scognet */ 33140308Scognet 34140308Scognet#ifndef lint 35140308Scognetstatic const char copyright[] = 36140308Scognet"@(#) Copyright (c) 1983, 1988, 1993, 1994\n\ 37140308Scognet The Regents of the University of California. All rights reserved.\n"; 38140308Scognet#endif /* not lint */ 39140308Scognet 40140308Scognet#ifndef lint 41140308Scognet#if 0 42140308Scognetstatic char sccsid[] = "@(#)syslogd.c 8.3 (Berkeley) 4/4/94"; 43140308Scognet#endif 44140308Scognetstatic const char rcsid[] = 45140308Scognet "$FreeBSD: head/usr.sbin/syslogd/syslogd.c 69175 2000-11-25 21:00:58Z phk $"; 46140308Scognet#endif /* not lint */ 47140308Scognet 48140308Scognet/* 49140308Scognet * syslogd -- log system messages 50140350Scognet * 51140308Scognet * This program implements a system log. It takes a series of lines. 52140308Scognet * Each line may have a priority, signified as "<n>" as 53140308Scognet * the first characters of the line. If this is 54140308Scognet * not present, a default priority is used. 55140308Scognet * 56140308Scognet * To kill syslogd, send a signal 15 (terminate). A signal 1 (hup) will 57140308Scognet * cause it to reread its configuration file. 58140308Scognet * 59140308Scognet * Defined Constants: 60140308Scognet * 61140308Scognet * MAXLINE -- the maximimum line length that can be handled. 62140308Scognet * DEFUPRI -- the default priority for user messages 63140308Scognet * DEFSPRI -- the default priority for kernel messages 64140308Scognet * 65140308Scognet * Author: Eric Allman 66140308Scognet * extensive changes by Ralph Campbell 67140308Scognet * more extensive changes by Eric Allman (again) 68140308Scognet * Extension to log by program name as well as facility and priority 69140308Scognet * by Peter da Silva. 70140308Scognet * -u and -v by Harlan Stenn. 71140308Scognet * Priority comparison code by Harlan Stenn. 72140308Scognet */ 73140308Scognet 74140308Scognet#define MAXLINE 1024 /* maximum line length */ 75140308Scognet#define MAXSVLINE 120 /* maximum saved line length */ 76140308Scognet#define DEFUPRI (LOG_USER|LOG_NOTICE) 77140308Scognet#define DEFSPRI (LOG_KERN|LOG_CRIT) 78140308Scognet#define TIMERINTVL 30 /* interval for checking flush, mark */ 79140308Scognet#define TTYMSGTIME 1 /* timed out passed to ttymsg */ 80140308Scognet 81140308Scognet#include <sys/param.h> 82140308Scognet#include <sys/ioctl.h> 83140308Scognet#include <sys/stat.h> 84140308Scognet#include <sys/wait.h> 85140308Scognet#include <sys/socket.h> 86140308Scognet#include <sys/queue.h> 87140308Scognet#include <sys/uio.h> 88140308Scognet#include <sys/un.h> 89140308Scognet#include <sys/time.h> 90140308Scognet#include <sys/resource.h> 91140308Scognet#include <sys/syslimits.h> 92140308Scognet#include <paths.h> 93140308Scognet 94140308Scognet#include <netinet/in.h> 95140308Scognet#include <netdb.h> 96140308Scognet#include <arpa/inet.h> 97140308Scognet 98140308Scognet#include <ctype.h> 99140308Scognet#include <err.h> 100140308Scognet#include <errno.h> 101140308Scognet#include <fcntl.h> 102140308Scognet#include <regex.h> 103140308Scognet#include <setjmp.h> 104140308Scognet#include <signal.h> 105140308Scognet#include <stdio.h> 106140308Scognet#include <stdlib.h> 107140308Scognet#include <string.h> 108140308Scognet#include <sysexits.h> 109140308Scognet#include <unistd.h> 110140308Scognet#include <utmp.h> 111140308Scognet#include "pathnames.h" 112140308Scognet 113140308Scognet#define SYSLOG_NAMES 114140308Scognet#include <sys/syslog.h> 115140308Scognet 116140308Scognetconst char *ConfFile = _PATH_LOGCONF; 117140308Scognetconst char *PidFile = _PATH_LOGPID; 118140308Scognetconst char ctty[] = _PATH_CONSOLE; 119140308Scognet 120140308Scognet#define dprintf if (Debug) printf 121140308Scognet 122140308Scognet#define MAXUNAMES 20 /* maximum number of user names */ 123140308Scognet 124140308Scognet#define MAXFUNIX 20 125140308Scognet 126140308Scognetint nfunix = 1; 127140308Scognetchar *funixn[MAXFUNIX] = { _PATH_LOG }; 128140308Scognetint funix[MAXFUNIX]; 129140308Scognet 130140308Scognet/* 131140308Scognet * Flags to logmsg(). 132140308Scognet */ 133140308Scognet 134140308Scognet#define IGN_CONS 0x001 /* don't print on console */ 135140308Scognet#define SYNC_FILE 0x002 /* do fsync on file after printing */ 136140308Scognet#define ADDDATE 0x004 /* add a date to the message */ 137140308Scognet#define MARK 0x008 /* this message is a mark */ 138140308Scognet#define ISKERNEL 0x010 /* kernel generated message */ 139140308Scognet 140140308Scognet/* 141140308Scognet * This structure represents the files that will have log 142140308Scognet * copies printed. 143140308Scognet */ 144140308Scognet 145140308Scognetstruct filed { 146140308Scognet struct filed *f_next; /* next in linked list */ 147140308Scognet short f_type; /* entry type, see below */ 148140308Scognet short f_file; /* file descriptor */ 149140308Scognet time_t f_time; /* time this was last written */ 150140308Scognet char *f_host; /* host from which to recd. */ 151140308Scognet u_char f_pmask[LOG_NFACILITIES+1]; /* priority mask */ 152140308Scognet u_char f_pcmp[LOG_NFACILITIES+1]; /* compare priority */ 153140308Scognet#define PRI_LT 0x1 154140308Scognet#define PRI_EQ 0x2 155140308Scognet#define PRI_GT 0x4 156140308Scognet char *f_program; /* program this applies to */ 157140308Scognet union { 158140308Scognet char f_uname[MAXUNAMES][UT_NAMESIZE+1]; 159140308Scognet struct { 160140308Scognet char f_hname[MAXHOSTNAMELEN+1]; 161140308Scognet struct sockaddr_in f_addr; 162140308Scognet } f_forw; /* forwarding address */ 163140308Scognet char f_fname[MAXPATHLEN]; 164140308Scognet struct { 165140308Scognet char f_pname[MAXPATHLEN]; 166140308Scognet pid_t f_pid; 167140308Scognet } f_pipe; 168140308Scognet } f_un; 169140308Scognet char f_prevline[MAXSVLINE]; /* last message logged */ 170140308Scognet char f_lasttime[16]; /* time of last occurrence */ 171140308Scognet char f_prevhost[MAXHOSTNAMELEN+1]; /* host from which recd. */ 172140308Scognet int f_prevpri; /* pri of f_prevline */ 173140308Scognet int f_prevlen; /* length of f_prevline */ 174140308Scognet int f_prevcount; /* repetition cnt of prevline */ 175140308Scognet int f_repeatcount; /* number of "repeated" msgs */ 176140308Scognet}; 177140308Scognet 178140308Scognet/* 179140308Scognet * Queue of about-to-be dead processes we should watch out for. 180140308Scognet */ 181140308Scognet 182140308ScognetTAILQ_HEAD(stailhead, deadq_entry) deadq_head; 183140308Scognetstruct stailhead *deadq_headp; 184140308Scognet 185140308Scognetstruct deadq_entry { 186140308Scognet pid_t dq_pid; 187140308Scognet int dq_timeout; 188140308Scognet TAILQ_ENTRY(deadq_entry) dq_entries; 189140308Scognet}; 190140308Scognet 191140308Scognet/* 192140308Scognet * The timeout to apply to processes waiting on the dead queue. Unit 193140308Scognet * of measure is `mark intervals', i.e. 20 minutes by default. 194140308Scognet * Processes on the dead queue will be terminated after that time. 195140308Scognet */ 196140308Scognet 197140308Scognet#define DQ_TIMO_INIT 2 198140308Scognet 199140308Scognettypedef struct deadq_entry *dq_t; 200140308Scognet 201140308Scognet 202140308Scognet/* 203140308Scognet * Struct to hold records of network addresses that are allowed to log 204140308Scognet * to us. 205140308Scognet */ 206140308Scognetstruct allowedpeer { 207140308Scognet int isnumeric; 208140308Scognet u_short port; 209140308Scognet union { 210140308Scognet struct { 211140308Scognet struct in_addr addr; 212140308Scognet struct in_addr mask; 213140308Scognet } numeric; 214140308Scognet char *name; 215140308Scognet } u; 216140308Scognet#define a_addr u.numeric.addr 217140308Scognet#define a_mask u.numeric.mask 218140308Scognet#define a_name u.name 219140308Scognet}; 220140308Scognet 221140308Scognet 222140308Scognet/* 223140308Scognet * Intervals at which we flush out "message repeated" messages, 224140308Scognet * in seconds after previous message is logged. After each flush, 225140308Scognet * we move to the next interval until we reach the largest. 226140308Scognet */ 227140308Scognetint repeatinterval[] = { 30, 120, 600 }; /* # of secs before flush */ 228140308Scognet#define MAXREPEAT ((sizeof(repeatinterval) / sizeof(repeatinterval[0])) - 1) 229140308Scognet#define REPEATTIME(f) ((f)->f_time + repeatinterval[(f)->f_repeatcount]) 230140308Scognet#define BACKOFF(f) { if (++(f)->f_repeatcount > MAXREPEAT) \ 231140308Scognet (f)->f_repeatcount = MAXREPEAT; \ 232140308Scognet } 233140308Scognet 234140308Scognet/* values for f_type */ 235140308Scognet#define F_UNUSED 0 /* unused entry */ 236140308Scognet#define F_FILE 1 /* regular file */ 237140308Scognet#define F_TTY 2 /* terminal */ 238140308Scognet#define F_CONSOLE 3 /* console terminal */ 239140308Scognet#define F_FORW 4 /* remote machine */ 240140308Scognet#define F_USERS 5 /* list of users */ 241140308Scognet#define F_WALL 6 /* everyone logged on */ 242140308Scognet#define F_PIPE 7 /* pipe to program */ 243140308Scognet 244140308Scognetchar *TypeNames[8] = { 245140308Scognet "UNUSED", "FILE", "TTY", "CONSOLE", 246140308Scognet "FORW", "USERS", "WALL", "PIPE" 247140308Scognet}; 248140308Scognet 249140308Scognetstruct filed *Files; 250140308Scognetstruct filed consfile; 251140308Scognet 252140308Scognetint Debug; /* debug flag */ 253140308Scognetint resolve = 1; /* resolve hostname */ 254140308Scognetchar LocalHostName[MAXHOSTNAMELEN+1]; /* our hostname */ 255140308Scognetchar *LocalDomain; /* our local domain name */ 256140308Scognetint finet = -1; /* Internet datagram socket */ 257140308Scognetint fklog = -1; /* /dev/klog */ 258140308Scognetint LogPort; /* port number for INET connections */ 259140308Scognetint Initialized = 0; /* set when we have initialized ourselves */ 260140308Scognetint MarkInterval = 20 * 60; /* interval between marks in seconds */ 261140308Scognetint MarkSeq = 0; /* mark sequence number */ 262140308Scognetint SecureMode = 0; /* when true, receive only unix domain socks */ 263140308Scognet 264140308Scognetchar bootfile[MAXLINE+1]; /* booted kernel file */ 265140308Scognet 266140308Scognetstruct allowedpeer *AllowedPeers; 267140308Scognetint NumAllowed = 0; /* # of AllowedPeer entries */ 268140308Scognet 269140308Scognetint UniquePriority = 0; /* Only log specified priority? */ 270140308Scognetint LogFacPri = 0; /* Put facility and priority in log message: */ 271140308Scognet /* 0=no, 1=numeric, 2=names */ 272140308Scognetint KeepKernFac = 0; /* Keep remotely logged kernel facility */ 273140308Scognet 274140308Scognetint allowaddr __P((char *)); 275140308Scognetvoid cfline __P((char *, struct filed *, char *, char *)); 276140308Scognetchar *cvthname __P((struct sockaddr_in *)); 277140308Scognetvoid deadq_enter __P((pid_t, const char *)); 278140308Scognetint deadq_remove __P((pid_t)); 279140308Scognetint decode __P((const char *, CODE *)); 280140308Scognetvoid die __P((int)); 281140308Scognetvoid domark __P((int)); 282140308Scognetvoid fprintlog __P((struct filed *, int, char *)); 283140308Scognetvoid init __P((int)); 284140308Scognetvoid logerror __P((const char *)); 285140308Scognetvoid logmsg __P((int, char *, char *, int)); 286140308Scognetvoid log_deadchild __P((pid_t, int, const char *)); 287140308Scognetvoid printline __P((char *, char *)); 288140308Scognetvoid printsys __P((char *)); 289140308Scognetint p_open __P((char *, pid_t *)); 290140308Scognetvoid readklog __P((void)); 291140308Scognetvoid reapchild __P((int)); 292140308Scognetchar *ttymsg __P((struct iovec *, int, char *, int)); 293140308Scognetstatic void usage __P((void)); 294140308Scognetint validate __P((struct sockaddr_in *, const char *)); 295140308Scognetvoid wallmsg __P((struct filed *, struct iovec *)); 296140308Scognetint waitdaemon __P((int, int, int)); 297140308Scognetvoid timedout __P((int)); 298140308Scognet 299140308Scognetint 300140308Scognetmain(argc, argv) 301140308Scognet int argc; 302140308Scognet char *argv[]; 303140308Scognet{ 304140308Scognet int ch, i, l; 305140308Scognet struct sockaddr_un sunx, fromunix; 306140308Scognet struct sockaddr_in sin, frominet; 307140308Scognet FILE *fp; 308140308Scognet char *p, *hname, line[MAXLINE + 1]; 309140308Scognet struct timeval tv, *tvp; 310140308Scognet struct sigaction sact; 311140308Scognet sigset_t mask; 312140308Scognet pid_t ppid = 1; 313140308Scognet socklen_t len; 314140308Scognet 315140308Scognet while ((ch = getopt(argc, argv, "a:df:kl:m:np:suv")) != -1) 316140308Scognet switch (ch) { 317140308Scognet case 'a': /* allow specific network addresses only */ 318140308Scognet if (allowaddr(optarg) == -1) 319140308Scognet usage(); 320140308Scognet break; 321140308Scognet case 'd': /* debug */ 322140308Scognet Debug++; 323140308Scognet break; 324140308Scognet case 'f': /* configuration file */ 325140308Scognet ConfFile = optarg; 326140308Scognet break; 327140308Scognet case 'k': /* keep remote kern fac */ 328140308Scognet KeepKernFac = 1; 329140308Scognet break; 330140308Scognet case 'l': 331140308Scognet if (nfunix < MAXFUNIX) 332140308Scognet funixn[nfunix++] = optarg; 333140308Scognet else 334140308Scognet warnx("out of descriptors, ignoring %s", 335140308Scognet optarg); 336140308Scognet break; 337140350Scognet case 'm': /* mark interval */ 338140350Scognet MarkInterval = atoi(optarg) * 60; 339140350Scognet break; 340140350Scognet case 'n': 341140308Scognet resolve = 0; 342140308Scognet break; 343140308Scognet case 'p': /* path */ 344140308Scognet funixn[0] = optarg; 345140308Scognet break; 346140308Scognet case 's': /* no network mode */ 347140308Scognet SecureMode++; 348140350Scognet break; 349140308Scognet case 'u': /* only log specified priority */ 350140308Scognet UniquePriority++; 351140308Scognet break; 352140308Scognet case 'v': /* log facility and priority */ 353140308Scognet LogFacPri++; 354140308Scognet break; 355140308Scognet case '?': 356140308Scognet default: 357140308Scognet usage(); 358140308Scognet } 359140308Scognet if ((argc -= optind) != 0) 360140308Scognet usage(); 361140308Scognet 362140308Scognet if (!Debug) { 363140308Scognet ppid = waitdaemon(0, 0, 30); 364140308Scognet if (ppid < 0) 365140308Scognet err(1, "could not become daemon"); 366140308Scognet } else 367140308Scognet setlinebuf(stdout); 368140308Scognet 369140308Scognet if (NumAllowed) 370140308Scognet endservent(); 371140308Scognet 372140308Scognet consfile.f_type = F_CONSOLE; 373140308Scognet (void)strcpy(consfile.f_un.f_fname, ctty + sizeof _PATH_DEV - 1); 374140308Scognet (void)gethostname(LocalHostName, sizeof(LocalHostName)); 375140308Scognet if ((p = strchr(LocalHostName, '.')) != NULL) { 376140308Scognet *p++ = '\0'; 377140308Scognet LocalDomain = p; 378140308Scognet } else 379140308Scognet LocalDomain = ""; 380140308Scognet (void)strcpy(bootfile, getbootfile()); 381140308Scognet (void)signal(SIGTERM, die); 382140308Scognet (void)signal(SIGINT, Debug ? die : SIG_IGN); 383140308Scognet (void)signal(SIGQUIT, Debug ? die : SIG_IGN); 384140308Scognet /* 385140308Scognet * We don't want the SIGCHLD and SIGHUP handlers to interfere 386140308Scognet * with each other; they are likely candidates for being called 387140308Scognet * simultaneously (SIGHUP closes pipe descriptor, process dies, 388140308Scognet * SIGCHLD happens). 389140308Scognet */ 390140308Scognet sigemptyset(&mask); 391 sigaddset(&mask, SIGHUP); 392 sact.sa_handler = reapchild; 393 sact.sa_mask = mask; 394 sact.sa_flags = SA_RESTART; 395 (void)sigaction(SIGCHLD, &sact, NULL); 396 (void)signal(SIGALRM, domark); 397 (void)signal(SIGPIPE, SIG_IGN); /* We'll catch EPIPE instead. */ 398 (void)alarm(TIMERINTVL); 399 400 TAILQ_INIT(&deadq_head); 401 402#ifndef SUN_LEN 403#define SUN_LEN(unp) (strlen((unp)->sun_path) + 2) 404#endif 405 for (i = 0; i < nfunix; i++) { 406 memset(&sunx, 0, sizeof(sunx)); 407 sunx.sun_family = AF_UNIX; 408 (void)strncpy(sunx.sun_path, funixn[i], sizeof(sunx.sun_path)); 409 funix[i] = socket(AF_UNIX, SOCK_DGRAM, 0); 410 if (funix[i] < 0 || 411 bind(funix[i], (struct sockaddr *)&sunx, 412 SUN_LEN(&sunx)) < 0 || 413 chmod(funixn[i], 0666) < 0) { 414 (void) snprintf(line, sizeof line, 415 "cannot create %s", funixn[i]); 416 logerror(line); 417 dprintf("cannot create %s (%d)\n", funixn[i], errno); 418 if (i == 0) 419 die(0); 420 } 421 } 422 if (SecureMode <= 1) 423 finet = socket(AF_INET, SOCK_DGRAM, 0); 424 if (finet >= 0) { 425 struct servent *sp; 426 427 sp = getservbyname("syslog", "udp"); 428 if (sp == NULL) { 429 errno = 0; 430 logerror("syslog/udp: unknown service"); 431 die(0); 432 } 433 memset(&sin, 0, sizeof(sin)); 434 sin.sin_family = AF_INET; 435 sin.sin_port = LogPort = sp->s_port; 436 437 if (bind(finet, (struct sockaddr *)&sin, sizeof(sin)) < 0) { 438 logerror("bind"); 439 if (!Debug) 440 die(0); 441 } 442 } 443 if (finet >= 0 && SecureMode) { 444 if (shutdown(finet, SHUT_RD) < 0) { 445 logerror("shutdown"); 446 if (!Debug) 447 die(0); 448 } 449 } 450 451 if ((fklog = open(_PATH_KLOG, O_RDONLY, 0)) >= 0) 452 if (fcntl(fklog, F_SETFL, O_NONBLOCK) < 0) 453 fklog = -1; 454 if (fklog < 0) 455 dprintf("can't open %s (%d)\n", _PATH_KLOG, errno); 456 457 /* tuck my process id away */ 458 fp = fopen(PidFile, "w"); 459 if (fp != NULL) { 460 fprintf(fp, "%d\n", getpid()); 461 (void) fclose(fp); 462 } 463 464 dprintf("off & running....\n"); 465 466 init(0); 467 /* prevent SIGHUP and SIGCHLD handlers from running in parallel */ 468 sigemptyset(&mask); 469 sigaddset(&mask, SIGCHLD); 470 sact.sa_handler = init; 471 sact.sa_mask = mask; 472 sact.sa_flags = SA_RESTART; 473 (void)sigaction(SIGHUP, &sact, NULL); 474 475 tvp = &tv; 476 tv.tv_sec = tv.tv_usec = 0; 477 478 for (;;) { 479 fd_set readfds; 480 int nfds = 0; 481 482 FD_ZERO(&readfds); 483 if (fklog != -1) { 484 FD_SET(fklog, &readfds); 485 if (fklog > nfds) 486 nfds = fklog; 487 } 488 if (finet != -1 && !SecureMode) { 489 FD_SET(finet, &readfds); 490 if (finet > nfds) 491 nfds = finet; 492 } 493 for (i = 0; i < nfunix; i++) { 494 if (funix[i] != -1) { 495 FD_SET(funix[i], &readfds); 496 if (funix[i] > nfds) 497 nfds = funix[i]; 498 } 499 } 500 501 /*dprintf("readfds = %#x\n", readfds);*/ 502 nfds = select(nfds+1, &readfds, (fd_set *)NULL, 503 (fd_set *)NULL, tvp); 504 if (nfds == 0) { 505 if (tvp) { 506 tvp = NULL; 507 if (ppid != 1) 508 kill(ppid, SIGALRM); 509 } 510 continue; 511 } 512 if (nfds < 0) { 513 if (errno != EINTR) 514 logerror("select"); 515 continue; 516 } 517 /*dprintf("got a message (%d, %#x)\n", nfds, readfds);*/ 518 if (fklog != -1 && FD_ISSET(fklog, &readfds)) 519 readklog(); 520 if (finet != -1 && FD_ISSET(finet, &readfds)) { 521 len = sizeof(frominet); 522 l = recvfrom(finet, line, MAXLINE, 0, 523 (struct sockaddr *)&frominet, &len); 524 if (l > 0) { 525 line[l] = '\0'; 526 if (resolve) 527 hname = cvthname(&frominet); 528 else 529 hname = inet_ntoa(frominet.sin_addr); 530 if (validate(&frominet, hname)) 531 printline(hname, line); 532 } else if (l < 0 && errno != EINTR) 533 logerror("recvfrom inet"); 534 } 535 for (i = 0; i < nfunix; i++) { 536 if (funix[i] != -1 && FD_ISSET(funix[i], &readfds)) { 537 len = sizeof(fromunix); 538 l = recvfrom(funix[i], line, MAXLINE, 0, 539 (struct sockaddr *)&fromunix, &len); 540 if (l > 0) { 541 line[l] = '\0'; 542 printline(LocalHostName, line); 543 } else if (l < 0 && errno != EINTR) 544 logerror("recvfrom unix"); 545 } 546 } 547 } 548} 549 550static void 551usage() 552{ 553 554 fprintf(stderr, "%s\n%s\n%s\n", 555 "usage: syslogd [-dnsuv] [-a allowed_peer] [-f config_file]", 556 " [-m mark_interval] [-p log_socket]", 557 " [-l log_socket]"); 558 exit(1); 559} 560 561/* 562 * Take a raw input line, decode the message, and print the message 563 * on the appropriate log files. 564 */ 565void 566printline(hname, msg) 567 char *hname; 568 char *msg; 569{ 570 int c, pri; 571 char *p, *q, line[MAXLINE + 1]; 572 573 /* test for special codes */ 574 pri = DEFUPRI; 575 p = msg; 576 if (*p == '<') { 577 pri = 0; 578 while (isdigit(*++p)) 579 pri = 10 * pri + (*p - '0'); 580 if (*p == '>') 581 ++p; 582 } 583 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 584 pri = DEFUPRI; 585 586 /* don't allow users to log kernel messages */ 587 if (LOG_FAC(pri) == LOG_KERN && !KeepKernFac) 588 pri = LOG_MAKEPRI(LOG_USER, LOG_PRI(pri)); 589 590 q = line; 591 592 while ((c = (unsigned char)*p++) != '\0' && 593 q < &line[sizeof(line) - 4]) { 594 if ((c & 0x80) && c < 0xA0) { 595 c &= 0x7F; 596 *q++ = 'M'; 597 *q++ = '-'; 598 } 599 if (isascii(c) && iscntrl(c)) { 600 if (c == '\n') 601 *q++ = ' '; 602 else if (c == '\t') 603 *q++ = '\t'; 604 else { 605 *q++ = '^'; 606 *q++ = c ^ 0100; 607 } 608 } else 609 *q++ = c; 610 } 611 *q = '\0'; 612 613 logmsg(pri, line, hname, 0); 614} 615 616/* 617 * Read /dev/klog while data are available, split into lines. 618 */ 619void 620readklog() 621{ 622 char *p, *q, line[MAXLINE + 1]; 623 int len, i; 624 625 len = 0; 626 for (;;) { 627 i = read(fklog, line + len, MAXLINE - 1 - len); 628 if (i > 0) 629 line[i + len] = '\0'; 630 else if (i < 0 && errno != EINTR && errno != EAGAIN) { 631 logerror("klog"); 632 fklog = -1; 633 break; 634 } else 635 break; 636 637 for (p = line; (q = strchr(p, '\n')) != NULL; p = q + 1) { 638 *q = '\0'; 639 printsys(p); 640 } 641 len = strlen(p); 642 if (len >= MAXLINE - 1) { 643 printsys(p); 644 len = 0; 645 } 646 if (len > 0) 647 memmove(line, p, len + 1); 648 } 649 if (len > 0) 650 printsys(line); 651} 652 653/* 654 * Take a raw input line from /dev/klog, format similar to syslog(). 655 */ 656void 657printsys(p) 658 char *p; 659{ 660 int pri, flags; 661 662 flags = ISKERNEL | SYNC_FILE | ADDDATE; /* fsync after write */ 663 pri = DEFSPRI; 664 if (*p == '<') { 665 pri = 0; 666 while (isdigit(*++p)) 667 pri = 10 * pri + (*p - '0'); 668 if (*p == '>') 669 ++p; 670 if (LOG_FAC(pri) == LOG_CONSOLE) 671 flags |= IGN_CONS; 672 } else { 673 /* kernel printf's come out on console */ 674 flags |= IGN_CONS; 675 } 676 if (pri &~ (LOG_FACMASK|LOG_PRIMASK)) 677 pri = DEFSPRI; 678 logmsg(pri, p, LocalHostName, flags); 679} 680 681time_t now; 682 683/* 684 * Log a message to the appropriate log files, users, etc. based on 685 * the priority. 686 */ 687void 688logmsg(pri, msg, from, flags) 689 int pri; 690 char *msg, *from; 691 int flags; 692{ 693 struct filed *f; 694 int i, fac, msglen, omask, prilev; 695 char *timestamp; 696 char prog[NAME_MAX+1]; 697 char buf[MAXLINE+1]; 698 699 dprintf("logmsg: pri %o, flags %x, from %s, msg %s\n", 700 pri, flags, from, msg); 701 702 omask = sigblock(sigmask(SIGHUP)|sigmask(SIGALRM)); 703 704 /* 705 * Check to see if msg looks non-standard. 706 */ 707 msglen = strlen(msg); 708 if (msglen < 16 || msg[3] != ' ' || msg[6] != ' ' || 709 msg[9] != ':' || msg[12] != ':' || msg[15] != ' ') 710 flags |= ADDDATE; 711 712 (void)time(&now); 713 if (flags & ADDDATE) 714 timestamp = ctime(&now) + 4; 715 else { 716 timestamp = msg; 717 msg += 16; 718 msglen -= 16; 719 } 720 721 /* skip leading blanks */ 722 while (isspace(*msg)) { 723 msg++; 724 msglen--; 725 } 726 727 /* extract facility and priority level */ 728 if (flags & MARK) 729 fac = LOG_NFACILITIES; 730 else 731 fac = LOG_FAC(pri); 732 prilev = LOG_PRI(pri); 733 734 /* extract program name */ 735 for (i = 0; i < NAME_MAX; i++) { 736 if (!isalnum(msg[i])) 737 break; 738 prog[i] = msg[i]; 739 } 740 prog[i] = 0; 741 742 /* add kernel prefix for kernel messages */ 743 if (flags & ISKERNEL) { 744 snprintf(buf, sizeof(buf), "%s: %s", bootfile, msg); 745 msg = buf; 746 msglen = strlen(buf); 747 } 748 749 /* log the message to the particular outputs */ 750 if (!Initialized) { 751 f = &consfile; 752 f->f_file = open(ctty, O_WRONLY, 0); 753 754 if (f->f_file >= 0) { 755 fprintlog(f, flags, msg); 756 (void)close(f->f_file); 757 } 758 (void)sigsetmask(omask); 759 return; 760 } 761 for (f = Files; f; f = f->f_next) { 762 /* skip messages that are incorrect priority */ 763 if (!(((f->f_pcmp[fac] & PRI_EQ) && (f->f_pmask[fac] == prilev)) 764 ||((f->f_pcmp[fac] & PRI_LT) && (f->f_pmask[fac] < prilev)) 765 ||((f->f_pcmp[fac] & PRI_GT) && (f->f_pmask[fac] > prilev)) 766 ) 767 || f->f_pmask[fac] == INTERNAL_NOPRI) 768 continue; 769 /* skip messages with the incorrect hostname */ 770 if (f->f_host) 771 switch (f->f_host[0]) { 772 case '+': 773 if (strcmp(from, f->f_host + 1) != 0) 774 continue; 775 break; 776 case '-': 777 if (strcmp(from, f->f_host + 1) == 0) 778 continue; 779 break; 780 } 781 782 /* skip messages with the incorrect program name */ 783 if (f->f_program) 784 if (strcmp(prog, f->f_program) != 0) 785 continue; 786 787 if (f->f_type == F_CONSOLE && (flags & IGN_CONS)) 788 continue; 789 790 /* don't output marks to recently written files */ 791 if ((flags & MARK) && (now - f->f_time) < MarkInterval / 2) 792 continue; 793 794 /* 795 * suppress duplicate lines to this file 796 */ 797 if ((flags & MARK) == 0 && msglen == f->f_prevlen && 798 !strcmp(msg, f->f_prevline) && 799 !strcasecmp(from, f->f_prevhost)) { 800 (void)strncpy(f->f_lasttime, timestamp, 15); 801 f->f_prevcount++; 802 dprintf("msg repeated %d times, %ld sec of %d\n", 803 f->f_prevcount, (long)(now - f->f_time), 804 repeatinterval[f->f_repeatcount]); 805 /* 806 * If domark would have logged this by now, 807 * flush it now (so we don't hold isolated messages), 808 * but back off so we'll flush less often 809 * in the future. 810 */ 811 if (now > REPEATTIME(f)) { 812 fprintlog(f, flags, (char *)NULL); 813 BACKOFF(f); 814 } 815 } else { 816 /* new line, save it */ 817 if (f->f_prevcount) 818 fprintlog(f, 0, (char *)NULL); 819 f->f_repeatcount = 0; 820 f->f_prevpri = pri; 821 (void)strncpy(f->f_lasttime, timestamp, 15); 822 (void)strncpy(f->f_prevhost, from, 823 sizeof(f->f_prevhost)-1); 824 f->f_prevhost[sizeof(f->f_prevhost)-1] = '\0'; 825 if (msglen < MAXSVLINE) { 826 f->f_prevlen = msglen; 827 (void)strcpy(f->f_prevline, msg); 828 fprintlog(f, flags, (char *)NULL); 829 } else { 830 f->f_prevline[0] = 0; 831 f->f_prevlen = 0; 832 fprintlog(f, flags, msg); 833 } 834 } 835 } 836 (void)sigsetmask(omask); 837} 838 839void 840fprintlog(f, flags, msg) 841 struct filed *f; 842 int flags; 843 char *msg; 844{ 845 struct iovec iov[7]; 846 struct iovec *v; 847 int l; 848 char line[MAXLINE + 1], repbuf[80], greetings[200]; 849 char *msgret; 850 851 v = iov; 852 if (f->f_type == F_WALL) { 853 v->iov_base = greetings; 854 v->iov_len = snprintf(greetings, sizeof greetings, 855 "\r\n\7Message from syslogd@%s at %.24s ...\r\n", 856 f->f_prevhost, ctime(&now)); 857 v++; 858 v->iov_base = ""; 859 v->iov_len = 0; 860 v++; 861 } else { 862 v->iov_base = f->f_lasttime; 863 v->iov_len = 15; 864 v++; 865 v->iov_base = " "; 866 v->iov_len = 1; 867 v++; 868 } 869 870 if (LogFacPri) { 871 static char fp_buf[30]; /* Hollow laugh */ 872 int fac = f->f_prevpri & LOG_FACMASK; 873 int pri = LOG_PRI(f->f_prevpri); 874 char *f_s = 0; 875 char f_n[5]; /* Hollow laugh */ 876 char *p_s = 0; 877 char p_n[5]; /* Hollow laugh */ 878 879 if (LogFacPri > 1) { 880 CODE *c; 881 882 for (c = facilitynames; c->c_name; c++) { 883 if (c->c_val == fac) { 884 f_s = c->c_name; 885 break; 886 } 887 } 888 for (c = prioritynames; c->c_name; c++) { 889 if (c->c_val == pri) { 890 p_s = c->c_name; 891 break; 892 } 893 } 894 } 895 if (!f_s) { 896 snprintf(f_n, sizeof f_n, "%d", LOG_FAC(fac)); 897 f_s = f_n; 898 } 899 if (!p_s) { 900 snprintf(p_n, sizeof p_n, "%d", pri); 901 p_s = p_n; 902 } 903 snprintf(fp_buf, sizeof fp_buf, "<%s.%s> ", f_s, p_s); 904 v->iov_base = fp_buf; 905 v->iov_len = strlen(fp_buf); 906 } else { 907 v->iov_base=""; 908 v->iov_len = 0; 909 } 910 v++; 911 912 v->iov_base = f->f_prevhost; 913 v->iov_len = strlen(v->iov_base); 914 v++; 915 v->iov_base = " "; 916 v->iov_len = 1; 917 v++; 918 919 if (msg) { 920 v->iov_base = msg; 921 v->iov_len = strlen(msg); 922 } else if (f->f_prevcount > 1) { 923 v->iov_base = repbuf; 924 v->iov_len = sprintf(repbuf, "last message repeated %d times", 925 f->f_prevcount); 926 } else { 927 v->iov_base = f->f_prevline; 928 v->iov_len = f->f_prevlen; 929 } 930 v++; 931 932 dprintf("Logging to %s", TypeNames[f->f_type]); 933 f->f_time = now; 934 935 switch (f->f_type) { 936 case F_UNUSED: 937 dprintf("\n"); 938 break; 939 940 case F_FORW: 941 dprintf(" %s\n", f->f_un.f_forw.f_hname); 942 /* check for local vs remote messages */ 943 if (strcasecmp(f->f_prevhost, LocalHostName)) 944 l = snprintf(line, sizeof line - 1, 945 "<%d>%.15s Forwarded from %s: %s", 946 f->f_prevpri, iov[0].iov_base, f->f_prevhost, 947 iov[5].iov_base); 948 else 949 l = snprintf(line, sizeof line - 1, "<%d>%.15s %s", 950 f->f_prevpri, iov[0].iov_base, iov[5].iov_base); 951 if (l > MAXLINE) 952 l = MAXLINE; 953 if ((finet >= 0) && 954 (sendto(finet, line, l, 0, 955 (struct sockaddr *)&f->f_un.f_forw.f_addr, 956 sizeof(f->f_un.f_forw.f_addr)) != l)) { 957 int e = errno; 958 (void)close(f->f_file); 959 f->f_type = F_UNUSED; 960 errno = e; 961 logerror("sendto"); 962 } 963 break; 964 965 case F_FILE: 966 dprintf(" %s\n", f->f_un.f_fname); 967 v->iov_base = "\n"; 968 v->iov_len = 1; 969 if (writev(f->f_file, iov, 7) < 0) { 970 int e = errno; 971 (void)close(f->f_file); 972 f->f_type = F_UNUSED; 973 errno = e; 974 logerror(f->f_un.f_fname); 975 } else if (flags & SYNC_FILE) 976 (void)fsync(f->f_file); 977 break; 978 979 case F_PIPE: 980 dprintf(" %s\n", f->f_un.f_pipe.f_pname); 981 v->iov_base = "\n"; 982 v->iov_len = 1; 983 if (f->f_un.f_pipe.f_pid == 0) { 984 if ((f->f_file = p_open(f->f_un.f_pipe.f_pname, 985 &f->f_un.f_pipe.f_pid)) < 0) { 986 f->f_type = F_UNUSED; 987 logerror(f->f_un.f_pipe.f_pname); 988 break; 989 } 990 } 991 if (writev(f->f_file, iov, 7) < 0) { 992 int e = errno; 993 (void)close(f->f_file); 994 if (f->f_un.f_pipe.f_pid > 0) 995 deadq_enter(f->f_un.f_pipe.f_pid, 996 f->f_un.f_pipe.f_pname); 997 f->f_un.f_pipe.f_pid = 0; 998 errno = e; 999 logerror(f->f_un.f_pipe.f_pname); 1000 } 1001 break; 1002 1003 case F_CONSOLE: 1004 if (flags & IGN_CONS) { 1005 dprintf(" (ignored)\n"); 1006 break; 1007 } 1008 /* FALLTHROUGH */ 1009 1010 case F_TTY: 1011 dprintf(" %s%s\n", _PATH_DEV, f->f_un.f_fname); 1012 v->iov_base = "\r\n"; 1013 v->iov_len = 2; 1014 1015 errno = 0; /* ttymsg() only sometimes returns an errno */ 1016 if ((msgret = ttymsg(iov, 7, f->f_un.f_fname, 10))) { 1017 f->f_type = F_UNUSED; 1018 logerror(msgret); 1019 } 1020 break; 1021 1022 case F_USERS: 1023 case F_WALL: 1024 dprintf("\n"); 1025 v->iov_base = "\r\n"; 1026 v->iov_len = 2; 1027 wallmsg(f, iov); 1028 break; 1029 } 1030 f->f_prevcount = 0; 1031} 1032 1033/* 1034 * WALLMSG -- Write a message to the world at large 1035 * 1036 * Write the specified message to either the entire 1037 * world, or a list of approved users. 1038 */ 1039void 1040wallmsg(f, iov) 1041 struct filed *f; 1042 struct iovec *iov; 1043{ 1044 static int reenter; /* avoid calling ourselves */ 1045 FILE *uf; 1046 struct utmp ut; 1047 int i; 1048 char *p; 1049 char line[sizeof(ut.ut_line) + 1]; 1050 1051 if (reenter++) 1052 return; 1053 if ((uf = fopen(_PATH_UTMP, "r")) == NULL) { 1054 logerror(_PATH_UTMP); 1055 reenter = 0; 1056 return; 1057 } 1058 /* NOSTRICT */ 1059 while (fread((char *)&ut, sizeof(ut), 1, uf) == 1) { 1060 if (ut.ut_name[0] == '\0') 1061 continue; 1062 strncpy(line, ut.ut_line, sizeof(ut.ut_line)); 1063 line[sizeof(ut.ut_line)] = '\0'; 1064 if (f->f_type == F_WALL) { 1065 if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) != NULL) { 1066 errno = 0; /* already in msg */ 1067 logerror(p); 1068 } 1069 continue; 1070 } 1071 /* should we send the message to this user? */ 1072 for (i = 0; i < MAXUNAMES; i++) { 1073 if (!f->f_un.f_uname[i][0]) 1074 break; 1075 if (!strncmp(f->f_un.f_uname[i], ut.ut_name, 1076 UT_NAMESIZE)) { 1077 if ((p = ttymsg(iov, 7, line, TTYMSGTIME)) 1078 != NULL) { 1079 errno = 0; /* already in msg */ 1080 logerror(p); 1081 } 1082 break; 1083 } 1084 } 1085 } 1086 (void)fclose(uf); 1087 reenter = 0; 1088} 1089 1090void 1091reapchild(signo) 1092 int signo; 1093{ 1094 int status; 1095 pid_t pid; 1096 struct filed *f; 1097 1098 while ((pid = wait3(&status, WNOHANG, (struct rusage *)NULL)) > 0) { 1099 if (!Initialized) 1100 /* Don't tell while we are initting. */ 1101 continue; 1102 1103 /* First, look if it's a process from the dead queue. */ 1104 if (deadq_remove(pid)) 1105 goto oncemore; 1106 1107 /* Now, look in list of active processes. */ 1108 for (f = Files; f; f = f->f_next) 1109 if (f->f_type == F_PIPE && 1110 f->f_un.f_pipe.f_pid == pid) { 1111 (void)close(f->f_file); 1112 f->f_un.f_pipe.f_pid = 0; 1113 log_deadchild(pid, status, 1114 f->f_un.f_pipe.f_pname); 1115 break; 1116 } 1117 oncemore: 1118 continue; 1119 } 1120} 1121 1122/* 1123 * Return a printable representation of a host address. 1124 */ 1125char * 1126cvthname(f) 1127 struct sockaddr_in *f; 1128{ 1129 struct hostent *hp; 1130 sigset_t omask, nmask; 1131 char *p; 1132 1133 dprintf("cvthname(%s)\n", inet_ntoa(f->sin_addr)); 1134 1135 if (f->sin_family != AF_INET) { 1136 dprintf("Malformed from address\n"); 1137 return ("???"); 1138 } 1139 sigemptyset(&nmask); 1140 sigaddset(&nmask, SIGHUP); 1141 sigprocmask(SIG_BLOCK, &nmask, &omask); 1142 hp = gethostbyaddr((char *)&f->sin_addr, 1143 sizeof(struct in_addr), f->sin_family); 1144 sigprocmask(SIG_SETMASK, &omask, NULL); 1145 if (hp == 0) { 1146 dprintf("Host name for your address (%s) unknown\n", 1147 inet_ntoa(f->sin_addr)); 1148 return (inet_ntoa(f->sin_addr)); 1149 } 1150 if ((p = strchr(hp->h_name, '.')) && 1151 strcasecmp(p + 1, LocalDomain) == 0) 1152 *p = '\0'; 1153 return (hp->h_name); 1154} 1155 1156void 1157domark(signo) 1158 int signo; 1159{ 1160 struct filed *f; 1161 dq_t q; 1162 1163 now = time((time_t *)NULL); 1164 MarkSeq += TIMERINTVL; 1165 if (MarkSeq >= MarkInterval) { 1166 logmsg(LOG_INFO, "-- MARK --", LocalHostName, ADDDATE|MARK); 1167 MarkSeq = 0; 1168 } 1169 1170 for (f = Files; f; f = f->f_next) { 1171 if (f->f_prevcount && now >= REPEATTIME(f)) { 1172 dprintf("flush %s: repeated %d times, %d sec.\n", 1173 TypeNames[f->f_type], f->f_prevcount, 1174 repeatinterval[f->f_repeatcount]); 1175 fprintlog(f, 0, (char *)NULL); 1176 BACKOFF(f); 1177 } 1178 } 1179 1180 /* Walk the dead queue, and see if we should signal somebody. */ 1181 for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries)) 1182 switch (q->dq_timeout) { 1183 case 0: 1184 /* Already signalled once, try harder now. */ 1185 if (kill(q->dq_pid, SIGKILL) != 0) 1186 (void)deadq_remove(q->dq_pid); 1187 break; 1188 1189 case 1: 1190 /* 1191 * Timed out on dead queue, send terminate 1192 * signal. Note that we leave the removal 1193 * from the dead queue to reapchild(), which 1194 * will also log the event (unless the process 1195 * didn't even really exist, in case we simply 1196 * drop it from the dead queue). 1197 */ 1198 if (kill(q->dq_pid, SIGTERM) != 0) 1199 (void)deadq_remove(q->dq_pid); 1200 /* FALLTHROUGH */ 1201 1202 default: 1203 q->dq_timeout--; 1204 } 1205 1206 (void)alarm(TIMERINTVL); 1207} 1208 1209/* 1210 * Print syslogd errors some place. 1211 */ 1212void 1213logerror(type) 1214 const char *type; 1215{ 1216 char buf[512]; 1217 1218 if (errno) 1219 (void)snprintf(buf, 1220 sizeof buf, "syslogd: %s: %s", type, strerror(errno)); 1221 else 1222 (void)snprintf(buf, sizeof buf, "syslogd: %s", type); 1223 errno = 0; 1224 dprintf("%s\n", buf); 1225 logmsg(LOG_SYSLOG|LOG_ERR, buf, LocalHostName, ADDDATE); 1226} 1227 1228void 1229die(signo) 1230 int signo; 1231{ 1232 struct filed *f; 1233 int was_initialized; 1234 char buf[100]; 1235 int i; 1236 1237 was_initialized = Initialized; 1238 Initialized = 0; /* Don't log SIGCHLDs. */ 1239 for (f = Files; f != NULL; f = f->f_next) { 1240 /* flush any pending output */ 1241 if (f->f_prevcount) 1242 fprintlog(f, 0, (char *)NULL); 1243 if (f->f_type == F_PIPE) 1244 (void)close(f->f_file); 1245 } 1246 Initialized = was_initialized; 1247 if (signo) { 1248 dprintf("syslogd: exiting on signal %d\n", signo); 1249 (void)sprintf(buf, "exiting on signal %d", signo); 1250 errno = 0; 1251 logerror(buf); 1252 } 1253 for (i = 0; i < nfunix; i++) 1254 if (funixn[i] && funix[i] != -1) 1255 (void)unlink(funixn[i]); 1256 exit(1); 1257} 1258 1259/* 1260 * INIT -- Initialize syslogd from configuration table 1261 */ 1262void 1263init(signo) 1264 int signo; 1265{ 1266 int i; 1267 FILE *cf; 1268 struct filed *f, *next, **nextp; 1269 char *p; 1270 char cline[LINE_MAX]; 1271 char prog[NAME_MAX+1]; 1272 char host[MAXHOSTNAMELEN+1]; 1273 1274 dprintf("init\n"); 1275 1276 /* 1277 * Close all open log files. 1278 */ 1279 Initialized = 0; 1280 for (f = Files; f != NULL; f = next) { 1281 /* flush any pending output */ 1282 if (f->f_prevcount) 1283 fprintlog(f, 0, (char *)NULL); 1284 1285 switch (f->f_type) { 1286 case F_FILE: 1287 case F_FORW: 1288 case F_CONSOLE: 1289 case F_TTY: 1290 (void)close(f->f_file); 1291 break; 1292 case F_PIPE: 1293 (void)close(f->f_file); 1294 if (f->f_un.f_pipe.f_pid > 0) 1295 deadq_enter(f->f_un.f_pipe.f_pid, 1296 f->f_un.f_pipe.f_pname); 1297 f->f_un.f_pipe.f_pid = 0; 1298 break; 1299 } 1300 next = f->f_next; 1301 if (f->f_program) free(f->f_program); 1302 if (f->f_host) free(f->f_host); 1303 free((char *)f); 1304 } 1305 Files = NULL; 1306 nextp = &Files; 1307 1308 /* open the configuration file */ 1309 if ((cf = fopen(ConfFile, "r")) == NULL) { 1310 dprintf("cannot open %s\n", ConfFile); 1311 *nextp = (struct filed *)calloc(1, sizeof(*f)); 1312 cfline("*.ERR\t/dev/console", *nextp, "*", "*"); 1313 (*nextp)->f_next = (struct filed *)calloc(1, sizeof(*f)); 1314 cfline("*.PANIC\t*", (*nextp)->f_next, "*", "*"); 1315 Initialized = 1; 1316 return; 1317 } 1318 1319 /* 1320 * Foreach line in the conf table, open that file. 1321 */ 1322 f = NULL; 1323 strcpy(host, "*"); 1324 strcpy(prog, "*"); 1325 while (fgets(cline, sizeof(cline), cf) != NULL) { 1326 /* 1327 * check for end-of-section, comments, strip off trailing 1328 * spaces and newline character. #!prog is treated specially: 1329 * following lines apply only to that program. 1330 */ 1331 for (p = cline; isspace(*p); ++p) 1332 continue; 1333 if (*p == 0) 1334 continue; 1335 if (*p == '#') { 1336 p++; 1337 if (*p != '!' && *p != '+' && *p != '-') 1338 continue; 1339 } 1340 if (*p == '+' || *p == '-') { 1341 host[0] = *p++; 1342 while (isspace(*p)) p++; 1343 if ((!*p) || (*p == '*')) { 1344 strcpy(host, "*"); 1345 continue; 1346 } 1347 if (*p == '@') 1348 p = LocalHostName; 1349 for (i = 1; i < MAXHOSTNAMELEN; i++) { 1350 if (!isalnum(*p) && *p != '.' && *p != '-') 1351 break; 1352 host[i] = *p++; 1353 } 1354 host[i] = '\0'; 1355 continue; 1356 } 1357 if (*p == '!') { 1358 p++; 1359 while (isspace(*p)) p++; 1360 if ((!*p) || (*p == '*')) { 1361 strcpy(prog, "*"); 1362 continue; 1363 } 1364 for (i = 0; i < NAME_MAX; i++) { 1365 if (!isalnum(p[i])) 1366 break; 1367 prog[i] = p[i]; 1368 } 1369 prog[i] = 0; 1370 continue; 1371 } 1372 for (p = strchr(cline, '\0'); isspace(*--p);) 1373 continue; 1374 *++p = '\0'; 1375 f = (struct filed *)calloc(1, sizeof(*f)); 1376 *nextp = f; 1377 nextp = &f->f_next; 1378 cfline(cline, f, prog, host); 1379 } 1380 1381 /* close the configuration file */ 1382 (void)fclose(cf); 1383 1384 Initialized = 1; 1385 1386 if (Debug) { 1387 for (f = Files; f; f = f->f_next) { 1388 for (i = 0; i <= LOG_NFACILITIES; i++) 1389 if (f->f_pmask[i] == INTERNAL_NOPRI) 1390 printf("X "); 1391 else 1392 printf("%d ", f->f_pmask[i]); 1393 printf("%s: ", TypeNames[f->f_type]); 1394 switch (f->f_type) { 1395 case F_FILE: 1396 printf("%s", f->f_un.f_fname); 1397 break; 1398 1399 case F_CONSOLE: 1400 case F_TTY: 1401 printf("%s%s", _PATH_DEV, f->f_un.f_fname); 1402 break; 1403 1404 case F_FORW: 1405 printf("%s", f->f_un.f_forw.f_hname); 1406 break; 1407 1408 case F_PIPE: 1409 printf("%s", f->f_un.f_pipe.f_pname); 1410 break; 1411 1412 case F_USERS: 1413 for (i = 0; i < MAXUNAMES && *f->f_un.f_uname[i]; i++) 1414 printf("%s, ", f->f_un.f_uname[i]); 1415 break; 1416 } 1417 if (f->f_program) 1418 printf(" (%s)", f->f_program); 1419 printf("\n"); 1420 } 1421 } 1422 1423 logmsg(LOG_SYSLOG|LOG_INFO, "syslogd: restart", LocalHostName, ADDDATE); 1424 dprintf("syslogd: restarted\n"); 1425} 1426 1427/* 1428 * Crack a configuration file line 1429 */ 1430void 1431cfline(line, f, prog, host) 1432 char *line; 1433 struct filed *f; 1434 char *prog; 1435 char *host; 1436{ 1437 struct hostent *hp; 1438 int i, pri; 1439 char *bp, *p, *q; 1440 char buf[MAXLINE], ebuf[100]; 1441 1442 dprintf("cfline(\"%s\", f, \"%s\", \"%s\")\n", line, prog, host); 1443 1444 errno = 0; /* keep strerror() stuff out of logerror messages */ 1445 1446 /* clear out file entry */ 1447 memset(f, 0, sizeof(*f)); 1448 for (i = 0; i <= LOG_NFACILITIES; i++) 1449 f->f_pmask[i] = INTERNAL_NOPRI; 1450 1451 /* save hostname if any */ 1452 if (host && *host == '*') 1453 host = NULL; 1454 if (host) 1455 f->f_host = strdup(host); 1456 1457 /* save program name if any */ 1458 if (prog && *prog == '*') 1459 prog = NULL; 1460 if (prog) 1461 f->f_program = strdup(prog); 1462 1463 /* scan through the list of selectors */ 1464 for (p = line; *p && *p != '\t' && *p != ' ';) { 1465 int pri_done; 1466 int pri_cmp; 1467 1468 /* find the end of this facility name list */ 1469 for (q = p; *q && *q != '\t' && *q != ' ' && *q++ != '.'; ) 1470 continue; 1471 1472 /* get the priority comparison */ 1473 pri_cmp = 0; 1474 pri_done = 0; 1475 while (!pri_done) { 1476 switch (*q) { 1477 case '<': 1478 pri_cmp |= PRI_LT; 1479 q++; 1480 break; 1481 case '=': 1482 pri_cmp |= PRI_EQ; 1483 q++; 1484 break; 1485 case '>': 1486 pri_cmp |= PRI_GT; 1487 q++; 1488 break; 1489 default: 1490 pri_done++; 1491 break; 1492 } 1493 } 1494 if (!pri_cmp) 1495 pri_cmp = (UniquePriority) 1496 ? (PRI_EQ) 1497 : (PRI_EQ | PRI_GT) 1498 ; 1499 1500 /* collect priority name */ 1501 for (bp = buf; *q && !strchr("\t,; ", *q); ) 1502 *bp++ = *q++; 1503 *bp = '\0'; 1504 1505 /* skip cruft */ 1506 while (strchr(",;", *q)) 1507 q++; 1508 1509 /* decode priority name */ 1510 if (*buf == '*') 1511 pri = LOG_PRIMASK + 1; 1512 else { 1513 pri = decode(buf, prioritynames); 1514 if (pri < 0) { 1515 (void)snprintf(ebuf, sizeof ebuf, 1516 "unknown priority name \"%s\"", buf); 1517 logerror(ebuf); 1518 return; 1519 } 1520 } 1521 1522 /* scan facilities */ 1523 while (*p && !strchr("\t.; ", *p)) { 1524 for (bp = buf; *p && !strchr("\t,;. ", *p); ) 1525 *bp++ = *p++; 1526 *bp = '\0'; 1527 1528 if (*buf == '*') 1529 for (i = 0; i < LOG_NFACILITIES; i++) { 1530 f->f_pmask[i] = pri; 1531 f->f_pcmp[i] = pri_cmp; 1532 } 1533 else { 1534 i = decode(buf, facilitynames); 1535 if (i < 0) { 1536 (void)snprintf(ebuf, sizeof ebuf, 1537 "unknown facility name \"%s\"", 1538 buf); 1539 logerror(ebuf); 1540 return; 1541 } 1542 f->f_pmask[i >> 3] = pri; 1543 f->f_pcmp[i >> 3] = pri_cmp; 1544 } 1545 while (*p == ',' || *p == ' ') 1546 p++; 1547 } 1548 1549 p = q; 1550 } 1551 1552 /* skip to action part */ 1553 while (*p == '\t' || *p == ' ') 1554 p++; 1555 1556 switch (*p) 1557 { 1558 case '@': 1559 (void)strncpy(f->f_un.f_forw.f_hname, ++p, 1560 sizeof(f->f_un.f_forw.f_hname)-1); 1561 f->f_un.f_forw.f_hname[sizeof(f->f_un.f_forw.f_hname)-1] = '\0'; 1562 hp = gethostbyname(f->f_un.f_forw.f_hname); 1563 if (hp == NULL) { 1564 1565 logerror(hstrerror(h_errno)); 1566 break; 1567 } 1568 memset(&f->f_un.f_forw.f_addr, 0, 1569 sizeof(f->f_un.f_forw.f_addr)); 1570 f->f_un.f_forw.f_addr.sin_family = AF_INET; 1571 f->f_un.f_forw.f_addr.sin_port = LogPort; 1572 memmove(&f->f_un.f_forw.f_addr.sin_addr, hp->h_addr, hp->h_length); 1573 f->f_type = F_FORW; 1574 break; 1575 1576 case '/': 1577 if ((f->f_file = open(p, O_WRONLY|O_APPEND, 0)) < 0) { 1578 f->f_type = F_UNUSED; 1579 logerror(p); 1580 break; 1581 } 1582 if (isatty(f->f_file)) { 1583 if (strcmp(p, ctty) == 0) 1584 f->f_type = F_CONSOLE; 1585 else 1586 f->f_type = F_TTY; 1587 (void)strcpy(f->f_un.f_fname, p + sizeof _PATH_DEV - 1); 1588 } else { 1589 (void)strcpy(f->f_un.f_fname, p); 1590 f->f_type = F_FILE; 1591 } 1592 break; 1593 1594 case '|': 1595 f->f_un.f_pipe.f_pid = 0; 1596 (void)strcpy(f->f_un.f_pipe.f_pname, p + 1); 1597 f->f_type = F_PIPE; 1598 break; 1599 1600 case '*': 1601 f->f_type = F_WALL; 1602 break; 1603 1604 default: 1605 for (i = 0; i < MAXUNAMES && *p; i++) { 1606 for (q = p; *q && *q != ','; ) 1607 q++; 1608 (void)strncpy(f->f_un.f_uname[i], p, UT_NAMESIZE); 1609 if ((q - p) > UT_NAMESIZE) 1610 f->f_un.f_uname[i][UT_NAMESIZE] = '\0'; 1611 else 1612 f->f_un.f_uname[i][q - p] = '\0'; 1613 while (*q == ',' || *q == ' ') 1614 q++; 1615 p = q; 1616 } 1617 f->f_type = F_USERS; 1618 break; 1619 } 1620} 1621 1622 1623/* 1624 * Decode a symbolic name to a numeric value 1625 */ 1626int 1627decode(name, codetab) 1628 const char *name; 1629 CODE *codetab; 1630{ 1631 CODE *c; 1632 char *p, buf[40]; 1633 1634 if (isdigit(*name)) 1635 return (atoi(name)); 1636 1637 for (p = buf; *name && p < &buf[sizeof(buf) - 1]; p++, name++) { 1638 if (isupper(*name)) 1639 *p = tolower(*name); 1640 else 1641 *p = *name; 1642 } 1643 *p = '\0'; 1644 for (c = codetab; c->c_name; c++) 1645 if (!strcmp(buf, c->c_name)) 1646 return (c->c_val); 1647 1648 return (-1); 1649} 1650 1651/* 1652 * fork off and become a daemon, but wait for the child to come online 1653 * before returing to the parent, or we get disk thrashing at boot etc. 1654 * Set a timer so we don't hang forever if it wedges. 1655 */ 1656int 1657waitdaemon(nochdir, noclose, maxwait) 1658 int nochdir, noclose, maxwait; 1659{ 1660 int fd; 1661 int status; 1662 pid_t pid, childpid; 1663 1664 switch (childpid = fork()) { 1665 case -1: 1666 return (-1); 1667 case 0: 1668 break; 1669 default: 1670 signal(SIGALRM, timedout); 1671 alarm(maxwait); 1672 while ((pid = wait3(&status, 0, NULL)) != -1) { 1673 if (WIFEXITED(status)) 1674 errx(1, "child pid %d exited with return code %d", 1675 pid, WEXITSTATUS(status)); 1676 if (WIFSIGNALED(status)) 1677 errx(1, "child pid %d exited on signal %d%s", 1678 pid, WTERMSIG(status), 1679 WCOREDUMP(status) ? " (core dumped)" : 1680 ""); 1681 if (pid == childpid) /* it's gone... */ 1682 break; 1683 } 1684 exit(0); 1685 } 1686 1687 if (setsid() == -1) 1688 return (-1); 1689 1690 if (!nochdir) 1691 (void)chdir("/"); 1692 1693 if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { 1694 (void)dup2(fd, STDIN_FILENO); 1695 (void)dup2(fd, STDOUT_FILENO); 1696 (void)dup2(fd, STDERR_FILENO); 1697 if (fd > 2) 1698 (void)close (fd); 1699 } 1700 return (getppid()); 1701} 1702 1703/* 1704 * We get a SIGALRM from the child when it's running and finished doing it's 1705 * fsync()'s or O_SYNC writes for all the boot messages. 1706 * 1707 * We also get a signal from the kernel if the timer expires, so check to 1708 * see what happened. 1709 */ 1710void 1711timedout(sig) 1712 int sig __unused; 1713{ 1714 int left; 1715 left = alarm(0); 1716 signal(SIGALRM, SIG_DFL); 1717 if (left == 0) 1718 errx(1, "timed out waiting for child"); 1719 else 1720 exit(0); 1721} 1722 1723/* 1724 * Add `s' to the list of allowable peer addresses to accept messages 1725 * from. 1726 * 1727 * `s' is a string in the form: 1728 * 1729 * [*]domainname[:{servicename|portnumber|*}] 1730 * 1731 * or 1732 * 1733 * netaddr/maskbits[:{servicename|portnumber|*}] 1734 * 1735 * Returns -1 on error, 0 if the argument was valid. 1736 */ 1737int 1738allowaddr(s) 1739 char *s; 1740{ 1741 char *cp1, *cp2; 1742 struct allowedpeer ap; 1743 struct servent *se; 1744 regex_t re; 1745 int i; 1746 1747 if ((cp1 = strrchr(s, ':'))) { 1748 /* service/port provided */ 1749 *cp1++ = '\0'; 1750 if (strlen(cp1) == 1 && *cp1 == '*') 1751 /* any port allowed */ 1752 ap.port = htons(0); 1753 else if ((se = getservbyname(cp1, "udp"))) 1754 ap.port = se->s_port; 1755 else { 1756 ap.port = htons((int)strtol(cp1, &cp2, 0)); 1757 if (*cp2 != '\0') 1758 return -1; /* port not numeric */ 1759 } 1760 } else { 1761 if ((se = getservbyname("syslog", "udp"))) 1762 ap.port = se->s_port; 1763 else 1764 /* sanity, should not happen */ 1765 ap.port = htons(514); 1766 } 1767 1768 /* the regexp's are ugly, but the cleanest way */ 1769 1770 if (regcomp(&re, "^[0-9]+\\.[0-9]+\\.[0-9]+\\.[0-9]+(/[0-9]+)?$", 1771 REG_EXTENDED)) 1772 /* if RE compilation fails, that's an internal error */ 1773 abort(); 1774 if (regexec(&re, s, 0, 0, 0) == 0) { 1775 /* arg `s' is numeric */ 1776 ap.isnumeric = 1; 1777 if ((cp1 = strchr(s, '/')) != NULL) { 1778 *cp1++ = '\0'; 1779 i = atoi(cp1); 1780 if (i < 0 || i > 32) 1781 return -1; 1782 /* convert masklen to netmask */ 1783 ap.a_mask.s_addr = htonl(~((1 << (32 - i)) - 1)); 1784 } 1785 if (ascii2addr(AF_INET, s, &ap.a_addr) == -1) 1786 return -1; 1787 if (cp1 == NULL) { 1788 /* use default netmask */ 1789 if (IN_CLASSA(ntohl(ap.a_addr.s_addr))) 1790 ap.a_mask.s_addr = htonl(IN_CLASSA_NET); 1791 else if (IN_CLASSB(ntohl(ap.a_addr.s_addr))) 1792 ap.a_mask.s_addr = htonl(IN_CLASSB_NET); 1793 else 1794 ap.a_mask.s_addr = htonl(IN_CLASSC_NET); 1795 } 1796 } else { 1797 /* arg `s' is domain name */ 1798 ap.isnumeric = 0; 1799 ap.a_name = s; 1800 } 1801 regfree(&re); 1802 1803 if (Debug) { 1804 printf("allowaddr: rule %d: ", NumAllowed); 1805 if (ap.isnumeric) { 1806 printf("numeric, "); 1807 printf("addr = %s, ", 1808 addr2ascii(AF_INET, &ap.a_addr, sizeof(struct in_addr), 0)); 1809 printf("mask = %s; ", 1810 addr2ascii(AF_INET, &ap.a_mask, sizeof(struct in_addr), 0)); 1811 } else 1812 printf("domainname = %s; ", ap.a_name); 1813 printf("port = %d\n", ntohs(ap.port)); 1814 } 1815 1816 if ((AllowedPeers = realloc(AllowedPeers, 1817 ++NumAllowed * sizeof(struct allowedpeer))) 1818 == NULL) { 1819 fprintf(stderr, "Out of memory!\n"); 1820 exit(EX_OSERR); 1821 } 1822 memcpy(&AllowedPeers[NumAllowed - 1], &ap, sizeof(struct allowedpeer)); 1823 return 0; 1824} 1825 1826/* 1827 * Validate that the remote peer has permission to log to us. 1828 */ 1829int 1830validate(sin, hname) 1831 struct sockaddr_in *sin; 1832 const char *hname; 1833{ 1834 int i; 1835 size_t l1, l2; 1836 char *cp, name[MAXHOSTNAMELEN]; 1837 struct allowedpeer *ap; 1838 1839 if (NumAllowed == 0) 1840 /* traditional behaviour, allow everything */ 1841 return 1; 1842 1843 strlcpy(name, hname, sizeof name); 1844 if (strchr(name, '.') == NULL) { 1845 strlcat(name, ".", sizeof name); 1846 strlcat(name, LocalDomain, sizeof name); 1847 } 1848 dprintf("validate: dgram from IP %s, port %d, name %s;\n", 1849 addr2ascii(AF_INET, &sin->sin_addr, sizeof(struct in_addr), 0), 1850 ntohs(sin->sin_port), name); 1851 1852 /* now, walk down the list */ 1853 for (i = 0, ap = AllowedPeers; i < NumAllowed; i++, ap++) { 1854 if (ntohs(ap->port) != 0 && ap->port != sin->sin_port) { 1855 dprintf("rejected in rule %d due to port mismatch.\n", i); 1856 continue; 1857 } 1858 1859 if (ap->isnumeric) { 1860 if ((sin->sin_addr.s_addr & ap->a_mask.s_addr) 1861 != ap->a_addr.s_addr) { 1862 dprintf("rejected in rule %d due to IP mismatch.\n", i); 1863 continue; 1864 } 1865 } else { 1866 cp = ap->a_name; 1867 l1 = strlen(name); 1868 if (*cp == '*') { 1869 /* allow wildmatch */ 1870 cp++; 1871 l2 = strlen(cp); 1872 if (l2 > l1 || memcmp(cp, &name[l1 - l2], l2) != 0) { 1873 dprintf("rejected in rule %d due to name mismatch.\n", i); 1874 continue; 1875 } 1876 } else { 1877 /* exact match */ 1878 l2 = strlen(cp); 1879 if (l2 != l1 || memcmp(cp, name, l1) != 0) { 1880 dprintf("rejected in rule %d due to name mismatch.\n", i); 1881 continue; 1882 } 1883 } 1884 } 1885 dprintf("accepted in rule %d.\n", i); 1886 return 1; /* hooray! */ 1887 } 1888 return 0; 1889} 1890 1891/* 1892 * Fairly similar to popen(3), but returns an open descriptor, as 1893 * opposed to a FILE *. 1894 */ 1895int 1896p_open(prog, pid) 1897 char *prog; 1898 pid_t *pid; 1899{ 1900 int pfd[2], nulldesc, i; 1901 sigset_t omask, mask; 1902 char *argv[4]; /* sh -c cmd NULL */ 1903 char errmsg[200]; 1904 1905 if (pipe(pfd) == -1) 1906 return -1; 1907 if ((nulldesc = open(_PATH_DEVNULL, O_RDWR)) == -1) 1908 /* we are royally screwed anyway */ 1909 return -1; 1910 1911 sigemptyset(&mask); 1912 sigaddset(&mask, SIGALRM); 1913 sigaddset(&mask, SIGHUP); 1914 sigprocmask(SIG_BLOCK, &mask, &omask); 1915 switch ((*pid = fork())) { 1916 case -1: 1917 sigprocmask(SIG_SETMASK, &omask, 0); 1918 close(nulldesc); 1919 return -1; 1920 1921 case 0: 1922 argv[0] = "sh"; 1923 argv[1] = "-c"; 1924 argv[2] = prog; 1925 argv[3] = NULL; 1926 1927 alarm(0); 1928 (void)setsid(); /* Avoid catching SIGHUPs. */ 1929 1930 /* 1931 * Throw away pending signals, and reset signal 1932 * behaviour to standard values. 1933 */ 1934 signal(SIGALRM, SIG_IGN); 1935 signal(SIGHUP, SIG_IGN); 1936 sigprocmask(SIG_SETMASK, &omask, 0); 1937 signal(SIGPIPE, SIG_DFL); 1938 signal(SIGQUIT, SIG_DFL); 1939 signal(SIGALRM, SIG_DFL); 1940 signal(SIGHUP, SIG_DFL); 1941 1942 dup2(pfd[0], STDIN_FILENO); 1943 dup2(nulldesc, STDOUT_FILENO); 1944 dup2(nulldesc, STDERR_FILENO); 1945 for (i = getdtablesize(); i > 2; i--) 1946 (void) close(i); 1947 1948 (void) execvp(_PATH_BSHELL, argv); 1949 _exit(255); 1950 } 1951 1952 sigprocmask(SIG_SETMASK, &omask, 0); 1953 close(nulldesc); 1954 close(pfd[0]); 1955 /* 1956 * Avoid blocking on a hung pipe. With O_NONBLOCK, we are 1957 * supposed to get an EWOULDBLOCK on writev(2), which is 1958 * caught by the logic above anyway, which will in turn close 1959 * the pipe, and fork a new logging subprocess if necessary. 1960 * The stale subprocess will be killed some time later unless 1961 * it terminated itself due to closing its input pipe (so we 1962 * get rid of really dead puppies). 1963 */ 1964 if (fcntl(pfd[1], F_SETFL, O_NONBLOCK) == -1) { 1965 /* This is bad. */ 1966 (void)snprintf(errmsg, sizeof errmsg, 1967 "Warning: cannot change pipe to PID %d to " 1968 "non-blocking behaviour.", 1969 (int)*pid); 1970 logerror(errmsg); 1971 } 1972 return pfd[1]; 1973} 1974 1975void 1976deadq_enter(pid, name) 1977 pid_t pid; 1978 const char *name; 1979{ 1980 dq_t p; 1981 int status; 1982 1983 /* 1984 * Be paranoid, if we can't signal the process, don't enter it 1985 * into the dead queue (perhaps it's already dead). If possible, 1986 * we try to fetch and log the child's status. 1987 */ 1988 if (kill(pid, 0) != 0) { 1989 if (waitpid(pid, &status, WNOHANG) > 0) 1990 log_deadchild(pid, status, name); 1991 return; 1992 } 1993 1994 p = malloc(sizeof(struct deadq_entry)); 1995 if (p == 0) { 1996 errno = 0; 1997 logerror("panic: out of virtual memory!"); 1998 exit(1); 1999 } 2000 2001 p->dq_pid = pid; 2002 p->dq_timeout = DQ_TIMO_INIT; 2003 TAILQ_INSERT_TAIL(&deadq_head, p, dq_entries); 2004} 2005 2006int 2007deadq_remove(pid) 2008 pid_t pid; 2009{ 2010 dq_t q; 2011 2012 for (q = TAILQ_FIRST(&deadq_head); q != NULL; q = TAILQ_NEXT(q, dq_entries)) 2013 if (q->dq_pid == pid) { 2014 TAILQ_REMOVE(&deadq_head, q, dq_entries); 2015 free(q); 2016 return 1; 2017 } 2018 2019 return 0; 2020} 2021 2022void 2023log_deadchild(pid, status, name) 2024 pid_t pid; 2025 int status; 2026 const char *name; 2027{ 2028 int code; 2029 char buf[256]; 2030 const char *reason; 2031 2032 errno = 0; /* Keep strerror() stuff out of logerror messages. */ 2033 if (WIFSIGNALED(status)) { 2034 reason = "due to signal"; 2035 code = WTERMSIG(status); 2036 } else { 2037 reason = "with status"; 2038 code = WEXITSTATUS(status); 2039 if (code == 0) 2040 return; 2041 } 2042 (void)snprintf(buf, sizeof buf, 2043 "Logging subprocess %d (%s) exited %s %d.", 2044 pid, name, reason, code); 2045 logerror(buf); 2046} 2047