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