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