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