Home | History | Annotate | Download | only in syslogd
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  *	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
     28  *	All Rights Reserved
     29  */
     30 
     31 /*
     32  * University Copyright- Copyright (c) 1982, 1986, 1988
     33  * The Regents of the University of California
     34  * All Rights Reserved
     35  *
     36  * University Acknowledgment- Portions of this document are derived from
     37  * software developed by the University of California, Berkeley, and its
     38  * contributors.
     39  */
     40 
     41 /*
     42  *  syslogd -- log system messages
     43  *
     44  * This program implements a system log. It takes a series of lines.
     45  * Each line may have a priority, signified as "<n>" as
     46  * the first characters of the line.  If this is
     47  * not present, a default priority is used.
     48  *
     49  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
     50  * cause it to reconfigure.
     51  *
     52  * Defined Constants:
     53  *
     54  * MAXLINE -- the maximimum line length that can be handled.
     55  * DEFUPRI -- the default priority for user messages.
     56  * DEFSPRI -- the default priority for kernel messages.
     57  *
     58  */
     59 
     60 #include <unistd.h>
     61 #include <note.h>
     62 #include <errno.h>
     63 #include <sys/types.h>
     64 #include <stdio.h>
     65 #include <stdio_ext.h>
     66 #include <stdlib.h>
     67 #include <ctype.h>
     68 #include <signal.h>
     69 #include <string.h>
     70 #include <strings.h>
     71 #include <libscf.h>
     72 #include <netconfig.h>
     73 #include <netdir.h>
     74 #include <pwd.h>
     75 #include <sys/socket.h>
     76 #include <tiuser.h>
     77 #include <utmpx.h>
     78 #include <limits.h>
     79 #include <pthread.h>
     80 #include <fcntl.h>
     81 #include <stropts.h>
     82 #include <assert.h>
     83 #include <sys/statvfs.h>
     84 
     85 #include <sys/param.h>
     86 #include <sys/sysmacros.h>
     87 #include <sys/syslog.h>
     88 #include <sys/strlog.h>
     89 #include <sys/stat.h>
     90 #include <sys/time.h>
     91 #include <sys/utsname.h>
     92 #include <sys/poll.h>
     93 #include <sys/wait.h>
     94 #include <sys/resource.h>
     95 #include <sys/mman.h>
     96 #include <sys/note.h>
     97 #include <door.h>
     98 
     99 #include <wchar.h>
    100 #include <locale.h>
    101 #include <stdarg.h>
    102 
    103 #include "dataq.h"
    104 #include "conf.h"
    105 #include "syslogd.h"
    106 
    107 #define	DOORFILE		"/var/run/syslog_door"
    108 #define	RELATIVE_DOORFILE	"../var/run/syslog_door"
    109 #define	OLD_DOORFILE		"/etc/.syslog_door"
    110 
    111 #define	PIDFILE			"/var/run/syslog.pid"
    112 #define	RELATIVE_PIDFILE	"../var/run/syslog.pid"
    113 #define	OLD_PIDFILE		"/etc/syslog.pid"
    114 
    115 static char		*LogName = "/dev/log";
    116 static char		*ConfFile = "/etc/syslog.conf";
    117 static char		ctty[] = "/dev/console";
    118 static char		sysmsg[] = "/dev/sysmsg";
    119 static int		DoorFd = -1;
    120 static int		DoorCreated = 0;
    121 static int		PidfileCreated = 0;
    122 static char		*DoorFileName = DOORFILE;
    123 static char		*PidFileName = PIDFILE;
    124 
    125 /*
    126  * configuration file directives
    127  */
    128 
    129 static struct code	PriNames[] = {
    130 	"panic",	LOG_EMERG,
    131 	"emerg",	LOG_EMERG,
    132 	"alert",	LOG_ALERT,
    133 	"crit",		LOG_CRIT,
    134 	"err",		LOG_ERR,
    135 	"error",	LOG_ERR,
    136 	"warn",		LOG_WARNING,
    137 	"warning",	LOG_WARNING,
    138 	"notice",	LOG_NOTICE,
    139 	"info",		LOG_INFO,
    140 	"debug",	LOG_DEBUG,
    141 	"none",		NOPRI,
    142 	NULL,		-1
    143 };
    144 
    145 static struct code	FacNames[] = {
    146 	"kern",		LOG_KERN,
    147 	"user",		LOG_USER,
    148 	"mail",		LOG_MAIL,
    149 	"daemon",	LOG_DAEMON,
    150 	"auth",		LOG_AUTH,
    151 	"security",	LOG_AUTH,
    152 	"mark",		LOG_MARK,
    153 	"syslog",	LOG_SYSLOG,
    154 	"lpr",		LOG_LPR,
    155 	"news",		LOG_NEWS,
    156 	"uucp",		LOG_UUCP,
    157 	"audit",	LOG_AUDIT,
    158 	"cron",		LOG_CRON,
    159 	"local0",	LOG_LOCAL0,
    160 	"local1",	LOG_LOCAL1,
    161 	"local2",	LOG_LOCAL2,
    162 	"local3",	LOG_LOCAL3,
    163 	"local4",	LOG_LOCAL4,
    164 	"local5",	LOG_LOCAL5,
    165 	"local6",	LOG_LOCAL6,
    166 	"local7",	LOG_LOCAL7,
    167 	NULL,		-1
    168 };
    169 
    170 static char		*TypeNames[7] = {
    171 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
    172 	"FORW",		"USERS",	"WALL"
    173 };
    174 
    175 /*
    176  * we allocate our own thread stacks so we can create them
    177  * without the MAP_NORESERVE option. We need to be sure
    178  * we have stack space even if the machine runs out of swap
    179  */
    180 
    181 #define	DEFAULT_STACKSIZE (100 * 1024)  /* 100 k stack */
    182 #define	DEFAULT_REDZONESIZE (8 * 1024)	/* 8k redzone */
    183 
    184 static pthread_mutex_t wmp = PTHREAD_MUTEX_INITIALIZER;	/* wallmsg lock */
    185 
    186 static pthread_mutex_t cft = PTHREAD_MUTEX_INITIALIZER;
    187 static int conf_threads = 0;
    188 
    189 static pthread_mutex_t hup_lock = PTHREAD_MUTEX_INITIALIZER;
    190 static pthread_cond_t hup_done = PTHREAD_COND_INITIALIZER;
    191 
    192 static pthread_mutex_t logerror_lock = PTHREAD_MUTEX_INITIALIZER;
    193 
    194 #define	HUP_ACCEPTABLE		0x0000	/* can start SIGHUP process */
    195 #define	HUP_INPROGRESS		0x0001	/* SIGHUP process in progress */
    196 #define	HUP_COMPLETED		0x0002	/* SIGHUP process completed */
    197 #define	HUP_SUSP_LOGMSG_REQD	0x1000	/* request to suspend */
    198 #define	HUP_LOGMSG_SUSPENDED	0x2000	/* logmsg is suspended */
    199 static int hup_state = HUP_ACCEPTABLE;
    200 
    201 static size_t stacksize;		/* thread stack size */
    202 static size_t redzonesize;		/* thread stack redzone size */
    203 static char *stack_ptr;			/* ptr to allocated stacks */
    204 static char *cstack_ptr;		/* ptr to conf_thr stacks */
    205 
    206 static time_t start_time;
    207 
    208 static pthread_t sys_thread;		/* queues messages from us */
    209 static pthread_t net_thread;		/* queues messages from the net */
    210 static pthread_t log_thread;		/* message processing thread */
    211 static pthread_t hnl_thread;		/* hostname lookup thread */
    212 
    213 static dataq_t inputq;			/* the input queue */
    214 static dataq_t tmpq;			/* temporary queue for err msg */
    215 static dataq_t hnlq;			/* hostname lookup queue */
    216 
    217 static struct filed fallback[2];
    218 static struct filed *Files;
    219 static int nlogs;
    220 static int Debug;			/* debug flag */
    221 static host_list_t LocalHostName;	/* our hostname */
    222 static host_list_t NullHostName;	/* in case of lookup failure */
    223 static int debuglev = 1;		/* debug print level */
    224 static int interrorlog;			/* internal error logging */
    225 
    226 static int MarkInterval = 20;		/* interval between marks (mins) */
    227 static int Marking = 0;			/* non-zero if marking some file */
    228 static int Ninputs = 0;			/* number of network inputs */
    229 static int curalarm = 0;		/* current timeout value (secs) */
    230 static int sys_msg_count = 0;		/* total msgs rcvd from local log */
    231 static int sys_init_msg_count = 0;	/* initially received */
    232 static int net_msg_count = 0;		/* total msgs rcvd from net */
    233 
    234 static struct pollfd Pfd;		/* Pollfd for local the log device */
    235 static struct pollfd *Nfd;		/* Array of pollfds for udp ports */
    236 static struct netconfig *Ncf;
    237 static struct netbuf **Myaddrs;
    238 static struct t_unitdata **Udp;
    239 static struct t_uderr **Errp;
    240 static int turnoff = 0;
    241 static int shutting_down;
    242 
    243 /* for managing door server threads */
    244 static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
    245 static uint_t door_server_cnt = 0;
    246 static pthread_attr_t door_thr_attr;
    247 
    248 static struct hostname_cache **hnc_cache;
    249 static pthread_mutex_t hnc_mutex = PTHREAD_MUTEX_INITIALIZER;
    250 static size_t hnc_size = DEF_HNC_SIZE;
    251 static unsigned int hnc_ttl = DEF_HNC_TTL;
    252 
    253 #define	DPRINT0(d, m)		if ((Debug) && debuglev >= (d)) \
    254 				(void) fprintf(stderr, m)
    255 #define	DPRINT1(d, m, a)	if ((Debug) && debuglev >= (d)) \
    256 				(void) fprintf(stderr, m, a)
    257 #define	DPRINT2(d, m, a, b)	if ((Debug) && debuglev >= (d)) \
    258 				(void) fprintf(stderr, m, a, b)
    259 #define	DPRINT3(d, m, a, b, c)	if ((Debug) && debuglev >= (d)) \
    260 				(void) fprintf(stderr, m, a, b, c)
    261 #define	DPRINT4(d, m, a, b, c, e)	if ((Debug) && debuglev >= (d)) \
    262 				(void) fprintf(stderr, m, a, b, c, e)
    263 #define	MALLOC_FAIL(x)	\
    264 		logerror("malloc failed: " x)
    265 #define	MALLOC_FAIL_EXIT	\
    266 		logerror("malloc failed - fatal"); \
    267 		exit(1)
    268 
    269 
    270 #define	MAILCMD "mailx -s \"syslogd shut down\" root"
    271 
    272 /*
    273  * Number of seconds to wait before giving up on threads that won't
    274  * shutdown: (that's right, 10 minutes!)
    275  */
    276 #define	LOOP_MAX	(10 * 60)
    277 
    278 /*
    279  * Interval(sec) to check the status of output queue while processing
    280  * HUP signal.
    281  */
    282 #define	LOOP_INTERVAL	(15)
    283 
    284 int
    285 main(int argc, char **argv)
    286 {
    287 	int i;
    288 	char *pstr;
    289 	int sig, fd;
    290 	int tflag = 0, Tflag = 0;
    291 	sigset_t sigs, allsigs;
    292 	struct rlimit rlim;
    293 	char *debugstr;
    294 	int mcount = 0;
    295 	struct sigaction act;
    296 	pthread_t mythreadno = 0;
    297 	char cbuf [30];
    298 	struct stat sb;
    299 
    300 #ifdef DEBUG
    301 #define	DEBUGDIR "/var/tmp"
    302 	if (chdir(DEBUGDIR))
    303 		DPRINT2(1, "main(%u): Unable to cd to %s\n", mythreadno,
    304 		    DEBUGDIR);
    305 #endif /* DEBUG */
    306 
    307 	(void) setlocale(LC_ALL, "");
    308 
    309 	if ((debugstr = getenv("SYSLOGD_DEBUG")) != NULL)
    310 		if ((debuglev = atoi(debugstr)) == 0)
    311 			debuglev = 1;
    312 
    313 #if ! defined(TEXT_DOMAIN)	/* should be defined by cc -D */
    314 #define	TEXT_DOMAIN "SYS_TEST"
    315 #endif
    316 	(void) textdomain(TEXT_DOMAIN);
    317 
    318 	(void) time(&start_time);
    319 
    320 	if (lstat("/var/run", &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
    321 		DoorFileName = OLD_DOORFILE;
    322 		PidFileName  = OLD_PIDFILE;
    323 	}
    324 
    325 	properties();
    326 
    327 	while ((i = getopt(argc, argv, "df:p:m:tT")) != EOF) {
    328 		switch (i) {
    329 		case 'f':		/* configuration file */
    330 			ConfFile = optarg;
    331 			break;
    332 
    333 		case 'd':		/* debug */
    334 			Debug++;
    335 			break;
    336 
    337 		case 'p':		/* path */
    338 			LogName = optarg;
    339 			break;
    340 
    341 		case 'm':		/* mark interval */
    342 			for (pstr = optarg; *pstr; pstr++) {
    343 				if (! (isdigit(*pstr))) {
    344 					(void) fprintf(stderr,
    345 					    "Illegal interval\n");
    346 					usage();
    347 				}
    348 			}
    349 			MarkInterval = atoi(optarg);
    350 			if (MarkInterval < 1 || MarkInterval > INT_MAX) {
    351 				(void) fprintf(stderr,
    352 				    "Interval must be between 1 and %d\n",
    353 				    INT_MAX);
    354 				usage();
    355 			}
    356 			break;
    357 		case 't':		/* turn off remote reception */
    358 			tflag++;
    359 			turnoff++;
    360 			break;
    361 		case 'T':		/* turn on remote reception */
    362 			Tflag++;
    363 			turnoff = 0;
    364 			break;
    365 		default:
    366 			usage();
    367 		}
    368 	}
    369 
    370 	if (optind < argc)
    371 		usage();
    372 
    373 	if (tflag && Tflag) {
    374 		(void) fprintf(stderr, "specify only one of -t and -T\n");
    375 		usage();
    376 	}
    377 
    378 	/*
    379 	 * close all fd's except 0-2
    380 	 */
    381 
    382 	closefrom(3);
    383 
    384 	if (!Debug) {
    385 		if (fork())
    386 			return (0);
    387 		(void) close(0);
    388 		(void) open("/", 0);
    389 		(void) dup2(0, 1);
    390 		(void) dup2(0, 2);
    391 		untty();
    392 	}
    393 
    394 	if (Debug) {
    395 		mythreadno = pthread_self();
    396 	}
    397 
    398 	/*
    399 	 * DO NOT call logerror() until tmpq is initialized.
    400 	 */
    401 	disable_errorlog();
    402 
    403 	/*
    404 	 * ensure that file descriptor limit is "high enough"
    405 	 */
    406 	(void) getrlimit(RLIMIT_NOFILE, &rlim);
    407 	if (rlim.rlim_cur < rlim.rlim_max)
    408 		rlim.rlim_cur = rlim.rlim_max;
    409 	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
    410 		logerror("Unable to increase file descriptor limit.");
    411 	(void) enable_extended_FILE_stdio(-1, -1);
    412 
    413 	/* block all signals from all threads initially */
    414 	(void) sigfillset(&allsigs);
    415 	(void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL);
    416 
    417 	DPRINT2(1, "main(%u): Started at time %s", mythreadno,
    418 	    ctime_r(&start_time, cbuf));
    419 
    420 	init();			/* read configuration, start threads */
    421 
    422 	DPRINT1(1, "main(%u): off & running....\n", mythreadno);
    423 
    424 	/* now set up to catch signals we care about */
    425 
    426 	(void) sigemptyset(&sigs);
    427 	(void) sigaddset(&sigs, SIGHUP);	/* reconfigure */
    428 	(void) sigaddset(&sigs, SIGALRM);	/* mark & flush timer */
    429 	(void) sigaddset(&sigs, SIGTERM);	/* exit */
    430 	(void) sigaddset(&sigs, SIGINT);	/* exit if debugging */
    431 	(void) sigaddset(&sigs, SIGQUIT);	/* exit if debugging */
    432 	(void) sigaddset(&sigs, SIGPIPE);	/* catch & discard */
    433 	(void) sigaddset(&sigs, SIGUSR1);	/* dump debug stats */
    434 
    435 	/*
    436 	 * We must set up to catch these signals, even though sigwait
    437 	 * will get them before the isr does.  Setting SA_SIGINFO ensures
    438 	 * that signals will be enqueued.
    439 	 */
    440 
    441 	act.sa_flags = SA_SIGINFO;
    442 	act.sa_sigaction = signull;
    443 
    444 	(void) sigaction(SIGHUP, &act, NULL);
    445 	(void) sigaction(SIGALRM, &act, NULL);
    446 	(void) sigaction(SIGTERM, &act, NULL);
    447 	(void) sigaction(SIGINT, &act, NULL);
    448 	(void) sigaction(SIGQUIT, &act, NULL);
    449 	(void) sigaction(SIGPIPE, &act, NULL);
    450 	(void) sigaction(SIGUSR1, &act, NULL);
    451 
    452 	/* we now turn into the signal handling thread */
    453 
    454 	DPRINT1(2, "main(%u): now handling signals\n", mythreadno);
    455 	for (;;) {
    456 		(void) sigwait(&sigs, &sig);
    457 		DPRINT2(2, "main(%u): received signal %d\n", mythreadno, sig);
    458 		switch (sig) {
    459 		case SIGALRM:
    460 			DPRINT1(1, "main(%u): Got SIGALRM\n",
    461 			    mythreadno);
    462 			flushmsg(NOCOPY);
    463 			if (Marking && (++mcount % MARKCOUNT == 0)) {
    464 				if (logmymsg(LOG_INFO, "-- MARK --",
    465 				    ADDDATE|MARK|NOCOPY, 0) == -1) {
    466 					MALLOC_FAIL(
    467 					    "dropping MARK message");
    468 				}
    469 
    470 				mcount = 0;
    471 			}
    472 			curalarm = MarkInterval * 60 / MARKCOUNT;
    473 			(void) alarm((unsigned)curalarm);
    474 			DPRINT2(2, "main(%u): Next alarm in %d "
    475 			    "seconds\n", mythreadno, curalarm);
    476 			break;
    477 		case SIGHUP:
    478 			DPRINT1(1, "main(%u): got SIGHUP - "
    479 			    "reconfiguring\n", mythreadno);
    480 
    481 			reconfigure();
    482 
    483 			DPRINT1(1, "main(%u): done processing SIGHUP\n",
    484 			    mythreadno);
    485 			break;
    486 		case SIGQUIT:
    487 		case SIGINT:
    488 			if (!Debug) {
    489 				/* allow these signals if debugging */
    490 				break;
    491 			}
    492 			/* FALLTHROUGH */
    493 		case SIGTERM:
    494 			DPRINT2(1, "main(%u): going down on signal %d\n",
    495 			    mythreadno, sig);
    496 			(void) alarm(0);
    497 			flushmsg(0);
    498 			errno = 0;
    499 			t_errno = 0;
    500 			logerror("going down on signal %d", sig);
    501 			disable_errorlog();	/* force msg to console */
    502 			(void) shutdown_msg();	/* stop threads */
    503 			shutdown_input();
    504 			close_door();
    505 			delete_doorfiles();
    506 			return (0);
    507 			break;
    508 		case SIGUSR1:			/* secret debug dump mode */
    509 			/* if in debug mode, use stdout */
    510 
    511 			if (Debug) {
    512 				dumpstats(STDOUT_FILENO);
    513 				break;
    514 			}
    515 			/* otherwise dump to a debug file */
    516 			if ((fd = open(DEBUGFILE,
    517 			    (O_WRONLY|O_CREAT|O_TRUNC|O_EXCL),
    518 			    0644)) < 0)
    519 				break;
    520 			dumpstats(fd);
    521 			(void) close(fd);
    522 			break;
    523 		default:
    524 			DPRINT2(2, "main(%u): unexpected signal %d\n",
    525 			    mythreadno, sig);
    526 			break;
    527 		}
    528 	}
    529 }
    530 
    531 /*
    532  * Attempts to open the local log device
    533  * and return a file descriptor.
    534  */
    535 static int
    536 openklog(char *name, int mode)
    537 {
    538 	int fd;
    539 	struct strioctl str;
    540 	pthread_t mythreadno;
    541 
    542 	if (Debug) {
    543 		mythreadno = pthread_self();
    544 	}
    545 
    546 	if ((fd = open(name, mode)) < 0) {
    547 		logerror("cannot open %s", name);
    548 		DPRINT3(1, "openklog(%u): cannot create %s (%d)\n",
    549 		    mythreadno, name, errno);
    550 		return (-1);
    551 	}
    552 	str.ic_cmd = I_CONSLOG;
    553 	str.ic_timout = 0;
    554 	str.ic_len = 0;
    555 	str.ic_dp = NULL;
    556 	if (ioctl(fd, I_STR, &str) < 0) {
    557 		logerror("cannot register to log console messages");
    558 		DPRINT2(1, "openklog(%u): cannot register to log "
    559 		    "console messages (%d)\n", mythreadno, errno);
    560 		return (-1);
    561 	}
    562 	return (fd);
    563 }
    564 
    565 
    566 /*
    567  * Open the log device, and pull up all pending messages.
    568  */
    569 static void
    570 prepare_sys_poll()
    571 {
    572 	int nfds, funix;
    573 
    574 	if ((funix = openklog(LogName, O_RDONLY)) < 0) {
    575 		logerror("can't open kernel log device - fatal");
    576 		exit(1);
    577 	}
    578 
    579 	Pfd.fd = funix;
    580 	Pfd.events = POLLIN;
    581 
    582 	for (;;) {
    583 		nfds = poll(&Pfd, 1, 0);
    584 		if (nfds <= 0) {
    585 			if (sys_init_msg_count > 0)
    586 				flushmsg(SYNC_FILE);
    587 			break;
    588 		}
    589 
    590 		if (Pfd.revents & POLLIN) {
    591 			getkmsg(0);
    592 		} else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
    593 			logerror("kernel log driver poll error");
    594 			break;
    595 		}
    596 	}
    597 
    598 }
    599 
    600 /*
    601  * this thread listens to the local stream log driver for log messages
    602  * generated by this host, formats them, and queues them to the logger
    603  * thread.
    604  */
    605 /*ARGSUSED*/
    606 static void *
    607 sys_poll(void *ap)
    608 {
    609 	int nfds;
    610 	static int klogerrs = 0;
    611 	pthread_t mythreadno;
    612 
    613 	if (Debug) {
    614 		mythreadno = pthread_self();
    615 	}
    616 
    617 	DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno);
    618 
    619 	/*
    620 	 * Try to process as many messages as we can without blocking on poll.
    621 	 * We count such "initial" messages with sys_init_msg_count and
    622 	 * enqueue them without the SYNC_FILE flag.  When no more data is
    623 	 * waiting on the local log device, we set timeout to INFTIM,
    624 	 * clear sys_init_msg_count, and generate a flush message to sync
    625 	 * the previously counted initial messages out to disk.
    626 	 */
    627 
    628 	sys_init_msg_count = 0;
    629 
    630 	for (;;) {
    631 		errno = 0;
    632 		t_errno = 0;
    633 
    634 		nfds = poll(&Pfd, 1, INFTIM);
    635 
    636 		if (nfds == 0)
    637 			continue;
    638 
    639 		if (nfds < 0) {
    640 			if (errno != EINTR)
    641 				logerror("poll");
    642 			continue;
    643 		}
    644 		if (Pfd.revents & POLLIN) {
    645 			getkmsg(INFTIM);
    646 		} else {
    647 			if (shutting_down) {
    648 				pthread_exit(0);
    649 			}
    650 			if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
    651 				logerror("kernel log driver poll error");
    652 				(void) close(Pfd.fd);
    653 				Pfd.fd = -1;
    654 			}
    655 		}
    656 
    657 		while (Pfd.fd == -1 && klogerrs++ < 10) {
    658 			Pfd.fd = openklog(LogName, O_RDONLY);
    659 		}
    660 		if (klogerrs >= 10) {
    661 			logerror("can't reopen kernel log device - fatal");
    662 			exit(1);
    663 		}
    664 	}
    665 	/*NOTREACHED*/
    666 	return (NULL);
    667 }
    668 
    669 /*
    670  * Pull up one message from log driver.
    671  */
    672 static void
    673 getkmsg(int timeout)
    674 {
    675 	int flags = 0, i;
    676 	char *lastline;
    677 	struct strbuf ctl, dat;
    678 	struct log_ctl hdr;
    679 	char buf[MAXLINE+1];
    680 	size_t buflen;
    681 	size_t len;
    682 	char tmpbuf[MAXLINE+1];
    683 	pthread_t mythreadno;
    684 
    685 	if (Debug) {
    686 		mythreadno = pthread_self();
    687 	}
    688 
    689 	dat.maxlen = MAXLINE;
    690 	dat.buf = buf;
    691 	ctl.maxlen = sizeof (struct log_ctl);
    692 	ctl.buf = (caddr_t)&hdr;
    693 
    694 	while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
    695 		lastline = &dat.buf[dat.len];
    696 		*lastline = '\0';
    697 
    698 		DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n",
    699 		    mythreadno, dat.len);
    700 		buflen = strlen(buf);
    701 		len = findnl_bkwd(buf, buflen);
    702 
    703 		(void) memcpy(tmpbuf, buf, len);
    704 		tmpbuf[len] = '\0';
    705 
    706 		/*
    707 		 * Format sys will enqueue the log message.
    708 		 * Set the sync flag if timeout != 0, which
    709 		 * means that we're done handling all the
    710 		 * initial messages ready during startup.
    711 		 */
    712 		if (timeout == 0) {
    713 			formatsys(&hdr, tmpbuf, 0);
    714 			sys_init_msg_count++;
    715 		} else {
    716 			formatsys(&hdr, tmpbuf, 1);
    717 		}
    718 		sys_msg_count++;
    719 
    720 		if (len != buflen) {
    721 			/* If anything remains in buf */
    722 			size_t remlen;
    723 
    724 			if (buf[len] == '\n') {
    725 				/* skip newline */
    726 				len++;
    727 			}
    728 
    729 			/*
    730 			 *  Move the remaining bytes to
    731 			 * the beginnning of buf.
    732 			 */
    733 
    734 			remlen = buflen - len;
    735 			(void) memcpy(buf, &buf[len], remlen);
    736 			dat.maxlen = MAXLINE - remlen;
    737 			dat.buf = &buf[remlen];
    738 		} else {
    739 			dat.maxlen = MAXLINE;
    740 			dat.buf = buf;
    741 		}
    742 	}
    743 
    744 	if (i == 0 && dat.len > 0) {
    745 		dat.buf[dat.len] = '\0';
    746 		/*
    747 		 * Format sys will enqueue the log message.
    748 		 * Set the sync flag if timeout != 0, which
    749 		 * means that we're done handling all the
    750 		 * initial messages ready during startup.
    751 		 */
    752 		DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n",
    753 		    mythreadno, dat.maxlen);
    754 		DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n",
    755 		    mythreadno, dat.len);
    756 		DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n",
    757 		    mythreadno, strlen(dat.buf));
    758 		DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n",
    759 		    mythreadno, dat.buf);
    760 		DPRINT2(5, "getkmsg(%u): buf len = %d\n",
    761 		    mythreadno, strlen(buf));
    762 		if (timeout == 0) {
    763 			formatsys(&hdr, buf, 0);
    764 			sys_init_msg_count++;
    765 		} else {
    766 			formatsys(&hdr, buf, 1);
    767 		}
    768 		sys_msg_count++;
    769 	} else if (i < 0 && errno != EINTR) {
    770 		if (!shutting_down) {
    771 			logerror("kernel log driver read error");
    772 		}
    773 		(void) close(Pfd.fd);
    774 		Pfd.fd = -1;
    775 	}
    776 }
    777 
    778 /*
    779  * this thread polls all the network interfaces for syslog messages
    780  * forwarded to us, tags them with the hostname they are received
    781  * from, and queues them to the logger thread.
    782  */
    783 /*ARGSUSED*/
    784 static void *
    785 net_poll(void *ap)
    786 {
    787 	int nfds, i;
    788 	int flags = 0;
    789 	struct t_unitdata *udp;
    790 	struct t_uderr *errp;
    791 	char buf[MAXLINE+1];
    792 	char *uap;
    793 	log_message_t *mp;
    794 	host_info_t *hinfo;
    795 	pthread_t mythreadno;
    796 
    797 	if (Debug) {
    798 		mythreadno = pthread_self();
    799 	}
    800 
    801 	DPRINT1(1, "net_poll(%u): net_thread started\n", mythreadno);
    802 
    803 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
    804 
    805 	for (;;) {
    806 		errno = 0;
    807 		t_errno = 0;
    808 		nfds = poll(Nfd, Ninputs, -1);
    809 		if (nfds == 0)
    810 			continue;
    811 
    812 		if (nfds < 0) {
    813 			if (errno != EINTR)
    814 				logerror("poll");
    815 			continue;
    816 		}
    817 		for (i = 0; nfds > 0 && i < Ninputs; i++) {
    818 			if ((Nfd[i].revents & POLLIN) == 0) {
    819 				if (shutting_down) {
    820 					pthread_exit(0);
    821 				}
    822 				if (Nfd[i].revents &
    823 				    (POLLNVAL|POLLHUP|POLLERR)) {
    824 					logerror("POLLNVAL|POLLHUP|POLLERR");
    825 					(void) t_close(Nfd[i].fd);
    826 					Nfd[i].fd = -1;
    827 					nfds--;
    828 				}
    829 				continue;
    830 			}
    831 
    832 			udp = Udp[i];
    833 			udp->udata.buf = buf;
    834 			udp->udata.maxlen = MAXLINE;
    835 			udp->udata.len = 0;
    836 			flags = 0;
    837 			if (t_rcvudata(Nfd[i].fd, udp, &flags) < 0) {
    838 				errp = Errp[i];
    839 				if (t_errno == TLOOK) {
    840 					if (t_rcvuderr(Nfd[i].fd, errp) < 0) {
    841 						if (!shutting_down) {
    842 							logerror("t_rcvuderr");
    843 						}
    844 						(void) t_close(Nfd[i].fd);
    845 						Nfd[i].fd = -1;
    846 					}
    847 				} else {
    848 					if (!shutting_down) {
    849 						logerror("t_rcvudata");
    850 					}
    851 					(void) t_close(Nfd[i].fd);
    852 					Nfd[i].fd = -1;
    853 				}
    854 				nfds--;
    855 				if (shutting_down) {
    856 					pthread_exit(0);
    857 				}
    858 				continue;
    859 			}
    860 			nfds--;
    861 
    862 			if (udp->udata.len == 0) {
    863 				if (Debug) {
    864 					uap = NULL;
    865 					if (udp->addr.len > 0) {
    866 						uap = taddr2uaddr(&Ncf[i],
    867 						    &udp->addr);
    868 					}
    869 					DPRINT2(1, "net_poll(%u):"
    870 					    " received empty packet"
    871 					    " from %s\n", mythreadno,
    872 					    uap ? uap : "<unknown>");
    873 					if (uap)
    874 						free(uap);
    875 				}
    876 				continue;	/* No data */
    877 			}
    878 			if (udp->addr.len == 0) {
    879 				/*
    880 				 * The previous message was larger than
    881 				 * MAXLINE, and T_MORE should have been set.
    882 				 * Further data needs to be discarded as
    883 				 * we've already received MAXLINE.
    884 				 */
    885 				DPRINT1(1, "net_poll(%u): discarding packet "
    886 				    "exceeds max line size\n", mythreadno);
    887 				continue;
    888 			}
    889 
    890 			net_msg_count++;
    891 
    892 			if ((mp = new_msg()) == NULL) {
    893 				MALLOC_FAIL("dropping message from "
    894 				    "remote");
    895 				continue;
    896 			}
    897 
    898 			buf[udp->udata.len] = '\0';
    899 			formatnet(&udp->udata, mp);
    900 
    901 			if (Debug) {
    902 				uap = taddr2uaddr(&Ncf[i], &udp->addr);
    903 				DPRINT2(1, "net_poll(%u): received message"
    904 				    " from %s\n", mythreadno,
    905 				    uap ? uap : "<unknown>");
    906 				free(uap);
    907 			}
    908 			if ((hinfo = malloc(sizeof (*hinfo))) == NULL ||
    909 			    (hinfo->addr.buf =
    910 			    malloc(udp->addr.len)) == NULL) {
    911 				MALLOC_FAIL("dropping message from "
    912 				    "remote");
    913 				if (hinfo) {
    914 					free(hinfo);
    915 				}
    916 				free_msg(mp);
    917 				continue;
    918 			}
    919 
    920 			hinfo->ncp = &Ncf[i];
    921 			hinfo->addr.len = udp->addr.len;
    922 			(void) memcpy(hinfo->addr.buf, udp->addr.buf,
    923 			    udp->addr.len);
    924 			mp->ptr = hinfo;
    925 			if (dataq_enqueue(&hnlq, (void *)mp) == -1) {
    926 				MALLOC_FAIL("dropping message from "
    927 				    "remote");
    928 				free_msg(mp);
    929 				free(hinfo->addr.buf);
    930 				free(hinfo);
    931 				continue;
    932 			}
    933 			DPRINT3(5, "net_poll(%u): enqueued msg %p "
    934 			    "on queue %p\n", mythreadno, (void *)mp,
    935 			    (void *)&hnlq);
    936 		}
    937 	}
    938 	/*NOTREACHED*/
    939 	return (NULL);
    940 }
    941 
    942 static void
    943 usage(void)
    944 {
    945 	(void) fprintf(stderr,
    946 	    "usage: syslogd [-d] [-t|-T] [-mmarkinterval] [-ppath]"
    947 	    " [-fconffile]\n");
    948 	exit(1);
    949 }
    950 
    951 static void
    952 untty(void)
    953 {
    954 	if (!Debug)
    955 		(void) setsid();
    956 }
    957 
    958 /*
    959  * generate a log message internally. The original version of syslogd
    960  * simply called logmsg directly, but because everything is now based
    961  * on message passing, we need an internal way to generate and queue
    962  * log messages from within syslogd itself.
    963  */
    964 static int
    965 logmymsg(int pri, char *msg, int flags, int pending)
    966 {
    967 	log_message_t *mp;
    968 	pthread_t mythreadno;
    969 	dataq_t *qptr;
    970 
    971 	if (Debug) {
    972 		mythreadno = pthread_self();
    973 	}
    974 
    975 	if ((mp = new_msg()) == NULL) {
    976 		return (-1);
    977 	}
    978 
    979 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
    980 	mp->pri = pri;
    981 	mp->hlp = &LocalHostName;
    982 	(void) strlcpy(mp->msg, msg, MAXLINE+1);
    983 	mp->flags = flags;
    984 	(void) time(&mp->ts);
    985 
    986 	qptr = pending ? &tmpq : &inputq;
    987 	if (dataq_enqueue(qptr, (void *)mp) == -1) {
    988 		free_msg(mp);
    989 		return (-1);
    990 	}
    991 
    992 	DPRINT3(5, "logmymsg(%u): enqueued msg %p on queue %p\n",
    993 	    mythreadno, (void *)mp, (void *)qptr);
    994 	DPRINT2(5, "logmymsg(%u): Message content: %s\n", mythreadno, msg);
    995 	return (0);
    996 }
    997 
    998 /*
    999  * Generate an internal shutdown message
   1000  */
   1001 static int
   1002 shutdown_msg(void)
   1003 {
   1004 	pthread_t mythreadno;
   1005 	log_message_t *mp;
   1006 
   1007 	if (Debug) {
   1008 		mythreadno = pthread_self();
   1009 	}
   1010 
   1011 	if ((mp = new_msg()) == NULL) {
   1012 		return (-1);
   1013 	}
   1014 
   1015 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
   1016 	mp->flags = SHUTDOWN;
   1017 	mp->hlp = &LocalHostName;
   1018 
   1019 	if (dataq_enqueue(&inputq, (void *)mp) == -1) {
   1020 		free_msg(mp);
   1021 		return (-1);
   1022 	}
   1023 
   1024 	DPRINT3(5, "shutdown_msg(%u): enqueued msg %p on queue %p\n",
   1025 	    mythreadno, (void *)mp, (void *)&inputq);
   1026 	return (0);
   1027 }
   1028 
   1029 /*
   1030  * Generate an internal flush message
   1031  */
   1032 static void
   1033 flushmsg(int flags)
   1034 {
   1035 	log_message_t *mp;
   1036 	pthread_t mythreadno;
   1037 
   1038 	if (Debug) {
   1039 		mythreadno = pthread_self();
   1040 	}
   1041 
   1042 	if ((mp = new_msg()) == NULL) {
   1043 		MALLOC_FAIL("dropping flush msg");
   1044 		return;
   1045 	}
   1046 
   1047 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
   1048 	mp->flags = FLUSHMSG | flags;
   1049 	mp->hlp = &LocalHostName;
   1050 
   1051 	if (dataq_enqueue(&inputq, (void *)mp) == -1) {
   1052 		free_msg(mp);
   1053 		MALLOC_FAIL("dropping flush msg");
   1054 		return;
   1055 	}
   1056 
   1057 	DPRINT4(5, "flush_msg(%u): enqueued msg %p on queue %p, flags "
   1058 	    "0x%x\n", mythreadno, (void *)mp, (void *)&inputq, flags);
   1059 }
   1060 
   1061 /*
   1062  * Do some processing on messages received from the net
   1063  */
   1064 static void
   1065 formatnet(struct netbuf *nbp, log_message_t *mp)
   1066 {
   1067 	char *p;
   1068 	int pri;
   1069 	pthread_t mythreadno;
   1070 
   1071 	if (Debug) {
   1072 		mythreadno = pthread_self();
   1073 	}
   1074 
   1075 	DPRINT2(5, "formatnet(%u): called for msg %p\n", mythreadno,
   1076 	    (void *)mp);
   1077 
   1078 	mp->flags = NETWORK;
   1079 	(void) time(&mp->ts);
   1080 
   1081 	/* test for special codes */
   1082 	pri = DEFUPRI;
   1083 	p = nbp->buf;
   1084 	DPRINT2(9, "formatnet(%u): Message content:\n>%s<\n", mythreadno,
   1085 	    p);
   1086 	if (*p == '<' && isdigit(*(p+1))) {
   1087 		pri = 0;
   1088 		while (isdigit(*++p))
   1089 			pri = 10 * pri + (*p - '0');
   1090 		if (*p == '>')
   1091 			++p;
   1092 		if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
   1093 			pri = DEFUPRI;
   1094 	}
   1095 
   1096 	mp->pri = pri;
   1097 	(void) strlcpy(mp->msg, p, MAXLINE+1);
   1098 }
   1099 
   1100 /*
   1101  * Do some processing on messages generated by this host
   1102  * and then enqueue the log message.
   1103  */
   1104 static void
   1105 formatsys(struct log_ctl *lp, char *msg, int sync)
   1106 {
   1107 	char *p, *q;
   1108 	char line[MAXLINE + 1];
   1109 	size_t msglen;
   1110 	log_message_t	*mp;
   1111 	char cbuf[30];
   1112 	pthread_t mythreadno;
   1113 
   1114 	if (Debug) {
   1115 		mythreadno = pthread_self();
   1116 	}
   1117 
   1118 	DPRINT3(3, "formatsys(%u): log_ctl.mid = %d, log_ctl.sid = %d\n",
   1119 	    mythreadno, lp->mid, lp->sid);
   1120 	DPRINT2(9, "formatsys(%u): Message Content:\n>%s<\n", mythreadno,
   1121 	    msg);
   1122 
   1123 	/* msglen includes the null termination */
   1124 	msglen = strlen(msg) + 1;
   1125 
   1126 	for (p = msg; *p != '\0'; ) {
   1127 		size_t linelen;
   1128 		size_t len;
   1129 
   1130 		/*
   1131 		 * Allocate a log_message_t structure.
   1132 		 * We should do it here since a single message (msg)
   1133 		 * could be composed of many lines.
   1134 		 */
   1135 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
   1136 
   1137 		if ((mp = new_msg()) == NULL) {
   1138 			MALLOC_FAIL("dropping message");
   1139 			/*
   1140 			 * Should bail out from the loop.
   1141 			 */
   1142 			break;
   1143 		}
   1144 
   1145 		mp->flags &= ~NETWORK;
   1146 		mp->hlp = &LocalHostName;
   1147 		mp->ts = lp->ttime;
   1148 		if (lp->flags & SL_LOGONLY)
   1149 			mp->flags |= IGN_CONS;
   1150 		if (lp->flags & SL_CONSONLY)
   1151 			mp->flags |= IGN_FILE;
   1152 
   1153 		/* extract facility */
   1154 		if ((lp->pri & LOG_FACMASK) == LOG_KERN) {
   1155 			(void) sprintf(line, "%.15s ",
   1156 			    ctime_r(&mp->ts, cbuf) + 4);
   1157 		} else {
   1158 			(void) sprintf(line, "");
   1159 		}
   1160 
   1161 		linelen = strlen(line);
   1162 		q = line + linelen;
   1163 
   1164 		DPRINT2(5, "formatsys(%u): msglen = %d\n", mythreadno, msglen);
   1165 		len = copynl_frwd(q, MAXLINE + 1 - linelen, p, msglen);
   1166 		DPRINT2(5, "formatsys(%u): len (copynl_frwd) = %d\n",
   1167 		    mythreadno, len);
   1168 
   1169 		p += len;
   1170 		msglen -= len;
   1171 
   1172 		if (*p == '\n') {
   1173 			/* skip newline */
   1174 			p++;
   1175 		}
   1176 
   1177 		if (sync && ((lp->pri & LOG_FACMASK) == LOG_KERN))
   1178 			mp->flags |= SYNC_FILE;	/* fsync file after write */
   1179 
   1180 		if (len != 0) {
   1181 			(void) strlcpy(mp->msg, line, MAXLINE+1);
   1182 			mp->pri = lp->pri;
   1183 
   1184 			if (dataq_enqueue(&inputq, (void *)mp) == -1) {
   1185 				free_msg(mp);
   1186 				MALLOC_FAIL("dropping message");
   1187 				break;
   1188 			}
   1189 
   1190 			DPRINT3(5, "formatsys(%u): sys_thread enqueued msg "
   1191 			    "%p on queue %p\n", mythreadno, (void *)mp,
   1192 			    (void *)&inputq);
   1193 		} else
   1194 			free_msg(mp);
   1195 	}
   1196 }
   1197 
   1198 /*
   1199  * Log a message to the appropriate log files, users, etc. based on
   1200  * the priority.
   1201  */
   1202 /*ARGSUSED*/
   1203 static void *
   1204 logmsg(void *ap)
   1205 {
   1206 	struct filed *f;
   1207 	int fac, prilev, flags, refcnt;
   1208 	int fake_shutdown, skip_shutdown;
   1209 	log_message_t *mp, *save_mp;
   1210 	pthread_t mythreadno;
   1211 
   1212 	if (Debug) {
   1213 		mythreadno = pthread_self();
   1214 	}
   1215 
   1216 	DPRINT1(1, "logmsg(%u): msg dispatcher started\n", mythreadno);
   1217 
   1218 	fake_shutdown = skip_shutdown = 0;
   1219 	save_mp = NULL;
   1220 	for (;;) {
   1221 		if (save_mp) {
   1222 			/*
   1223 			 * If we have set aside a message in order to fake a
   1224 			 * SHUTDOWN, use that message before picking from the
   1225 			 * queue again.
   1226 			 */
   1227 			mp = save_mp;
   1228 			save_mp = NULL;
   1229 		} else {
   1230 			(void) dataq_dequeue(&inputq, (void **)&mp, 0);
   1231 		}
   1232 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
   1233 		DPRINT3(5, "logmsg(%u): msg dispatcher dequeued %p from "
   1234 		    "queue %p\n", mythreadno, (void *)mp,
   1235 		    (void *)&inputq);
   1236 
   1237 		/*
   1238 		 * In most cases, if the message traffic is low, logmsg() wakes
   1239 		 * up when it receives the SHUTDOWN msg, and will sleep until
   1240 		 * HUP process is complete.  However, if the inputq is too
   1241 		 * long, logmsg() may not receive SHUTDOWN before reconfigure()
   1242 		 * releases the logger fds, filed and logit threads.  That, in
   1243 		 * turn, will cause logmsg to refer to invalid fileds.
   1244 		 *
   1245 		 * logmsg() needs to respond to the SHUTDOWN message within
   1246 		 * LOOP_INTERVAL seconds when reconfigure() enqueues it. It
   1247 		 * does so in most cases.  When it does not respond in time,
   1248 		 * logmsg() needs to be in suspended state immediately, since
   1249 		 * filed may have been invalidated. reconfigure() will set the
   1250 		 * HUP_SUSP_LOGMSG_REQD bit in hup_state and wait another
   1251 		 * LOOP_INTERVAL seconds before proceeding.
   1252 		 *
   1253 		 * When HUP_SUSP_LOGMSG_REQD is set, we will create a fake
   1254 		 * SHUTDOWN message, and dispatch it to the various logit
   1255 		 * threads, and logmsg() itself will suspend.  In order to
   1256 		 * ignore the real SHUTDOWN which will arrive later, we keep a
   1257 		 * counter (skip_shutdown) and decrement it when the SHUTDOWN
   1258 		 * message arrives.
   1259 		 */
   1260 		if ((hup_state & HUP_SUSP_LOGMSG_REQD) &&
   1261 		    (mp->flags & SHUTDOWN) == 0) {
   1262 			DPRINT1(3, "logmsg(%u): suspend request\n",
   1263 			    mythreadno);
   1264 
   1265 			save_mp = mp;
   1266 
   1267 			/* create a fake SHUTDOWN msg */
   1268 			if ((mp = new_msg()) == NULL) {
   1269 				MALLOC_FAIL("dropping message");
   1270 				if (mp->flags & SHUTDOWN) {
   1271 					(void) logerror_to_console(1,
   1272 					    "unable to shutdown "
   1273 					    "logger thread");
   1274 				}
   1275 				continue;
   1276 			}
   1277 			mp->flags = SHUTDOWN;
   1278 			mp->hlp = &LocalHostName;
   1279 			fake_shutdown = 1;
   1280 			skip_shutdown++;
   1281 			DPRINT2(3, "logmsg(%u): pending SHUTDOWN %d\n",
   1282 			    mythreadno, skip_shutdown);
   1283 		}
   1284 
   1285 		/*
   1286 		 * is it a shutdown or flush message ?
   1287 		 */
   1288 		if ((mp->flags & SHUTDOWN) || (mp->flags & FLUSHMSG)) {
   1289 			(void) pthread_mutex_lock(&mp->msg_mutex);
   1290 
   1291 			if ((mp->flags & SHUTDOWN) &&
   1292 			    !fake_shutdown && skip_shutdown > 0) {
   1293 				skip_shutdown--;
   1294 				(void) pthread_mutex_unlock(&mp->msg_mutex);
   1295 				free_msg(mp);
   1296 				DPRINT2(3, "logmsg(%u): released late "
   1297 				    "arrived SHUTDOWN. pending %d\n",
   1298 				    mythreadno, skip_shutdown);
   1299 				continue;
   1300 			}
   1301 
   1302 			for (f = Files; f < &Files[nlogs]; f++) {
   1303 				(void) pthread_mutex_lock(&f->filed_mutex);
   1304 
   1305 				if (f->f_type == F_UNUSED) {
   1306 					(void) pthread_mutex_unlock(
   1307 					    &f->filed_mutex);
   1308 					continue;
   1309 				}
   1310 
   1311 				f->f_queue_count++;
   1312 				mp->refcnt++;
   1313 
   1314 				if (dataq_enqueue(&f->f_queue,
   1315 				    (void *)mp) == -1) {
   1316 					f->f_queue_count--;
   1317 					mp->refcnt--;
   1318 					(void) pthread_mutex_unlock(
   1319 					    &f->filed_mutex);
   1320 					MALLOC_FAIL("dropping message");
   1321 
   1322 					if (mp->flags & SHUTDOWN) {
   1323 						(void) logerror_to_console(1,
   1324 						    "unable to shutdown "
   1325 						    "logger thread");
   1326 					}
   1327 
   1328 					continue;
   1329 				}
   1330 				DPRINT3(5, "logmsg(%u): enqueued msg %p "
   1331 				    "on queue %p\n", mythreadno,
   1332 				    (void *)mp, (void *)&f->f_queue);
   1333 				(void) pthread_mutex_unlock(&f->filed_mutex);
   1334 			}
   1335 
   1336 			/*
   1337 			 * flags value needs to be saved because mp may
   1338 			 * have been freed before SHUTDOWN test below.
   1339 			 */
   1340 			flags = mp->flags;
   1341 			refcnt = mp->refcnt;
   1342 
   1343 			(void) pthread_mutex_unlock(&mp->msg_mutex);
   1344 			if (refcnt == 0)
   1345 				free_msg(mp);
   1346 
   1347 			if (flags & SHUTDOWN) {
   1348 				(void) pthread_mutex_lock(&hup_lock);
   1349 				while (hup_state != HUP_COMPLETED) {
   1350 					hup_state |= HUP_LOGMSG_SUSPENDED;
   1351 					(void) pthread_cond_wait(&hup_done,
   1352 					    &hup_lock);
   1353 					hup_state &= ~HUP_LOGMSG_SUSPENDED;
   1354 				}
   1355 				hup_state = HUP_ACCEPTABLE;
   1356 				(void) pthread_mutex_unlock(&hup_lock);
   1357 				fake_shutdown = 0;
   1358 			}
   1359 			continue;
   1360 		}
   1361 
   1362 		/*
   1363 		 * Check to see if msg looks non-standard.
   1364 		 */
   1365 		if ((int)strlen(mp->msg) < 16 || mp->msg[3] != ' ' ||
   1366 		    mp->msg[6] != ' ' || mp->msg[9] != ':' ||
   1367 		    mp->msg[12] != ':' || mp->msg[15] != ' ')
   1368 			mp->flags |= ADDDATE;
   1369 
   1370 		/* extract facility and priority level */
   1371 		fac = (mp->pri & LOG_FACMASK) >> 3;
   1372 		if (mp->flags & MARK)
   1373 			fac = LOG_NFACILITIES;
   1374 		prilev = mp->pri & LOG_PRIMASK;
   1375 
   1376 		DPRINT3(3, "logmsg(%u): fac = %d, pri = %d\n",
   1377 		    mythreadno, fac, prilev);
   1378 
   1379 		/*
   1380 		 * Because different devices log at different speeds,
   1381 		 * it's important to hold the mutex for the current
   1382 		 * message until it's been enqueued to all log files,
   1383 		 * so the reference count is accurate before any
   1384 		 * of the log threads can decrement it.
   1385 		 */
   1386 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mp))
   1387 		_NOTE(COMPETING_THREADS_NOW)
   1388 		(void) pthread_mutex_lock(&mp->msg_mutex);
   1389 
   1390 		for (f = Files; f < &Files[nlogs]; f++) {
   1391 			/* skip messages that are incorrect priority */
   1392 			if (f->f_pmask[fac] < (unsigned)prilev ||
   1393 			    f->f_pmask[fac] == NOPRI)
   1394 				continue;
   1395 			if (f->f_queue_count > Q_HIGHWATER_MARK) {
   1396 				DPRINT4(5, "logmsg(%u): Dropping message "
   1397 				    "%p on file %p, count = %d\n",
   1398 				    mythreadno, (void *)mp, (void *)f,
   1399 				    f->f_queue_count);
   1400 				continue;
   1401 			}
   1402 
   1403 			/*
   1404 			 * Need to grab filed_mutex before testing the f_type.
   1405 			 * Otherwise logit() may set F_UNUSED after the test
   1406 			 * below, and start pulling out the pending messages.
   1407 			 */
   1408 
   1409 			(void) pthread_mutex_lock(&f->filed_mutex);
   1410 
   1411 			if (f->f_type == F_UNUSED ||
   1412 			    (f->f_type == F_FILE && (mp->flags & IGN_FILE)) ||
   1413 			    (f->f_type == F_CONSOLE &&
   1414 			    (mp->flags & IGN_CONS))) {
   1415 				(void) pthread_mutex_unlock(&f->filed_mutex);
   1416 				continue;
   1417 			}
   1418 
   1419 			f->f_queue_count++;
   1420 			mp->refcnt++;
   1421 
   1422 			if (dataq_enqueue(&f->f_queue, (void *)mp) == -1) {
   1423 				f->f_queue_count--;
   1424 				mp->refcnt--;
   1425 				(void) pthread_mutex_unlock(&f->filed_mutex);
   1426 				MALLOC_FAIL("dropping message");
   1427 				continue;
   1428 			}
   1429 
   1430 			DPRINT3(5, "logmsg(%u): enqueued msg %p on queue "
   1431 			    "%p\n", mythreadno, (void *)mp,
   1432 			    (void *)&f->f_queue);
   1433 			(void) pthread_mutex_unlock(&f->filed_mutex);
   1434 		}
   1435 		refcnt = mp->refcnt;
   1436 		(void) pthread_mutex_unlock(&mp->msg_mutex);
   1437 		if (refcnt == 0)
   1438 			free_msg(mp);
   1439 	}
   1440 	/*NOTREACHED*/
   1441 	return (NULL);
   1442 }
   1443 
   1444 /*
   1445  * function to actually write the log message to the selected file.
   1446  * each file has a logger thread that runs this routine. The function
   1447  * is called with a pointer to its file structure.
   1448  */
   1449 static void *
   1450 logit(void *ap)
   1451 {
   1452 	struct filed *f = ap;
   1453 	log_message_t *mp;
   1454 	int forwardingloop = 0;
   1455 	const char *errmsg = "logit(%u): %s to %s forwarding loop detected\n";
   1456 	int i, currofst, prevofst, refcnt;
   1457 	host_list_t *hlp;
   1458 
   1459 	assert(f != NULL);
   1460 
   1461 	DPRINT4(5, "logit(%u): logger started for \"%s\" (queue %p, filed "
   1462 	    "%p)\n", f->f_thread, f->f_un.f_fname, (void *)&f->f_queue,
   1463 	    (void *)f);
   1464 	_NOTE(COMPETING_THREADS_NOW);
   1465 
   1466 	while (f->f_type != F_UNUSED) {
   1467 		(void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
   1468 		DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
   1469 		    "%p\n", f->f_thread, (void *)mp, (void *)&f->f_queue);
   1470 		(void) pthread_mutex_lock(&f->filed_mutex);
   1471 		assert(f->f_queue_count > 0);
   1472 		f->f_queue_count--;
   1473 		(void) pthread_mutex_unlock(&f->filed_mutex);
   1474 		assert(mp->refcnt > 0);
   1475 
   1476 		/*
   1477 		 * is it a shutdown message ?
   1478 		 */
   1479 		if (mp->flags & SHUTDOWN) {
   1480 			(void) pthread_mutex_lock(&mp->msg_mutex);
   1481 			refcnt = --mp->refcnt;
   1482 			(void) pthread_mutex_unlock(&mp->msg_mutex);
   1483 			if (refcnt == 0)
   1484 				free_msg(mp);
   1485 			break;
   1486 		}
   1487 
   1488 		/*
   1489 		 * Is it a logsync message?
   1490 		 */
   1491 		if ((mp->flags & (FLUSHMSG | LOGSYNC)) ==
   1492 		    (FLUSHMSG | LOGSYNC)) {
   1493 			if (f->f_type != F_FILE)
   1494 				goto out;	/* nothing to do */
   1495 			(void) close(f->f_file);
   1496 			f->f_file = open64(f->f_un.f_fname,
   1497 			    O_WRONLY|O_APPEND|O_NOCTTY);
   1498 			if (f->f_file < 0) {
   1499 				f->f_type = F_UNUSED;
   1500 				logerror(f->f_un.f_fname);
   1501 				f->f_stat.errs++;
   1502 			}
   1503 			goto out;
   1504 		}
   1505 
   1506 		/*
   1507 		 * If the message flags include both flush and sync,
   1508 		 * then just sync the file out to disk if appropriate.
   1509 		 */
   1510 		if ((mp->flags & (FLUSHMSG | SYNC_FILE)) ==
   1511 		    (FLUSHMSG | SYNC_FILE)) {
   1512 			if (f->f_type == F_FILE) {
   1513 				DPRINT2(5, "logit(%u): got FLUSH|SYNC "
   1514 				    "for filed %p\n", f->f_thread,
   1515 				    (void *)f);
   1516 				(void) fsync(f->f_file);
   1517 			}
   1518 			goto out;
   1519 		}
   1520 
   1521 		/*
   1522 		 * Otherwise if it's a standard flush message, write
   1523 		 * out any saved messages to the file.
   1524 		 */
   1525 		if ((mp->flags & FLUSHMSG) && (f->f_prevcount > 0)) {
   1526 			set_flush_msg(f);
   1527 			writemsg(SAVED, f);
   1528 			goto out;
   1529 		}
   1530 
   1531 		(void) strlcpy(f->f_current.msg, mp->msg, MAXLINE+1);
   1532 		(void) strlcpy(f->f_current.host, mp->hlp->hl_hosts[0],
   1533 		    SYS_NMLN);
   1534 		f->f_current.pri = mp->pri;
   1535 		f->f_current.flags = mp->flags;
   1536 		f->f_current.time = mp->ts;
   1537 		f->f_msgflag &= ~CURRENT_VALID;
   1538 		hlp = mp->hlp;
   1539 
   1540 		prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
   1541 		currofst = (f->f_current.flags & ADDDATE) ? 0 : 16;
   1542 
   1543 		if (f->f_type == F_FORW) {
   1544 			/*
   1545 			 * Should not forward MARK messages, as they are
   1546 			 * not defined outside of the current system.
   1547 			 */
   1548 
   1549 			if (mp->flags & MARK) {
   1550 				DPRINT1(1, "logit(%u): cannot forward "
   1551 				    "Mark\n", f->f_thread);
   1552 				goto out;
   1553 			}
   1554 
   1555 			/*
   1556 			 * can not forward message if we do
   1557 			 * not have a host to forward to
   1558 			 */
   1559 			if (hlp == (host_list_t *)NULL)
   1560 				goto out;
   1561 			/*
   1562 			 * a forwarding loop is created on machines
   1563 			 * with multiple interfaces because the
   1564 			 * network address of the sender is different
   1565 			 * to the receiver even though it is the
   1566 			 * same machine. Instead, if the
   1567 			 * hostname the source and target are
   1568 			 * the same the message if thrown away
   1569 			 */
   1570 			forwardingloop = 0;
   1571 			for (i = 0; i < hlp->hl_cnt; i++) {
   1572 				if (strcmp(hlp->hl_hosts[i],
   1573 				    f->f_un.f_forw.f_hname) == 0) {
   1574 					DPRINT3(1, errmsg, f->f_thread,
   1575 					    f->f_un.f_forw.f_hname,
   1576 					    hlp->hl_hosts[i]);
   1577 					forwardingloop = 1;
   1578 					break;
   1579 				}
   1580 			}
   1581 
   1582 			if (forwardingloop == 1) {
   1583 				f->f_stat.cantfwd++;
   1584 				goto out;
   1585 			}
   1586 		}
   1587 
   1588 		f->f_msgflag |= CURRENT_VALID;
   1589 
   1590 		/* check for dup message */
   1591 		if (f->f_type != F_FORW &&
   1592 		    (f->f_msgflag & OLD_VALID) &&
   1593 		    prevofst == currofst &&
   1594 		    (strcmp(f->f_prevmsg.msg + prevofst,
   1595 		    f->f_current.msg + currofst) == 0) &&
   1596 		    (strcmp(f->f_prevmsg.host,
   1597 		    f->f_current.host) == 0)) {
   1598 			/* a dup */
   1599 			DPRINT2(2, "logit(%u): msg is dup - %p\n",
   1600 			    f->f_thread, (void *)mp);
   1601 			if (currofst == 16) {
   1602 				(void) strncpy(f->f_prevmsg.msg,
   1603 				    f->f_current.msg, 15); /* update time */
   1604 			}
   1605 			f->f_prevcount++;
   1606 			f->f_stat.dups++;
   1607 			f->f_stat.total++;
   1608 			f->f_msgflag &= ~CURRENT_VALID;
   1609 		} else {
   1610 			/* new: mark or prior dups exist */
   1611 			if (f->f_current.flags & MARK || f->f_prevcount > 0) {
   1612 				if (f->f_prevcount > 0 && f->f_type != F_FORW) {
   1613 					set_flush_msg(f);
   1614 					if (f->f_msgflag & OLD_VALID) {
   1615 						writemsg(SAVED, f);
   1616 					}
   1617 				}
   1618 				if (f->f_msgflag & CURRENT_VALID)
   1619 					writemsg(CURRENT, f);
   1620 				if (!(mp->flags & NOCOPY))
   1621 					copy_msg(f);
   1622 				if (f->f_current.flags & MARK) {
   1623 					DPRINT2(2, "logit(%u): msg is "
   1624 					    "mark - %p)\n", f->f_thread,
   1625 					    (void *)mp);
   1626 					f->f_msgflag &= ~OLD_VALID;
   1627 				} else {
   1628 					DPRINT2(2, "logit(%u): saving "
   1629 					    "message - %p\n", f->f_thread,
   1630 					    (void *)mp);
   1631 				}
   1632 				f->f_stat.total++;
   1633 			} else { /* new message */
   1634 				DPRINT2(2, "logit(%u): msg is new "
   1635 				    "- %p\n", f->f_thread, (void *)mp);
   1636 				writemsg(CURRENT, f);
   1637 				if (!(mp->flags & NOCOPY))
   1638 					copy_msg(f);
   1639 				f->f_stat.total++;
   1640 			}
   1641 		}
   1642 		/*
   1643 		 * if message refcnt goes to zero after we decrement
   1644 		 * it here, we are the last consumer of the message,
   1645 		 * and we should free it.  We need to hold the lock
   1646 		 * between decrementing the count and checking for
   1647 		 * zero so another thread doesn't beat us to it.
   1648 		 */
   1649 out:
   1650 		(void) pthread_mutex_lock(&mp->msg_mutex);
   1651 		refcnt = --mp->refcnt;
   1652 		(void) pthread_mutex_unlock(&mp->msg_mutex);
   1653 		if (refcnt == 0)
   1654 			free_msg(mp);
   1655 	}
   1656 	/* register our exit */
   1657 
   1658 	/*
   1659 	 * Pull out all pending messages, if they exist.
   1660 	 */
   1661 
   1662 	(void) pthread_mutex_lock(&f->filed_mutex);
   1663 
   1664 	while (f->f_queue_count > 0) {
   1665 		(void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
   1666 		DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
   1667 		    "%p\n",
   1668 		    f->f_thread, (void *)mp, (void *)&f->f_queue);
   1669 		(void) pthread_mutex_lock(&mp->msg_mutex);
   1670 		refcnt = --mp->refcnt;
   1671 		(void) pthread_mutex_unlock(&mp->msg_mutex);
   1672 		if (refcnt == 0)
   1673 			free_msg(mp);
   1674 		f->f_queue_count--;
   1675 	}
   1676 
   1677 	(void) pthread_mutex_unlock(&f->filed_mutex);
   1678 
   1679 	if (f->f_type != F_USERS && f->f_type != F_WALL &&
   1680 	    f->f_type != F_UNUSED) {
   1681 		if (f->f_type == F_FORW)
   1682 			(void) t_close(f->f_file);
   1683 		else
   1684 			(void) close(f->f_file);
   1685 	}
   1686 
   1687 	/*
   1688 	 * Since f_type may have been changed before this point, we need
   1689 	 * to test orig_type.
   1690 	 */
   1691 	if (f->f_orig_type == F_FORW) {
   1692 		free(f->f_un.f_forw.f_addr.buf);
   1693 	}
   1694 
   1695 	f->f_type = F_UNUSED;
   1696 	(void) pthread_mutex_lock(&cft);
   1697 	--conf_threads;
   1698 	(void) pthread_mutex_unlock(&cft);
   1699 	DPRINT1(5, "logit(%u): logging thread exited\n", f->f_thread);
   1700 	return (NULL);
   1701 }
   1702 
   1703 /*
   1704  * change the previous message to a flush message, stating how
   1705  * many repeats occurred since the last flush
   1706  */
   1707 static void
   1708 set_flush_msg(struct filed *f)
   1709 {
   1710 	char tbuf[10];
   1711 	int prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
   1712 
   1713 	if (f->f_prevcount == 1)
   1714 		(void) strncpy(tbuf, "time", sizeof (tbuf));
   1715 	else
   1716 		(void) strncpy(tbuf, "times", sizeof (tbuf));
   1717 
   1718 	(void) snprintf(f->f_prevmsg.msg+prevofst,
   1719 	    sizeof (f->f_prevmsg.msg) - prevofst,
   1720 	    "last message repeated %d %s", f->f_prevcount, tbuf);
   1721 	f->f_prevcount = 0;
   1722 	f->f_msgflag |= OLD_VALID;
   1723 }
   1724 
   1725 
   1726 /*
   1727  * the actual writing of the message is broken into a separate function
   1728  * because each file has a current and saved message associated with
   1729  * it (for duplicate message detection). It is necessary to be able
   1730  * to write either the saved message or the current message.
   1731  */
   1732 static void
   1733 writemsg(int selection, struct filed *f)
   1734 {
   1735 	char *cp, *p;
   1736 	int pri;
   1737 	int flags;
   1738 	int l;
   1739 	time_t ts;
   1740 	struct t_unitdata ud;
   1741 	char *eomp, *eomp2, *from, *text, *msg;
   1742 	char line[MAXLINE*2];
   1743 	char head[MAXLINE+1];
   1744 	char tmpbuf[MAXLINE+1];
   1745 	char cbuf[30];
   1746 	char *filtered;
   1747 	char *msgid_start, *msgid_end;
   1748 	pthread_t mythreadno;
   1749 	size_t	hlen, filter_len;
   1750 
   1751 	if (Debug) {
   1752 		mythreadno = pthread_self();
   1753 	}
   1754 
   1755 	switch (selection) {
   1756 	default:
   1757 	case CURRENT:		/* print current message */
   1758 		msg = f->f_current.msg;
   1759 		from = f->f_current.host;
   1760 		pri = f->f_current.pri;
   1761 		flags = f->f_current.flags;
   1762 		ts = f->f_current.time;
   1763 		f->f_msgflag &= ~CURRENT_VALID;
   1764 		break;
   1765 	case SAVED:		/* print saved message */
   1766 		msg = f->f_prevmsg.msg;
   1767 		from = f->f_prevmsg.host;
   1768 		pri = f->f_prevmsg.pri;
   1769 		flags = f->f_prevmsg.flags;
   1770 		ts = f->f_prevmsg.time;
   1771 		f->f_msgflag &= ~OLD_VALID;
   1772 		break;
   1773 	}
   1774 
   1775 	if (msg[0] == '\0')
   1776 		return;
   1777 
   1778 	cp = line;
   1779 
   1780 	if (flags & ADDDATE)
   1781 		(void) strncpy(cp, ctime_r(&ts, cbuf) + 4, 15);
   1782 	else
   1783 		(void) strncpy(cp, msg, 15);
   1784 
   1785 	line[15] = '\0';
   1786 	(void) strcat(cp, " ");
   1787 	(void) strcat(cp, from);
   1788 	(void) strcat(cp, " ");
   1789 	text = cp + strlen(cp);
   1790 
   1791 	if (flags & ADDDATE)
   1792 		(void) strcat(cp, msg);
   1793 	else
   1794 		(void) strcat(cp, msg+16);
   1795 	DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
   1796 
   1797 	errno = 0;
   1798 	t_errno = 0;
   1799 	switch (f->f_type) {
   1800 	case F_UNUSED:
   1801 		DPRINT1(1, "writemsg(%u): UNUSED\n", mythreadno);
   1802 		break;
   1803 	case F_FORW:
   1804 		DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
   1805 		    mythreadno, msg, TypeNames[f->f_type],
   1806 		    f->f_un.f_forw.f_hname);
   1807 
   1808 		hlen = snprintf(head, sizeof (head),
   1809 		    "<%d>%.15s ", pri, cp);
   1810 
   1811 		DPRINT2(5, "writemsg(%u): head = \"%s\"\n", mythreadno, head);
   1812 		DPRINT2(5, "writemsg(%u): hlen = %d\n", mythreadno, hlen);
   1813 
   1814 		l = strlen(text);
   1815 		p = text;
   1816 
   1817 		DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
   1818 		DPRINT2(5, "writemsg(%u): strlen(text) = %d\n", mythreadno, l);
   1819 
   1820 		(void) strncpy(tmpbuf, head, hlen);
   1821 
   1822 		while (l > 0) {
   1823 			size_t	len;
   1824 
   1825 			len = copy_frwd(tmpbuf + hlen, sizeof (tmpbuf) - hlen,
   1826 			    p, l);
   1827 
   1828 			DPRINT2(5, "writemsg(%u): tmpbuf = \"%s\"\n",
   1829 			    mythreadno, tmpbuf);
   1830 			DPRINT2(5, "writemsg(%u): len = %d\n", mythreadno,
   1831 			    len);
   1832 			DPRINT2(5, "writemsg(%u): strlen(tmpbuf) = %d\n",
   1833 			    mythreadno, strlen(tmpbuf));
   1834 
   1835 			ud.opt.buf = NULL;
   1836 			ud.opt.len = 0;
   1837 			ud.udata.buf = tmpbuf;
   1838 			ud.udata.len = len + hlen;
   1839 			ud.addr.maxlen = f->f_un.f_forw.f_addr.maxlen;
   1840 			ud.addr.buf = f->f_un.f_forw.f_addr.buf;
   1841 			ud.addr.len = f->f_un.f_forw.f_addr.len;
   1842 			if (t_sndudata(f->f_file, &ud) < 0) {
   1843 				if ((hup_state & HUP_INPROGRESS) &&
   1844 				    f->f_type == F_UNUSED) {
   1845 					break;
   1846 				}
   1847 				(void) t_close(f->f_file);
   1848 				f->f_type = F_UNUSED;
   1849 				logerror("t_sndudata");
   1850 
   1851 				/*
   1852 				 * Since it has already failed, it's not worth
   1853 				 * continuing output from the middle of
   1854 				 * message string.
   1855 				 */
   1856 				break;
   1857 			}
   1858 			p += len;
   1859 			l -= len;
   1860 		}
   1861 		break;
   1862 	case F_CONSOLE:
   1863 	case F_TTY:
   1864 	case F_FILE:
   1865 	case F_USERS:
   1866 	case F_WALL:
   1867 		DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
   1868 		    mythreadno, msg, TypeNames[f->f_type],
   1869 		    ((f->f_type == F_USERS) || (f->f_type == F_WALL)) ?
   1870 		    "" : f->f_un.f_fname);
   1871 		/*
   1872 		 * filter the string in preparation for writing it
   1873 		 * save the original for possible forwarding.
   1874 		 * In case every byte in cp is a control character,
   1875 		 * allocates large enough buffer for filtered.
   1876 		 */
   1877 
   1878 		filter_len = strlen(cp) * 4 + 1;
   1879 		filtered = (char *)malloc(filter_len);
   1880 		if (!filtered) {
   1881 			MALLOC_FAIL("dropping message");
   1882 			/* seems we can just return */
   1883 			return;
   1884 		}
   1885 		DPRINT3(5, "writemsg(%u): "
   1886 		    "filtered allocated (%p: %d bytes)\n",
   1887 		    mythreadno, (void *)filtered, filter_len);
   1888 		/* -3 : we may add "\r\n" to ecomp(filtered) later */
   1889 		filter_string(cp, filtered, filter_len - 3);
   1890 
   1891 		DPRINT2(5, "writemsg(%u): strlen(filtered) = %d\n",
   1892 		    mythreadno, strlen(filtered));
   1893 		/*
   1894 		 * If we're writing to the console, strip out the message ID
   1895 		 * to reduce visual clutter.
   1896 		 */
   1897 		if ((msgid_start = strstr(filtered, "[ID ")) != NULL &&
   1898 		    (msgid_end = strstr(msgid_start, "] ")) != NULL &&
   1899 		    f->f_type == F_CONSOLE)
   1900 			(void) strcpy(msgid_start, msgid_end + 2);
   1901 
   1902 		eomp = filtered + strlen(filtered);
   1903 
   1904 		if ((f->f_type == F_USERS) || (f->f_type == F_WALL)) {
   1905 			/* CSTYLED */
   1906 			(void) strcat(eomp, "\r\n"); /*lint !e669*/
   1907 			/*
   1908 			 * Since wallmsg messes with utmpx we need
   1909 			 * to guarantee single threadedness...
   1910 			 */
   1911 			(void) pthread_mutex_lock(&wmp);
   1912 			wallmsg(f, from, filtered);
   1913 			(void) pthread_mutex_unlock(&wmp);
   1914 
   1915 			/*
   1916 			 * The contents of filtered have been copied
   1917 			 * out to the struct walldev. We should free it here.
   1918 			 */
   1919 
   1920 			free(filtered);
   1921 
   1922 			/* exiting the switch */
   1923 			break;
   1924 		} else if (f->f_type != F_FILE) {
   1925 			/* CSTYLED */
   1926 			(void) strncpy(eomp, "\r\n", 3); /*lint !e669*/
   1927 		} else {
   1928 			if ((eomp2 = strchr(filtered, '\r')) != NULL) {
   1929 				(void) strncpy(eomp2, "\n", 2);
   1930 			} else {
   1931 				/* CSTYLED */
   1932 				(void) strncpy(eomp, "\n", 2); /*lint !e669*/
   1933 			}
   1934 		}
   1935 		if (write(f->f_file, filtered, strlen(filtered)) < 0) {
   1936 			int e = errno;
   1937 
   1938 			if ((hup_state & HUP_INPROGRESS) &&
   1939 			    f->f_type == F_UNUSED) {
   1940 				free(filtered);
   1941 				break;
   1942 			}
   1943 			(void) close(f->f_file);
   1944 			/*
   1945 			 * Check for EBADF on TTY's due
   1946 			 * to vhangup() XXX
   1947 			 */
   1948 			if (e == EBADF && f->f_type != F_FILE) {
   1949 				f->f_file = open(f->f_un.f_fname,
   1950 				    O_WRONLY|O_APPEND|O_NOCTTY);
   1951 				if (f->f_file < 0) {
   1952 					f->f_type = F_UNUSED;
   1953 					logerror(f->f_un.f_fname);
   1954 					f->f_stat.errs++;
   1955 				}
   1956 				untty();
   1957 			} else {
   1958 				f->f_type = F_UNUSED;
   1959 				f->f_stat.errs++;
   1960 				errno = e;
   1961 				logerror(f->f_un.f_fname);
   1962 			}
   1963 		} else if (flags & SYNC_FILE)
   1964 			if (((pri & LOG_FACMASK) >> 3) == LOG_KERN)
   1965 				(void) fsync(f->f_file);
   1966 
   1967 		DPRINT2(5, "writemsg(%u): freeing filtered (%p)\n",
   1968 		    mythreadno, (void *)filtered);
   1969 
   1970 		free(filtered);
   1971 		break;
   1972 	}
   1973 }
   1974 
   1975 /*
   1976  *  WALLMSG -- Write a message to the world at large
   1977  *
   1978  *	Write the specified message to either the entire
   1979  *	world, or a list of approved users.
   1980  */
   1981 static void
   1982 wallmsg(struct filed *f, char *from, char *msg)
   1983 {
   1984 	int i;
   1985 	size_t	len, clen;
   1986 	char *buf = NULL;
   1987 	struct utmpx *utxp;
   1988 	time_t now;
   1989 	char line[512], dev[100];
   1990 	char cp[MAXLINE+1];
   1991 	struct stat statbuf;
   1992 	walldev_t *w;
   1993 	char cbuf[30];
   1994 	pthread_t mythreadno;
   1995 
   1996 	if (Debug) {
   1997 		mythreadno = pthread_self();
   1998 	}
   1999 
   2000 	if (access(UTMPX_FILE, R_OK) != 0 || stat(UTMPX_FILE, &statbuf) != 0) {
   2001 		logerror(UTMPX_FILE);
   2002 		return;
   2003 	} else if (statbuf.st_uid != 0 || (statbuf.st_mode & 07777) != 0644) {
   2004 		(void) snprintf(line, sizeof (line), "%s %s", UTMPX_FILE,
   2005 		    "not owned by root or not mode 644.\n"
   2006 		    "This file must be owned by root "
   2007 		    "and not writable by\n"
   2008 		    "anyone other than root.  This alert is being "
   2009 		    "dropped because of\n"
   2010 		    "this problem.");
   2011 		logerror(line);
   2012 		return;
   2013 	}
   2014 
   2015 	if (f->f_type == F_WALL) {
   2016 		(void) time(&now);
   2017 		len = snprintf(line, sizeof (line),
   2018 		    "\r\n\7Message from syslogd@%s "
   2019 		    "at %.24s ...\r\n", from, ctime_r(&now, cbuf));
   2020 		len += strlen(msg + 16);
   2021 		buf = (char *)malloc(len + 1);
   2022 		if (!buf) {
   2023 			MALLOC_FAIL("dropping message");
   2024 			return;
   2025 		}
   2026 		DPRINT3(5, "wallmsg(%u): buf allocated (%p: %d bytes)\n",
   2027 		    mythreadno, (void *)buf, len + 1);
   2028 		(void) strcpy(buf, line);
   2029 		(void) strcat(buf, msg + 16);
   2030 		clen = copy_frwd(cp, sizeof (cp), buf, len);
   2031 		DPRINT2(5, "wallmsg(%u): clen = %d\n",
   2032 		    mythreadno, clen);
   2033 		DPRINT2(5, "wallmsg(%u): freeing buf (%p)\n",
   2034 		    mythreadno, (void *)buf);
   2035 		free(buf);
   2036 	} else {
   2037 		clen = copy_frwd(cp, sizeof (cp), msg, strlen(msg));
   2038 		DPRINT2(5, "wallmsg(%u): clen = %d\n",
   2039 		    mythreadno, clen);
   2040 	}
   2041 	/* scan the user login file */
   2042 	setutxent();
   2043 	while ((utxp = getutxent()) != NULL) {
   2044 		/* is this slot used? */
   2045 		if (utxp->ut_name[0] == '\0' ||
   2046 		    utxp->ut_line[0] == '\0' ||
   2047 		    utxp->ut_type != USER_PROCESS)
   2048 			continue;
   2049 		/* should we send the message to this user? */
   2050 		if (f->f_type == F_USERS) {
   2051 			for (i = 0; i < MAXUNAMES; i++) {
   2052 				if (!f->f_un.f_uname[i][0]) {
   2053 					i = MAXUNAMES;
   2054 					break;
   2055 				}
   2056 				if (strncmp(f->f_un.f_uname[i],
   2057 				    utxp->ut_name, UNAMESZ) == 0)
   2058 					break;
   2059 			}
   2060 			if (i >= MAXUNAMES)
   2061 				continue;
   2062 		}
   2063 
   2064 		/* compute the device name */
   2065 		if (utxp->ut_line[0] == '/') {
   2066 			(void) strncpy(dev, utxp->ut_line, UDEVSZ);
   2067 		} else {
   2068 			(void) strcpy(dev, "/dev/");
   2069 			(void) strncat(dev, utxp->ut_line, UDEVSZ);
   2070 		}
   2071 		DPRINT2(1, "wallmsg(%u): write to '%s'\n", mythreadno,
   2072 		    dev);
   2073 
   2074 		if ((w = malloc(sizeof (walldev_t))) != NULL) {
   2075 			int rc;
   2076 			(void) pthread_attr_init(&w->thread_attr);
   2077 			(void) pthread_attr_setdetachstate(&w->thread_attr,
   2078 			    PTHREAD_CREATE_DETACHED);
   2079 			(void) strncpy(w->dev, dev, PATH_MAX);
   2080 			(void) strncpy(w->msg, cp, MAXLINE+1);
   2081 			(void) strncpy(w->ut_name, utxp->ut_name,
   2082 			    sizeof (w->ut_name));
   2083 
   2084 			if ((rc = pthread_create(&w->thread, &w->thread_attr,
   2085 			    writetodev, (void *) w)) != 0) {
   2086 				DPRINT2(5, "wallmsg(%u): wallmsg thread "
   2087 				    "create failed rc = %d\n",
   2088 				    mythreadno, rc);
   2089 				free(w);
   2090 				break;
   2091 			}
   2092 		} else {
   2093 			MALLOC_FAIL("dropping message to user");
   2094 		}
   2095 	}
   2096 	/* close the user login file */
   2097 	endutxent();
   2098 }
   2099 
   2100 /*
   2101  * Each time we need to write to a tty device (a potentially expensive
   2102  * or long-running operation) this routine gets called as a new
   2103  * detached, unbound thread. This allows writes to many devices
   2104  * to proceed nearly in parallel, without having to resort to
   2105  * asynchronous I/O or forking.
   2106  */
   2107 static void *
   2108 writetodev(void *ap)
   2109 {
   2110 	walldev_t *w = ap;
   2111 	int ttyf;
   2112 	int len;
   2113 	struct stat statb;
   2114 	struct passwd pw, *pwp;
   2115 	char pwbuf[MAXLINE];
   2116 	pthread_t mythreadno;
   2117 
   2118 	if (Debug) {
   2119 		mythreadno = pthread_self();
   2120 	}
   2121 
   2122 	DPRINT1(1, "writetodev(%u): Device writer thread started\n",
   2123 	    mythreadno);
   2124 
   2125 	len = strlen(w->msg);
   2126 
   2127 	ttyf = open(w->dev, O_WRONLY|O_NOCTTY|O_NDELAY);
   2128 	if (ttyf >= 0) {
   2129 		if (fstat(ttyf, &statb) != 0) {
   2130 			DPRINT2(1, "writetodev(%u): Can't stat '%s'\n",
   2131 			    mythreadno, w->dev);
   2132 			errno = 0;
   2133 			logerror("Can't stat '%s'", w->dev);
   2134 		} else if (!(statb.st_mode & S_IWRITE)) {
   2135 			DPRINT2(1, "writetodev(%u): Can't write to "
   2136 			    "'%s'\n", mythreadno, w->dev);
   2137 		} else if (!isatty(ttyf)) {
   2138 			DPRINT2(1, "writetodev(%u): '%s' not a tty\n",
   2139 			    mythreadno, w->dev);
   2140 			/*
   2141 			 * We might hit dtremote here. Don't generate
   2142 			 * error message.
   2143 			 */
   2144 		} else if (getpwuid_r(statb.st_uid, &pw, pwbuf,
   2145 		    sizeof (pwbuf), &pwp) != 0) {
   2146 			DPRINT2(1, "writetodev(%u): Can't determine owner "
   2147 			    "of '%s'\n", mythreadno, w->dev);
   2148 			errno = 0;
   2149 			logerror("Can't determine owner of '%s'", w->dev);
   2150 		} else if (strncmp(pw.pw_name, w->ut_name, UNAMESZ) != 0) {
   2151 			DPRINT2(1, "writetodev(%u): Bad terminal owner '%s'"
   2152 			    "\n", mythreadno, w->dev);
   2153 			errno = 0;
   2154 			logerror("%s %s owns '%s' %s %.*s",
   2155 			    "Bad terminal owner;", pw.pw_name, w->dev,
   2156 			    "but utmpx says", UNAMESZ, w->ut_name);
   2157 		} else if (write(ttyf, w->msg, len) != len) {
   2158 			DPRINT2(1, "writetodev(%u): Write failed to "
   2159 			    "'%s'\n", mythreadno, w->dev);
   2160 			errno = 0;
   2161 			logerror("Write failed to '%s'", w->dev);
   2162 		}
   2163 
   2164 		DPRINT2(1, "writetodev(%u): write to '%s' succeeded\n",
   2165 		    mythreadno, w->dev);
   2166 
   2167 		(void) close(ttyf);
   2168 	} else {
   2169 		DPRINT2(1, "writetodev(%u): Can't open '%s'\n",
   2170 		    mythreadno, w->dev);
   2171 	}
   2172 
   2173 	(void) pthread_attr_destroy(&w->thread_attr);
   2174 	free(w);
   2175 
   2176 	DPRINT1(1, "writetodev(%u): Device writer thread exiting\n",
   2177 	    mythreadno);
   2178 
   2179 	pthread_exit(0);
   2180 	return (NULL);
   2181 	/*NOTREACHED*/
   2182 }
   2183 
   2184 /*
   2185  * Return a printable representation of a host address. If unable to
   2186  * look up hostname, format the numeric address for display instead.
   2187  *
   2188  * First calls hnc_lookup to see if there is valid cache entry for
   2189  * given network address. If it failed, cvthname looks up hostname,
   2190  * and push the results into the hostname cache.
   2191  */
   2192 static host_list_t *
   2193 cvthname(struct netbuf *nbp, struct netconfig *ncp, char *failsafe_addr)
   2194 {
   2195 	int i;
   2196 	host_list_t *h;
   2197 	struct nd_hostservlist *hsp;
   2198 	struct nd_hostserv *hspp;
   2199 	pthread_t mythreadno;
   2200 	int hindex;
   2201 	char *uap;
   2202 
   2203 	if (Debug) {
   2204 		mythreadno = pthread_self();
   2205 	}
   2206 
   2207 	if (Debug)
   2208 		uap = taddr2uaddr(ncp, nbp);
   2209 
   2210 	DPRINT2(2, "cvthname(%u): looking up hostname for %s\n",
   2211 	    mythreadno, uap ? uap : "<unknown>");
   2212 
   2213 	if ((h = hnc_lookup(nbp, ncp, &hindex)) != NULL) {
   2214 		DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n",
   2215 		    mythreadno, (void *)h, uap ? uap : "<unknown>",
   2216 		    h->hl_hosts[0]);
   2217 		return (h);
   2218 	}
   2219 	DPRINT2(2, "cvthname(%u): No cache found for %s\n",
   2220 	    mythreadno, uap ? uap : "<unknown>");
   2221 
   2222 	if (Debug)
   2223 		free(uap);
   2224 
   2225 	if (ncp->nc_semantics != NC_TPI_CLTS) {
   2226 		return (NULL);
   2227 	}
   2228 
   2229 	/* memory allocation failure here is fatal */
   2230 	if ((h = malloc(sizeof (host_list_t))) == NULL) {
   2231 		MALLOC_FAIL("host name conversion");
   2232 		return (NULL);
   2233 	}
   2234 
   2235 	if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) {
   2236 		if (hsp->h_cnt <= 0) {
   2237 out:			netdir_free((void *)hsp, ND_HOSTSERVLIST);
   2238 			free(h);
   2239 			return (NULL);
   2240 		}
   2241 
   2242 		hspp = hsp->h_hostservs;
   2243 		h->hl_cnt = hsp->h_cnt;
   2244 		h->hl_hosts = (char **)malloc(sizeof (char *) * (h->hl_cnt));
   2245 		if (h->hl_hosts == NULL) {
   2246 			MALLOC_FAIL("host name conversion");
   2247 			goto out;
   2248 		}
   2249 
   2250 		DPRINT2(2, "cvthname(%u): Found %d hostnames\n",
   2251 		    mythreadno, h->hl_cnt);
   2252 		for (i = 0; i < h->hl_cnt; i++) {
   2253 			h->hl_hosts[i] = (char *)
   2254 			    malloc(sizeof (char) * (strlen(hspp->h_host) + 1));
   2255 			if (h->hl_hosts[i] == NULL) {
   2256 				int j;
   2257 				for (j = 0; j < i; j++) {
   2258 					free(h->hl_hosts[j]);
   2259 				}
   2260 				free(h->hl_hosts);
   2261 				MALLOC_FAIL("host name conversion");
   2262 				goto out;
   2263 			}
   2264 			(void) strcpy(h->hl_hosts[i], hspp->h_host);
   2265 			hspp++;
   2266 		}
   2267 		netdir_free((void *)hsp, ND_HOSTSERVLIST);
   2268 	} else { /* unknown address */
   2269 		h->hl_cnt = 1;
   2270 		h->hl_hosts = (char **)malloc(sizeof (char *));
   2271 		if (h->hl_hosts == NULL) {
   2272 			free(h);
   2273 			MALLOC_FAIL("host name conversion");
   2274 			return (NULL);
   2275 		}
   2276 		h->hl_hosts[0] = (char *)malloc(strlen(failsafe_addr) + 3);
   2277 		if (h->hl_hosts[0] == NULL) {
   2278 			free(h->hl_hosts);
   2279 			free(h);
   2280 			MALLOC_FAIL("host name conversion");
   2281 			return (NULL);
   2282 		}
   2283 		/*LINTED*/
   2284 		(void) sprintf(h->hl_hosts[0], "[%s]", failsafe_addr);
   2285 		DPRINT2(1, "cvthname(%u): Hostname lookup failed "
   2286 		    "- using address %s instead\n",
   2287 		    mythreadno, h->hl_hosts[0]);
   2288 	}
   2289 
   2290 	h->hl_refcnt = 1;
   2291 	if (pthread_mutex_init(&h->hl_mutex, NULL) != 0) {
   2292 		logerror("pthread_mutex_init failed");
   2293 		/* This host_list won't be shared by the cache. */
   2294 		return (h);
   2295 	}
   2296 	hnc_register(nbp, ncp, h, hindex);
   2297 	DPRINT3(2, "cvthname(%u): returning %p for %s\n",
   2298 	    mythreadno, (void *)h, h->hl_hosts[0]);
   2299 	return (h);
   2300 }
   2301 
   2302 /*
   2303  * Print syslogd errors some place. Need to be careful here, because
   2304  * this routine is called at times when we're not initialized and
   2305  * ready to log messages...in this case, fall back to using the console.
   2306  */
   2307 void
   2308 logerror(const char *type, ...)
   2309 {
   2310 	char buf[MAXLINE+1];
   2311 	pthread_t mythreadno;
   2312 	int flag;
   2313 	va_list ap;
   2314 
   2315 	if (Debug) {
   2316 		mythreadno = pthread_self();
   2317 	}
   2318 
   2319 	va_start(ap, type);
   2320 	logerror_format(type, buf, ap);
   2321 	va_end(ap);
   2322 	DPRINT2(1, "logerror(%u): %s\n", mythreadno, buf);
   2323 
   2324 	(void) pthread_mutex_lock(&logerror_lock);
   2325 	if (!interrorlog) {
   2326 		flag = 0;
   2327 		if (logerror_to_console(1, buf) == 0) {
   2328 			/* has written to the console */
   2329 			flag = IGN_CONS;
   2330 		}
   2331 		(void) logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE|flag, 1);
   2332 	} else {
   2333 		if (logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE, 0) == -1) {
   2334 			(void) logerror_to_console(1, buf);
   2335 		}
   2336 	}
   2337 	(void) pthread_mutex_unlock(&logerror_lock);
   2338 
   2339 	errno = 0;
   2340 	t_errno = 0;
   2341 }
   2342 
   2343 static void
   2344 logerror_format(const char *type, char *buf, va_list ap)
   2345 {
   2346 	char tmpbuf[MAXLINE + 1];
   2347 	pthread_t mythreadno;
   2348 
   2349 	if (Debug) {
   2350 		mythreadno = pthread_self();
   2351 	}
   2352 
   2353 	(void) vsnprintf(tmpbuf, MAXLINE, type, ap);
   2354 
   2355 	if (t_errno == 0 || t_errno == TSYSERR) {
   2356 		char *errstr;
   2357 
   2358 		if (errno == 0) {
   2359 			(void) snprintf(buf, MAXLINE, "syslogd: %.*s",
   2360 			    MAXLINE, tmpbuf);
   2361 		} else if ((errstr = strerror(errno)) == (char *)NULL) {
   2362 			(void) snprintf(buf, MAXLINE, "syslogd: %s: error"
   2363 			    " %d", tmpbuf, errno);
   2364 		} else {
   2365 			(void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
   2366 			    tmpbuf, errstr);
   2367 		}
   2368 	} else {
   2369 		if (t_errno > t_nerr) {
   2370 			(void) snprintf(buf, MAXLINE, "syslogd: %s:"
   2371 			    " t_error %d", tmpbuf, t_errno);
   2372 		} else {
   2373 			(void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
   2374 			    tmpbuf, t_errlist[t_errno]);
   2375 		}
   2376 	}
   2377 
   2378 	DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno, buf);
   2379 }
   2380 
   2381 static int
   2382 logerror_to_console(int nonblock, const char *buf)
   2383 {
   2384 	int cfd, modes;
   2385 	pthread_t mythreadno;
   2386 	int ret = 0, len;
   2387 	char tmpbuf[MAXLINE + 1];
   2388 
   2389 	if (Debug) {
   2390 		mythreadno = pthread_self();
   2391 	}
   2392 
   2393 	DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno, buf);
   2394 
   2395 	/*
   2396 	 * must use open here instead of fopen, because
   2397 	 * we need the O_NOCTTY behavior - otherwise we
   2398 	 * could hang the console at boot time
   2399 	 */
   2400 
   2401 	modes = (nonblock) ?
   2402 	    O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK :
   2403 	    O_WRONLY|O_APPEND|O_NOCTTY;
   2404 
   2405 	if (((cfd = open(sysmsg, modes)) >= 0) ||
   2406 	    ((cfd = open(ctty, modes)) >= 0)) {
   2407 		(void) snprintf(tmpbuf, MAXLINE, "%s\n", buf);
   2408 		len = strlen(tmpbuf);
   2409 		if (write(cfd, tmpbuf, len) != len) {
   2410 			ret = 1;
   2411 		}
   2412 		(void) close(cfd);
   2413 	} else {
   2414 		ret = 1;
   2415 
   2416 		/* punt */
   2417 		DPRINT1(1, "logerror_console(%u): can't open console\n",
   2418 		    mythreadno);
   2419 	}
   2420 	return (ret);
   2421 }
   2422 
   2423 /*
   2424  * copy current message to saved message in filed structure.
   2425  */
   2426 static void
   2427 copy_msg(struct filed *f)
   2428 {
   2429 	(void) strlcpy(f->f_prevmsg.msg, f->f_current.msg, MAXLINE+1);
   2430 	(void) strlcpy(f->f_prevmsg.host, f->f_current.host, SYS_NMLN);
   2431 	f->f_prevmsg.pri = f->f_current.pri;
   2432 	f->f_prevmsg.flags = f->f_current.flags;
   2433 	f->f_prevmsg.time = f->f_current.time;
   2434 	f->f_msgflag |= OLD_VALID;
   2435 }
   2436 
   2437 
   2438 /*
   2439  * function to free a host_list_t struct that was allocated
   2440  * out of cvthname(). There is a special case where we don't
   2441  * free the hostname list in LocalHostName, because that's
   2442  * our own addresses, and we just want to have to look it
   2443  * up once and save it.  Also don't free it if it's
   2444  * NullHostName, because that's a special one we use if
   2445  * name service lookup fails.
   2446  *
   2447  * By having hostname cache, now host_list_t will be shared
   2448  * by messages and hostname cache. hl_refcnt is used for
   2449  * the purpose.
   2450  */
   2451 static void
   2452 freehl(host_list_t *h)
   2453 {
   2454 	int i, refcnt;
   2455 	pthread_t mythreadno;
   2456 
   2457 	if (Debug) {
   2458 		mythreadno = pthread_self();
   2459 	}
   2460 
   2461 	DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno, (void *)h);
   2462 
   2463 	if (h == NULL || h == &LocalHostName || h == &NullHostName) {
   2464 		return;
   2465 	}
   2466 
   2467 	(void) pthread_mutex_lock(&h->hl_mutex);
   2468 	refcnt = --h->hl_refcnt;
   2469 	(void) pthread_mutex_unlock(&h->hl_mutex);
   2470 
   2471 	if (refcnt != 0) {
   2472 		DPRINT3(5, "freehl(%u): %p has reference %d\n",
   2473 		    mythreadno, (void *)h, refcnt);
   2474 		return;
   2475 	}
   2476 
   2477 	(void) pthread_mutex_destroy(&h->hl_mutex);
   2478 
   2479 	DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno, (void *)h);
   2480 
   2481 	for (i = 0; i < h->hl_cnt; i++) {
   2482 		free(h->hl_hosts[i]);
   2483 	}
   2484 
   2485 	free(h->hl_hosts);
   2486 	free(h);
   2487 }
   2488 
   2489 /*
   2490  * Create the door file and the pid file in /var/run.  If the filesystem
   2491  * containing /etc is writable, create symlinks /etc/.syslog_door and
   2492  * /etc/syslog.pid to them.  On systems that do not support /var/run, create
   2493  * /etc/.syslog_door and /etc/syslog.pid directly.
   2494  *
   2495  * Note: it is not considered fatal to fail to create the pid file or its
   2496  * symlink.  Attempts to use them in the usual way will fail, of course, but
   2497  * syslogd will function nicely without it (not so for the door file).
   2498  */
   2499 
   2500 static void
   2501 open_door(void)
   2502 {
   2503 	struct stat buf;
   2504 	door_info_t info;
   2505 	char line[MAXLINE+1];
   2506 	pthread_t mythreadno;
   2507 	int err;
   2508 
   2509 	if (Debug) {
   2510 		mythreadno = pthread_self();
   2511 	}
   2512 
   2513 	/*
   2514 	 * first see if another syslogd is running by trying
   2515 	 * a door call - if it succeeds, there is already
   2516 	 * a syslogd process active
   2517 	 */
   2518 
   2519 	if (!DoorCreated) {
   2520 		int door;
   2521 
   2522 		if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
   2523 			DPRINT2(5, "open_door(%u): %s opened "
   2524 			    "successfully\n", mythreadno, DoorFileName);
   2525 
   2526 			if (door_info(door, &info) >= 0) {
   2527 				DPRINT2(5, "open_door(%u): "
   2528 				    "door_info:info.di_target = %ld\n",
   2529 				    mythreadno, info.di_target);
   2530 
   2531 				if (info.di_target > 0) {
   2532 					(void) sprintf(line, "syslogd pid %ld"
   2533 					    " already running. Cannot "
   2534 					    "start another syslogd pid %ld",
   2535 					    info.di_target, getpid());
   2536 					DPRINT2(5, "open_door(%u): error: "
   2537 					    "%s\n", mythreadno, line);
   2538 					errno = 0;
   2539 					logerror(line);
   2540 					exit(1);
   2541 				}
   2542 			}
   2543 
   2544 			(void) close(door);
   2545 		} else {
   2546 			if (lstat(DoorFileName, &buf) < 0) {
   2547 				err = errno;
   2548 
   2549 				DPRINT3(5, "open_door(%u): lstat() of %s "
   2550 				    "failed, errno=%d\n",
   2551 				    mythreadno, DoorFileName, err);
   2552 
   2553 				if ((door = creat(DoorFileName, 0644)) < 0) {
   2554 					err = errno;
   2555 					(void) snprintf(line, sizeof (line),
   2556 					    "creat() of %s failed - fatal",
   2557 					    DoorFileName);
   2558 					DPRINT3(1, "open_door(%u): error: %s, "
   2559 					    "errno=%d\n", mythreadno, line,
   2560 					    err);
   2561 					errno = err;
   2562 					logerror(line);
   2563 					delete_doorfiles();
   2564 					exit(1);
   2565 				}
   2566 
   2567 				(void) fchmod(door,
   2568 				    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
   2569 
   2570 				DPRINT2(5, "open_door(%u): creat() of %s "
   2571 				    "succeeded\n", mythreadno,
   2572 				    DoorFileName);
   2573 
   2574 				(void) close(door);
   2575 			}
   2576 		}
   2577 
   2578 		if (strcmp(DoorFileName, DOORFILE) == 0) {
   2579 			if (lstat(OLD_DOORFILE, &buf) == 0) {
   2580 				DPRINT2(5, "open_door(%u): lstat() of %s "
   2581 				    "succeeded\n", mythreadno,
   2582 				    OLD_DOORFILE);
   2583 
   2584 				if (S_ISDIR(buf.st_mode)) {
   2585 					(void) snprintf(line, sizeof (line),
   2586 					    "%s is a directory - fatal",
   2587 					    OLD_DOORFILE);
   2588 					DPRINT2(1, "open_door(%u): error: "
   2589 					    "%s\n", mythreadno, line);
   2590 					errno = 0;
   2591 					logerror(line);
   2592 					delete_doorfiles();
   2593 					exit(1);
   2594 				}
   2595 
   2596 				DPRINT2(5, "open_door(%u): %s is not a "
   2597 				    "directory\n",
   2598 				    mythreadno, OLD_DOORFILE);
   2599 
   2600 				if (unlink(OLD_DOORFILE) < 0) {
   2601 					err = errno;
   2602 					(void) snprintf(line, sizeof (line),
   2603 					    "unlink() of %s failed",
   2604 					    OLD_DOORFILE);
   2605 					DPRINT2(5, "open_door(%u): %s\n",
   2606 					    mythreadno, line);
   2607 
   2608 					if (err != EROFS) {
   2609 						DPRINT3(1, "open_door(%u): "
   2610 						    "error: %s, "
   2611 						    "errno=%d\n",
   2612 						    mythreadno, line, err);
   2613 						(void) strcat(line, " - fatal");
   2614 						errno = err;
   2615 						logerror(line);
   2616 						delete_doorfiles();
   2617 						exit(1);
   2618 					}
   2619 
   2620 					DPRINT1(5, "open_door(%u): unlink "
   2621 					    "failure OK on RO file "
   2622 					    "system\n", mythreadno);
   2623 				}
   2624 			} else {
   2625 				DPRINT2(5, "open_door(%u): file %s doesn't "
   2626 				    "exist\n", mythreadno, OLD_DOORFILE);
   2627 			}
   2628 
   2629 			if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
   2630 				err = errno;
   2631 				(void) snprintf(line, sizeof (line),
   2632 				    "symlink %s -> %s failed", OLD_DOORFILE,
   2633 				    RELATIVE_DOORFILE);
   2634 				DPRINT2(5, "open_door(%u): %s\n", mythreadno,
   2635 				    line);
   2636 
   2637 				if (err != EROFS) {
   2638 					DPRINT3(1, "open_door(%u): error: %s, "
   2639 					    "errno=%d\n", mythreadno, line,
   2640 					    err);
   2641 					errno = err;
   2642 					(void) strcat(line, " - fatal");
   2643 					logerror(line);
   2644 					delete_doorfiles();
   2645 					exit(1);
   2646 				}
   2647 
   2648 				DPRINT1(5, "open_door(%u): symlink failure OK "
   2649 				    "on RO file system\n", mythreadno);
   2650 			} else {
   2651 				DPRINT3(5, "open_door(%u): symlink %s -> %s "
   2652 				    "succeeded\n", mythreadno,
   2653 				    OLD_DOORFILE, RELATIVE_DOORFILE);
   2654 			}
   2655 		}
   2656 
   2657 		if ((DoorFd = door_create(server, 0,
   2658 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
   2659 			err = errno;
   2660 			(void) sprintf(line, "door_create() failed - fatal");
   2661 			DPRINT3(1, "open_door(%u): error: %s, errno=%d\n",
   2662 			    mythreadno, line, err);
   2663 			errno = err;
   2664 			logerror(line);
   2665 			delete_doorfiles();
   2666 			exit(1);
   2667 		}
   2668 		(void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
   2669 		DPRINT2(5, "open_door(%u): door_create() succeeded, "
   2670 		    "DoorFd=%d\n", mythreadno, DoorFd);
   2671 
   2672 		DoorCreated = 1;
   2673 	}
   2674 
   2675 	(void) fdetach(DoorFileName);	/* just in case... */
   2676 
   2677 	(void) door_server_create(door_server_pool);
   2678 
   2679 	if (fattach(DoorFd, DoorFileName) < 0) {
   2680 		err = errno;
   2681 		(void) snprintf(line, sizeof (line), "fattach() of fd"
   2682 		    " %d to %s failed - fatal", DoorFd, DoorFileName);
   2683 		DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno,
   2684 		    line, err);
   2685 		errno = err;
   2686 		logerror(line);
   2687 		delete_doorfiles();
   2688 		exit(1);
   2689 	}
   2690 
   2691 	DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno,
   2692 	    DoorFileName);
   2693 
   2694 	/*
   2695 	 * create pidfile anyway, so those using it to control
   2696 	 * syslogd (with kill `cat /etc/syslog.pid` perhaps)
   2697 	 * don't get broken.
   2698 	 */
   2699 
   2700 	if (!PidfileCreated) {
   2701 		int pidfd;
   2702 
   2703 		PidfileCreated = 1;
   2704 
   2705 		if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644))
   2706 		    < 0) {
   2707 			err = errno;
   2708 			(void) snprintf(line, sizeof (line),
   2709 			    "open() of %s failed", PidFileName);
   2710 			DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
   2711 			    mythreadno, line, err);
   2712 			errno = err;
   2713 			logerror(line);
   2714 			return;
   2715 		}
   2716 
   2717 		(void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
   2718 		(void) sprintf(line, "%ld\n", getpid());
   2719 
   2720 		if (write(pidfd, line, strlen(line)) < 0) {
   2721 			err = errno;
   2722 			(void) snprintf(line, sizeof (line),
   2723 			    "write to %s on fd %d failed", PidFileName, pidfd);
   2724 			DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
   2725 			    mythreadno, line, err);
   2726 			errno = err;
   2727 			logerror(line);
   2728 			return;
   2729 		}
   2730 
   2731 		(void) close(pidfd);
   2732 
   2733 		DPRINT2(5, "open_door(%u): %s created\n",
   2734 		    mythreadno, PidFileName);
   2735 
   2736 		if (strcmp(PidFileName, PIDFILE) == 0) {
   2737 			if (lstat(OLD_PIDFILE, &buf) == 0) {
   2738 				DPRINT2(5, "open_door(%u): lstat() of %s "
   2739 				    "succeded\n", mythreadno, OLD_PIDFILE);
   2740 
   2741 				if (S_ISDIR(buf.st_mode)) {
   2742 					(void) snprintf(line, sizeof (line),
   2743 					    "file %s is a directory",
   2744 					    OLD_PIDFILE);
   2745 					DPRINT2(1, "open_door(%u): warning: "
   2746 					    "%s\n", mythreadno, line);
   2747 					errno = 0;
   2748 					logerror(line);
   2749 					return;
   2750 				}
   2751 
   2752 				if (unlink(OLD_PIDFILE) < 0) {
   2753 					err = errno;
   2754 					(void) snprintf(line, sizeof (line),
   2755 					    "unlink() of %s failed",
   2756 					    OLD_PIDFILE);
   2757 					DPRINT2(5, "open_door(%u): %s\n",
   2758 					    mythreadno, line);
   2759 
   2760 					if (err != EROFS) {
   2761 						DPRINT3(1, "open_door (%u): "
   2762 						    "warning: %s, "
   2763 						    "errno=%d\n",
   2764 						    mythreadno, line, err);
   2765 						errno = err;
   2766 						logerror(line);
   2767 						return;
   2768 					}
   2769 
   2770 					DPRINT1(5, "open_door(%u): unlink "
   2771 					    "failure OK on RO file "
   2772 					    "system\n", mythreadno);
   2773 				}
   2774 			} else {
   2775 				DPRINT2(5, "open_door(%u): file %s doesn't "
   2776 				    "exist\n", mythreadno, OLD_PIDFILE);
   2777 			}
   2778 
   2779 			if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) {
   2780 				err = errno;
   2781 				(void) snprintf(line, sizeof (line),
   2782 				    "symlink %s -> %s failed", OLD_PIDFILE,
   2783 				    RELATIVE_PIDFILE);
   2784 				DPRINT2(5, "open_door(%u): %s\n", mythreadno,
   2785 				    line);
   2786 
   2787 				if (err != EROFS) {
   2788 					DPRINT3(1, "open_door(%u): warning: "
   2789 					    "%s, errno=%d\n", mythreadno,
   2790 					    line, err);
   2791 					errno = err;
   2792 					logerror(line);
   2793 					return;
   2794 				}
   2795 
   2796 				DPRINT1(5, "open_door(%u): symlink failure OK "
   2797 				    "on RO file system\n", mythreadno);
   2798 				return;
   2799 			}
   2800 
   2801 			DPRINT3(5, "open_door(%u): symlink %s -> %s "
   2802 			    "succeeded\n", mythreadno, OLD_PIDFILE,
   2803 			    RELATIVE_PIDFILE);
   2804 		}
   2805 	}
   2806 }
   2807 
   2808 /*
   2809  * the 'server' function that we export via the door. It does
   2810  * nothing but return.
   2811  */
   2812 /*ARGSUSED*/
   2813 static void
   2814 server(void *cookie, char *argp, size_t arg_size,
   2815     door_desc_t *dp, uint_t n)
   2816 {
   2817 	(void) door_return(NULL, 0, NULL, 0);
   2818 	/* NOTREACHED */
   2819 }
   2820 
   2821 /*ARGSUSED*/
   2822 static void *
   2823 create_door_thr(void *arg)
   2824 {
   2825 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
   2826 	(void) door_return(NULL, 0, NULL, 0);
   2827 
   2828 	/*
   2829 	 * If there is an error in door_return(), it will return here and
   2830 	 * the thread will exit. Hence we need to decrement door_server_cnt.
   2831 	 */
   2832 	(void) pthread_mutex_lock(&door_server_cnt_lock);
   2833 	door_server_cnt--;
   2834 	(void) pthread_mutex_unlock(&door_server_cnt_lock);
   2835 	return (NULL);
   2836 }
   2837 
   2838 /*
   2839  * Max number of door server threads for syslogd. Since door is used
   2840  * to check the health of syslogd, we don't need large number of
   2841  * server threads.
   2842  */
   2843 #define	MAX_DOOR_SERVER_THR	3
   2844 
   2845 /*
   2846  * Manage door server thread pool.
   2847  */
   2848 /*ARGSUSED*/
   2849 static void
   2850 door_server_pool(door_info_t *dip)
   2851 {
   2852 	(void) pthread_mutex_lock(&door_server_cnt_lock);
   2853 	if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
   2854 	    pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
   2855 		door_server_cnt++;
   2856 		(void) pthread_mutex_unlock(&door_server_cnt_lock);
   2857 		return;
   2858 	}
   2859 
   2860 	(void) pthread_mutex_unlock(&door_server_cnt_lock);
   2861 }
   2862 
   2863 /*
   2864  * checkm4 - used to verify that the external utilities that
   2865  * syslogd depends on are where we expect them to be.
   2866  * Returns 0 if all utilities are found, > 0 if any are missing.
   2867  * Also logs errors so user knows what's missing
   2868  */
   2869 static int
   2870 checkm4(void)
   2871 {
   2872 	int notfound = 0;
   2873 	int saverrno;
   2874 	pthread_t mythreadno;
   2875 
   2876 	if (Debug) {
   2877 		mythreadno = pthread_self();
   2878 	}
   2879 
   2880 	if (access("/usr/ccs/bin/m4", X_OK) < 0) {
   2881 		saverrno = errno;
   2882 		logerror("/usr/ccs/bin/m4");
   2883 		DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access "
   2884 		    "returned %d\n", mythreadno, saverrno);
   2885 		notfound++;
   2886 	}
   2887 
   2888 	return (notfound);
   2889 }
   2890 
   2891 /*
   2892  *  INIT -- Initialize syslogd from configuration table, start up
   2893  *  input and logger threads. This routine is called only once.
   2894  */
   2895 static void
   2896 init(void)
   2897 {
   2898 	struct utsname *up;
   2899 	pthread_attr_t sys_attr, net_attr, log_attr, hnl_attr;
   2900 	int nthread;
   2901 	pthread_t mythreadno;
   2902 
   2903 	if (Debug) {
   2904 		mythreadno = pthread_self();
   2905 	}
   2906 
   2907 	DPRINT1(2, "init(%u): initializing\n", mythreadno);
   2908 
   2909 	/* hand-craft a host_list_t entry for our local host name */
   2910 	if ((up = malloc(sizeof (struct utsname))) == NULL) {
   2911 		MALLOC_FAIL_EXIT;
   2912 	}
   2913 	(void) uname(up);
   2914 	LocalHostName.hl_cnt = 1;
   2915 	if ((LocalHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
   2916 		MALLOC_FAIL_EXIT;
   2917 	}
   2918 	if ((LocalHostName.hl_hosts[0] = strdup(up->nodename)) == NULL) {
   2919 		free(LocalHostName.hl_hosts);
   2920 		MALLOC_FAIL_EXIT;
   2921 	}
   2922 	free(up);
   2923 	/* also hand craft one for use if name resolution fails */
   2924 	NullHostName.hl_cnt = 1;
   2925 	if ((NullHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
   2926 		MALLOC_FAIL_EXIT;
   2927 	}
   2928 	if ((NullHostName.hl_hosts[0] = strdup("name lookup failed")) == NULL) {
   2929 		MALLOC_FAIL_EXIT;
   2930 	}
   2931 
   2932 	hnc_init(0);
   2933 
   2934 	/*
   2935 	 * Note that getnets will allocate network resources, but won't be
   2936 	 * binding UDP port. This is because, there could be a race
   2937 	 * condition between door. If we bind here, one syslogd could grab
   2938 	 * UDP port first, but later another syslogd could take over without
   2939 	 * getting UDP port but grab the door file. The 2nd syslogd could
   2940 	 * continue to run without listening network.
   2941 	 * bindnet() will be called after door was successfully opened.
   2942 	 */
   2943 	getnets();
   2944 
   2945 	/*
   2946 	 * Start up configured theads
   2947 	 */
   2948 	conf_init();
   2949 
   2950 	/*
   2951 	 * allocate thread stacks for the persistant threads
   2952 	 */
   2953 	nthread = (turnoff == 0) ? 4 : 2;
   2954 
   2955 	if ((stack_ptr = alloc_stacks(nthread)) == NULL) {
   2956 		logerror("alloc_stacks failed - fatal");
   2957 		exit(1);
   2958 	}
   2959 
   2960 	if (Debug) {
   2961 		dumpstats(STDOUT_FILENO);
   2962 	}
   2963 
   2964 	(void) dataq_init(&inputq);	/* init the input queue */
   2965 
   2966 	if (pthread_attr_init(&sys_attr) != 0 ||
   2967 	    pthread_attr_init(&log_attr) != 0 ||
   2968 	    pthread_attr_init(&net_attr) != 0 ||
   2969 	    pthread_attr_init(&hnl_attr) != 0 ||
   2970 	    pthread_attr_init(&door_thr_attr) != 0) {
   2971 		logerror("pthread_attr_init failed - fatal");
   2972 		exit(1);
   2973 	}
   2974 
   2975 	(void) pthread_attr_setscope(&sys_attr, PTHREAD_SCOPE_PROCESS);
   2976 	(void) pthread_attr_setscope(&log_attr, PTHREAD_SCOPE_PROCESS);
   2977 	(void) pthread_attr_setscope(&net_attr, PTHREAD_SCOPE_PROCESS);
   2978 	(void) pthread_attr_setscope(&hnl_attr, PTHREAD_SCOPE_PROCESS);
   2979 	(void) pthread_attr_setscope(&door_thr_attr, PTHREAD_SCOPE_SYSTEM);
   2980 	(void) pthread_attr_setdetachstate(&door_thr_attr,
   2981 	    PTHREAD_CREATE_DETACHED);
   2982 
   2983 	/* 1: logmsg thread */
   2984 	(void) pthread_attr_setstacksize(&log_attr, stacksize);
   2985 	(void) pthread_attr_setstackaddr(&log_attr, stack_ptr);
   2986 	stack_ptr += stacksize + redzonesize;
   2987 	if (pthread_create(&log_thread, &log_attr, logmsg, NULL) != 0) {
   2988 		logerror("pthread_create failed - fatal");
   2989 		exit(1);
   2990 	}
   2991 
   2992 	/*
   2993 	 * open the log device, and pull up all pending message
   2994 	 * from the log driver.
   2995 	 */
   2996 	prepare_sys_poll();
   2997 
   2998 	/*
   2999 	 * Now we can deliver the pending internal error messages.
   3000 	 */
   3001 	enable_errorlog();
   3002 
   3003 	/* 2: sys_poll thread */
   3004 	(void) pthread_attr_setstacksize(&sys_attr, stacksize);
   3005 	(void) pthread_attr_setstackaddr(&sys_attr, stack_ptr);
   3006 	stack_ptr += stacksize + redzonesize;
   3007 	if (pthread_create(&sys_thread, &sys_attr, sys_poll, NULL) != 0) {
   3008 		logerror("pthread_create failed - fatal");
   3009 		exit(1);
   3010 	}
   3011 
   3012 	/*
   3013 	 * We've started the sys_poll() and logmsg() threads.  Now we are ready
   3014 	 * to open the door.  This cannot happen before spawning sys_poll(),
   3015 	 * because after opening the door, syslog() will no longer take care of
   3016 	 * LOG_CONS.  Therefor, we should pull up all pending log messages and
   3017 	 * activate sys_poll() before opening the door, so that log driver
   3018 	 * won't drop messages.
   3019 	 */
   3020 	open_door();
   3021 
   3022 	DPRINT1(1, "init(%u): accepting messages from local system\n",
   3023 	    mythreadno);
   3024 
   3025 	if (turnoff == 0) {
   3026 		/* init the hostname lookup queue */
   3027 		(void) dataq_init(&hnlq);
   3028 
   3029 		/* 3: hostname lookup thread */
   3030 		(void) pthread_attr_setstacksize(&hnl_attr, stacksize);
   3031 		(void) pthread_attr_setstackaddr(&hnl_attr, stack_ptr);
   3032 		stack_ptr += stacksize + redzonesize;
   3033 		if (pthread_create(&hnl_thread, &hnl_attr,
   3034 		    hostname_lookup, NULL) != 0) {
   3035 			logerror("pthread_create failed - fatal");
   3036 			exit(1);
   3037 		}
   3038 
   3039 		/* 4: net_poll thread */
   3040 		(void) pthread_attr_setstacksize(&net_attr, stacksize);
   3041 		(void) pthread_attr_setstackaddr(&net_attr, stack_ptr);
   3042 		stack_ptr += stacksize + redzonesize;
   3043 
   3044 		/* grab UDP port */
   3045 		bindnet();
   3046 
   3047 		if (pthread_create(&net_thread, &net_attr, net_poll,
   3048 		    NULL) != 0) {
   3049 			logerror("pthread_create failed - fatal");
   3050 			exit(1);
   3051 		}
   3052 		DPRINT1(1, "init(%u): accepting messages from remote\n",
   3053 		    mythreadno);
   3054 	}
   3055 
   3056 	(void) pthread_attr_destroy(&sys_attr);
   3057 	(void) pthread_attr_destroy(&net_attr);
   3058 	(void) pthread_attr_destroy(&log_attr);
   3059 	(void) pthread_attr_destroy(&hnl_attr);
   3060 
   3061 	curalarm = MarkInterval * 60 / MARKCOUNT;
   3062 	(void) alarm((unsigned)curalarm);
   3063 	DPRINT2(2, "init(%u): Next alarm in %d seconds\n",
   3064 	    mythreadno, curalarm);
   3065 	DPRINT1(1, "init(%u): syslogd: started\n", mythreadno);
   3066 }
   3067 
   3068 /*
   3069  * will print a bunch of debugging stats on 'fd'
   3070  */
   3071 static void
   3072 dumpstats(int fd)
   3073 {
   3074 	FILE *out;
   3075 	struct filed *f;
   3076 	int i;
   3077 	char users[1024];
   3078 	char cbuf[30];
   3079 	char *dashes = "------------------------";
   3080 	static int conversion_printed;
   3081 
   3082 	if ((out = fdopen(fd, "w+")) == NULL)
   3083 		return;
   3084 
   3085 	(void) fprintf(out, "\nSyslogd started: %s",
   3086 	    ctime_r(&start_time, cbuf));
   3087 	(void) fprintf(out, "Input message count: system %d, network %d\n",
   3088 	    sys_msg_count, net_msg_count);
   3089 	(void) fprintf(out, "# Outputs: %d\n\n", nlogs);
   3090 
   3091 	(void) fprintf(out, "%s priority = [file, facility] %s\n\n",
   3092 	    dashes, dashes);
   3093 
   3094 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
   3095 		(void) fprintf(out, "%d ", i / 10);
   3096 	}
   3097 	(void) fprintf(out, "\n");
   3098 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
   3099 		(void) fprintf(out, "%d ", i % 10);
   3100 	}
   3101 	(void) fprintf(out, "\n");
   3102 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
   3103 		(void) fprintf(out, "--");
   3104 	}
   3105 	(void) fprintf(out, "\n");
   3106 
   3107 	for (f = Files; f < &Files[nlogs]; f++) {
   3108 		for (i = 0; i < LOG_NFACILITIES + 1; i++) {
   3109 			if (f->f_pmask[i] == NOPRI)
   3110 				(void) fprintf(out, "X ");
   3111 			else
   3112 				(void) fprintf(out, "%d ",
   3113 				    f->f_pmask[i]);
   3114 		}
   3115 		(void) fprintf(out, "%s: ", TypeNames[f->f_type]);
   3116 		switch (f->f_type) {
   3117 		case F_FILE:
   3118 		case F_TTY:
   3119 		case F_CONSOLE:
   3120 			(void) fprintf(out, "%s", f->f_un.f_fname);
   3121 			break;
   3122 		case F_FORW:
   3123 			(void) fprintf(out, "%s", f->f_un.f_forw.f_hname);
   3124 			break;
   3125 		case F_USERS:
   3126 			for (i = 0; i < MAXUNAMES &&
   3127 			    *f->f_un.f_uname[i]; i++) {
   3128 				if (!i)
   3129 					(void) fprintf(out, "%s",
   3130 					    f->f_un.f_uname[i]);
   3131 				else
   3132 					(void) fprintf(out, ", %s",
   3133 					    f->f_un.f_uname[i]);
   3134 			}
   3135 			break;
   3136 		}
   3137 		(void) fprintf(out, "\n");
   3138 	}
   3139 
   3140 	if (!conversion_printed) {
   3141 		(void) fprintf(out, "\nFacilities:\n");
   3142 
   3143 		for (i = 0; FacNames[i].c_val != -1; i++) {
   3144 			(void) fprintf(out, "  [%02d] %s: %3d\n", i,
   3145 			    FacNames[i].c_name, FacNames[i].c_val);
   3146 		}
   3147 
   3148 		(void) fprintf(out, "\nPriorities:\n");
   3149 
   3150 		for (i = 0; PriNames[i].c_val != -1; i++) {
   3151 			(void) fprintf(out, "  [%02d] %s: %3d\n", i,
   3152 			    PriNames[i].c_name, PriNames[i].c_val);
   3153 		}
   3154 
   3155 		conversion_printed = 1;
   3156 	}
   3157 
   3158 	(void) fprintf(out, "\n\n\n\t\tPer File Statistics\n");
   3159 	(void) fprintf(out, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File");
   3160 	(void) fprintf(out, "%-24s\t---\t----\t-----\t----\n", "----");
   3161 	for (f = Files; f < &Files[nlogs]; f++) {
   3162 		switch (f->f_type) {
   3163 		case F_FILE:
   3164 		case F_TTY:
   3165 		case F_CONSOLE:
   3166 			(void) fprintf(out, "%-24s", f->f_un.f_fname);
   3167 			break;
   3168 		case F_WALL:
   3169 			(void) fprintf(out, "%-24s", TypeNames[f->f_type]);
   3170 			break;
   3171 		case F_FORW:
   3172 			(void) fprintf(out, "%-24s", f->f_un.f_forw.f_hname);
   3173 			break;
   3174 		case F_USERS:
   3175 			for (i = 0; i < MAXUNAMES &&
   3176 			    *f->f_un.f_uname[i]; i++) {
   3177 				if (!i)
   3178 					(void) strcpy(users,
   3179 					    f->f_un.f_uname[i]);
   3180 				else {
   3181 					(void) strcat(users, ",");
   3182 					(void) strcat(users,
   3183 					    f->f_un.f_uname[i]);
   3184 				}
   3185 			}
   3186 			(void) fprintf(out, "%-24s", users);
   3187 			break;
   3188 		}
   3189 		(void) fprintf(out, "\t%d\t%d\t%d\t%d\n",
   3190 		    f->f_stat.total, f->f_stat.dups,
   3191 		    f->f_stat.cantfwd, f->f_stat.errs);
   3192 	}
   3193 	(void) fprintf(out, "\n\n");
   3194 	if (Debug && fd == 1)
   3195 		return;
   3196 	(void) fclose(out);
   3197 }
   3198 
   3199 /*
   3200  * conf_init - This routine is code seperated from the
   3201  * init routine in order to be re-callable when we get
   3202  * a SIGHUP signal.
   3203  */
   3204 static void
   3205 conf_init(void)
   3206 {
   3207 	char *p;
   3208 	int i;
   3209 	struct filed *f;
   3210 	char *m4argv[4];
   3211 	int m4argc = 0;
   3212 	conf_t cf;
   3213 	pthread_t mythreadno;
   3214 
   3215 	if (Debug) {
   3216 		mythreadno = pthread_self();
   3217 	}
   3218 
   3219 	DPRINT1(2, "conf_init(%u): starting logger threads\n",
   3220 	    mythreadno);
   3221 
   3222 	m4argv[m4argc++] = "m4";
   3223 
   3224 	if (amiloghost() == 1) {
   3225 		DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno);
   3226 		m4argv[m4argc++] = "-DLOGHOST=1";
   3227 	}
   3228 
   3229 	m4argv[m4argc++] = ConfFile;
   3230 	m4argv[m4argc] = NULL;
   3231 
   3232 	/*
   3233 	 * Make sure the configuration file and m4 exist, and then parse
   3234 	 * the configuration file with m4.  If any of these fail, resort
   3235 	 * to our hardcoded fallback configuration.
   3236 	 */
   3237 
   3238 	if (access(ConfFile, R_OK) == -1) {
   3239 		DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno,
   3240 		    ConfFile);
   3241 		logerror("can't open configuration file");
   3242 		/* CSTYLED */
   3243 		Files = (struct filed *) &fallback; /*lint !e545 */
   3244 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
   3245 		cfline("*.PANIC\t*", 0, &Files[1]);
   3246 		nlogs = 2;
   3247 		goto nofile;
   3248 	}
   3249 
   3250 	if (checkm4() != 0 || conf_open(&cf, "/usr/ccs/bin/m4", m4argv) == -1) {
   3251 		DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno,
   3252 		    ConfFile);
   3253 		/* CSTYLED */
   3254 		Files = (struct filed *) &fallback; /*lint !e545 */
   3255 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
   3256 		cfline("*.PANIC\t*", 0, &Files[1]);
   3257 		nlogs = 2;
   3258 		goto nofile;
   3259 	}
   3260 
   3261 	/* Count the number of lines which are not blanks or comments */
   3262 	nlogs = 0;
   3263 	while ((p = conf_read(&cf)) != NULL) {
   3264 		if (p[0] != '\0' && p[0] != '#')
   3265 			nlogs++;
   3266 	}
   3267 
   3268 	Files = (struct filed *)malloc(sizeof (struct filed) * nlogs);
   3269 
   3270 	if (!Files) {
   3271 		DPRINT1(1, "conf_init(%u): malloc failed - can't "
   3272 		    "allocate 'Files' array\n", mythreadno);
   3273 		MALLOC_FAIL("loading minimum configuration");
   3274 		/* CSTYLED */
   3275 		Files = (struct filed *) &fallback; /*lint !e545 */
   3276 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
   3277 		cfline("*.PANIC\t*", 0, &Files[1]);
   3278 		nlogs = 2;
   3279 		conf_close(&cf);
   3280 		goto nofile;
   3281 	}
   3282 
   3283 	/*
   3284 	 *  Foreach line in the conf table, open that file.
   3285 	 */
   3286 	conf_rewind(&cf);
   3287 	f = Files;
   3288 	i = 0;
   3289 	while (((p = conf_read(&cf)) != NULL) && (f < &Files[nlogs])) {
   3290 		i++;
   3291 		/* check for end-of-section */
   3292 		if (p[0] == '\0' || p[0] == '#')
   3293 			continue;
   3294 
   3295 		cfline(p, i, f);
   3296 		if (f->f_type == F_UNUSED)
   3297 			nlogs--;
   3298 		else
   3299 			f++;
   3300 	}
   3301 
   3302 	conf_close(&cf);
   3303 
   3304 	/*
   3305 	 * See if marks are to be written to any files.  If so, set up a
   3306 	 * timeout for marks.
   3307 	 */
   3308 nofile:
   3309 	Marking = 0;
   3310 
   3311 	/*
   3312 	 * allocate thread stacks - one for each logger thread.
   3313 	 */
   3314 	if ((cstack_ptr = alloc_stacks(nlogs)) == NULL) {
   3315 		logerror("alloc_stacks failed - fatal");
   3316 		exit(1);
   3317 	}
   3318 
   3319 	/* And now one thread for each configured file */
   3320 	for (f = Files; f < &Files[nlogs]; f++) {
   3321 		if (filed_init(f) != 0) {
   3322 			logerror("pthread_create failed - fatal");
   3323 			exit(1);
   3324 		}
   3325 
   3326 		(void) pthread_mutex_lock(&cft);
   3327 		++conf_threads;
   3328 		(void) pthread_mutex_unlock(&cft);
   3329 
   3330 		if (f->f_type != F_UNUSED &&
   3331 		    f->f_pmask[LOG_NFACILITIES] != NOPRI)
   3332 			Marking = 1;
   3333 	}
   3334 }
   3335 
   3336 /*
   3337  * filed init - initialize fields in a file descriptor struct
   3338  * this is called before multiple threads are running, so no mutex
   3339  * needs to be held at this time.
   3340  */
   3341 static int
   3342 filed_init(struct filed *f)
   3343 {
   3344 	pthread_attr_t stack_attr;
   3345 	pthread_t mythreadno;
   3346 
   3347 	if (Debug) {
   3348 		mythreadno = pthread_self();
   3349 	}
   3350 
   3351 	if (pthread_mutex_init(&f->filed_mutex, NULL) != 0) {
   3352 		logerror("pthread_mutex_init failed");
   3353 		return (-1);
   3354 	}
   3355 
   3356 	DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n",
   3357 	    mythreadno, (void *)&f->f_queue);
   3358 	(void) dataq_init(&f->f_queue);
   3359 
   3360 	if (pthread_attr_init(&stack_attr) != 0) {
   3361 		logerror("pthread_attr_init failed");
   3362 		return (-1);
   3363 	}
   3364 
   3365 	(void) pthread_attr_setstacksize(&stack_attr, stacksize);
   3366 	(void) pthread_attr_setstackaddr(&stack_attr, cstack_ptr);
   3367 	cstack_ptr += stacksize + redzonesize;
   3368 
   3369 	f->f_msgflag = 0;
   3370 	f->f_prevmsg.msg[0] = '\0';
   3371 	f->f_prevmsg.flags = 0;
   3372 	f->f_prevmsg.pri = 0;
   3373 	f->f_prevmsg.host[0] = '\0';
   3374 
   3375 	f->f_current.msg[0] = '\0';
   3376 	f->f_current.flags = 0;
   3377 	f->f_current.pri = 0;
   3378 	f->f_current.host[0] = '\0';
   3379 
   3380 	f->f_prevcount = 0;
   3381 
   3382 	f->f_stat.flag = 0;
   3383 	f->f_stat.total = 0;
   3384 	f->f_stat.dups = 0;
   3385 	f->f_stat.cantfwd = 0;
   3386 	f->f_stat.errs = 0;
   3387 
   3388 	if (pthread_create(&f->f_thread, NULL, logit, (void *)f) != 0) {
   3389 		logerror("pthread_create failed");
   3390 		(void) pthread_attr_destroy(&stack_attr);
   3391 		return (-1);
   3392 	}
   3393 
   3394 	(void) pthread_attr_destroy(&stack_attr);
   3395 	return (0);
   3396 }
   3397 
   3398 
   3399 /*
   3400  * Crack a configuration file line
   3401  */
   3402 static void
   3403 cfline(char *line, int lineno, struct filed *f)
   3404 {
   3405 	char *p;
   3406 	char *q;
   3407 	int i;
   3408 	char *bp;
   3409 	int pri;
   3410 	char buf[MAXLINE];
   3411 	char ebuf[SYS_NMLN+1+40];
   3412 	mode_t fmode, omode = O_WRONLY|O_APPEND|O_NOCTTY;
   3413 	struct stat64 sbuf;
   3414 	pthread_t mythreadno;
   3415 
   3416 	if (Debug) {
   3417 		mythreadno = pthread_self();
   3418 	}
   3419 
   3420 	DPRINT2(1, "cfline(%u): (%s)\n", mythreadno, line);
   3421 
   3422 	errno = 0;	/* keep errno related stuff out of logerror messages */
   3423 
   3424 	/* clear out file entry */
   3425 	bzero((char *)f, sizeof (*f));
   3426 	for (i = 0; i <= LOG_NFACILITIES; i++)
   3427 		f->f_pmask[i] = NOPRI;
   3428 
   3429 	/* scan through the list of selectors */
   3430 	for (p = line; *p && *p != '\t'; ) {
   3431 
   3432 		/* find the end of this facility name list */
   3433 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
   3434 			continue;
   3435 
   3436 		/* collect priority name */
   3437 		for (bp = buf; *q && !strchr("\t,;", *q); )
   3438 			*bp++ = *q++;
   3439 		*bp = '\0';
   3440 
   3441 		/* skip cruft */
   3442 		while (strchr(", ;", *q))
   3443 			q++;
   3444 
   3445 		/* decode priority name */
   3446 		pri = decode(buf, PriNames);
   3447 		if (pri < 0) {
   3448 			logerror("line %d: unknown priority name \"%s\"",
   3449 			    lineno, buf);
   3450 			return;
   3451 		}
   3452 
   3453 		/* scan facilities */
   3454 		while (*p && !strchr("\t.;", *p)) {
   3455 			for (bp = buf; *p && !strchr("\t,;.", *p); )
   3456 				*bp++ = *p++;
   3457 			*bp = '\0';
   3458 			if (*buf == '*')
   3459 				for (i = 0; i < LOG_NFACILITIES; i++)
   3460 					f->f_pmask[i] = (uchar_t)pri;
   3461 			else {
   3462 				i = decode(buf, FacNames);
   3463 				if (i < 0) {
   3464 					logerror("line %d: unknown facility"
   3465 					    " name \"%s\"", lineno, buf);
   3466 					return;
   3467 				}
   3468 				f->f_pmask[i >> 3] = (uchar_t)pri;
   3469 			}
   3470 			while (*p == ',' || *p == ' ')
   3471 				p++;
   3472 		}
   3473 
   3474 		p = q;
   3475 	}
   3476 
   3477 	/* skip to action part */
   3478 	while (*p == '\t' || *p == ' ')
   3479 		p++;
   3480 
   3481 	switch (*p) {
   3482 	case '\0':
   3483 		errno = 0;
   3484 		logerror("line %d: no action part", lineno);
   3485 		break;
   3486 
   3487 	case '@':
   3488 		(void) strlcpy(f->f_un.f_forw.f_hname, ++p, SYS_NMLN);
   3489 		if (logforward(f, ebuf, sizeof (ebuf)) != 0) {
   3490 			logerror("line %d: %s", lineno, ebuf);
   3491 			break;
   3492 		}
   3493 		f->f_type = F_FORW;
   3494 		break;
   3495 
   3496 	case '/':
   3497 		(void) strlcpy(f->f_un.f_fname, p, MAXPATHLEN);
   3498 		if (stat64(p, &sbuf) < 0) {
   3499 			logerror(p);
   3500 			break;
   3501 		}
   3502 		/*
   3503 		 * don't block trying to open a pipe
   3504 		 * with no reader on the other end
   3505 		 */
   3506 		fmode = 0; 	/* reset each pass */
   3507 		if (S_ISFIFO(sbuf.st_mode))
   3508 			fmode = O_NONBLOCK;
   3509 
   3510 		f->f_file = open64(p, omode|fmode);
   3511 		if (f->f_file < 0) {
   3512 			if (fmode && errno == ENXIO) {
   3513 				errno = 0;
   3514 				logerror("%s - no reader", p);
   3515 			} else
   3516 				logerror(p);
   3517 			break;
   3518 		}
   3519 
   3520 		/*
   3521 		 * Fifos are initially opened NONBLOCK
   3522 		 * to insure we don't hang, but once
   3523 		 * we are open, we need to change the
   3524 		 * behavior back to blocking, otherwise
   3525 		 * we may get write errors, and the log
   3526 		 * will get closed down the line.
   3527 		 */
   3528 		if (S_ISFIFO(sbuf.st_mode))
   3529 			(void) fcntl(f->f_file, F_SETFL, omode);
   3530 
   3531 		if (isatty(f->f_file)) {
   3532 			f->f_type = F_TTY;
   3533 			untty();
   3534 		} else
   3535 			f->f_type = F_FILE;
   3536 
   3537 		if ((strcmp(p, ctty) == 0) || (strcmp(p, sysmsg) == 0))
   3538 			f->f_type = F_CONSOLE;
   3539 		break;
   3540 
   3541 	case '*':
   3542 		f->f_type = F_WALL;
   3543 		break;
   3544 
   3545 	default:
   3546 		for (i = 0; i < MAXUNAMES && *p; i++) {
   3547 			for (q = p; *q && *q != ','; )
   3548 				q++;
   3549 			(void) strlcpy(f->f_un.f_uname[i], p, UNAMESZ);
   3550 			if ((q - p) > UNAMESZ)
   3551 				f->f_un.f_uname[i][UNAMESZ] = '\0';
   3552 			else
   3553 				f->f_un.f_uname[i][q - p] = '\0';
   3554 			while (*q == ',' || *q == ' ')
   3555 				q++;
   3556 			p = q;
   3557 		}
   3558 		f->f_type = F_USERS;
   3559 		break;
   3560 	}
   3561 	f->f_orig_type = f->f_type;
   3562 }
   3563 
   3564 
   3565 /*
   3566  *  Decode a symbolic name to a numeric value
   3567  */
   3568 static int
   3569 decode(char *name, struct code *codetab)
   3570 {
   3571 	struct code *c;
   3572 	char *p;
   3573 	char buf[40];
   3574 
   3575 	if (isdigit(*name))
   3576 		return (atoi(name));
   3577 
   3578 	(void) strncpy(buf, name, sizeof (buf) - 1);
   3579 	for (p = buf; *p; p++)
   3580 		if (isupper(*p))
   3581 			*p = tolower(*p);
   3582 	for (c = codetab; c->c_name; c++)
   3583 		if (!(strcmp(buf, c->c_name)))
   3584 			return (c->c_val);
   3585 
   3586 	return (-1);
   3587 }
   3588 
   3589 static int
   3590 ismyaddr(struct netbuf *nbp)
   3591 {
   3592 	int i;
   3593 
   3594 	if (nbp == NULL)
   3595 		return (0);
   3596 
   3597 	for (i = 1; i < Ninputs; i++) {
   3598 		if (same_addr(nbp, Myaddrs[i]))
   3599 			return (1);
   3600 	}
   3601 	return (0);
   3602 }
   3603 
   3604 static void
   3605 getnets(void)
   3606 {
   3607 	struct nd_hostserv hs;
   3608 	struct netconfig *ncp;
   3609 	struct nd_addrlist *nap;
   3610 	struct netbuf *nbp;
   3611 	int i, inputs;
   3612 	void *handle;
   3613 	char *uap;
   3614 	pthread_t mythreadno;
   3615 
   3616 	if (Debug) {
   3617 		mythreadno = pthread_self();
   3618 	}
   3619 
   3620 	if (turnoff) {
   3621 		DPRINT1(1, "getnets(%u): network is being turned off\n",
   3622 		    mythreadno);
   3623 		return;
   3624 	}
   3625 
   3626 	hs.h_host = HOST_SELF;
   3627 	hs.h_serv = "syslog";
   3628 
   3629 	if ((handle = setnetconfig()) == NULL) {
   3630 		return;
   3631 	}
   3632 
   3633 	while ((ncp = getnetconfig(handle)) != NULL) {
   3634 		if (ncp->nc_semantics != NC_TPI_CLTS) {
   3635 			continue;
   3636 		}
   3637 
   3638 		if (netdir_getbyname(ncp, &hs, &nap) != 0) {
   3639 			continue;
   3640 		}
   3641 
   3642 		if (nap == NULL || nap->n_cnt <= 0) {
   3643 			DPRINT1(1, "getnets(%u): found no address\n",
   3644 			    mythreadno);
   3645 			netdir_free((void *)nap, ND_ADDRLIST);
   3646 			continue;
   3647 		}
   3648 
   3649 		if (Debug) {
   3650 			DPRINT2(1, "getnets(%u): found %d addresses",
   3651 			    mythreadno, nap->n_cnt);
   3652 			DPRINT0(1, ", they are: ");
   3653 			nbp = nap->n_addrs;
   3654 
   3655 			for (i = 0; i < nap->n_cnt; i++) {
   3656 				if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
   3657 					DPRINT1(1, "%s ", uap);
   3658 					free(uap);
   3659 				}
   3660 				nbp++;
   3661 			}
   3662 
   3663 			DPRINT0(1, "\n");
   3664 		}
   3665 
   3666 		inputs = Ninputs + nap->n_cnt;
   3667 
   3668 		Nfd = realloc(Nfd, inputs * sizeof (struct pollfd));
   3669 		Ncf = realloc(Ncf, inputs * sizeof (struct netconfig));
   3670 		Myaddrs = realloc(Myaddrs, inputs * sizeof (struct netbuf *));
   3671 		Udp = realloc(Udp, inputs * sizeof (struct t_unitdata *));
   3672 		Errp = realloc(Errp, inputs * sizeof (struct t_uderr *));
   3673 
   3674 		/*
   3675 		 * all malloc failures here are fatal
   3676 		 */
   3677 		if (Nfd == NULL || Ncf == NULL || Myaddrs == NULL ||
   3678 		    Udp == NULL || Errp == NULL) {
   3679 			MALLOC_FAIL_EXIT;
   3680 		}
   3681 
   3682 		nbp = nap->n_addrs;
   3683 
   3684 		for (i = 0; i < nap->n_cnt; i++, nbp++) {
   3685 			char ebuf[128];
   3686 
   3687 			if (addnet(ncp, nbp) == 0) {
   3688 				/* no error */
   3689 				continue;
   3690 			}
   3691 
   3692 			(void) strcpy(ebuf, "Unable to configure syslog port");
   3693 
   3694 			if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
   3695 				size_t l = strlen(ebuf);
   3696 				(void) snprintf(ebuf + l, sizeof (ebuf) - l,
   3697 				    " for %s", uap);
   3698 			}
   3699 
   3700 			DPRINT2(1, "getnets(%u): %s",
   3701 			    mythreadno, ebuf);
   3702 
   3703 			if (uap) {
   3704 				free(uap);
   3705 			}
   3706 
   3707 			logerror(ebuf);
   3708 			/*
   3709 			 * Here maybe syslogd can quit. However, syslogd
   3710 			 * has been ignoring this error and keep running.
   3711 			 * So we won't break it.
   3712 			 */
   3713 		}
   3714 
   3715 		netdir_free((void *)nap, ND_ADDRLIST);
   3716 	}
   3717 
   3718 	(void) endnetconfig(handle);
   3719 }
   3720 
   3721 /*
   3722  * Open the network device, and allocate necessary resources.
   3723  * Myaddrs will also be filled, so that we can call ismyaddr() before
   3724  * being bound to the network.
   3725  */
   3726 static int
   3727 addnet(struct netconfig *ncp, struct netbuf *nbp)
   3728 {
   3729 	int fd;
   3730 	struct netbuf *bp;
   3731 
   3732 	fd = t_open(ncp->nc_device, O_RDWR, NULL);
   3733 
   3734 	if (fd < 0) {
   3735 		return (1);
   3736 	}
   3737 
   3738 	(void) memcpy(&Ncf[Ninputs], ncp, sizeof (struct netconfig));
   3739 
   3740 	/*LINTED*/
   3741 	Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR);
   3742 
   3743 	if (Udp[Ninputs] == NULL) {
   3744 		(void) t_close(fd);
   3745 		return (1);
   3746 	}
   3747 
   3748 	/*LINTED*/
   3749 	Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR);
   3750 
   3751 	if (Errp[Ninputs] == NULL) {
   3752 		(void) t_close(fd);
   3753 		(void) t_free((char *)Udp[Ninputs], T_UNITDATA);
   3754 		return (1);
   3755 	}
   3756 
   3757 	if ((bp = malloc(sizeof (struct netbuf))) == NULL ||
   3758 	    (bp->buf = malloc(nbp->len)) == NULL) {
   3759 		MALLOC_FAIL("allocating address buffer");
   3760 		(void) t_close(fd);
   3761 		(void) t_free((char *)Udp[Ninputs], T_UNITDATA);
   3762 		(void) t_free((char *)Errp[Ninputs], T_UDERROR);
   3763 
   3764 		if (bp) {
   3765 			free(bp);
   3766 		}
   3767 
   3768 		return (1);
   3769 	}
   3770 
   3771 	bp->len = nbp->len;
   3772 	(void) memcpy(bp->buf, nbp->buf, nbp->len);
   3773 	Myaddrs[Ninputs] = bp;
   3774 
   3775 	Nfd[Ninputs].fd = fd;
   3776 	Nfd[Ninputs].events = POLLIN;
   3777 	Ninputs++;
   3778 	return (0);
   3779 }
   3780 
   3781 /*
   3782  * Allocate UDP buffer to minimize packet loss.
   3783  */
   3784 static void
   3785 set_udp_buffer(int fd)
   3786 {
   3787 	struct t_optmgmt req, resp;
   3788 	struct opthdr *opt;
   3789 	size_t optsize, bsize = 256 * 1024;
   3790 	pthread_t mythreadno;
   3791 
   3792 	if (Debug) {
   3793 		mythreadno = pthread_self();
   3794 	}
   3795 
   3796 	optsize = sizeof (struct opthdr) + sizeof (int);
   3797 	if ((opt = malloc(optsize)) == NULL) {
   3798 		MALLOC_FAIL("will have no udp buffer");
   3799 		return;
   3800 	}
   3801 	opt->level = SOL_SOCKET;
   3802 	opt->name = SO_RCVBUF;
   3803 	opt->len = sizeof (int);
   3804 	*(int *)(opt + 1) = bsize;
   3805 
   3806 	req.flags = T_NEGOTIATE;
   3807 	req.opt.len = optsize;
   3808 	req.opt.buf = (char *)opt;
   3809 
   3810 	resp.flags = 0;
   3811 	resp.opt.maxlen = optsize;
   3812 	resp.opt.buf = (char *)opt;
   3813 
   3814 	while (t_optmgmt(fd, &req, &resp) == -1 || resp.flags != T_SUCCESS) {
   3815 		if (t_errno != TSYSERR || errno != ENOBUFS) {
   3816 			bsize = 0;
   3817 			break;
   3818 		}
   3819 		bsize >>= 1;
   3820 		if (bsize < 8192) {
   3821 			break;
   3822 		}
   3823 		*(int *)(opt + 1) = bsize;
   3824 	}
   3825 	if (bsize == 0) {
   3826 		logerror("failed to allocate UDP buffer");
   3827 	}
   3828 	DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n",
   3829 	    mythreadno, bsize, fd);
   3830 	free(opt);
   3831 }
   3832 
   3833 /*
   3834  * Attach the network, and allocate UDP buffer for the interface.
   3835  */
   3836 static void
   3837 bindnet(void)
   3838 {
   3839 	struct t_bind bind, *bound;
   3840 	int cnt, i;
   3841 	char *uap;
   3842 	pthread_t mythreadno;
   3843 
   3844 	if (Debug) {
   3845 		mythreadno = pthread_self();
   3846 	}
   3847 
   3848 	cnt = 0;
   3849 
   3850 	while (cnt < Ninputs) {
   3851 		char ebuf[128];
   3852 
   3853 		/*LINTED*/
   3854 		bound  = (struct t_bind *)t_alloc(Nfd[cnt].fd, T_BIND, T_ADDR);
   3855 		bind.addr = *Myaddrs[cnt];
   3856 		bind.qlen = 0;
   3857 
   3858 		if (t_bind(Nfd[cnt].fd, &bind, bound) == 0) {
   3859 			if (same_addr(&bind.addr, &bound->addr)) {
   3860 				(void) t_free((char *)bound, T_BIND);
   3861 				set_udp_buffer(Nfd[cnt].fd);
   3862 				cnt++;
   3863 				continue;
   3864 			}
   3865 		}
   3866 
   3867 		/* failed to bind port */
   3868 		(void) t_free((char *)bound, T_BIND);
   3869 
   3870 		(void) strcpy(ebuf, "Unable to bind syslog port");
   3871 
   3872 		uap = taddr2uaddr(&Ncf[cnt], Myaddrs[cnt]);
   3873 		if (uap) {
   3874 			i = strlen(ebuf);
   3875 			(void) snprintf(ebuf + i, sizeof (ebuf) - i,
   3876 			    " for %s", uap);
   3877 		}
   3878 
   3879 		DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n",
   3880 		    mythreadno, uap ? uap : "<unknown>");
   3881 
   3882 		if (uap) {
   3883 			free(uap);
   3884 		}
   3885 
   3886 		errno = 0;
   3887 		logerror(ebuf);
   3888 
   3889 		(void) t_close(Nfd[cnt].fd);
   3890 		free(Myaddrs[cnt]->buf);
   3891 		free(Myaddrs[cnt]);
   3892 		(void) t_free((char *)Udp[cnt], T_UNITDATA);
   3893 		(void) t_free((char *)Errp[cnt], T_UDERROR);
   3894 
   3895 		for (i = cnt; i < (Ninputs-1); i++) {
   3896 			Nfd[i] = Nfd[i + 1];
   3897 			Ncf[i] = Ncf[i + 1];
   3898 			Myaddrs[i] = Myaddrs[i + 1];
   3899 			Udp[i] = Udp[i + 1];
   3900 			Errp[i] = Errp[i + 1];
   3901 		}
   3902 
   3903 		Ninputs--;
   3904 	}
   3905 }
   3906 
   3907 static int
   3908 logforward(struct filed *f, char *ebuf, size_t elen)
   3909 {
   3910 	struct nd_hostserv hs;
   3911 	struct netbuf *nbp;
   3912 	struct netconfig *ncp;
   3913 	struct nd_addrlist *nap;
   3914 	void *handle;
   3915 	char *hp;
   3916 
   3917 	hp = f->f_un.f_forw.f_hname;
   3918 	hs.h_host = hp;
   3919 	hs.h_serv = "syslog";
   3920 
   3921 	if ((handle = setnetconfig()) == NULL) {
   3922 		(void) strlcpy(ebuf,
   3923 		    "unable to rewind the netconfig database", elen);
   3924 		errno = 0;
   3925 		return (-1);
   3926 	}
   3927 	nap = (struct nd_addrlist *)NULL;
   3928 	while ((ncp = getnetconfig(handle)) != NULL) {
   3929 		if (ncp->nc_semantics == NC_TPI_CLTS) {
   3930 			if (netdir_getbyname(ncp, &hs, &nap) == 0) {
   3931 				if (!nap)
   3932 					continue;
   3933 				nbp = nap->n_addrs;
   3934 				break;
   3935 			}
   3936 		}
   3937 	}
   3938 	if (ncp == NULL) {
   3939 		(void) endnetconfig(handle);
   3940 		(void) snprintf(ebuf, elen,
   3941 		    "WARNING: %s could not be resolved", hp);
   3942 		errno = 0;
   3943 		return (-1);
   3944 	}
   3945 	if (nap == (struct nd_addrlist *)NULL) {
   3946 		(void) endnetconfig(handle);
   3947 		(void) snprintf(ebuf, elen, "unknown host %s", hp);
   3948 		errno = 0;
   3949 		return (-1);
   3950 	}
   3951 	/* CSTYLED */
   3952 	if (ismyaddr(nbp)) { /*lint !e644 */
   3953 		netdir_free((void *)nap, ND_ADDRLIST);
   3954 		(void) endnetconfig(handle);
   3955 		(void) snprintf(ebuf, elen,
   3956 		    "host %s is this host - logging loop", hp);
   3957 		errno = 0;
   3958 		return (-1);
   3959 	}
   3960 	f->f_un.f_forw.f_addr.buf = malloc(nbp->len);
   3961 	if (f->f_un.f_forw.f_addr.buf == NULL) {
   3962 		netdir_free((void *)nap, ND_ADDRLIST);
   3963 		(void) endnetconfig(handle);
   3964 		(void) strlcpy(ebuf, "malloc failed", elen);
   3965 		return (-1);
   3966 	}
   3967 	bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len);
   3968 	f->f_un.f_forw.f_addr.len = nbp->len;
   3969 	f->f_file = t_open(ncp->nc_device, O_RDWR, NULL);
   3970 	if (f->f_file < 0) {
   3971 		netdir_free((void *)nap, ND_ADDRLIST);
   3972 		(void) endnetconfig(handle);
   3973 		free(f->f_un.f_forw.f_addr.buf);
   3974 		(void) strlcpy(ebuf, "t_open", elen);
   3975 		return (-1);
   3976 	}
   3977 	netdir_free((void *)nap, ND_ADDRLIST);
   3978 	(void) endnetconfig(handle);
   3979 	if (t_bind(f->f_file, NULL, NULL) < 0) {
   3980 		(void) strlcpy(ebuf, "t_bind", elen);
   3981 		free(f->f_un.f_forw.f_addr.buf);
   3982 		(void) t_close(f->f_file);
   3983 		return (-1);
   3984 	}
   3985 	return (0);
   3986 }
   3987 
   3988 static int
   3989 amiloghost(void)
   3990 {
   3991 	struct nd_hostserv hs;
   3992 	struct netconfig *ncp;
   3993 	struct nd_addrlist *nap;
   3994 	struct netbuf *nbp;
   3995 	int i, fd;
   3996 	void *handle;
   3997 	char *uap;
   3998 	struct t_bind bind, *bound;
   3999 	pthread_t mythreadno;
   4000 
   4001 	if (Debug) {
   4002 		mythreadno = pthread_self();
   4003 	}
   4004 
   4005 	/*
   4006 	 * we need to know if we are running on the loghost. This is
   4007 	 * checked by binding to the address associated with "loghost"
   4008 	 * and "syslogd" service over the connectionless transport
   4009 	 */
   4010 	hs.h_host = "loghost";
   4011 	hs.h_serv = "syslog";
   4012 
   4013 	if ((handle = setnetconfig()) == NULL) {
   4014 		return (0);
   4015 	}
   4016 
   4017 	while ((ncp = getnetconfig(handle)) != NULL) {
   4018 		if (ncp->nc_semantics != NC_TPI_CLTS) {
   4019 			continue;
   4020 		}
   4021 
   4022 		if (netdir_getbyname(ncp, &hs, &nap) != 0) {
   4023 			continue;
   4024 		}
   4025 
   4026 		if (nap == NULL) {
   4027 			continue;
   4028 		}
   4029 
   4030 		nbp = nap->n_addrs;
   4031 
   4032 		for (i = 0; i < nap->n_cnt; i++) {
   4033 			if ((uap = taddr2uaddr(ncp, nbp)) != (char *)NULL) {
   4034 				DPRINT2(1, "amiloghost(%u): testing %s\n",
   4035 				    mythreadno, uap);
   4036 			}
   4037 
   4038 			free(uap);
   4039 
   4040 			fd = t_open(ncp->nc_device, O_RDWR, NULL);
   4041 
   4042 			if (fd < 0) {
   4043 				netdir_free((void *)nap, ND_ADDRLIST);
   4044 				(void) endnetconfig(handle);
   4045 				return (0);
   4046 			}
   4047 
   4048 			/*LINTED*/
   4049 			bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
   4050 			bind.addr = *nbp;
   4051 			bind.qlen = 0;
   4052 
   4053 			if (t_bind(fd, &bind, bound) == 0) {
   4054 				(void) t_close(fd);
   4055 				(void) t_free((char *)bound, T_BIND);
   4056 				netdir_free((void *)nap, ND_ADDRLIST);
   4057 				(void) endnetconfig(handle);
   4058 				return (1);
   4059 			} else {
   4060 				(void) t_close(fd);
   4061 				(void) t_free((char *)bound, T_BIND);
   4062 			}
   4063 
   4064 			nbp++;
   4065 		}
   4066 
   4067 		netdir_free((void *)nap, ND_ADDRLIST);
   4068 	}
   4069 
   4070 	(void) endnetconfig(handle);
   4071 	return (0);
   4072 }
   4073 
   4074 int
   4075 same_addr(struct netbuf *na, struct netbuf *nb)
   4076 {
   4077 	char *a, *b;
   4078 	size_t n;
   4079 
   4080 	assert(na->buf != NULL && nb->buf != NULL);
   4081 
   4082 	if (na->len != nb->len) {
   4083 		return (0);
   4084 	}
   4085 
   4086 	a = na->buf;
   4087 	b = nb->buf;
   4088 	n = nb->len;
   4089 
   4090 	while (n-- > 0) {
   4091 		if (*a++ != *b++) {
   4092 			return (0);
   4093 		}
   4094 	}
   4095 
   4096 	return (1);
   4097 }
   4098 
   4099 /*
   4100  * allocates a new message structure, initializes it
   4101  * and returns a pointer to it
   4102  */
   4103 static log_message_t *
   4104 new_msg(void)
   4105 {
   4106 	log_message_t *lm;
   4107 	pthread_t mythreadno;
   4108 
   4109 	if (Debug) {
   4110 		mythreadno = pthread_self();
   4111 	}
   4112 
   4113 	if ((lm = malloc(sizeof (log_message_t))) == NULL)
   4114 		return ((log_message_t *)NULL);
   4115 
   4116 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lm))
   4117 
   4118 	if (pthread_mutex_init(&lm->msg_mutex, NULL) != 0)
   4119 		return ((log_message_t *)NULL);
   4120 	lm->refcnt = 0;
   4121 	lm->pri = 0;
   4122 	lm->flags = 0;
   4123 	lm->hlp = NULL;
   4124 	lm->msg[0] = '\0';
   4125 	lm->ptr = NULL;
   4126 
   4127 	DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno, (void *)lm);
   4128 	return (lm);
   4129 }
   4130 
   4131 /*
   4132  * frees a message structure - should only be called if
   4133  * the refcount is 0
   4134  */
   4135 static void
   4136 free_msg(log_message_t *lm)
   4137 {
   4138 	pthread_t mythreadno;
   4139 
   4140 	if (Debug) {
   4141 		mythreadno = pthread_self();
   4142 	}
   4143 
   4144 	assert(lm != NULL && lm->refcnt == 0);
   4145 	if (lm->hlp != NULL)
   4146 		freehl(lm->hlp);
   4147 	DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno, (void *)lm);
   4148 	free(lm);
   4149 }
   4150 
   4151 /*
   4152  *  Make sure that the message makes sense in the current locale, and
   4153  *  does not contain stray control characters.
   4154  */
   4155 static void
   4156 filter_string(char *mbstr, char *filtered, size_t max)
   4157 {
   4158 	size_t	cs = 0;
   4159 	size_t	mb_cur_max;
   4160 	unsigned char	*p = (unsigned char *)mbstr;
   4161 	pthread_t mythreadno = 0;
   4162 
   4163 	if (Debug) {
   4164 		mythreadno = pthread_self();
   4165 	}
   4166 
   4167 	assert(mbstr != NULL && filtered != NULL);
   4168 
   4169 	/*
   4170 	 * Since the access to MB_CUR_MAX is expensive (because
   4171 	 * MB_CUR_MAX lives in a global area), it should be
   4172 	 * restrained for the better performance.
   4173 	 */
   4174 	mb_cur_max = (size_t)MB_CUR_MAX;
   4175 	if (mb_cur_max > 1) {
   4176 		/* multibyte locale */
   4177 		int	mlen;
   4178 		wchar_t	wc;
   4179 
   4180 		while (*p != '\0') {
   4181 			if ((mlen = mbtowc(&wc, (char *)p,
   4182 			    mb_cur_max)) == -1) {
   4183 				/*
   4184 				 * Invalid byte sequence found.
   4185 				 *
   4186 				 * try to print one byte
   4187 				 * in ASCII format.
   4188 				 */
   4189 				DPRINT2(9, "filter_string(%u): Invalid "
   4190 				    "MB sequence: %ld\n", mythreadno,
   4191 				    wc);
   4192 
   4193 				if (!putctrlc(*p++, &filtered, &cs, max)) {
   4194 					/* not enough buffer */
   4195 					goto end;
   4196 				} else {
   4197 					continue;
   4198 				}
   4199 			} else {
   4200 				/*
   4201 				 * Since *p is not a null byte here,
   4202 				 * mbtowc should have never returned 0.
   4203 				 *
   4204 				 * A valid wide character found.
   4205 				 */
   4206 
   4207 				if (wc != L'\t' && iswcntrl(wc)) {
   4208 					/*
   4209 					 * non-tab, non-newline, and
   4210 					 * control character found.
   4211 					 *
   4212 					 * try to print this wide character
   4213 					 * in ASCII-format.
   4214 					 */
   4215 					char	*q = filtered;
   4216 
   4217 					DPRINT2(9, "filter_string(%u): MB"
   4218 					    " control character: %ld\n",
   4219 					    mythreadno, wc);
   4220 
   4221 					while (mlen--) {
   4222 						if (!putctrlc(*p++, &filtered,
   4223 						    &cs, max)) {
   4224 							/*
   4225 							 * not enough buffer in
   4226 							 * filtered
   4227 							 *
   4228 							 * cancel already
   4229 							 * stored bytes in
   4230 							 * filtered for this
   4231 							 * wide character.
   4232 							 */
   4233 							filtered = q;
   4234 							goto end;
   4235 						}
   4236 					}
   4237 					continue;
   4238 				} else {
   4239 					/*
   4240 					 * tab, newline, or non-control
   4241 					 * character found.
   4242 					 */
   4243 					if (cs + mlen < max) {
   4244 						/* enough buffer */
   4245 						cs += mlen;
   4246 						while (mlen--) {
   4247 							*filtered++ = *p++;
   4248 						}
   4249 						continue;
   4250 					} else {
   4251 						/* not enough buffer */
   4252 						goto end;
   4253 					}
   4254 				}
   4255 			}
   4256 		}
   4257 	} else {
   4258 		/* singlebyte locale */
   4259 
   4260 		while (*p != '\0') {
   4261 			if (*p != '\t' && iscntrl(*p)) {
   4262 				/*
   4263 				 * non-tab, non-newline,
   4264 				 * and control character found.
   4265 				 *
   4266 				 * try to print this singlebyte character
   4267 				 * in ASCII format.
   4268 				 */
   4269 				DPRINT2(9, "filter_string(%u): control "
   4270 				    "character: %d\n", mythreadno, *p);
   4271 
   4272 				if (!putctrlc(*p++, &filtered, &cs, max)) {
   4273 					/* not enough buffer */
   4274 					goto end;
   4275 				} else {
   4276 					continue;
   4277 				}
   4278 			} else if (*p != '\t' && !isprint(*p)) {
   4279 				/*
   4280 				 * non-tab and non printable character found
   4281 				 * this check is required for the C locale
   4282 				 */
   4283 				DPRINT2(9, "filter_string(%u): non-printable "
   4284 				    "character: %d\n", mythreadno, *p);
   4285 				if (!putctrlc(*p++, &filtered, &cs, max)) {
   4286 					/* not enough buffer */
   4287 					goto end;
   4288 				} else {
   4289 					continue;
   4290 				}
   4291 			} else {
   4292 				/*
   4293 				 * tab, newline, non-control character, or
   4294 				 * printable found.
   4295 				 */
   4296 				if (cs + 1 < max) {
   4297 					*filtered++ = *p++;
   4298 					cs++;
   4299 					continue;
   4300 				} else {
   4301 					/* not enough buffer */
   4302 					goto end;
   4303 				}
   4304 			}
   4305 		}
   4306 	}
   4307 
   4308 end:
   4309 	*filtered = '\0';
   4310 
   4311 	if (cs >= 2 &&
   4312 	    filtered[-2] == '\\' && filtered[-1] == 'n') {
   4313 		filtered[-2] = '\0';
   4314 	}
   4315 }
   4316 
   4317 static char *
   4318 alloc_stacks(int numstacks)
   4319 {
   4320 	size_t pagesize, mapsize;
   4321 	char *stack_top;
   4322 	char *addr;
   4323 	int i;
   4324 
   4325 	pagesize = (size_t)sysconf(_SC_PAGESIZE);
   4326 	/*
   4327 	 * stacksize and redzonesize are global so threads
   4328 	 * can be created elsewhere and refer to the sizes
   4329 	 */
   4330 	stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
   4331 	    DEFAULT_STACKSIZE, pagesize);
   4332 	redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
   4333 
   4334 	/*
   4335 	 * allocate an additional "redzonesize" chunk in addition
   4336 	 * to what we require, so we can create a redzone at the
   4337 	 * bottom of the last stack as well.
   4338 	 */
   4339 	mapsize = redzonesize + numstacks * (stacksize + redzonesize);
   4340 	stack_top = mmap(NULL, mapsize, PROT_READ|PROT_WRITE,
   4341 	    MAP_PRIVATE|MAP_ANON, -1, 0);
   4342 	if (stack_top == MAP_FAILED)
   4343 		return (NULL);
   4344 
   4345 	addr = stack_top;
   4346 	/*
   4347 	 * this loop is intentionally <= instead of <, so we can
   4348 	 * protect the redzone at the bottom of the last stack
   4349 	 */
   4350 	for (i = 0; i <= numstacks; i++) {
   4351 		(void) mprotect(addr, redzonesize, PROT_NONE);
   4352 		addr += stacksize + redzonesize;
   4353 	}
   4354 	return ((char *)(stack_top + redzonesize));
   4355 }
   4356 
   4357 static void
   4358 dealloc_stacks(int numstacks)
   4359 {
   4360 	size_t pagesize, mapsize;
   4361 
   4362 	pagesize = (size_t)sysconf(_SC_PAGESIZE);
   4363 
   4364 	stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
   4365 	    DEFAULT_STACKSIZE, pagesize);
   4366 
   4367 	redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
   4368 
   4369 	mapsize = redzonesize + numstacks * (stacksize + redzonesize);
   4370 	(void) munmap(cstack_ptr - mapsize, mapsize);
   4371 }
   4372 
   4373 static void
   4374 filed_destroy(struct filed *f)
   4375 {
   4376 	(void) dataq_destroy(&f->f_queue);
   4377 	(void) pthread_mutex_destroy(&f->filed_mutex);
   4378 }
   4379 
   4380 static void
   4381 close_door(void)
   4382 {
   4383 	pthread_t mythreadno;
   4384 
   4385 	if (Debug) {
   4386 		mythreadno = pthread_self();
   4387 	}
   4388 
   4389 	(void) fdetach(DoorFileName);
   4390 
   4391 	DPRINT2(5, "close_door(%u): detached server() from %s\n",
   4392 	    mythreadno, DoorFileName);
   4393 }
   4394 
   4395 static void
   4396 delete_doorfiles(void)
   4397 {
   4398 	pthread_t mythreadno;
   4399 	struct stat sb;
   4400 	int err;
   4401 	char line[MAXLINE+1];
   4402 
   4403 	if (Debug) {
   4404 		mythreadno = pthread_self();
   4405 	}
   4406 
   4407 
   4408 	if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
   4409 		if (unlink(DoorFileName) < 0) {
   4410 			err = errno;
   4411 			(void) snprintf(line, sizeof (line),
   4412 			    "unlink() of %s failed - fatal", DoorFileName);
   4413 			errno = err;
   4414 			logerror(line);
   4415 			DPRINT3(1, "delete_doorfiles(%u): error: %s, "
   4416 			    "errno=%d\n", mythreadno, line, err);
   4417 			exit(1);
   4418 		}
   4419 
   4420 		DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
   4421 		    mythreadno, DoorFileName);
   4422 	}
   4423 
   4424 	if (strcmp(DoorFileName, DOORFILE) == 0) {
   4425 		if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
   4426 			if (unlink(OLD_DOORFILE) < 0) {
   4427 				err = errno;
   4428 				(void) snprintf(line, sizeof (line),
   4429 				    "unlink() of %s failed", OLD_DOORFILE);
   4430 				DPRINT2(5, "delete_doorfiles(%u): %s\n",
   4431 				    mythreadno, line);
   4432 
   4433 				if (err != EROFS) {
   4434 					errno = err;
   4435 					(void) strlcat(line, " - fatal",
   4436 					    sizeof (line));
   4437 					logerror(line);
   4438 					DPRINT3(1, "delete_doorfiles(%u): "
   4439 					    "error: %s, errno=%d\n",
   4440 					    mythreadno, line, err);
   4441 					exit(1);
   4442 				}
   4443 
   4444 				DPRINT1(5, "delete_doorfiles(%u): unlink() "
   4445 				    "failure OK on RO file system\n",
   4446 				    mythreadno);
   4447 			}
   4448 
   4449 			DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
   4450 			    mythreadno, OLD_DOORFILE);
   4451 		}
   4452 	}
   4453 
   4454 	if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
   4455 		if (unlink(PidFileName) < 0) {
   4456 			err = errno;
   4457 			(void) snprintf(line, sizeof (line),
   4458 			    "unlink() of %s failed - fatal", PidFileName);
   4459 			errno = err;
   4460 			logerror(line);
   4461 			DPRINT3(1, "delete_doorfiles(%u): error: %s, "
   4462 			    "errno=%d\n", mythreadno, line, err);
   4463 			exit(1);
   4464 		}
   4465 
   4466 		DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno,
   4467 		    PidFileName);
   4468 	}
   4469 
   4470 	if (strcmp(PidFileName, PIDFILE) == 0) {
   4471 		if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
   4472 			if (unlink(OLD_PIDFILE) < 0) {
   4473 				err = errno;
   4474 				(void) snprintf(line, sizeof (line),
   4475 				    "unlink() of %s failed", OLD_PIDFILE);
   4476 				DPRINT2(5, "delete_doorfiles(%u): %s, \n",
   4477 				    mythreadno, line);
   4478 
   4479 				if (err != EROFS) {
   4480 					errno = err;
   4481 					(void) strlcat(line, " - fatal",
   4482 					    sizeof (line));
   4483 					logerror(line);
   4484 					DPRINT3(1, "delete_doorfiles(%u): "
   4485 					    "error: %s, errno=%d\n",
   4486 					    mythreadno, line, err);
   4487 					exit(1);
   4488 				}
   4489 
   4490 				DPRINT1(5, "delete_doorfiles(%u): unlink "
   4491 				    "failure OK on RO file system\n",
   4492 				    mythreadno);
   4493 			}
   4494 
   4495 			DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
   4496 			    mythreadno, OLD_PIDFILE);
   4497 		}
   4498 	}
   4499 
   4500 	if (DoorFd != -1) {
   4501 		(void) door_revoke(DoorFd);
   4502 	}
   4503 
   4504 	DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n",
   4505 	    mythreadno, DoorFd);
   4506 }
   4507 
   4508 
   4509 /*ARGSUSED*/
   4510 static void
   4511 signull(int sig, siginfo_t *sip, void *utp)
   4512 {
   4513 	DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n",
   4514 	    pthread_self());
   4515 	/*
   4516 	 * Do nothing, as this is a place-holder used in conjunction with
   4517 	 * sigaction()/sigwait() to ensure that the proper disposition is
   4518 	 * given to the signals we handle in main().
   4519 	 */
   4520 }
   4521 
   4522 /*
   4523  * putctrlc returns zero, if failed due to not enough buffer.
   4524  * Otherwise, putctrlc returns non-zero.
   4525  *
   4526  * c:     a byte to print in ASCII format
   4527  * **buf: a pointer to the pointer to the output buffer.
   4528  * *cl:   current length of characters in the output buffer
   4529  * max:   maximum length of the buffer
   4530  */
   4531 
   4532 static int
   4533 putctrlc(int c, char **buf, size_t *cl, size_t max)
   4534 {
   4535 	char	*p = *buf;
   4536 
   4537 	if (c == '\n') {
   4538 		if (*cl + 2 < max) {
   4539 			*p++ = '\\';
   4540 			*p++ = 'n';
   4541 			*cl += 2;
   4542 			*buf = p;
   4543 			return (2);
   4544 		} else {
   4545 			return (0);
   4546 		}
   4547 	} else if (c < 0200) {
   4548 		/* ascii control character */
   4549 		if (*cl + 2 < max) {
   4550 			*p++ = '^';
   4551 			*p++ = c ^ 0100;
   4552 			*cl += 2;
   4553 			*buf = p;
   4554 			return (2);
   4555 		} else {
   4556 			return (0);
   4557 		}
   4558 	} else {
   4559 		if (*cl + 4 < max) {
   4560 			*p++ = '\\';
   4561 			*p++ = ((c >> 6) & 07) + '0';
   4562 			*p++ = ((c >> 3) & 07) + '0';
   4563 			*p++ = (c & 07) + '0';
   4564 			*cl += 4;
   4565 			*buf = p;
   4566 			return (4);
   4567 		} else {
   4568 			return (0);
   4569 		}
   4570 	}
   4571 }
   4572 
   4573 /*
   4574  * findnl_bkwd:
   4575  *	Scans each character in buf until it finds the last newline in buf,
   4576  *	or the scanned character becomes the last COMPLETE character in buf.
   4577  *	Returns the number of scanned bytes.
   4578  *
   4579  *	buf - pointer to a buffer containing the message string
   4580  *	len - the length of the buffer
   4581  */
   4582 size_t
   4583 findnl_bkwd(const char *buf, const size_t len)
   4584 {
   4585 	const char *p;
   4586 	size_t	mb_cur_max;
   4587 	pthread_t mythreadno;
   4588 
   4589 	if (Debug) {
   4590 		mythreadno = pthread_self();
   4591 	}
   4592 
   4593 	if (len == 0) {
   4594 		return (0);
   4595 	}
   4596 
   4597 	mb_cur_max = MB_CUR_MAX;
   4598 
   4599 	if (mb_cur_max == 1) {
   4600 		/* single-byte locale */
   4601 		for (p = buf + len - 1; p != buf; p--) {
   4602 			if (*p == '\n') {
   4603 				return ((size_t)(p - buf));
   4604 			}
   4605 		}
   4606 		return ((size_t)len);
   4607 	} else {
   4608 		/* multi-byte locale */
   4609 		int mlen;
   4610 		const char *nl;
   4611 		size_t	rem;
   4612 
   4613 		p = buf;
   4614 		nl = NULL;
   4615 		for (rem = len; rem >= mb_cur_max; ) {
   4616 			mlen = mblen(p, mb_cur_max);
   4617 			if (mlen == -1) {
   4618 				/*
   4619 				 * Invalid character found.
   4620 				 */
   4621 				DPRINT1(9, "findnl_bkwd(%u): Invalid MB "
   4622 				    "sequence\n", mythreadno);
   4623 				/*
   4624 				 * handle as a single byte character.
   4625 				 */
   4626 				p++;
   4627 				rem--;
   4628 			} else {
   4629 				/*
   4630 				 * It's guaranteed that *p points to
   4631 				 * the 1st byte of a multibyte character.
   4632 				 */
   4633 				if (*p == '\n') {
   4634 					nl = p;
   4635 				}
   4636 				p += mlen;
   4637 				rem -= mlen;
   4638 			}
   4639 		}
   4640 		if (nl) {
   4641 			return ((size_t)(nl - buf));
   4642 		}
   4643 		/*
   4644 		 * no newline nor null byte found.
   4645 		 * Also it's guaranteed that *p points to
   4646 		 * the 1st byte of a (multibyte) character
   4647 		 * at this point.
   4648 		 */
   4649 		return (len - rem);
   4650 	}
   4651 }
   4652 
   4653 /*
   4654  * copynl_frwd:
   4655  *	Scans each character in buf and copies the scanned character to obuf
   4656  *	until it finds a null byte or a newline, or
   4657  *	the number of the remaining bytes in obuf gets to exceed obuflen
   4658  *	if copying the scanned character to obuf.
   4659  *	Returns the number of scanned bytes.
   4660  *
   4661  *	obuf - buffer to be copied the scanned character
   4662  *	obuflen - the size of obuf
   4663  *	buf - pointer to a buffer containing the message string
   4664  *	len - the length of the buffer
   4665  */
   4666 size_t
   4667 copynl_frwd(char *obuf, const size_t obuflen,
   4668 	    const char *buf, const size_t len)
   4669 {
   4670 	const char *p;
   4671 	char	*q = obuf;
   4672 	size_t	olen = 0;
   4673 	size_t	mb_cur_max;
   4674 	pthread_t mythreadno;
   4675 
   4676 	if (Debug) {
   4677 		mythreadno = pthread_self();
   4678 	}
   4679 
   4680 	if (len == 0) {
   4681 		return (0);
   4682 	}
   4683 
   4684 	mb_cur_max = MB_CUR_MAX;
   4685 
   4686 	if (mb_cur_max == 1) {
   4687 		/* single-byte locale */
   4688 		for (p = buf; *p; ) {
   4689 			if (obuflen > olen + 1) {
   4690 				if (*p != '\n') {
   4691 					*q++ = *p++;
   4692 					olen++;
   4693 				} else {
   4694 					*q = '\0';
   4695 					return ((size_t)(p - buf));
   4696 				}
   4697 			} else {
   4698 				*q = '\0';
   4699 				return ((size_t)(p - buf));
   4700 			}
   4701 		}
   4702 		*q = '\0';
   4703 		return ((size_t)(p - buf));
   4704 	} else {
   4705 		/* multi-byte locale */
   4706 		int mlen;
   4707 
   4708 		for (p = buf; *p; ) {
   4709 			mlen = mblen(p, mb_cur_max);
   4710 			if (mlen == -1) {
   4711 				/*
   4712 				 * Invalid character found.
   4713 				 */
   4714 				DPRINT1(9, "copynl_frwd(%u): Invalid MB "
   4715 				    "sequence\n", mythreadno);
   4716 				/*
   4717 				 * handle as a single byte character.
   4718 				 */
   4719 				if (obuflen > olen + 1) {
   4720 					*q++ = *p++;
   4721 					olen++;
   4722 				} else {
   4723 					*q = '\0';
   4724 					return ((size_t)(p - buf));
   4725 				}
   4726 			} else {
   4727 				/*
   4728 				 * It's guaranteed that *p points to
   4729 				 * the 1st byte of a multibyte character.
   4730 				 */
   4731 				if (*p == '\n') {
   4732 					*q = '\0';
   4733 					return ((size_t)(p - buf));
   4734 				}
   4735 				if (obuflen > olen + mlen) {
   4736 					int	n;
   4737 					for (n = 0; n < mlen; n++) {
   4738 						*q++ = *p++;
   4739 					}
   4740 					olen += mlen;
   4741 				} else {
   4742 					*q = '\0';
   4743 					return ((size_t)(p - buf));
   4744 				}
   4745 			}
   4746 		}
   4747 		/*
   4748 		 * no newline nor null byte found.
   4749 		 * Also it's guaranteed that *p points to
   4750 		 * the 1st byte of a (multibyte) character
   4751 		 * at this point.
   4752 		 */
   4753 		*q = '\0';
   4754 		return ((size_t)(p - buf));
   4755 	}
   4756 }
   4757 
   4758 /*
   4759  * copy_frwd:
   4760  *	Scans each character in buf and copies the scanned character to obuf
   4761  *	until the number of the remaining bytes in obuf gets to exceed obuflen
   4762  *	if copying the scanned character to obuf.
   4763  *	Returns the number of scanned (copied) bytes.
   4764  *
   4765  *	obuf - buffer to be copied the scanned character
   4766  *	obuflen - the size of obuf
   4767  *	buf - pointer to a buffer containing the message string
   4768  *	len - the length of the buffer
   4769  */
   4770 size_t
   4771 copy_frwd(char *obuf, const size_t obuflen,
   4772 	const char *buf, const size_t len)
   4773 {
   4774 	const char *p;
   4775 	char	*q = obuf;
   4776 	size_t	olen = 0;
   4777 	size_t	mb_cur_max;
   4778 	pthread_t mythreadno;
   4779 
   4780 	if (Debug) {
   4781 		mythreadno = pthread_self();
   4782 	}
   4783 
   4784 	if (len == 0) {
   4785 		return (0);
   4786 	}
   4787 
   4788 	mb_cur_max = MB_CUR_MAX;
   4789 
   4790 	if (mb_cur_max == 1) {
   4791 		/* single-byte locale */
   4792 		if (obuflen > len) {
   4793 			(void) memcpy(obuf, buf, len);
   4794 			obuf[len] = '\0';
   4795 			return ((size_t)len);
   4796 		} else {
   4797 			(void) memcpy(obuf, buf, obuflen - 1);
   4798 			obuf[obuflen - 1] = '\0';
   4799 			return (obuflen - 1);
   4800 		}
   4801 	} else {
   4802 		/* multi-byte locale */
   4803 		int mlen;
   4804 
   4805 		for (p = buf; *p; ) {
   4806 			mlen = mblen(p, mb_cur_max);
   4807 			if (mlen == -1) {
   4808 				/*
   4809 				 * Invalid character found.
   4810 				 */
   4811 				DPRINT1(9, "copy_frwd(%u): Invalid MB "
   4812 				    "sequence\n", mythreadno);
   4813 				/*
   4814 				 * handle as a single byte character.
   4815 				 */
   4816 				if (obuflen > olen + 1) {
   4817 					*q++ = *p++;
   4818 					olen++;
   4819 				} else {
   4820 					*q = '\0';
   4821 					return ((size_t)(p - buf));
   4822 				}
   4823 			} else {
   4824 				if (obuflen > olen + mlen) {
   4825 					int	n;
   4826 					for (n = 0; n < mlen; n++) {
   4827 						*q++ = *p++;
   4828 					}
   4829 					olen += mlen;
   4830 				} else {
   4831 					*q = '\0';
   4832 					return ((size_t)(p - buf));
   4833 				}
   4834 			}
   4835 		}
   4836 		*q = '\0';
   4837 		return ((size_t)(p - buf));
   4838 	}
   4839 }
   4840 
   4841 /*
   4842  * properties:
   4843  *	Get properties from SMF framework.
   4844  */
   4845 static void
   4846 properties(void)
   4847 {
   4848 	scf_simple_prop_t *prop;
   4849 	uint8_t *bool;
   4850 
   4851 	if ((prop = scf_simple_prop_get(NULL, NULL, "config",
   4852 	    "log_from_remote")) != NULL) {
   4853 		if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
   4854 			if (*bool == 0)
   4855 				turnoff = 1; /* log_from_remote = false */
   4856 			else
   4857 				turnoff = 0; /* log_from_remote = true */
   4858 		}
   4859 		scf_simple_prop_free(prop);
   4860 		DPRINT1(1, "properties: setting turnoff to %s\n",
   4861 		    turnoff ? "true" : "false");
   4862 	}
   4863 }
   4864 
   4865 /*
   4866  * close all the input devices.
   4867  */
   4868 static void
   4869 shutdown_input(void)
   4870 {
   4871 	int cnt;
   4872 
   4873 	shutting_down = 1;
   4874 
   4875 	for (cnt = 0; cnt < Ninputs; cnt++) {
   4876 		(void) t_close(Nfd[cnt].fd);
   4877 	}
   4878 
   4879 	(void) close(Pfd.fd);
   4880 }
   4881 
   4882 /*
   4883  * This is for the one thread that dedicates to resolve the
   4884  * hostname. This will get the messages from net_poll() through
   4885  * hnlq, and resolve the hostname, and push the messages back
   4886  * into the inputq.
   4887  */
   4888 /*ARGSUSED*/
   4889 static void *
   4890 hostname_lookup(void *ap)
   4891 {
   4892 	char *uap;
   4893 	log_message_t *mp;
   4894 	host_info_t *hip;
   4895 	char failsafe_addr[SYS_NMLN + 1];
   4896 	pthread_t mythreadno;
   4897 
   4898 	if (Debug) {
   4899 		mythreadno = pthread_self();
   4900 	}
   4901 
   4902 	DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n",
   4903 	    mythreadno);
   4904 
   4905 	for (;;) {
   4906 		(void) dataq_dequeue(&hnlq, (void **)&mp, 0);
   4907 
   4908 		DPRINT3(5, "hostname_lookup(%u): dequeued msg %p"
   4909 		    " from queue %p\n", mythreadno, (void *)mp,
   4910 		    (void *)&hnlq);
   4911 
   4912 		hip = (host_info_t *)mp->ptr;
   4913 		if ((uap = taddr2uaddr(hip->ncp, &hip->addr)) != NULL) {
   4914 			(void) strlcpy(failsafe_addr, uap, SYS_NMLN);
   4915 			free(uap);
   4916 		} else {
   4917 			(void) strlcpy(failsafe_addr, "<unknown>", SYS_NMLN);
   4918 		}
   4919 
   4920 		mp->hlp = cvthname(&hip->addr, hip->ncp, failsafe_addr);
   4921 
   4922 		if (mp->hlp == NULL) {
   4923 			mp->hlp = &NullHostName;
   4924 		}
   4925 
   4926 		free(hip->addr.buf);
   4927 		free(hip);
   4928 		mp->ptr = NULL;
   4929 
   4930 		if (dataq_enqueue(&inputq, (void *)mp) == -1) {
   4931 			MALLOC_FAIL("dropping message from remote");
   4932 			free_msg(mp);
   4933 			continue;
   4934 		}
   4935 
   4936 		DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue "
   4937 		    "%p\n", mythreadno, (void *)mp, (void *)&inputq);
   4938 	}
   4939 
   4940 	/*NOTREACHED*/
   4941 	return (NULL);
   4942 }
   4943 
   4944 /*
   4945  * Does all HUP(re-configuration) process.
   4946  */
   4947 static void
   4948 reconfigure()
   4949 {
   4950 	int cnt, loop, drops;
   4951 	int really_stuck;
   4952 	int console_stuck = 0;
   4953 	struct filed *f;
   4954 	char buf[LINE_MAX];
   4955 	struct utsname up;
   4956 	char cbuf[30];
   4957 	time_t tim;
   4958 	pthread_t mythreadno;
   4959 
   4960 	if (Debug) {
   4961 		mythreadno = pthread_self();
   4962 	}
   4963 
   4964 	/* If we get here then we must need to regen */
   4965 	flushmsg(0);
   4966 
   4967 	if (logmymsg(LOG_SYSLOG|LOG_INFO, "syslogd: configuration restart",
   4968 	    ADDDATE, 0) == -1) {
   4969 		MALLOC_FAIL("dropping message");
   4970 	}
   4971 
   4972 	/*
   4973 	 * make sure the logmsg thread is not in the waiting state.
   4974 	 * Otherwise, changing hup_state will prevent the logmsg thread
   4975 	 * getting out from the waiting loop.
   4976 	 */
   4977 
   4978 	if (Debug) {
   4979 		tim = time(NULL);
   4980 		DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()"
   4981 		    " moving to the safe place\n",
   4982 		    mythreadno, ctime_r(&tim, cbuf)+4);
   4983 	}
   4984 
   4985 	for (loop = 0; loop < LOOP_MAX; loop++) {
   4986 		/* we don't need the mutex to read */
   4987 		if (hup_state == HUP_ACCEPTABLE)
   4988 			break;
   4989 		(void) sleep(1);
   4990 	}
   4991 	if (hup_state != HUP_ACCEPTABLE) {
   4992 		goto thread_stuck;
   4993 	}
   4994 
   4995 	if (Debug) {
   4996 		tim = time(NULL);
   4997 		DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n",
   4998 		    mythreadno, ctime_r(&tim, cbuf)+4);
   4999 	}
   5000 
   5001 	/*
   5002 	 * Prevent logging until we are truly done processing the HUP
   5003 	 */
   5004 	(void) pthread_mutex_lock(&hup_lock);
   5005 	hup_state = HUP_INPROGRESS;
   5006 	(void) pthread_mutex_unlock(&hup_lock);
   5007 
   5008 	/*
   5009 	 * We will be going into a critical state. Any error message
   5010 	 * from syslogd needs to be dumped to the console by default
   5011 	 * immediately. Also, those error messages are quened in a temporary
   5012 	 * queue to be able to post into the regular stream later.
   5013 	 */
   5014 	disable_errorlog();
   5015 
   5016 	if (Debug) {
   5017 		tim = time(NULL);
   5018 		DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n",
   5019 		    mythreadno, ctime_r(&tim, cbuf)+4);
   5020 	}
   5021 
   5022 	/* stop configured threads */
   5023 	if (shutdown_msg() == -1) {
   5024 		/*
   5025 		 * No memory, message will be dumped to the console.
   5026 		 */
   5027 		MALLOC_FAIL("unable to restart syslogd");
   5028 		goto out;
   5029 	}
   5030 
   5031 	/* make sure logmsg() is in suspended state */
   5032 	for (loop = 0; loop < LOOP_INTERVAL; loop++) {
   5033 		if (hup_state & HUP_LOGMSG_SUSPENDED)
   5034 			break;
   5035 		(void) sleep(1);
   5036 	}
   5037 
   5038 	if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
   5039 		if (Debug) {
   5040 			tim = time(NULL);
   5041 			DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not "
   5042 			    "stop. enforcing\n",
   5043 			    mythreadno, ctime_r(&tim, cbuf)+4);
   5044 		}
   5045 
   5046 		/* probably we have too long input queue, or really stuck */
   5047 		(void) pthread_mutex_lock(&hup_lock);
   5048 		hup_state |= HUP_SUSP_LOGMSG_REQD;
   5049 		(void) pthread_mutex_unlock(&hup_lock);
   5050 
   5051 		for (loop = 0; loop < LOOP_MAX; loop++) {
   5052 			if (hup_state & HUP_LOGMSG_SUSPENDED)
   5053 				break;
   5054 			(void) sleep(1);
   5055 		}
   5056 		if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
   5057 			if (Debug) {
   5058 				tim = time(NULL);
   5059 				DPRINT2(3, "reconfigure(%u): %.15s: logmsg()"
   5060 				    " does not stop. give up\n",
   5061 				    mythreadno, ctime_r(&tim, cbuf)+4);
   5062 			}
   5063 			logerror("could not suspend logmsg - fatal");
   5064 			goto thread_stuck;
   5065 		}
   5066 	}
   5067 
   5068 	if (Debug) {
   5069 		tim = time(NULL);
   5070 		DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n",
   5071 		    mythreadno, ctime_r(&tim, cbuf)+4);
   5072 	}
   5073 
   5074 	/*
   5075 	 * Will wait for LOOP_MAX secs with watching queue lengths for the
   5076 	 * each logger threads. If they have backlogs, and no change in the
   5077 	 * length of queue found in 30 seconds, those will be counted as
   5078 	 * "really stuck".
   5079 	 * If all running logger threads become "really stuck" state, there
   5080 	 * should be no worth waiting for them to quit.
   5081 	 * In that case, we will go ahead and close out file descriptors to
   5082 	 * have them pull out from hanging system call, and give them a last
   5083 	 * chance(LOOP_INTERVAL sec) to quit.
   5084 	 */
   5085 
   5086 	if (Debug) {
   5087 		tim = time(NULL);
   5088 		DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be"
   5089 		    " shutdown\n", mythreadno, ctime_r(&tim, cbuf)+4);
   5090 	}
   5091 
   5092 	cnt = 0;
   5093 	really_stuck = 0;
   5094 	while (cnt < (LOOP_MAX/LOOP_INTERVAL) &&
   5095 	    conf_threads > really_stuck) {
   5096 
   5097 		/* save initial queue count */
   5098 		for (f = Files; f < &Files[nlogs]; f++) {
   5099 			f->f_prev_queue_count = (f->f_type == F_UNUSED) ?
   5100 			    -1 : f->f_queue_count;
   5101 		}
   5102 
   5103 		for (loop = 0; loop < LOOP_INTERVAL; loop++) {
   5104 			if (conf_threads == 0)
   5105 				break;
   5106 			(void) sleep(1);
   5107 		}
   5108 
   5109 		if (conf_threads == 0)
   5110 			break;
   5111 
   5112 		if (Debug) {
   5113 			tim = time(NULL);
   5114 			DPRINT3(3, "reconfigure(%u): %.15s: "
   5115 			    "%d threads are still alive.\n",
   5116 			    mythreadno, ctime_r(&tim, cbuf)+4,
   5117 			    conf_threads);
   5118 		}
   5119 
   5120 		really_stuck = 0;
   5121 		for (f = Files; f < &Files[nlogs]; f++) {
   5122 			if (f->f_type == F_UNUSED) {
   5123 				f->f_prev_queue_count = -1;
   5124 				continue;
   5125 			}
   5126 			if (f->f_prev_queue_count == f->f_queue_count) {
   5127 				really_stuck++;
   5128 				f->f_prev_queue_count = 1;
   5129 				DPRINT2(3, "reconfigure(%u): "
   5130 				    "tid=%d is really stuck.\n",
   5131 				    mythreadno, f->f_thread);
   5132 			} else {
   5133 				f->f_prev_queue_count = 0;
   5134 				DPRINT2(3, "reconfigure(%u): "
   5135 				    "tid=%d is still active.\n",
   5136 				    mythreadno, f->f_thread);
   5137 			}
   5138 		}
   5139 		/*
   5140 		 * Here we have one of following values in the
   5141 		 * f_prev_queue_count:
   5142 		 *  0: logger thread is still actively working.
   5143 		 *  1: logger thread is really stuck.
   5144 		 * -1: logger thread has already died.
   5145 		 */
   5146 
   5147 		cnt++;
   5148 	}
   5149 
   5150 	if (Debug) {
   5151 		tim = time(NULL);
   5152 		DPRINT2(3, "reconfigure(%u): %.15s:"
   5153 		    " complete awaiting logit()\n",
   5154 		    mythreadno, ctime_r(&tim, cbuf)+4);
   5155 		DPRINT3(3, "reconfigure(%u): %d threads alive."
   5156 		    " %d threads stuck\n",
   5157 		    mythreadno, conf_threads, really_stuck);
   5158 	}
   5159 
   5160 	/*
   5161 	 * Still running? If so, mark it as UNUSED, and close
   5162 	 * the fd so that logger threads can bail out from the loop.
   5163 	 */
   5164 	drops = 0;
   5165 	if (conf_threads) {
   5166 		for (f = Files; f < &Files[nlogs]; f++) {
   5167 			if (f->f_type == F_CONSOLE &&
   5168 			    f->f_prev_queue_count == 1) {
   5169 				/* console is really stuck */
   5170 				console_stuck = 1;
   5171 			}
   5172 			if (f->f_type == F_USERS || f->f_type == F_WALL ||
   5173 			    f->f_type == F_UNUSED)
   5174 				continue;
   5175 			cnt = f->f_queue_count;
   5176 			drops += (cnt > 0) ? cnt - 1: 0;
   5177 			f->f_type = F_UNUSED;
   5178 
   5179 			if (f->f_orig_type == F_FORW)
   5180 				(void) t_close(f->f_file);
   5181 			else
   5182 				(void) close(f->f_file);
   5183 		}
   5184 
   5185 		if (Debug) {
   5186 			tim = time(NULL);
   5187 			DPRINT1(3, "reconfigure(%u): terminating logit()\n",
   5188 			    mythreadno);
   5189 		}
   5190 
   5191 		/* last chance to exit */
   5192 		for (loop = 0; loop < LOOP_MAX; loop++) {
   5193 			if (conf_threads == 0)
   5194 				break;
   5195 			(void) sleep(1);
   5196 		}
   5197 
   5198 		if (Debug) {
   5199 			tim = time(NULL);
   5200 			DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n",
   5201 			    mythreadno, ctime_r(&tim, cbuf)+4,
   5202 			    conf_threads);
   5203 		}
   5204 	}
   5205 
   5206 	if (conf_threads == 0 && drops) {
   5207 		errno = 0;
   5208 		logerror("Could not completely output pending messages"
   5209 		    " while preparing re-configuration");
   5210 		logerror("discarded %d messages and restart configuration.",
   5211 		    drops);
   5212 		if (Debug) {
   5213 			tim = time(NULL);
   5214 			DPRINT3(3, "reconfigure(%u): %.15s: "
   5215 			    "discarded %d messages\n",
   5216 			    mythreadno, ctime_r(&tim, cbuf)+4, drops);
   5217 		}
   5218 	}
   5219 
   5220 	/*
   5221 	 * If all threads still haven't exited
   5222 	 * something is stuck or hosed. We just
   5223 	 * have no option but to exit.
   5224 	 */
   5225 	if (conf_threads) {
   5226 thread_stuck:
   5227 		if (Debug) {
   5228 			tim = time(NULL);
   5229 			DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n",
   5230 			    mythreadno, ctime_r(&tim, cbuf)+4);
   5231 		}
   5232 
   5233 		shutdown_input();
   5234 		delete_doorfiles();
   5235 		(void) uname(&up);
   5236 
   5237 		(void) snprintf(buf, sizeof (buf),
   5238 		    "syslogd(%s): some logger thread(s) "
   5239 		    "are stuck%s; syslogd is shutting down.",
   5240 		    up.nodename,
   5241 		    console_stuck ? " (including the console)" : "");
   5242 
   5243 		if (console_stuck) {
   5244 			FILE *m = popen(MAILCMD, "w");
   5245 
   5246 			if (m != NULL) {
   5247 				(void) fprintf(m, "%s\n", buf);
   5248 				(void) pclose(m);
   5249 			}
   5250 		}
   5251 
   5252 		disable_errorlog();
   5253 		logerror(buf);
   5254 		exit(1);
   5255 	}
   5256 
   5257 	/* Free up some resources */
   5258 	if (Files != (struct filed *)&fallback) {
   5259 		for (f = Files; f < &Files[nlogs]; f++) {
   5260 			(void) pthread_join(f->f_thread, NULL);
   5261 			filed_destroy(f);
   5262 		}
   5263 		free(Files);
   5264 	}
   5265 
   5266 	dealloc_stacks(nlogs);
   5267 
   5268 	if (Debug) {
   5269 		tim = time(NULL);
   5270 		DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n",
   5271 		    mythreadno, ctime_r(&tim, cbuf)+4);
   5272 	}
   5273 
   5274 	hnc_init(1);	/* purge hostname cache */
   5275 	conf_init();	/* start reconfigure */
   5276 
   5277 out:;
   5278 	/* Now should be ready to dispatch error messages from syslogd. */
   5279 	enable_errorlog();
   5280 
   5281 	/* Wake up the log thread */
   5282 
   5283 	if (Debug) {
   5284 		tim = time(NULL);
   5285 		DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n",
   5286 		    mythreadno, ctime_r(&tim, cbuf)+4);
   5287 	}
   5288 
   5289 	(void) pthread_mutex_lock(&hup_lock);
   5290 	hup_state = HUP_COMPLETED;
   5291 	(void) pthread_cond_signal(&hup_done);
   5292 	(void) pthread_mutex_unlock(&hup_lock);
   5293 }
   5294 
   5295 /*
   5296  * The following function implements simple hostname cache mechanism.
   5297  * Host name cache is implemented through hash table bucket chaining method.
   5298  * Collisions are handled by bucket chaining.
   5299  *
   5300  * hnc_init():
   5301  * 	allocate and initialize the cache. If reinit is set,
   5302  *	invalidate all cache entries.
   5303  * hnc_look():
   5304  *	It hashes the ipaddress gets the index and walks thru the
   5305  *	single linked list. if cached entry was found, it will
   5306  *	put in the head of the list, and return.While going through
   5307  *	the entries, an entry which has already expired will be invalidated.
   5308  * hnc_register():
   5309  *	Hashes the ipaddress finds the index and puts current entry to the list.
   5310  * hnc_unreg():
   5311  *	invalidate the cachep.
   5312  */
   5313 
   5314 static void
   5315 hnc_init(int reinit)
   5316 {
   5317 	struct hostname_cache **hpp;
   5318 	pthread_t mythreadno;
   5319 	int i;
   5320 
   5321 	if (Debug) {
   5322 		mythreadno = pthread_self();
   5323 	}
   5324 
   5325 	if (reinit) {
   5326 		(void) pthread_mutex_lock(&hnc_mutex);
   5327 
   5328 		for (i = 0; i < hnc_size; i++) {
   5329 			for (hpp = &hnc_cache[i]; *hpp != NULL; ) {
   5330 				hnc_unreg(hpp);
   5331 			}
   5332 		}
   5333 
   5334 		(void) pthread_mutex_unlock(&hnc_mutex);
   5335 		DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n",
   5336 		    mythreadno);
   5337 	} else {
   5338 
   5339 		hnc_cache = calloc(hnc_size, sizeof (struct hostname_cache *));
   5340 
   5341 		if (hnc_cache == NULL) {
   5342 			MALLOC_FAIL("hostname cache");
   5343 			logerror("hostname cache disabled");
   5344 			return;
   5345 		}
   5346 
   5347 		DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry"
   5348 		    " ttl:%d\n", mythreadno, hnc_size, hnc_ttl);
   5349 	}
   5350 }
   5351 
   5352 static host_list_t *
   5353 hnc_lookup(struct netbuf *nbp, struct netconfig *ncp, int *hindex)
   5354 {
   5355 	struct hostname_cache **hpp, *hp;
   5356 	time_t now;
   5357 	pthread_t mythreadno;
   5358 	int index;
   5359 
   5360 	if (Debug) {
   5361 		mythreadno = pthread_self();
   5362 	}
   5363 
   5364 	if (hnc_cache == NULL) {
   5365 		return (NULL);
   5366 	}
   5367 
   5368 	(void) pthread_mutex_lock(&hnc_mutex);
   5369 	now = time(0);
   5370 
   5371 	*hindex = index = addr_hash(nbp);
   5372 
   5373 	for (hpp = &hnc_cache[index]; (hp = *hpp) != NULL; ) {
   5374 		DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n",
   5375 		    mythreadno, (void *)hp->h, (void *)hp,
   5376 		    hp->h->hl_hosts[0]);
   5377 
   5378 		if (hp->expire < now) {
   5379 			DPRINT2(9, "hnc_lookup(%u): purge %p\n",
   5380 			    mythreadno, (void *)hp);
   5381 			hnc_unreg(hpp);
   5382 			continue;
   5383 		}
   5384 
   5385 		if (ncp == hp->ncp && same_addr(&hp->addr, nbp)) {
   5386 			/*
   5387 			 * found!
   5388 			 * Put the entry at the top.
   5389 			 */
   5390 
   5391 			if (hp != hnc_cache[index]) {
   5392 				/* unlink from active list */
   5393 				*hpp = (*hpp)->next;
   5394 				/* push it onto the top */
   5395 				hp->next = hnc_cache[index];
   5396 				hnc_cache[index] = hp;
   5397 			}
   5398 
   5399 			(void) pthread_mutex_lock(&hp->h->hl_mutex);
   5400 			hp->h->hl_refcnt++;
   5401 			(void) pthread_mutex_unlock(&hp->h->hl_mutex);
   5402 
   5403 			DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n",
   5404 			    mythreadno, (void *)hp->h, (void *)hp,
   5405 			    hp->h->hl_hosts[0]);
   5406 
   5407 			(void) pthread_mutex_unlock(&hnc_mutex);
   5408 			return (hp->h);
   5409 		}
   5410 
   5411 		hpp = &hp->next;
   5412 	}
   5413 
   5414 	(void) pthread_mutex_unlock(&hnc_mutex);
   5415 	return (NULL);
   5416 }
   5417 
   5418 static void
   5419 hnc_register(struct netbuf *nbp, struct netconfig *ncp,
   5420 		    host_list_t *h, int hindex)
   5421 {
   5422 	struct hostname_cache **hpp, **tailp, *hp, *entry;
   5423 	void *addrbuf;
   5424 	time_t now;
   5425 	pthread_t mythreadno;
   5426 	int i;
   5427 
   5428 	if (Debug) {
   5429 		mythreadno = pthread_self();
   5430 	}
   5431 
   5432 	if (hnc_cache == NULL) {
   5433 		return;
   5434 	}
   5435 
   5436 	if ((addrbuf = malloc(nbp->len)) == NULL) {
   5437 		MALLOC_FAIL("pushing hostname cache");
   5438 		return;
   5439 	}
   5440 
   5441 	if ((entry = malloc(sizeof (struct hostname_cache))) == NULL) {
   5442 		MALLOC_FAIL("pushing hostname entry");
   5443 		free(addrbuf);
   5444 		return;
   5445 	}
   5446 
   5447 	(void) pthread_mutex_lock(&hnc_mutex);
   5448 
   5449 	i = 0;
   5450 
   5451 	now = time(0);
   5452 	/*
   5453 	 * first go through active list, and discard the
   5454 	 * caches which has been invalid. Count number of
   5455 	 * non-expired buckets.
   5456 	 */
   5457 
   5458 	for (hpp = &hnc_cache[hindex]; (hp = *hpp) != NULL; ) {
   5459 		tailp = hpp;
   5460 
   5461 		if (hp->expire < now) {
   5462 			DPRINT2(9, "hnc_register(%u): discard %p\n",
   5463 			    mythreadno, (void *)hp);
   5464 			hnc_unreg(hpp);
   5465 		} else {
   5466 			i++;
   5467 			hpp = &hp->next;
   5468 		}
   5469 	}
   5470 
   5471 	/*
   5472 	 * If max limit of chained hash buckets has been used up
   5473 	 * delete the least active element in the chain.
   5474 	 */
   5475 	if (i == MAX_BUCKETS) {
   5476 		hnc_unreg(tailp);
   5477 	}
   5478 
   5479 	(void) memcpy(addrbuf, nbp->buf, nbp->len);
   5480 	entry->addr.len = nbp->len;
   5481 	entry->addr.buf = addrbuf;
   5482 	entry->ncp = ncp;
   5483 	entry->h = h;
   5484 	entry->expire = time(NULL) + hnc_ttl;
   5485 
   5486 	/* insert it at the top */
   5487 	entry->next = hnc_cache[hindex];
   5488 	hnc_cache[hindex] = entry;
   5489 
   5490 	/*
   5491 	 * As far as cache is valid, corresponding host_list must
   5492 	 * also be valid. Increments the refcnt to avoid freeing
   5493 	 * host_list.
   5494 	 */
   5495 	h->hl_refcnt++;
   5496 	DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n",
   5497 	    mythreadno, (void *)entry->h, (void *)entry, entry->h->hl_hosts[0]);
   5498 	(void) pthread_mutex_unlock(&hnc_mutex);
   5499 }
   5500 
   5501 static void
   5502 hnc_unreg(struct hostname_cache **hpp)
   5503 {
   5504 	struct hostname_cache *hp = *hpp;
   5505 	pthread_t mythreadno;
   5506 
   5507 	if (Debug) {
   5508 		mythreadno = pthread_self();
   5509 	}
   5510 
   5511 	DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n",
   5512 	    mythreadno, (void *)hp->h, (void *)hp, hp->h->hl_hosts[0]);
   5513 	free(hp->addr.buf);
   5514 	freehl(hp->h);
   5515 
   5516 	/* unlink from active list */
   5517 	*hpp = (*hpp)->next;
   5518 
   5519 	free(hp);
   5520 }
   5521 
   5522 /*
   5523  * Once this is called, error messages through logerror() will go to
   5524  * the console immediately. Also, messages are queued into the tmpq
   5525  * to be able to later put them into inputq.
   5526  */
   5527 static void
   5528 disable_errorlog()
   5529 {
   5530 	(void) dataq_init(&tmpq);
   5531 
   5532 	(void) pthread_mutex_lock(&logerror_lock);
   5533 	interrorlog = 0;
   5534 	(void) pthread_mutex_unlock(&logerror_lock);
   5535 }
   5536 
   5537 /*
   5538  * Turn internal error messages to regular input stream.
   5539  * All pending messages are pulled and pushed into the regular
   5540  * input queue.
   5541  */
   5542 static void
   5543 enable_errorlog()
   5544 {
   5545 	log_message_t *mp;
   5546 
   5547 	(void) pthread_mutex_lock(&logerror_lock);
   5548 	interrorlog = 1;
   5549 	(void) pthread_mutex_unlock(&logerror_lock);
   5550 
   5551 	/*
   5552 	 * push all the pending messages into inputq.
   5553 	 */
   5554 	while (dataq_dequeue(&tmpq, (void **)&mp, 1) == 0) {
   5555 		(void) dataq_enqueue(&inputq, mp);
   5556 	}
   5557 	(void) dataq_destroy(&tmpq);
   5558 }
   5559 
   5560 /*
   5561  * Generate a hash value of the given address and derive
   5562  * an index into the hnc_cache hashtable.
   5563  * The hashing method is similar to what Java does for strings.
   5564  */
   5565 static int
   5566 addr_hash(struct netbuf *nbp)
   5567 {
   5568 	char *uap;
   5569 	int i;
   5570 	unsigned long hcode = 0;
   5571 
   5572 	uap = nbp->buf;
   5573 
   5574 	if (uap == NULL) {
   5575 		return (0);
   5576 	}
   5577 
   5578 	/*
   5579 	 * Compute a hashcode of the address string
   5580 	 */
   5581 	for (i = 0; i < nbp->len; i++)
   5582 		hcode = (31 * hcode) + uap[i];
   5583 
   5584 	/*
   5585 	 * Scramble the hashcode for better distribution
   5586 	 */
   5587 	hcode += ~(hcode << 9);
   5588 	hcode ^=  (hcode >> 14);
   5589 	hcode +=  (hcode << 4);
   5590 	hcode ^=  (hcode >> 10);
   5591 
   5592 	return ((int)(hcode % hnc_size));
   5593 }
   5594