xref: /onnv-gate/usr/src/cmd/syslogd/syslogd.c (revision 8094:55fd7ba41e49)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51914Scasper  * Common Development and Distribution License (the "License").
61914Scasper  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
226358Snakanon  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  *	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
280Sstevel@tonic-gate  *	All Rights Reserved
290Sstevel@tonic-gate  */
300Sstevel@tonic-gate 
310Sstevel@tonic-gate /*
320Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
330Sstevel@tonic-gate  * The Regents of the University of California
340Sstevel@tonic-gate  * All Rights Reserved
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
370Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
380Sstevel@tonic-gate  * contributors.
390Sstevel@tonic-gate  */
400Sstevel@tonic-gate 
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate  *  syslogd -- log system messages
430Sstevel@tonic-gate  *
440Sstevel@tonic-gate  * This program implements a system log. It takes a series of lines.
450Sstevel@tonic-gate  * Each line may have a priority, signified as "<n>" as
460Sstevel@tonic-gate  * the first characters of the line.  If this is
470Sstevel@tonic-gate  * not present, a default priority is used.
480Sstevel@tonic-gate  *
490Sstevel@tonic-gate  * To kill syslogd, send a signal 15 (terminate).  A signal 1 (hup) will
500Sstevel@tonic-gate  * cause it to reconfigure.
510Sstevel@tonic-gate  *
520Sstevel@tonic-gate  * Defined Constants:
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  * MAXLINE -- the maximimum line length that can be handled.
550Sstevel@tonic-gate  * DEFUPRI -- the default priority for user messages.
560Sstevel@tonic-gate  * DEFSPRI -- the default priority for kernel messages.
570Sstevel@tonic-gate  *
580Sstevel@tonic-gate  */
590Sstevel@tonic-gate 
600Sstevel@tonic-gate #include <unistd.h>
610Sstevel@tonic-gate #include <note.h>
620Sstevel@tonic-gate #include <errno.h>
630Sstevel@tonic-gate #include <sys/types.h>
640Sstevel@tonic-gate #include <stdio.h>
651914Scasper #include <stdio_ext.h>
660Sstevel@tonic-gate #include <stdlib.h>
670Sstevel@tonic-gate #include <ctype.h>
680Sstevel@tonic-gate #include <signal.h>
690Sstevel@tonic-gate #include <string.h>
700Sstevel@tonic-gate #include <strings.h>
712104Sjjj #include <libscf.h>
720Sstevel@tonic-gate #include <netconfig.h>
730Sstevel@tonic-gate #include <netdir.h>
740Sstevel@tonic-gate #include <pwd.h>
750Sstevel@tonic-gate #include <sys/socket.h>
760Sstevel@tonic-gate #include <tiuser.h>
770Sstevel@tonic-gate #include <utmpx.h>
780Sstevel@tonic-gate #include <limits.h>
790Sstevel@tonic-gate #include <pthread.h>
800Sstevel@tonic-gate #include <fcntl.h>
810Sstevel@tonic-gate #include <stropts.h>
820Sstevel@tonic-gate #include <assert.h>
830Sstevel@tonic-gate #include <sys/statvfs.h>
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #include <sys/param.h>
860Sstevel@tonic-gate #include <sys/sysmacros.h>
870Sstevel@tonic-gate #include <sys/syslog.h>
880Sstevel@tonic-gate #include <sys/strlog.h>
890Sstevel@tonic-gate #include <sys/stat.h>
900Sstevel@tonic-gate #include <sys/time.h>
910Sstevel@tonic-gate #include <sys/utsname.h>
920Sstevel@tonic-gate #include <sys/poll.h>
930Sstevel@tonic-gate #include <sys/wait.h>
940Sstevel@tonic-gate #include <sys/resource.h>
950Sstevel@tonic-gate #include <sys/mman.h>
960Sstevel@tonic-gate #include <sys/note.h>
970Sstevel@tonic-gate #include <door.h>
980Sstevel@tonic-gate 
990Sstevel@tonic-gate #include <wchar.h>
1000Sstevel@tonic-gate #include <locale.h>
1010Sstevel@tonic-gate #include <stdarg.h>
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate #include "dataq.h"
1040Sstevel@tonic-gate #include "conf.h"
1050Sstevel@tonic-gate #include "syslogd.h"
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate #define	DOORFILE		"/var/run/syslog_door"
1080Sstevel@tonic-gate #define	RELATIVE_DOORFILE	"../var/run/syslog_door"
1090Sstevel@tonic-gate #define	OLD_DOORFILE		"/etc/.syslog_door"
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate #define	PIDFILE			"/var/run/syslog.pid"
1120Sstevel@tonic-gate #define	RELATIVE_PIDFILE	"../var/run/syslog.pid"
1130Sstevel@tonic-gate #define	OLD_PIDFILE		"/etc/syslog.pid"
1140Sstevel@tonic-gate 
1150Sstevel@tonic-gate static char		*LogName = "/dev/log";
1160Sstevel@tonic-gate static char		*ConfFile = "/etc/syslog.conf";
1170Sstevel@tonic-gate static char		ctty[] = "/dev/console";
1180Sstevel@tonic-gate static char		sysmsg[] = "/dev/sysmsg";
1190Sstevel@tonic-gate static int		DoorFd = -1;
1200Sstevel@tonic-gate static int		DoorCreated = 0;
1210Sstevel@tonic-gate static int		PidfileCreated = 0;
1220Sstevel@tonic-gate static char		*DoorFileName = DOORFILE;
1230Sstevel@tonic-gate static char		*PidFileName = PIDFILE;
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * configuration file directives
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate static struct code	PriNames[] = {
1300Sstevel@tonic-gate 	"panic",	LOG_EMERG,
1310Sstevel@tonic-gate 	"emerg",	LOG_EMERG,
1320Sstevel@tonic-gate 	"alert",	LOG_ALERT,
1330Sstevel@tonic-gate 	"crit",		LOG_CRIT,
1340Sstevel@tonic-gate 	"err",		LOG_ERR,
1350Sstevel@tonic-gate 	"error",	LOG_ERR,
1360Sstevel@tonic-gate 	"warn",		LOG_WARNING,
1370Sstevel@tonic-gate 	"warning",	LOG_WARNING,
1380Sstevel@tonic-gate 	"notice",	LOG_NOTICE,
1390Sstevel@tonic-gate 	"info",		LOG_INFO,
1400Sstevel@tonic-gate 	"debug",	LOG_DEBUG,
1410Sstevel@tonic-gate 	"none",		NOPRI,
1420Sstevel@tonic-gate 	NULL,		-1
1430Sstevel@tonic-gate };
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate static struct code	FacNames[] = {
1460Sstevel@tonic-gate 	"kern",		LOG_KERN,
1470Sstevel@tonic-gate 	"user",		LOG_USER,
1480Sstevel@tonic-gate 	"mail",		LOG_MAIL,
1490Sstevel@tonic-gate 	"daemon",	LOG_DAEMON,
1500Sstevel@tonic-gate 	"auth",		LOG_AUTH,
1510Sstevel@tonic-gate 	"security",	LOG_AUTH,
1520Sstevel@tonic-gate 	"mark",		LOG_MARK,
1530Sstevel@tonic-gate 	"syslog",	LOG_SYSLOG,
1540Sstevel@tonic-gate 	"lpr",		LOG_LPR,
1550Sstevel@tonic-gate 	"news",		LOG_NEWS,
1560Sstevel@tonic-gate 	"uucp",		LOG_UUCP,
1570Sstevel@tonic-gate 	"audit",	LOG_AUDIT,
1580Sstevel@tonic-gate 	"cron",		LOG_CRON,
1590Sstevel@tonic-gate 	"local0",	LOG_LOCAL0,
1600Sstevel@tonic-gate 	"local1",	LOG_LOCAL1,
1610Sstevel@tonic-gate 	"local2",	LOG_LOCAL2,
1620Sstevel@tonic-gate 	"local3",	LOG_LOCAL3,
1630Sstevel@tonic-gate 	"local4",	LOG_LOCAL4,
1640Sstevel@tonic-gate 	"local5",	LOG_LOCAL5,
1650Sstevel@tonic-gate 	"local6",	LOG_LOCAL6,
1660Sstevel@tonic-gate 	"local7",	LOG_LOCAL7,
1670Sstevel@tonic-gate 	NULL,		-1
1680Sstevel@tonic-gate };
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate static char		*TypeNames[7] = {
1710Sstevel@tonic-gate 	"UNUSED",	"FILE",		"TTY",		"CONSOLE",
1720Sstevel@tonic-gate 	"FORW",		"USERS",	"WALL"
1730Sstevel@tonic-gate };
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate /*
1760Sstevel@tonic-gate  * we allocate our own thread stacks so we can create them
1770Sstevel@tonic-gate  * without the MAP_NORESERVE option. We need to be sure
1780Sstevel@tonic-gate  * we have stack space even if the machine runs out of swap
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate #define	DEFAULT_STACKSIZE (100 * 1024)  /* 100 k stack */
1820Sstevel@tonic-gate #define	DEFAULT_REDZONESIZE (8 * 1024)	/* 8k redzone */
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static pthread_mutex_t wmp = PTHREAD_MUTEX_INITIALIZER;	/* wallmsg lock */
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate static pthread_mutex_t cft = PTHREAD_MUTEX_INITIALIZER;
1870Sstevel@tonic-gate static int conf_threads = 0;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate static pthread_mutex_t hup_lock = PTHREAD_MUTEX_INITIALIZER;
1900Sstevel@tonic-gate static pthread_cond_t hup_done = PTHREAD_COND_INITIALIZER;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate static pthread_mutex_t logerror_lock = PTHREAD_MUTEX_INITIALIZER;
1930Sstevel@tonic-gate 
1940Sstevel@tonic-gate #define	HUP_ACCEPTABLE		0x0000	/* can start SIGHUP process */
1950Sstevel@tonic-gate #define	HUP_INPROGRESS		0x0001	/* SIGHUP process in progress */
1960Sstevel@tonic-gate #define	HUP_COMPLETED		0x0002	/* SIGHUP process completed */
1970Sstevel@tonic-gate #define	HUP_SUSP_LOGMSG_REQD	0x1000	/* request to suspend */
1980Sstevel@tonic-gate #define	HUP_LOGMSG_SUSPENDED	0x2000	/* logmsg is suspended */
1990Sstevel@tonic-gate static int hup_state = HUP_ACCEPTABLE;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate static size_t stacksize;		/* thread stack size */
2020Sstevel@tonic-gate static size_t redzonesize;		/* thread stack redzone size */
2030Sstevel@tonic-gate static char *stack_ptr;			/* ptr to allocated stacks */
2040Sstevel@tonic-gate static char *cstack_ptr;		/* ptr to conf_thr stacks */
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static time_t start_time;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate static pthread_t sys_thread;		/* queues messages from us */
2090Sstevel@tonic-gate static pthread_t net_thread;		/* queues messages from the net */
2100Sstevel@tonic-gate static pthread_t log_thread;		/* message processing thread */
2110Sstevel@tonic-gate static pthread_t hnl_thread;		/* hostname lookup thread */
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate static dataq_t inputq;			/* the input queue */
2140Sstevel@tonic-gate static dataq_t tmpq;			/* temporary queue for err msg */
2150Sstevel@tonic-gate static dataq_t hnlq;			/* hostname lookup queue */
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate static struct filed fallback[2];
2180Sstevel@tonic-gate static struct filed *Files;
2190Sstevel@tonic-gate static int nlogs;
2200Sstevel@tonic-gate static int Debug;			/* debug flag */
2210Sstevel@tonic-gate static host_list_t LocalHostName;	/* our hostname */
2220Sstevel@tonic-gate static host_list_t NullHostName;	/* in case of lookup failure */
2230Sstevel@tonic-gate static int debuglev = 1;		/* debug print level */
2240Sstevel@tonic-gate static int interrorlog;			/* internal error logging */
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate static int MarkInterval = 20;		/* interval between marks (mins) */
2270Sstevel@tonic-gate static int Marking = 0;			/* non-zero if marking some file */
2280Sstevel@tonic-gate static int Ninputs = 0;			/* number of network inputs */
2290Sstevel@tonic-gate static int curalarm = 0;		/* current timeout value (secs) */
2300Sstevel@tonic-gate static int sys_msg_count = 0;		/* total msgs rcvd from local log */
2310Sstevel@tonic-gate static int sys_init_msg_count = 0;	/* initially received */
2320Sstevel@tonic-gate static int net_msg_count = 0;		/* total msgs rcvd from net */
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate static struct pollfd Pfd;		/* Pollfd for local the log device */
2350Sstevel@tonic-gate static struct pollfd *Nfd;		/* Array of pollfds for udp ports */
2360Sstevel@tonic-gate static struct netconfig *Ncf;
2370Sstevel@tonic-gate static struct netbuf **Myaddrs;
2380Sstevel@tonic-gate static struct t_unitdata **Udp;
2390Sstevel@tonic-gate static struct t_uderr **Errp;
2400Sstevel@tonic-gate static int turnoff = 0;
2410Sstevel@tonic-gate static int shutting_down;
2420Sstevel@tonic-gate 
2436358Snakanon /* for managing door server threads */
2446358Snakanon static pthread_mutex_t door_server_cnt_lock = PTHREAD_MUTEX_INITIALIZER;
2456358Snakanon static uint_t door_server_cnt = 0;
2466358Snakanon static pthread_attr_t door_thr_attr;
2476358Snakanon 
248955Spd155743 static struct hostname_cache **hnc_cache;
2490Sstevel@tonic-gate static pthread_mutex_t hnc_mutex = PTHREAD_MUTEX_INITIALIZER;
2500Sstevel@tonic-gate static size_t hnc_size = DEF_HNC_SIZE;
2510Sstevel@tonic-gate static unsigned int hnc_ttl = DEF_HNC_TTL;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate #define	DPRINT0(d, m)		if ((Debug) && debuglev >= (d)) \
2540Sstevel@tonic-gate 				(void) fprintf(stderr, m)
2550Sstevel@tonic-gate #define	DPRINT1(d, m, a)	if ((Debug) && debuglev >= (d)) \
2560Sstevel@tonic-gate 				(void) fprintf(stderr, m, a)
2570Sstevel@tonic-gate #define	DPRINT2(d, m, a, b)	if ((Debug) && debuglev >= (d)) \
2580Sstevel@tonic-gate 				(void) fprintf(stderr, m, a, b)
2590Sstevel@tonic-gate #define	DPRINT3(d, m, a, b, c)	if ((Debug) && debuglev >= (d)) \
2600Sstevel@tonic-gate 				(void) fprintf(stderr, m, a, b, c)
2610Sstevel@tonic-gate #define	DPRINT4(d, m, a, b, c, e)	if ((Debug) && debuglev >= (d)) \
2620Sstevel@tonic-gate 				(void) fprintf(stderr, m, a, b, c, e)
2630Sstevel@tonic-gate #define	MALLOC_FAIL(x)	\
2640Sstevel@tonic-gate 		logerror("malloc failed: " x)
2650Sstevel@tonic-gate #define	MALLOC_FAIL_EXIT	\
2660Sstevel@tonic-gate 		logerror("malloc failed - fatal"); \
2670Sstevel@tonic-gate 		exit(1)
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 
2700Sstevel@tonic-gate #define	MAILCMD "mailx -s \"syslogd shut down\" root"
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate  * Number of seconds to wait before giving up on threads that won't
2740Sstevel@tonic-gate  * shutdown: (that's right, 10 minutes!)
2750Sstevel@tonic-gate  */
2760Sstevel@tonic-gate #define	LOOP_MAX	(10 * 60)
2770Sstevel@tonic-gate 
2780Sstevel@tonic-gate /*
2790Sstevel@tonic-gate  * Interval(sec) to check the status of output queue while processing
2800Sstevel@tonic-gate  * HUP signal.
2810Sstevel@tonic-gate  */
2820Sstevel@tonic-gate #define	LOOP_INTERVAL	(15)
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate int
main(int argc,char ** argv)2850Sstevel@tonic-gate main(int argc, char **argv)
2860Sstevel@tonic-gate {
2870Sstevel@tonic-gate 	int i;
2880Sstevel@tonic-gate 	char *pstr;
2890Sstevel@tonic-gate 	int sig, fd;
2900Sstevel@tonic-gate 	int tflag = 0, Tflag = 0;
2910Sstevel@tonic-gate 	sigset_t sigs, allsigs;
2920Sstevel@tonic-gate 	struct rlimit rlim;
2930Sstevel@tonic-gate 	char *debugstr;
2940Sstevel@tonic-gate 	int mcount = 0;
2950Sstevel@tonic-gate 	struct sigaction act;
2960Sstevel@tonic-gate 	pthread_t mythreadno = 0;
2970Sstevel@tonic-gate 	char cbuf [30];
2980Sstevel@tonic-gate 	struct stat sb;
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate #ifdef DEBUG
3010Sstevel@tonic-gate #define	DEBUGDIR "/var/tmp"
3020Sstevel@tonic-gate 	if (chdir(DEBUGDIR))
3030Sstevel@tonic-gate 		DPRINT2(1, "main(%u): Unable to cd to %s\n", mythreadno,
3046358Snakanon 		    DEBUGDIR);
3050Sstevel@tonic-gate #endif /* DEBUG */
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate 	if ((debugstr = getenv("SYSLOGD_DEBUG")) != NULL)
3100Sstevel@tonic-gate 		if ((debuglev = atoi(debugstr)) == 0)
3110Sstevel@tonic-gate 			debuglev = 1;
3120Sstevel@tonic-gate 
3130Sstevel@tonic-gate #if ! defined(TEXT_DOMAIN)	/* should be defined by cc -D */
3140Sstevel@tonic-gate #define	TEXT_DOMAIN "SYS_TEST"
3150Sstevel@tonic-gate #endif
3160Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	(void) time(&start_time);
3190Sstevel@tonic-gate 
3200Sstevel@tonic-gate 	if (lstat("/var/run", &sb) != 0 || !(S_ISDIR(sb.st_mode))) {
3210Sstevel@tonic-gate 		DoorFileName = OLD_DOORFILE;
3220Sstevel@tonic-gate 		PidFileName  = OLD_PIDFILE;
3230Sstevel@tonic-gate 	}
3240Sstevel@tonic-gate 
3252104Sjjj 	properties();
3260Sstevel@tonic-gate 
3270Sstevel@tonic-gate 	while ((i = getopt(argc, argv, "df:p:m:tT")) != EOF) {
3280Sstevel@tonic-gate 		switch (i) {
3290Sstevel@tonic-gate 		case 'f':		/* configuration file */
3300Sstevel@tonic-gate 			ConfFile = optarg;
3310Sstevel@tonic-gate 			break;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		case 'd':		/* debug */
3340Sstevel@tonic-gate 			Debug++;
3350Sstevel@tonic-gate 			break;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 		case 'p':		/* path */
3380Sstevel@tonic-gate 			LogName = optarg;
3390Sstevel@tonic-gate 			break;
3400Sstevel@tonic-gate 
3410Sstevel@tonic-gate 		case 'm':		/* mark interval */
3420Sstevel@tonic-gate 			for (pstr = optarg; *pstr; pstr++) {
3430Sstevel@tonic-gate 				if (! (isdigit(*pstr))) {
3440Sstevel@tonic-gate 					(void) fprintf(stderr,
3456358Snakanon 					    "Illegal interval\n");
3460Sstevel@tonic-gate 					usage();
3470Sstevel@tonic-gate 				}
3480Sstevel@tonic-gate 			}
3490Sstevel@tonic-gate 			MarkInterval = atoi(optarg);
3500Sstevel@tonic-gate 			if (MarkInterval < 1 || MarkInterval > INT_MAX) {
3510Sstevel@tonic-gate 				(void) fprintf(stderr,
3526358Snakanon 				    "Interval must be between 1 and %d\n",
3536358Snakanon 				    INT_MAX);
3540Sstevel@tonic-gate 				usage();
3550Sstevel@tonic-gate 			}
3560Sstevel@tonic-gate 			break;
3570Sstevel@tonic-gate 		case 't':		/* turn off remote reception */
3580Sstevel@tonic-gate 			tflag++;
3590Sstevel@tonic-gate 			turnoff++;
3600Sstevel@tonic-gate 			break;
3610Sstevel@tonic-gate 		case 'T':		/* turn on remote reception */
3620Sstevel@tonic-gate 			Tflag++;
3630Sstevel@tonic-gate 			turnoff = 0;
3640Sstevel@tonic-gate 			break;
3650Sstevel@tonic-gate 		default:
3660Sstevel@tonic-gate 			usage();
3670Sstevel@tonic-gate 		}
3680Sstevel@tonic-gate 	}
3690Sstevel@tonic-gate 
3700Sstevel@tonic-gate 	if (optind < argc)
3710Sstevel@tonic-gate 		usage();
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (tflag && Tflag) {
3740Sstevel@tonic-gate 		(void) fprintf(stderr, "specify only one of -t and -T\n");
3750Sstevel@tonic-gate 		usage();
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	/*
3790Sstevel@tonic-gate 	 * close all fd's except 0-2
3800Sstevel@tonic-gate 	 */
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	closefrom(3);
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate 	if (!Debug) {
3850Sstevel@tonic-gate 		if (fork())
3860Sstevel@tonic-gate 			return (0);
3870Sstevel@tonic-gate 		(void) close(0);
3880Sstevel@tonic-gate 		(void) open("/", 0);
3890Sstevel@tonic-gate 		(void) dup2(0, 1);
3900Sstevel@tonic-gate 		(void) dup2(0, 2);
3910Sstevel@tonic-gate 		untty();
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	if (Debug) {
3950Sstevel@tonic-gate 		mythreadno = pthread_self();
3960Sstevel@tonic-gate 	}
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate 	/*
3990Sstevel@tonic-gate 	 * DO NOT call logerror() until tmpq is initialized.
4000Sstevel@tonic-gate 	 */
4010Sstevel@tonic-gate 	disable_errorlog();
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 	/*
4040Sstevel@tonic-gate 	 * ensure that file descriptor limit is "high enough"
4050Sstevel@tonic-gate 	 */
4060Sstevel@tonic-gate 	(void) getrlimit(RLIMIT_NOFILE, &rlim);
4070Sstevel@tonic-gate 	if (rlim.rlim_cur < rlim.rlim_max)
4080Sstevel@tonic-gate 		rlim.rlim_cur = rlim.rlim_max;
4090Sstevel@tonic-gate 	if (setrlimit(RLIMIT_NOFILE, &rlim) < 0)
4100Sstevel@tonic-gate 		logerror("Unable to increase file descriptor limit.");
4111914Scasper 	(void) enable_extended_FILE_stdio(-1, -1);
4120Sstevel@tonic-gate 
4130Sstevel@tonic-gate 	/* block all signals from all threads initially */
4140Sstevel@tonic-gate 	(void) sigfillset(&allsigs);
4150Sstevel@tonic-gate 	(void) pthread_sigmask(SIG_BLOCK, &allsigs, NULL);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	DPRINT2(1, "main(%u): Started at time %s", mythreadno,
4186358Snakanon 	    ctime_r(&start_time, cbuf));
4190Sstevel@tonic-gate 
4200Sstevel@tonic-gate 	init();			/* read configuration, start threads */
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	DPRINT1(1, "main(%u): off & running....\n", mythreadno);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	/* now set up to catch signals we care about */
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	(void) sigemptyset(&sigs);
4270Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGHUP);	/* reconfigure */
4280Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGALRM);	/* mark & flush timer */
4290Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGTERM);	/* exit */
4300Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGINT);	/* exit if debugging */
4310Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGQUIT);	/* exit if debugging */
4320Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGPIPE);	/* catch & discard */
4330Sstevel@tonic-gate 	(void) sigaddset(&sigs, SIGUSR1);	/* dump debug stats */
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	/*
4360Sstevel@tonic-gate 	 * We must set up to catch these signals, even though sigwait
4370Sstevel@tonic-gate 	 * will get them before the isr does.  Setting SA_SIGINFO ensures
4380Sstevel@tonic-gate 	 * that signals will be enqueued.
4390Sstevel@tonic-gate 	 */
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	act.sa_flags = SA_SIGINFO;
4420Sstevel@tonic-gate 	act.sa_sigaction = signull;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	(void) sigaction(SIGHUP, &act, NULL);
4450Sstevel@tonic-gate 	(void) sigaction(SIGALRM, &act, NULL);
4460Sstevel@tonic-gate 	(void) sigaction(SIGTERM, &act, NULL);
4470Sstevel@tonic-gate 	(void) sigaction(SIGINT, &act, NULL);
4480Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &act, NULL);
4490Sstevel@tonic-gate 	(void) sigaction(SIGPIPE, &act, NULL);
4500Sstevel@tonic-gate 	(void) sigaction(SIGUSR1, &act, NULL);
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	/* we now turn into the signal handling thread */
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	DPRINT1(2, "main(%u): now handling signals\n", mythreadno);
4550Sstevel@tonic-gate 	for (;;) {
4560Sstevel@tonic-gate 		(void) sigwait(&sigs, &sig);
4570Sstevel@tonic-gate 		DPRINT2(2, "main(%u): received signal %d\n", mythreadno, sig);
4580Sstevel@tonic-gate 		switch (sig) {
4590Sstevel@tonic-gate 		case SIGALRM:
4600Sstevel@tonic-gate 			DPRINT1(1, "main(%u): Got SIGALRM\n",
4616358Snakanon 			    mythreadno);
4620Sstevel@tonic-gate 			flushmsg(NOCOPY);
4630Sstevel@tonic-gate 			if (Marking && (++mcount % MARKCOUNT == 0)) {
4640Sstevel@tonic-gate 				if (logmymsg(LOG_INFO, "-- MARK --",
4656358Snakanon 				    ADDDATE|MARK|NOCOPY, 0) == -1) {
4660Sstevel@tonic-gate 					MALLOC_FAIL(
4676358Snakanon 					    "dropping MARK message");
4680Sstevel@tonic-gate 				}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 				mcount = 0;
4710Sstevel@tonic-gate 			}
4720Sstevel@tonic-gate 			curalarm = MarkInterval * 60 / MARKCOUNT;
4730Sstevel@tonic-gate 			(void) alarm((unsigned)curalarm);
4740Sstevel@tonic-gate 			DPRINT2(2, "main(%u): Next alarm in %d "
4756358Snakanon 			    "seconds\n", mythreadno, curalarm);
4760Sstevel@tonic-gate 			break;
4770Sstevel@tonic-gate 		case SIGHUP:
4780Sstevel@tonic-gate 			DPRINT1(1, "main(%u): got SIGHUP - "
4796358Snakanon 			    "reconfiguring\n", mythreadno);
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 			reconfigure();
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 			DPRINT1(1, "main(%u): done processing SIGHUP\n",
4846358Snakanon 			    mythreadno);
4850Sstevel@tonic-gate 			break;
4860Sstevel@tonic-gate 		case SIGQUIT:
4870Sstevel@tonic-gate 		case SIGINT:
4880Sstevel@tonic-gate 			if (!Debug) {
4890Sstevel@tonic-gate 				/* allow these signals if debugging */
4900Sstevel@tonic-gate 				break;
4910Sstevel@tonic-gate 			}
4920Sstevel@tonic-gate 			/* FALLTHROUGH */
4930Sstevel@tonic-gate 		case SIGTERM:
4940Sstevel@tonic-gate 			DPRINT2(1, "main(%u): going down on signal %d\n",
4956358Snakanon 			    mythreadno, sig);
4960Sstevel@tonic-gate 			(void) alarm(0);
4970Sstevel@tonic-gate 			flushmsg(0);
4980Sstevel@tonic-gate 			errno = 0;
4990Sstevel@tonic-gate 			t_errno = 0;
5000Sstevel@tonic-gate 			logerror("going down on signal %d", sig);
5010Sstevel@tonic-gate 			disable_errorlog();	/* force msg to console */
5020Sstevel@tonic-gate 			(void) shutdown_msg();	/* stop threads */
5030Sstevel@tonic-gate 			shutdown_input();
5040Sstevel@tonic-gate 			close_door();
5050Sstevel@tonic-gate 			delete_doorfiles();
5060Sstevel@tonic-gate 			return (0);
5070Sstevel@tonic-gate 			break;
5080Sstevel@tonic-gate 		case SIGUSR1:			/* secret debug dump mode */
5090Sstevel@tonic-gate 			/* if in debug mode, use stdout */
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate 			if (Debug) {
5120Sstevel@tonic-gate 				dumpstats(STDOUT_FILENO);
5130Sstevel@tonic-gate 				break;
5140Sstevel@tonic-gate 			}
5150Sstevel@tonic-gate 			/* otherwise dump to a debug file */
5160Sstevel@tonic-gate 			if ((fd = open(DEBUGFILE,
5176358Snakanon 			    (O_WRONLY|O_CREAT|O_TRUNC|O_EXCL),
5186358Snakanon 			    0644)) < 0)
5190Sstevel@tonic-gate 				break;
5200Sstevel@tonic-gate 			dumpstats(fd);
5210Sstevel@tonic-gate 			(void) close(fd);
5220Sstevel@tonic-gate 			break;
5230Sstevel@tonic-gate 		default:
5240Sstevel@tonic-gate 			DPRINT2(2, "main(%u): unexpected signal %d\n",
5256358Snakanon 			    mythreadno, sig);
5260Sstevel@tonic-gate 			break;
5270Sstevel@tonic-gate 		}
5280Sstevel@tonic-gate 	}
5290Sstevel@tonic-gate }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate  * Attempts to open the local log device
5330Sstevel@tonic-gate  * and return a file descriptor.
5340Sstevel@tonic-gate  */
5350Sstevel@tonic-gate static int
openklog(char * name,int mode)5360Sstevel@tonic-gate openklog(char *name, int mode)
5370Sstevel@tonic-gate {
5380Sstevel@tonic-gate 	int fd;
5390Sstevel@tonic-gate 	struct strioctl str;
5400Sstevel@tonic-gate 	pthread_t mythreadno;
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	if (Debug) {
5430Sstevel@tonic-gate 		mythreadno = pthread_self();
5440Sstevel@tonic-gate 	}
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	if ((fd = open(name, mode)) < 0) {
5470Sstevel@tonic-gate 		logerror("cannot open %s", name);
5480Sstevel@tonic-gate 		DPRINT3(1, "openklog(%u): cannot create %s (%d)\n",
5496358Snakanon 		    mythreadno, name, errno);
5500Sstevel@tonic-gate 		return (-1);
5510Sstevel@tonic-gate 	}
5520Sstevel@tonic-gate 	str.ic_cmd = I_CONSLOG;
5530Sstevel@tonic-gate 	str.ic_timout = 0;
5540Sstevel@tonic-gate 	str.ic_len = 0;
5550Sstevel@tonic-gate 	str.ic_dp = NULL;
5560Sstevel@tonic-gate 	if (ioctl(fd, I_STR, &str) < 0) {
5570Sstevel@tonic-gate 		logerror("cannot register to log console messages");
5580Sstevel@tonic-gate 		DPRINT2(1, "openklog(%u): cannot register to log "
5596358Snakanon 		    "console messages (%d)\n", mythreadno, errno);
5600Sstevel@tonic-gate 		return (-1);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 	return (fd);
5630Sstevel@tonic-gate }
5640Sstevel@tonic-gate 
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * Open the log device, and pull up all pending messages.
5680Sstevel@tonic-gate  */
5690Sstevel@tonic-gate static void
prepare_sys_poll()5700Sstevel@tonic-gate prepare_sys_poll()
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	int nfds, funix;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if ((funix = openklog(LogName, O_RDONLY)) < 0) {
5750Sstevel@tonic-gate 		logerror("can't open kernel log device - fatal");
5760Sstevel@tonic-gate 		exit(1);
5770Sstevel@tonic-gate 	}
5780Sstevel@tonic-gate 
5790Sstevel@tonic-gate 	Pfd.fd = funix;
5800Sstevel@tonic-gate 	Pfd.events = POLLIN;
5810Sstevel@tonic-gate 
5820Sstevel@tonic-gate 	for (;;) {
5830Sstevel@tonic-gate 		nfds = poll(&Pfd, 1, 0);
5840Sstevel@tonic-gate 		if (nfds <= 0) {
5850Sstevel@tonic-gate 			if (sys_init_msg_count > 0)
5860Sstevel@tonic-gate 				flushmsg(SYNC_FILE);
5870Sstevel@tonic-gate 			break;
5880Sstevel@tonic-gate 		}
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 		if (Pfd.revents & POLLIN) {
5910Sstevel@tonic-gate 			getkmsg(0);
5920Sstevel@tonic-gate 		} else if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
5930Sstevel@tonic-gate 			logerror("kernel log driver poll error");
5940Sstevel@tonic-gate 			break;
5950Sstevel@tonic-gate 		}
5960Sstevel@tonic-gate 	}
5970Sstevel@tonic-gate 
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate /*
6010Sstevel@tonic-gate  * this thread listens to the local stream log driver for log messages
6020Sstevel@tonic-gate  * generated by this host, formats them, and queues them to the logger
6030Sstevel@tonic-gate  * thread.
6040Sstevel@tonic-gate  */
6050Sstevel@tonic-gate /*ARGSUSED*/
6060Sstevel@tonic-gate static void *
sys_poll(void * ap)6070Sstevel@tonic-gate sys_poll(void *ap)
6080Sstevel@tonic-gate {
6090Sstevel@tonic-gate 	int nfds;
6100Sstevel@tonic-gate 	static int klogerrs = 0;
6110Sstevel@tonic-gate 	pthread_t mythreadno;
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (Debug) {
6140Sstevel@tonic-gate 		mythreadno = pthread_self();
6150Sstevel@tonic-gate 	}
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate 	DPRINT1(1, "sys_poll(%u): sys_thread started\n", mythreadno);
6180Sstevel@tonic-gate 
6190Sstevel@tonic-gate 	/*
6200Sstevel@tonic-gate 	 * Try to process as many messages as we can without blocking on poll.
6210Sstevel@tonic-gate 	 * We count such "initial" messages with sys_init_msg_count and
6220Sstevel@tonic-gate 	 * enqueue them without the SYNC_FILE flag.  When no more data is
6230Sstevel@tonic-gate 	 * waiting on the local log device, we set timeout to INFTIM,
6240Sstevel@tonic-gate 	 * clear sys_init_msg_count, and generate a flush message to sync
6250Sstevel@tonic-gate 	 * the previously counted initial messages out to disk.
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	sys_init_msg_count = 0;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	for (;;) {
6310Sstevel@tonic-gate 		errno = 0;
6320Sstevel@tonic-gate 		t_errno = 0;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 		nfds = poll(&Pfd, 1, INFTIM);
6350Sstevel@tonic-gate 
6360Sstevel@tonic-gate 		if (nfds == 0)
6370Sstevel@tonic-gate 			continue;
6380Sstevel@tonic-gate 
6390Sstevel@tonic-gate 		if (nfds < 0) {
6400Sstevel@tonic-gate 			if (errno != EINTR)
6410Sstevel@tonic-gate 				logerror("poll");
6420Sstevel@tonic-gate 			continue;
6430Sstevel@tonic-gate 		}
6440Sstevel@tonic-gate 		if (Pfd.revents & POLLIN) {
6450Sstevel@tonic-gate 			getkmsg(INFTIM);
6460Sstevel@tonic-gate 		} else {
6470Sstevel@tonic-gate 			if (shutting_down) {
6480Sstevel@tonic-gate 				pthread_exit(0);
6490Sstevel@tonic-gate 			}
6500Sstevel@tonic-gate 			if (Pfd.revents & (POLLNVAL|POLLHUP|POLLERR)) {
6510Sstevel@tonic-gate 				logerror("kernel log driver poll error");
6520Sstevel@tonic-gate 				(void) close(Pfd.fd);
6530Sstevel@tonic-gate 				Pfd.fd = -1;
6540Sstevel@tonic-gate 			}
6550Sstevel@tonic-gate 		}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 		while (Pfd.fd == -1 && klogerrs++ < 10) {
6580Sstevel@tonic-gate 			Pfd.fd = openklog(LogName, O_RDONLY);
6590Sstevel@tonic-gate 		}
6600Sstevel@tonic-gate 		if (klogerrs >= 10) {
6610Sstevel@tonic-gate 			logerror("can't reopen kernel log device - fatal");
6620Sstevel@tonic-gate 			exit(1);
6630Sstevel@tonic-gate 		}
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 	/*NOTREACHED*/
6660Sstevel@tonic-gate 	return (NULL);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate  * Pull up one message from log driver.
6710Sstevel@tonic-gate  */
6720Sstevel@tonic-gate static void
getkmsg(int timeout)6730Sstevel@tonic-gate getkmsg(int timeout)
6740Sstevel@tonic-gate {
6750Sstevel@tonic-gate 	int flags = 0, i;
6760Sstevel@tonic-gate 	char *lastline;
6770Sstevel@tonic-gate 	struct strbuf ctl, dat;
6780Sstevel@tonic-gate 	struct log_ctl hdr;
6790Sstevel@tonic-gate 	char buf[MAXLINE+1];
6800Sstevel@tonic-gate 	size_t buflen;
6810Sstevel@tonic-gate 	size_t len;
6820Sstevel@tonic-gate 	char tmpbuf[MAXLINE+1];
6830Sstevel@tonic-gate 	pthread_t mythreadno;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	if (Debug) {
6860Sstevel@tonic-gate 		mythreadno = pthread_self();
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	dat.maxlen = MAXLINE;
6900Sstevel@tonic-gate 	dat.buf = buf;
6910Sstevel@tonic-gate 	ctl.maxlen = sizeof (struct log_ctl);
6920Sstevel@tonic-gate 	ctl.buf = (caddr_t)&hdr;
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	while ((i = getmsg(Pfd.fd, &ctl, &dat, &flags)) == MOREDATA) {
6950Sstevel@tonic-gate 		lastline = &dat.buf[dat.len];
6960Sstevel@tonic-gate 		*lastline = '\0';
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 		DPRINT2(5, "sys_poll:(%u): getmsg: dat.len = %d\n",
6996358Snakanon 		    mythreadno, dat.len);
7000Sstevel@tonic-gate 		buflen = strlen(buf);
7010Sstevel@tonic-gate 		len = findnl_bkwd(buf, buflen);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 		(void) memcpy(tmpbuf, buf, len);
7040Sstevel@tonic-gate 		tmpbuf[len] = '\0';
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		/*
7070Sstevel@tonic-gate 		 * Format sys will enqueue the log message.
7080Sstevel@tonic-gate 		 * Set the sync flag if timeout != 0, which
7090Sstevel@tonic-gate 		 * means that we're done handling all the
7100Sstevel@tonic-gate 		 * initial messages ready during startup.
7110Sstevel@tonic-gate 		 */
7120Sstevel@tonic-gate 		if (timeout == 0) {
7130Sstevel@tonic-gate 			formatsys(&hdr, tmpbuf, 0);
7140Sstevel@tonic-gate 			sys_init_msg_count++;
7150Sstevel@tonic-gate 		} else {
7160Sstevel@tonic-gate 			formatsys(&hdr, tmpbuf, 1);
7170Sstevel@tonic-gate 		}
7180Sstevel@tonic-gate 		sys_msg_count++;
7190Sstevel@tonic-gate 
7200Sstevel@tonic-gate 		if (len != buflen) {
7210Sstevel@tonic-gate 			/* If anything remains in buf */
7220Sstevel@tonic-gate 			size_t remlen;
7230Sstevel@tonic-gate 
7240Sstevel@tonic-gate 			if (buf[len] == '\n') {
7250Sstevel@tonic-gate 				/* skip newline */
7260Sstevel@tonic-gate 				len++;
7270Sstevel@tonic-gate 			}
7280Sstevel@tonic-gate 
7290Sstevel@tonic-gate 			/*
7300Sstevel@tonic-gate 			 *  Move the remaining bytes to
7310Sstevel@tonic-gate 			 * the beginnning of buf.
7320Sstevel@tonic-gate 			 */
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 			remlen = buflen - len;
7350Sstevel@tonic-gate 			(void) memcpy(buf, &buf[len], remlen);
7360Sstevel@tonic-gate 			dat.maxlen = MAXLINE - remlen;
7370Sstevel@tonic-gate 			dat.buf = &buf[remlen];
7380Sstevel@tonic-gate 		} else {
7390Sstevel@tonic-gate 			dat.maxlen = MAXLINE;
7400Sstevel@tonic-gate 			dat.buf = buf;
7410Sstevel@tonic-gate 		}
7420Sstevel@tonic-gate 	}
7430Sstevel@tonic-gate 
7440Sstevel@tonic-gate 	if (i == 0 && dat.len > 0) {
7450Sstevel@tonic-gate 		dat.buf[dat.len] = '\0';
7460Sstevel@tonic-gate 		/*
7470Sstevel@tonic-gate 		 * Format sys will enqueue the log message.
7480Sstevel@tonic-gate 		 * Set the sync flag if timeout != 0, which
7490Sstevel@tonic-gate 		 * means that we're done handling all the
7500Sstevel@tonic-gate 		 * initial messages ready during startup.
7510Sstevel@tonic-gate 		 */
7520Sstevel@tonic-gate 		DPRINT2(5, "getkmsg(%u): getmsg: dat.maxlen = %d\n",
7536358Snakanon 		    mythreadno, dat.maxlen);
7540Sstevel@tonic-gate 		DPRINT2(5, "getkmsg(%u): getmsg: dat.len = %d\n",
7556358Snakanon 		    mythreadno, dat.len);
7560Sstevel@tonic-gate 		DPRINT2(5, "getkmsg(%u): getmsg: strlen(dat.buf) = %d\n",
7576358Snakanon 		    mythreadno, strlen(dat.buf));
7580Sstevel@tonic-gate 		DPRINT2(5, "getkmsg(%u): getmsg: dat.buf = \"%s\"\n",
7596358Snakanon 		    mythreadno, dat.buf);
7600Sstevel@tonic-gate 		DPRINT2(5, "getkmsg(%u): buf len = %d\n",
7616358Snakanon 		    mythreadno, strlen(buf));
7620Sstevel@tonic-gate 		if (timeout == 0) {
7630Sstevel@tonic-gate 			formatsys(&hdr, buf, 0);
7640Sstevel@tonic-gate 			sys_init_msg_count++;
7650Sstevel@tonic-gate 		} else {
7660Sstevel@tonic-gate 			formatsys(&hdr, buf, 1);
7670Sstevel@tonic-gate 		}
7680Sstevel@tonic-gate 		sys_msg_count++;
7690Sstevel@tonic-gate 	} else if (i < 0 && errno != EINTR) {
7700Sstevel@tonic-gate 		if (!shutting_down) {
7710Sstevel@tonic-gate 			logerror("kernel log driver read error");
7720Sstevel@tonic-gate 		}
7730Sstevel@tonic-gate 		(void) close(Pfd.fd);
7740Sstevel@tonic-gate 		Pfd.fd = -1;
7750Sstevel@tonic-gate 	}
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate /*
7790Sstevel@tonic-gate  * this thread polls all the network interfaces for syslog messages
7800Sstevel@tonic-gate  * forwarded to us, tags them with the hostname they are received
7810Sstevel@tonic-gate  * from, and queues them to the logger thread.
7820Sstevel@tonic-gate  */
7830Sstevel@tonic-gate /*ARGSUSED*/
7840Sstevel@tonic-gate static void *
net_poll(void * ap)7850Sstevel@tonic-gate net_poll(void *ap)
7860Sstevel@tonic-gate {
7870Sstevel@tonic-gate 	int nfds, i;
7880Sstevel@tonic-gate 	int flags = 0;
7890Sstevel@tonic-gate 	struct t_unitdata *udp;
7900Sstevel@tonic-gate 	struct t_uderr *errp;
7910Sstevel@tonic-gate 	char buf[MAXLINE+1];
7920Sstevel@tonic-gate 	char *uap;
7930Sstevel@tonic-gate 	log_message_t *mp;
7940Sstevel@tonic-gate 	host_info_t *hinfo;
7950Sstevel@tonic-gate 	pthread_t mythreadno;
7960Sstevel@tonic-gate 
7970Sstevel@tonic-gate 	if (Debug) {
7980Sstevel@tonic-gate 		mythreadno = pthread_self();
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	DPRINT1(1, "net_poll(%u): net_thread started\n", mythreadno);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	for (;;) {
8060Sstevel@tonic-gate 		errno = 0;
8070Sstevel@tonic-gate 		t_errno = 0;
8080Sstevel@tonic-gate 		nfds = poll(Nfd, Ninputs, -1);
8090Sstevel@tonic-gate 		if (nfds == 0)
8100Sstevel@tonic-gate 			continue;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 		if (nfds < 0) {
8130Sstevel@tonic-gate 			if (errno != EINTR)
8140Sstevel@tonic-gate 				logerror("poll");
8150Sstevel@tonic-gate 			continue;
8160Sstevel@tonic-gate 		}
8170Sstevel@tonic-gate 		for (i = 0; nfds > 0 && i < Ninputs; i++) {
8180Sstevel@tonic-gate 			if ((Nfd[i].revents & POLLIN) == 0) {
8190Sstevel@tonic-gate 				if (shutting_down) {
8200Sstevel@tonic-gate 					pthread_exit(0);
8210Sstevel@tonic-gate 				}
8220Sstevel@tonic-gate 				if (Nfd[i].revents &
8236358Snakanon 				    (POLLNVAL|POLLHUP|POLLERR)) {
8240Sstevel@tonic-gate 					logerror("POLLNVAL|POLLHUP|POLLERR");
8250Sstevel@tonic-gate 					(void) t_close(Nfd[i].fd);
8260Sstevel@tonic-gate 					Nfd[i].fd = -1;
8270Sstevel@tonic-gate 					nfds--;
8280Sstevel@tonic-gate 				}
8290Sstevel@tonic-gate 				continue;
8300Sstevel@tonic-gate 			}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 			udp = Udp[i];
8330Sstevel@tonic-gate 			udp->udata.buf = buf;
8340Sstevel@tonic-gate 			udp->udata.maxlen = MAXLINE;
8350Sstevel@tonic-gate 			udp->udata.len = 0;
8360Sstevel@tonic-gate 			flags = 0;
8370Sstevel@tonic-gate 			if (t_rcvudata(Nfd[i].fd, udp, &flags) < 0) {
8380Sstevel@tonic-gate 				errp = Errp[i];
8390Sstevel@tonic-gate 				if (t_errno == TLOOK) {
8400Sstevel@tonic-gate 					if (t_rcvuderr(Nfd[i].fd, errp) < 0) {
8410Sstevel@tonic-gate 						if (!shutting_down) {
8420Sstevel@tonic-gate 							logerror("t_rcvuderr");
8430Sstevel@tonic-gate 						}
8442104Sjjj 						(void) t_close(Nfd[i].fd);
8450Sstevel@tonic-gate 						Nfd[i].fd = -1;
8460Sstevel@tonic-gate 					}
8470Sstevel@tonic-gate 				} else {
8480Sstevel@tonic-gate 					if (!shutting_down) {
8490Sstevel@tonic-gate 						logerror("t_rcvudata");
8500Sstevel@tonic-gate 					}
8512104Sjjj 					(void) t_close(Nfd[i].fd);
8520Sstevel@tonic-gate 					Nfd[i].fd = -1;
8530Sstevel@tonic-gate 				}
8540Sstevel@tonic-gate 				nfds--;
8550Sstevel@tonic-gate 				if (shutting_down) {
8560Sstevel@tonic-gate 					pthread_exit(0);
8570Sstevel@tonic-gate 				}
8580Sstevel@tonic-gate 				continue;
8590Sstevel@tonic-gate 			}
8600Sstevel@tonic-gate 			nfds--;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 			if (udp->udata.len == 0) {
8630Sstevel@tonic-gate 				if (Debug) {
8640Sstevel@tonic-gate 					uap = NULL;
8650Sstevel@tonic-gate 					if (udp->addr.len > 0) {
8660Sstevel@tonic-gate 						uap = taddr2uaddr(&Ncf[i],
8676358Snakanon 						    &udp->addr);
8680Sstevel@tonic-gate 					}
8690Sstevel@tonic-gate 					DPRINT2(1, "net_poll(%u):"
8706358Snakanon 					    " received empty packet"
8716358Snakanon 					    " from %s\n", mythreadno,
8726358Snakanon 					    uap ? uap : "<unknown>");
8730Sstevel@tonic-gate 					if (uap)
8740Sstevel@tonic-gate 						free(uap);
8750Sstevel@tonic-gate 				}
8760Sstevel@tonic-gate 				continue;	/* No data */
8770Sstevel@tonic-gate 			}
8780Sstevel@tonic-gate 			if (udp->addr.len == 0) {
8790Sstevel@tonic-gate 				/*
8800Sstevel@tonic-gate 				 * The previous message was larger than
8810Sstevel@tonic-gate 				 * MAXLINE, and T_MORE should have been set.
8820Sstevel@tonic-gate 				 * Further data needs to be discarded as
8830Sstevel@tonic-gate 				 * we've already received MAXLINE.
8840Sstevel@tonic-gate 				 */
8850Sstevel@tonic-gate 				DPRINT1(1, "net_poll(%u): discarding packet "
8866358Snakanon 				    "exceeds max line size\n", mythreadno);
8870Sstevel@tonic-gate 				continue;
8880Sstevel@tonic-gate 			}
8890Sstevel@tonic-gate 
8900Sstevel@tonic-gate 			net_msg_count++;
8910Sstevel@tonic-gate 
8920Sstevel@tonic-gate 			if ((mp = new_msg()) == NULL) {
8930Sstevel@tonic-gate 				MALLOC_FAIL("dropping message from "
8946358Snakanon 				    "remote");
8950Sstevel@tonic-gate 				continue;
8960Sstevel@tonic-gate 			}
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate 			buf[udp->udata.len] = '\0';
8990Sstevel@tonic-gate 			formatnet(&udp->udata, mp);
9000Sstevel@tonic-gate 
9010Sstevel@tonic-gate 			if (Debug) {
9020Sstevel@tonic-gate 				uap = taddr2uaddr(&Ncf[i], &udp->addr);
9030Sstevel@tonic-gate 				DPRINT2(1, "net_poll(%u): received message"
9046358Snakanon 				    " from %s\n", mythreadno,
9056358Snakanon 				    uap ? uap : "<unknown>");
9060Sstevel@tonic-gate 				free(uap);
9070Sstevel@tonic-gate 			}
9080Sstevel@tonic-gate 			if ((hinfo = malloc(sizeof (*hinfo))) == NULL ||
9096358Snakanon 			    (hinfo->addr.buf =
9106358Snakanon 			    malloc(udp->addr.len)) == NULL) {
9110Sstevel@tonic-gate 				MALLOC_FAIL("dropping message from "
9126358Snakanon 				    "remote");
9130Sstevel@tonic-gate 				if (hinfo) {
9140Sstevel@tonic-gate 					free(hinfo);
9150Sstevel@tonic-gate 				}
9160Sstevel@tonic-gate 				free_msg(mp);
9170Sstevel@tonic-gate 				continue;
9180Sstevel@tonic-gate 			}
9190Sstevel@tonic-gate 
9200Sstevel@tonic-gate 			hinfo->ncp = &Ncf[i];
9210Sstevel@tonic-gate 			hinfo->addr.len = udp->addr.len;
9220Sstevel@tonic-gate 			(void) memcpy(hinfo->addr.buf, udp->addr.buf,
9236358Snakanon 			    udp->addr.len);
9240Sstevel@tonic-gate 			mp->ptr = hinfo;
9250Sstevel@tonic-gate 			if (dataq_enqueue(&hnlq, (void *)mp) == -1) {
9260Sstevel@tonic-gate 				MALLOC_FAIL("dropping message from "
9276358Snakanon 				    "remote");
9280Sstevel@tonic-gate 				free_msg(mp);
9290Sstevel@tonic-gate 				free(hinfo->addr.buf);
9300Sstevel@tonic-gate 				free(hinfo);
9310Sstevel@tonic-gate 				continue;
9320Sstevel@tonic-gate 			}
9330Sstevel@tonic-gate 			DPRINT3(5, "net_poll(%u): enqueued msg %p "
9346358Snakanon 			    "on queue %p\n", mythreadno, (void *)mp,
9356358Snakanon 			    (void *)&hnlq);
9360Sstevel@tonic-gate 		}
9370Sstevel@tonic-gate 	}
9380Sstevel@tonic-gate 	/*NOTREACHED*/
9390Sstevel@tonic-gate 	return (NULL);
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate 
9420Sstevel@tonic-gate static void
usage(void)9430Sstevel@tonic-gate usage(void)
9440Sstevel@tonic-gate {
9450Sstevel@tonic-gate 	(void) fprintf(stderr,
9460Sstevel@tonic-gate 	    "usage: syslogd [-d] [-t|-T] [-mmarkinterval] [-ppath]"
9470Sstevel@tonic-gate 	    " [-fconffile]\n");
9480Sstevel@tonic-gate 	exit(1);
9490Sstevel@tonic-gate }
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate static void
untty(void)9520Sstevel@tonic-gate untty(void)
9530Sstevel@tonic-gate {
9540Sstevel@tonic-gate 	if (!Debug)
9550Sstevel@tonic-gate 		(void) setsid();
9560Sstevel@tonic-gate }
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate /*
9590Sstevel@tonic-gate  * generate a log message internally. The original version of syslogd
9600Sstevel@tonic-gate  * simply called logmsg directly, but because everything is now based
9610Sstevel@tonic-gate  * on message passing, we need an internal way to generate and queue
9620Sstevel@tonic-gate  * log messages from within syslogd itself.
9630Sstevel@tonic-gate  */
9640Sstevel@tonic-gate static int
logmymsg(int pri,char * msg,int flags,int pending)9650Sstevel@tonic-gate logmymsg(int pri, char *msg, int flags, int pending)
9660Sstevel@tonic-gate {
9670Sstevel@tonic-gate 	log_message_t *mp;
9680Sstevel@tonic-gate 	pthread_t mythreadno;
9690Sstevel@tonic-gate 	dataq_t *qptr;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	if (Debug) {
9720Sstevel@tonic-gate 		mythreadno = pthread_self();
9730Sstevel@tonic-gate 	}
9740Sstevel@tonic-gate 
9750Sstevel@tonic-gate 	if ((mp = new_msg()) == NULL) {
9760Sstevel@tonic-gate 		return (-1);
9770Sstevel@tonic-gate 	}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
9800Sstevel@tonic-gate 	mp->pri = pri;
9810Sstevel@tonic-gate 	mp->hlp = &LocalHostName;
9820Sstevel@tonic-gate 	(void) strlcpy(mp->msg, msg, MAXLINE+1);
9830Sstevel@tonic-gate 	mp->flags = flags;
9840Sstevel@tonic-gate 	(void) time(&mp->ts);
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate 	qptr = pending ? &tmpq : &inputq;
9870Sstevel@tonic-gate 	if (dataq_enqueue(qptr, (void *)mp) == -1) {
9880Sstevel@tonic-gate 		free_msg(mp);
9890Sstevel@tonic-gate 		return (-1);
9900Sstevel@tonic-gate 	}
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate 	DPRINT3(5, "logmymsg(%u): enqueued msg %p on queue %p\n",
9936358Snakanon 	    mythreadno, (void *)mp, (void *)qptr);
9940Sstevel@tonic-gate 	DPRINT2(5, "logmymsg(%u): Message content: %s\n", mythreadno, msg);
9950Sstevel@tonic-gate 	return (0);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate /*
9990Sstevel@tonic-gate  * Generate an internal shutdown message
10000Sstevel@tonic-gate  */
10010Sstevel@tonic-gate static int
shutdown_msg(void)10020Sstevel@tonic-gate shutdown_msg(void)
10030Sstevel@tonic-gate {
10040Sstevel@tonic-gate 	pthread_t mythreadno;
10050Sstevel@tonic-gate 	log_message_t *mp;
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	if (Debug) {
10080Sstevel@tonic-gate 		mythreadno = pthread_self();
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate 	if ((mp = new_msg()) == NULL) {
10120Sstevel@tonic-gate 		return (-1);
10130Sstevel@tonic-gate 	}
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
10160Sstevel@tonic-gate 	mp->flags = SHUTDOWN;
10170Sstevel@tonic-gate 	mp->hlp = &LocalHostName;
10180Sstevel@tonic-gate 
10190Sstevel@tonic-gate 	if (dataq_enqueue(&inputq, (void *)mp) == -1) {
10200Sstevel@tonic-gate 		free_msg(mp);
10210Sstevel@tonic-gate 		return (-1);
10220Sstevel@tonic-gate 	}
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	DPRINT3(5, "shutdown_msg(%u): enqueued msg %p on queue %p\n",
10256358Snakanon 	    mythreadno, (void *)mp, (void *)&inputq);
10260Sstevel@tonic-gate 	return (0);
10270Sstevel@tonic-gate }
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate /*
10300Sstevel@tonic-gate  * Generate an internal flush message
10310Sstevel@tonic-gate  */
10320Sstevel@tonic-gate static void
flushmsg(int flags)10330Sstevel@tonic-gate flushmsg(int flags)
10340Sstevel@tonic-gate {
10350Sstevel@tonic-gate 	log_message_t *mp;
10360Sstevel@tonic-gate 	pthread_t mythreadno;
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	if (Debug) {
10390Sstevel@tonic-gate 		mythreadno = pthread_self();
10400Sstevel@tonic-gate 	}
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate 	if ((mp = new_msg()) == NULL) {
10430Sstevel@tonic-gate 		MALLOC_FAIL("dropping flush msg");
10440Sstevel@tonic-gate 		return;
10450Sstevel@tonic-gate 	}
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
10480Sstevel@tonic-gate 	mp->flags = FLUSHMSG | flags;
10490Sstevel@tonic-gate 	mp->hlp = &LocalHostName;
10500Sstevel@tonic-gate 
10510Sstevel@tonic-gate 	if (dataq_enqueue(&inputq, (void *)mp) == -1) {
10520Sstevel@tonic-gate 		free_msg(mp);
10530Sstevel@tonic-gate 		MALLOC_FAIL("dropping flush msg");
10540Sstevel@tonic-gate 		return;
10550Sstevel@tonic-gate 	}
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 	DPRINT4(5, "flush_msg(%u): enqueued msg %p on queue %p, flags "
10586358Snakanon 	    "0x%x\n", mythreadno, (void *)mp, (void *)&inputq, flags);
10590Sstevel@tonic-gate }
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate /*
10620Sstevel@tonic-gate  * Do some processing on messages received from the net
10630Sstevel@tonic-gate  */
10640Sstevel@tonic-gate static void
formatnet(struct netbuf * nbp,log_message_t * mp)10650Sstevel@tonic-gate formatnet(struct netbuf *nbp, log_message_t *mp)
10660Sstevel@tonic-gate {
10670Sstevel@tonic-gate 	char *p;
10680Sstevel@tonic-gate 	int pri;
10690Sstevel@tonic-gate 	pthread_t mythreadno;
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate 	if (Debug) {
10720Sstevel@tonic-gate 		mythreadno = pthread_self();
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10752104Sjjj 	DPRINT2(5, "formatnet(%u): called for msg %p\n", mythreadno,
10766358Snakanon 	    (void *)mp);
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	mp->flags = NETWORK;
10790Sstevel@tonic-gate 	(void) time(&mp->ts);
10800Sstevel@tonic-gate 
10810Sstevel@tonic-gate 	/* test for special codes */
10820Sstevel@tonic-gate 	pri = DEFUPRI;
10830Sstevel@tonic-gate 	p = nbp->buf;
10840Sstevel@tonic-gate 	DPRINT2(9, "formatnet(%u): Message content:\n>%s<\n", mythreadno,
10856358Snakanon 	    p);
10860Sstevel@tonic-gate 	if (*p == '<' && isdigit(*(p+1))) {
10870Sstevel@tonic-gate 		pri = 0;
10880Sstevel@tonic-gate 		while (isdigit(*++p))
10890Sstevel@tonic-gate 			pri = 10 * pri + (*p - '0');
10900Sstevel@tonic-gate 		if (*p == '>')
10910Sstevel@tonic-gate 			++p;
10920Sstevel@tonic-gate 		if (pri <= 0 || pri >= (LOG_NFACILITIES << 3))
10930Sstevel@tonic-gate 			pri = DEFUPRI;
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 
10960Sstevel@tonic-gate 	mp->pri = pri;
10970Sstevel@tonic-gate 	(void) strlcpy(mp->msg, p, MAXLINE+1);
10980Sstevel@tonic-gate }
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate /*
11010Sstevel@tonic-gate  * Do some processing on messages generated by this host
11020Sstevel@tonic-gate  * and then enqueue the log message.
11030Sstevel@tonic-gate  */
11040Sstevel@tonic-gate static void
formatsys(struct log_ctl * lp,char * msg,int sync)11050Sstevel@tonic-gate formatsys(struct log_ctl *lp, char *msg, int sync)
11060Sstevel@tonic-gate {
11070Sstevel@tonic-gate 	char *p, *q;
11080Sstevel@tonic-gate 	char line[MAXLINE + 1];
11090Sstevel@tonic-gate 	size_t msglen;
11100Sstevel@tonic-gate 	log_message_t	*mp;
11110Sstevel@tonic-gate 	char cbuf[30];
11120Sstevel@tonic-gate 	pthread_t mythreadno;
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	if (Debug) {
11150Sstevel@tonic-gate 		mythreadno = pthread_self();
11160Sstevel@tonic-gate 	}
11170Sstevel@tonic-gate 
11180Sstevel@tonic-gate 	DPRINT3(3, "formatsys(%u): log_ctl.mid = %d, log_ctl.sid = %d\n",
11196358Snakanon 	    mythreadno, lp->mid, lp->sid);
11200Sstevel@tonic-gate 	DPRINT2(9, "formatsys(%u): Message Content:\n>%s<\n", mythreadno,
11216358Snakanon 	    msg);
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	/* msglen includes the null termination */
11240Sstevel@tonic-gate 	msglen = strlen(msg) + 1;
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	for (p = msg; *p != '\0'; ) {
11270Sstevel@tonic-gate 		size_t linelen;
11280Sstevel@tonic-gate 		size_t len;
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate 		/*
11310Sstevel@tonic-gate 		 * Allocate a log_message_t structure.
11320Sstevel@tonic-gate 		 * We should do it here since a single message (msg)
11330Sstevel@tonic-gate 		 * could be composed of many lines.
11340Sstevel@tonic-gate 		 */
11350Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp));
11360Sstevel@tonic-gate 
11370Sstevel@tonic-gate 		if ((mp = new_msg()) == NULL) {
11380Sstevel@tonic-gate 			MALLOC_FAIL("dropping message");
11390Sstevel@tonic-gate 			/*
11400Sstevel@tonic-gate 			 * Should bail out from the loop.
11410Sstevel@tonic-gate 			 */
11420Sstevel@tonic-gate 			break;
11430Sstevel@tonic-gate 		}
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 		mp->flags &= ~NETWORK;
11460Sstevel@tonic-gate 		mp->hlp = &LocalHostName;
11470Sstevel@tonic-gate 		mp->ts = lp->ttime;
11480Sstevel@tonic-gate 		if (lp->flags & SL_LOGONLY)
11490Sstevel@tonic-gate 			mp->flags |= IGN_CONS;
11500Sstevel@tonic-gate 		if (lp->flags & SL_CONSONLY)
11510Sstevel@tonic-gate 			mp->flags |= IGN_FILE;
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 		/* extract facility */
11540Sstevel@tonic-gate 		if ((lp->pri & LOG_FACMASK) == LOG_KERN) {
11550Sstevel@tonic-gate 			(void) sprintf(line, "%.15s ",
11566358Snakanon 			    ctime_r(&mp->ts, cbuf) + 4);
11570Sstevel@tonic-gate 		} else {
11580Sstevel@tonic-gate 			(void) sprintf(line, "");
11590Sstevel@tonic-gate 		}
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 		linelen = strlen(line);
11620Sstevel@tonic-gate 		q = line + linelen;
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 		DPRINT2(5, "formatsys(%u): msglen = %d\n", mythreadno, msglen);
11650Sstevel@tonic-gate 		len = copynl_frwd(q, MAXLINE + 1 - linelen, p, msglen);
11660Sstevel@tonic-gate 		DPRINT2(5, "formatsys(%u): len (copynl_frwd) = %d\n",
11676358Snakanon 		    mythreadno, len);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate 		p += len;
11700Sstevel@tonic-gate 		msglen -= len;
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate 		if (*p == '\n') {
11730Sstevel@tonic-gate 			/* skip newline */
11740Sstevel@tonic-gate 			p++;
11750Sstevel@tonic-gate 		}
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 		if (sync && ((lp->pri & LOG_FACMASK) == LOG_KERN))
11780Sstevel@tonic-gate 			mp->flags |= SYNC_FILE;	/* fsync file after write */
11790Sstevel@tonic-gate 
11800Sstevel@tonic-gate 		if (len != 0) {
11810Sstevel@tonic-gate 			(void) strlcpy(mp->msg, line, MAXLINE+1);
11820Sstevel@tonic-gate 			mp->pri = lp->pri;
11830Sstevel@tonic-gate 
11840Sstevel@tonic-gate 			if (dataq_enqueue(&inputq, (void *)mp) == -1) {
11850Sstevel@tonic-gate 				free_msg(mp);
11860Sstevel@tonic-gate 				MALLOC_FAIL("dropping message");
11870Sstevel@tonic-gate 				break;
11880Sstevel@tonic-gate 			}
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 			DPRINT3(5, "formatsys(%u): sys_thread enqueued msg "
11916358Snakanon 			    "%p on queue %p\n", mythreadno, (void *)mp,
11926358Snakanon 			    (void *)&inputq);
11930Sstevel@tonic-gate 		} else
11940Sstevel@tonic-gate 			free_msg(mp);
11950Sstevel@tonic-gate 	}
11960Sstevel@tonic-gate }
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate  * Log a message to the appropriate log files, users, etc. based on
12000Sstevel@tonic-gate  * the priority.
12010Sstevel@tonic-gate  */
12020Sstevel@tonic-gate /*ARGSUSED*/
12030Sstevel@tonic-gate static void *
logmsg(void * ap)12040Sstevel@tonic-gate logmsg(void *ap)
12050Sstevel@tonic-gate {
12060Sstevel@tonic-gate 	struct filed *f;
12070Sstevel@tonic-gate 	int fac, prilev, flags, refcnt;
12080Sstevel@tonic-gate 	int fake_shutdown, skip_shutdown;
12090Sstevel@tonic-gate 	log_message_t *mp, *save_mp;
12100Sstevel@tonic-gate 	pthread_t mythreadno;
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 	if (Debug) {
12130Sstevel@tonic-gate 		mythreadno = pthread_self();
12140Sstevel@tonic-gate 	}
12150Sstevel@tonic-gate 
12160Sstevel@tonic-gate 	DPRINT1(1, "logmsg(%u): msg dispatcher started\n", mythreadno);
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 	fake_shutdown = skip_shutdown = 0;
12190Sstevel@tonic-gate 	save_mp = NULL;
12200Sstevel@tonic-gate 	for (;;) {
12210Sstevel@tonic-gate 		if (save_mp) {
12220Sstevel@tonic-gate 			/*
12230Sstevel@tonic-gate 			 * If we have set aside a message in order to fake a
12240Sstevel@tonic-gate 			 * SHUTDOWN, use that message before picking from the
12250Sstevel@tonic-gate 			 * queue again.
12260Sstevel@tonic-gate 			 */
12270Sstevel@tonic-gate 			mp = save_mp;
12280Sstevel@tonic-gate 			save_mp = NULL;
12290Sstevel@tonic-gate 		} else {
12300Sstevel@tonic-gate 			(void) dataq_dequeue(&inputq, (void **)&mp, 0);
12310Sstevel@tonic-gate 		}
12320Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*mp))
12330Sstevel@tonic-gate 		DPRINT3(5, "logmsg(%u): msg dispatcher dequeued %p from "
12346358Snakanon 		    "queue %p\n", mythreadno, (void *)mp,
12356358Snakanon 		    (void *)&inputq);
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 		/*
12380Sstevel@tonic-gate 		 * In most cases, if the message traffic is low, logmsg() wakes
12390Sstevel@tonic-gate 		 * up when it receives the SHUTDOWN msg, and will sleep until
12400Sstevel@tonic-gate 		 * HUP process is complete.  However, if the inputq is too
12410Sstevel@tonic-gate 		 * long, logmsg() may not receive SHUTDOWN before reconfigure()
12420Sstevel@tonic-gate 		 * releases the logger fds, filed and logit threads.  That, in
12430Sstevel@tonic-gate 		 * turn, will cause logmsg to refer to invalid fileds.
12440Sstevel@tonic-gate 		 *
12450Sstevel@tonic-gate 		 * logmsg() needs to respond to the SHUTDOWN message within
12460Sstevel@tonic-gate 		 * LOOP_INTERVAL seconds when reconfigure() enqueues it. It
12470Sstevel@tonic-gate 		 * does so in most cases.  When it does not respond in time,
12480Sstevel@tonic-gate 		 * logmsg() needs to be in suspended state immediately, since
12490Sstevel@tonic-gate 		 * filed may have been invalidated. reconfigure() will set the
12500Sstevel@tonic-gate 		 * HUP_SUSP_LOGMSG_REQD bit in hup_state and wait another
12510Sstevel@tonic-gate 		 * LOOP_INTERVAL seconds before proceeding.
12520Sstevel@tonic-gate 		 *
12530Sstevel@tonic-gate 		 * When HUP_SUSP_LOGMSG_REQD is set, we will create a fake
12540Sstevel@tonic-gate 		 * SHUTDOWN message, and dispatch it to the various logit
12550Sstevel@tonic-gate 		 * threads, and logmsg() itself will suspend.  In order to
12560Sstevel@tonic-gate 		 * ignore the real SHUTDOWN which will arrive later, we keep a
12570Sstevel@tonic-gate 		 * counter (skip_shutdown) and decrement it when the SHUTDOWN
12580Sstevel@tonic-gate 		 * message arrives.
12590Sstevel@tonic-gate 		 */
12600Sstevel@tonic-gate 		if ((hup_state & HUP_SUSP_LOGMSG_REQD) &&
12616358Snakanon 		    (mp->flags & SHUTDOWN) == 0) {
12620Sstevel@tonic-gate 			DPRINT1(3, "logmsg(%u): suspend request\n",
12636358Snakanon 			    mythreadno);
12640Sstevel@tonic-gate 
12650Sstevel@tonic-gate 			save_mp = mp;
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate 			/* create a fake SHUTDOWN msg */
12680Sstevel@tonic-gate 			if ((mp = new_msg()) == NULL) {
12690Sstevel@tonic-gate 				MALLOC_FAIL("dropping message");
12700Sstevel@tonic-gate 				if (mp->flags & SHUTDOWN) {
12710Sstevel@tonic-gate 					(void) logerror_to_console(1,
12726358Snakanon 					    "unable to shutdown "
12736358Snakanon 					    "logger thread");
12740Sstevel@tonic-gate 				}
12750Sstevel@tonic-gate 				continue;
12760Sstevel@tonic-gate 			}
12770Sstevel@tonic-gate 			mp->flags = SHUTDOWN;
12780Sstevel@tonic-gate 			mp->hlp = &LocalHostName;
12790Sstevel@tonic-gate 			fake_shutdown = 1;
12800Sstevel@tonic-gate 			skip_shutdown++;
12810Sstevel@tonic-gate 			DPRINT2(3, "logmsg(%u): pending SHUTDOWN %d\n",
12826358Snakanon 			    mythreadno, skip_shutdown);
12830Sstevel@tonic-gate 		}
12840Sstevel@tonic-gate 
12850Sstevel@tonic-gate 		/*
12860Sstevel@tonic-gate 		 * is it a shutdown or flush message ?
12870Sstevel@tonic-gate 		 */
12880Sstevel@tonic-gate 		if ((mp->flags & SHUTDOWN) || (mp->flags & FLUSHMSG)) {
12892104Sjjj 			(void) pthread_mutex_lock(&mp->msg_mutex);
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate 			if ((mp->flags & SHUTDOWN) &&
12926358Snakanon 			    !fake_shutdown && skip_shutdown > 0) {
12930Sstevel@tonic-gate 				skip_shutdown--;
12942104Sjjj 				(void) pthread_mutex_unlock(&mp->msg_mutex);
12950Sstevel@tonic-gate 				free_msg(mp);
12960Sstevel@tonic-gate 				DPRINT2(3, "logmsg(%u): released late "
12976358Snakanon 				    "arrived SHUTDOWN. pending %d\n",
12986358Snakanon 				    mythreadno, skip_shutdown);
12990Sstevel@tonic-gate 				continue;
13000Sstevel@tonic-gate 			}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 			for (f = Files; f < &Files[nlogs]; f++) {
13032104Sjjj 				(void) pthread_mutex_lock(&f->filed_mutex);
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 				if (f->f_type == F_UNUSED) {
13062104Sjjj 					(void) pthread_mutex_unlock(
13072104Sjjj 					    &f->filed_mutex);
13080Sstevel@tonic-gate 					continue;
13090Sstevel@tonic-gate 				}
13100Sstevel@tonic-gate 
13110Sstevel@tonic-gate 				f->f_queue_count++;
13120Sstevel@tonic-gate 				mp->refcnt++;
13130Sstevel@tonic-gate 
13140Sstevel@tonic-gate 				if (dataq_enqueue(&f->f_queue,
13156358Snakanon 				    (void *)mp) == -1) {
13160Sstevel@tonic-gate 					f->f_queue_count--;
13170Sstevel@tonic-gate 					mp->refcnt--;
13182104Sjjj 					(void) pthread_mutex_unlock(
13192104Sjjj 					    &f->filed_mutex);
13200Sstevel@tonic-gate 					MALLOC_FAIL("dropping message");
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 					if (mp->flags & SHUTDOWN) {
13230Sstevel@tonic-gate 						(void) logerror_to_console(1,
13246358Snakanon 						    "unable to shutdown "
13256358Snakanon 						    "logger thread");
13260Sstevel@tonic-gate 					}
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 					continue;
13290Sstevel@tonic-gate 				}
13300Sstevel@tonic-gate 				DPRINT3(5, "logmsg(%u): enqueued msg %p "
13316358Snakanon 				    "on queue %p\n", mythreadno,
13326358Snakanon 				    (void *)mp, (void *)&f->f_queue);
13332104Sjjj 				(void) pthread_mutex_unlock(&f->filed_mutex);
13340Sstevel@tonic-gate 			}
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate 			/*
13370Sstevel@tonic-gate 			 * flags value needs to be saved because mp may
13380Sstevel@tonic-gate 			 * have been freed before SHUTDOWN test below.
13390Sstevel@tonic-gate 			 */
13400Sstevel@tonic-gate 			flags = mp->flags;
13410Sstevel@tonic-gate 			refcnt = mp->refcnt;
13420Sstevel@tonic-gate 
13432104Sjjj 			(void) pthread_mutex_unlock(&mp->msg_mutex);
13440Sstevel@tonic-gate 			if (refcnt == 0)
13450Sstevel@tonic-gate 				free_msg(mp);
13460Sstevel@tonic-gate 
13470Sstevel@tonic-gate 			if (flags & SHUTDOWN) {
13482104Sjjj 				(void) pthread_mutex_lock(&hup_lock);
13490Sstevel@tonic-gate 				while (hup_state != HUP_COMPLETED) {
13500Sstevel@tonic-gate 					hup_state |= HUP_LOGMSG_SUSPENDED;
13510Sstevel@tonic-gate 					(void) pthread_cond_wait(&hup_done,
13526358Snakanon 					    &hup_lock);
13530Sstevel@tonic-gate 					hup_state &= ~HUP_LOGMSG_SUSPENDED;
13540Sstevel@tonic-gate 				}
13550Sstevel@tonic-gate 				hup_state = HUP_ACCEPTABLE;
13562104Sjjj 				(void) pthread_mutex_unlock(&hup_lock);
13570Sstevel@tonic-gate 				fake_shutdown = 0;
13580Sstevel@tonic-gate 			}
13590Sstevel@tonic-gate 			continue;
13600Sstevel@tonic-gate 		}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 		/*
13630Sstevel@tonic-gate 		 * Check to see if msg looks non-standard.
13640Sstevel@tonic-gate 		 */
13650Sstevel@tonic-gate 		if ((int)strlen(mp->msg) < 16 || mp->msg[3] != ' ' ||
13666358Snakanon 		    mp->msg[6] != ' ' || mp->msg[9] != ':' ||
13676358Snakanon 		    mp->msg[12] != ':' || mp->msg[15] != ' ')
13680Sstevel@tonic-gate 			mp->flags |= ADDDATE;
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate 		/* extract facility and priority level */
13710Sstevel@tonic-gate 		fac = (mp->pri & LOG_FACMASK) >> 3;
13720Sstevel@tonic-gate 		if (mp->flags & MARK)
13730Sstevel@tonic-gate 			fac = LOG_NFACILITIES;
13740Sstevel@tonic-gate 		prilev = mp->pri & LOG_PRIMASK;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 		DPRINT3(3, "logmsg(%u): fac = %d, pri = %d\n",
13776358Snakanon 		    mythreadno, fac, prilev);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 		/*
13800Sstevel@tonic-gate 		 * Because different devices log at different speeds,
13810Sstevel@tonic-gate 		 * it's important to hold the mutex for the current
13820Sstevel@tonic-gate 		 * message until it's been enqueued to all log files,
13830Sstevel@tonic-gate 		 * so the reference count is accurate before any
13840Sstevel@tonic-gate 		 * of the log threads can decrement it.
13850Sstevel@tonic-gate 		 */
13860Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*mp))
13870Sstevel@tonic-gate 		_NOTE(COMPETING_THREADS_NOW)
13882104Sjjj 		(void) pthread_mutex_lock(&mp->msg_mutex);
13890Sstevel@tonic-gate 
13900Sstevel@tonic-gate 		for (f = Files; f < &Files[nlogs]; f++) {
13910Sstevel@tonic-gate 			/* skip messages that are incorrect priority */
13920Sstevel@tonic-gate 			if (f->f_pmask[fac] < (unsigned)prilev ||
13936358Snakanon 			    f->f_pmask[fac] == NOPRI)
13940Sstevel@tonic-gate 				continue;
13950Sstevel@tonic-gate 			if (f->f_queue_count > Q_HIGHWATER_MARK) {
13960Sstevel@tonic-gate 				DPRINT4(5, "logmsg(%u): Dropping message "
13976358Snakanon 				    "%p on file %p, count = %d\n",
13986358Snakanon 				    mythreadno, (void *)mp, (void *)f,
13996358Snakanon 				    f->f_queue_count);
14000Sstevel@tonic-gate 				continue;
14010Sstevel@tonic-gate 			}
14020Sstevel@tonic-gate 
14030Sstevel@tonic-gate 			/*
14040Sstevel@tonic-gate 			 * Need to grab filed_mutex before testing the f_type.
14050Sstevel@tonic-gate 			 * Otherwise logit() may set F_UNUSED after the test
14060Sstevel@tonic-gate 			 * below, and start pulling out the pending messages.
14070Sstevel@tonic-gate 			 */
14080Sstevel@tonic-gate 
14092104Sjjj 			(void) pthread_mutex_lock(&f->filed_mutex);
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate 			if (f->f_type == F_UNUSED ||
14120Sstevel@tonic-gate 			    (f->f_type == F_FILE && (mp->flags & IGN_FILE)) ||
14130Sstevel@tonic-gate 			    (f->f_type == F_CONSOLE &&
14146358Snakanon 			    (mp->flags & IGN_CONS))) {
14152104Sjjj 				(void) pthread_mutex_unlock(&f->filed_mutex);
14160Sstevel@tonic-gate 				continue;
14170Sstevel@tonic-gate 			}
14180Sstevel@tonic-gate 
14190Sstevel@tonic-gate 			f->f_queue_count++;
14200Sstevel@tonic-gate 			mp->refcnt++;
14210Sstevel@tonic-gate 
14220Sstevel@tonic-gate 			if (dataq_enqueue(&f->f_queue, (void *)mp) == -1) {
14230Sstevel@tonic-gate 				f->f_queue_count--;
14240Sstevel@tonic-gate 				mp->refcnt--;
14252104Sjjj 				(void) pthread_mutex_unlock(&f->filed_mutex);
14260Sstevel@tonic-gate 				MALLOC_FAIL("dropping message");
14270Sstevel@tonic-gate 				continue;
14280Sstevel@tonic-gate 			}
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate 			DPRINT3(5, "logmsg(%u): enqueued msg %p on queue "
14316358Snakanon 			    "%p\n", mythreadno, (void *)mp,
14326358Snakanon 			    (void *)&f->f_queue);
14332104Sjjj 			(void) pthread_mutex_unlock(&f->filed_mutex);
14340Sstevel@tonic-gate 		}
14350Sstevel@tonic-gate 		refcnt = mp->refcnt;
14362104Sjjj 		(void) pthread_mutex_unlock(&mp->msg_mutex);
14370Sstevel@tonic-gate 		if (refcnt == 0)
14380Sstevel@tonic-gate 			free_msg(mp);
14390Sstevel@tonic-gate 	}
14400Sstevel@tonic-gate 	/*NOTREACHED*/
14410Sstevel@tonic-gate 	return (NULL);
14420Sstevel@tonic-gate }
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate /*
14450Sstevel@tonic-gate  * function to actually write the log message to the selected file.
14460Sstevel@tonic-gate  * each file has a logger thread that runs this routine. The function
14470Sstevel@tonic-gate  * is called with a pointer to its file structure.
14480Sstevel@tonic-gate  */
14490Sstevel@tonic-gate static void *
logit(void * ap)14500Sstevel@tonic-gate logit(void *ap)
14510Sstevel@tonic-gate {
14520Sstevel@tonic-gate 	struct filed *f = ap;
14530Sstevel@tonic-gate 	log_message_t *mp;
14540Sstevel@tonic-gate 	int forwardingloop = 0;
14552104Sjjj 	const char *errmsg = "logit(%u): %s to %s forwarding loop detected\n";
14560Sstevel@tonic-gate 	int i, currofst, prevofst, refcnt;
14570Sstevel@tonic-gate 	host_list_t *hlp;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 	assert(f != NULL);
14600Sstevel@tonic-gate 
14610Sstevel@tonic-gate 	DPRINT4(5, "logit(%u): logger started for \"%s\" (queue %p, filed "
14626358Snakanon 	    "%p)\n", f->f_thread, f->f_un.f_fname, (void *)&f->f_queue,
14636358Snakanon 	    (void *)f);
14640Sstevel@tonic-gate 	_NOTE(COMPETING_THREADS_NOW);
14650Sstevel@tonic-gate 
14660Sstevel@tonic-gate 	while (f->f_type != F_UNUSED) {
14670Sstevel@tonic-gate 		(void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
14680Sstevel@tonic-gate 		DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
14696358Snakanon 		    "%p\n", f->f_thread, (void *)mp, (void *)&f->f_queue);
14702104Sjjj 		(void) pthread_mutex_lock(&f->filed_mutex);
14710Sstevel@tonic-gate 		assert(f->f_queue_count > 0);
14720Sstevel@tonic-gate 		f->f_queue_count--;
14732104Sjjj 		(void) pthread_mutex_unlock(&f->filed_mutex);
14740Sstevel@tonic-gate 		assert(mp->refcnt > 0);
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 		/*
14770Sstevel@tonic-gate 		 * is it a shutdown message ?
14780Sstevel@tonic-gate 		 */
14790Sstevel@tonic-gate 		if (mp->flags & SHUTDOWN) {
14802104Sjjj 			(void) pthread_mutex_lock(&mp->msg_mutex);
14810Sstevel@tonic-gate 			refcnt = --mp->refcnt;
14822104Sjjj 			(void) pthread_mutex_unlock(&mp->msg_mutex);
14830Sstevel@tonic-gate 			if (refcnt == 0)
14840Sstevel@tonic-gate 				free_msg(mp);
14850Sstevel@tonic-gate 			break;
14860Sstevel@tonic-gate 		}
14870Sstevel@tonic-gate 
14880Sstevel@tonic-gate 		/*
14890Sstevel@tonic-gate 		 * Is it a logsync message?
14900Sstevel@tonic-gate 		 */
14910Sstevel@tonic-gate 		if ((mp->flags & (FLUSHMSG | LOGSYNC)) ==
14920Sstevel@tonic-gate 		    (FLUSHMSG | LOGSYNC)) {
14930Sstevel@tonic-gate 			if (f->f_type != F_FILE)
14940Sstevel@tonic-gate 				goto out;	/* nothing to do */
14950Sstevel@tonic-gate 			(void) close(f->f_file);
14960Sstevel@tonic-gate 			f->f_file = open64(f->f_un.f_fname,
14976358Snakanon 			    O_WRONLY|O_APPEND|O_NOCTTY);
14980Sstevel@tonic-gate 			if (f->f_file < 0) {
14990Sstevel@tonic-gate 				f->f_type = F_UNUSED;
15000Sstevel@tonic-gate 				logerror(f->f_un.f_fname);
15010Sstevel@tonic-gate 				f->f_stat.errs++;
15020Sstevel@tonic-gate 			}
15030Sstevel@tonic-gate 			goto out;
15040Sstevel@tonic-gate 		}
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 		/*
15070Sstevel@tonic-gate 		 * If the message flags include both flush and sync,
15080Sstevel@tonic-gate 		 * then just sync the file out to disk if appropriate.
15090Sstevel@tonic-gate 		 */
15100Sstevel@tonic-gate 		if ((mp->flags & (FLUSHMSG | SYNC_FILE)) ==
15110Sstevel@tonic-gate 		    (FLUSHMSG | SYNC_FILE)) {
15120Sstevel@tonic-gate 			if (f->f_type == F_FILE) {
15130Sstevel@tonic-gate 				DPRINT2(5, "logit(%u): got FLUSH|SYNC "
15146358Snakanon 				    "for filed %p\n", f->f_thread,
15156358Snakanon 				    (void *)f);
15160Sstevel@tonic-gate 				(void) fsync(f->f_file);
15170Sstevel@tonic-gate 			}
15180Sstevel@tonic-gate 			goto out;
15190Sstevel@tonic-gate 		}
15200Sstevel@tonic-gate 
15210Sstevel@tonic-gate 		/*
15220Sstevel@tonic-gate 		 * Otherwise if it's a standard flush message, write
15230Sstevel@tonic-gate 		 * out any saved messages to the file.
15240Sstevel@tonic-gate 		 */
15250Sstevel@tonic-gate 		if ((mp->flags & FLUSHMSG) && (f->f_prevcount > 0)) {
15260Sstevel@tonic-gate 			set_flush_msg(f);
15270Sstevel@tonic-gate 			writemsg(SAVED, f);
15280Sstevel@tonic-gate 			goto out;
15290Sstevel@tonic-gate 		}
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 		(void) strlcpy(f->f_current.msg, mp->msg, MAXLINE+1);
15320Sstevel@tonic-gate 		(void) strlcpy(f->f_current.host, mp->hlp->hl_hosts[0],
15336358Snakanon 		    SYS_NMLN);
15340Sstevel@tonic-gate 		f->f_current.pri = mp->pri;
15350Sstevel@tonic-gate 		f->f_current.flags = mp->flags;
15360Sstevel@tonic-gate 		f->f_current.time = mp->ts;
15370Sstevel@tonic-gate 		f->f_msgflag &= ~CURRENT_VALID;
15380Sstevel@tonic-gate 		hlp = mp->hlp;
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 		prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
15410Sstevel@tonic-gate 		currofst = (f->f_current.flags & ADDDATE) ? 0 : 16;
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 		if (f->f_type == F_FORW) {
15440Sstevel@tonic-gate 			/*
15450Sstevel@tonic-gate 			 * Should not forward MARK messages, as they are
15460Sstevel@tonic-gate 			 * not defined outside of the current system.
15470Sstevel@tonic-gate 			 */
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 			if (mp->flags & MARK) {
15500Sstevel@tonic-gate 				DPRINT1(1, "logit(%u): cannot forward "
15516358Snakanon 				    "Mark\n", f->f_thread);
15520Sstevel@tonic-gate 				goto out;
15530Sstevel@tonic-gate 			}
15540Sstevel@tonic-gate 
15550Sstevel@tonic-gate 			/*
15560Sstevel@tonic-gate 			 * can not forward message if we do
15570Sstevel@tonic-gate 			 * not have a host to forward to
15580Sstevel@tonic-gate 			 */
15590Sstevel@tonic-gate 			if (hlp == (host_list_t *)NULL)
15600Sstevel@tonic-gate 				goto out;
15610Sstevel@tonic-gate 			/*
15620Sstevel@tonic-gate 			 * a forwarding loop is created on machines
15630Sstevel@tonic-gate 			 * with multiple interfaces because the
15640Sstevel@tonic-gate 			 * network address of the sender is different
15650Sstevel@tonic-gate 			 * to the receiver even though it is the
15660Sstevel@tonic-gate 			 * same machine. Instead, if the
15670Sstevel@tonic-gate 			 * hostname the source and target are
15680Sstevel@tonic-gate 			 * the same the message if thrown away
15690Sstevel@tonic-gate 			 */
15700Sstevel@tonic-gate 			forwardingloop = 0;
15710Sstevel@tonic-gate 			for (i = 0; i < hlp->hl_cnt; i++) {
15720Sstevel@tonic-gate 				if (strcmp(hlp->hl_hosts[i],
15736358Snakanon 				    f->f_un.f_forw.f_hname) == 0) {
15740Sstevel@tonic-gate 					DPRINT3(1, errmsg, f->f_thread,
15756358Snakanon 					    f->f_un.f_forw.f_hname,
15766358Snakanon 					    hlp->hl_hosts[i]);
15770Sstevel@tonic-gate 					forwardingloop = 1;
15780Sstevel@tonic-gate 					break;
15790Sstevel@tonic-gate 				}
15800Sstevel@tonic-gate 			}
15810Sstevel@tonic-gate 
15820Sstevel@tonic-gate 			if (forwardingloop == 1) {
15830Sstevel@tonic-gate 				f->f_stat.cantfwd++;
15840Sstevel@tonic-gate 				goto out;
15850Sstevel@tonic-gate 			}
15860Sstevel@tonic-gate 		}
15870Sstevel@tonic-gate 
15880Sstevel@tonic-gate 		f->f_msgflag |= CURRENT_VALID;
15890Sstevel@tonic-gate 
15900Sstevel@tonic-gate 		/* check for dup message */
15910Sstevel@tonic-gate 		if (f->f_type != F_FORW &&
15926358Snakanon 		    (f->f_msgflag & OLD_VALID) &&
15936358Snakanon 		    prevofst == currofst &&
15946358Snakanon 		    (strcmp(f->f_prevmsg.msg + prevofst,
15956358Snakanon 		    f->f_current.msg + currofst) == 0) &&
15966358Snakanon 		    (strcmp(f->f_prevmsg.host,
15976358Snakanon 		    f->f_current.host) == 0)) {
15980Sstevel@tonic-gate 			/* a dup */
15990Sstevel@tonic-gate 			DPRINT2(2, "logit(%u): msg is dup - %p\n",
16006358Snakanon 			    f->f_thread, (void *)mp);
16010Sstevel@tonic-gate 			if (currofst == 16) {
16020Sstevel@tonic-gate 				(void) strncpy(f->f_prevmsg.msg,
16036358Snakanon 				    f->f_current.msg, 15); /* update time */
16040Sstevel@tonic-gate 			}
16050Sstevel@tonic-gate 			f->f_prevcount++;
16060Sstevel@tonic-gate 			f->f_stat.dups++;
16070Sstevel@tonic-gate 			f->f_stat.total++;
16080Sstevel@tonic-gate 			f->f_msgflag &= ~CURRENT_VALID;
16090Sstevel@tonic-gate 		} else {
16100Sstevel@tonic-gate 			/* new: mark or prior dups exist */
16110Sstevel@tonic-gate 			if (f->f_current.flags & MARK || f->f_prevcount > 0) {
16120Sstevel@tonic-gate 				if (f->f_prevcount > 0 && f->f_type != F_FORW) {
16130Sstevel@tonic-gate 					set_flush_msg(f);
16140Sstevel@tonic-gate 					if (f->f_msgflag & OLD_VALID) {
16150Sstevel@tonic-gate 						writemsg(SAVED, f);
16160Sstevel@tonic-gate 					}
16170Sstevel@tonic-gate 				}
16180Sstevel@tonic-gate 				if (f->f_msgflag & CURRENT_VALID)
16190Sstevel@tonic-gate 					writemsg(CURRENT, f);
16200Sstevel@tonic-gate 				if (!(mp->flags & NOCOPY))
16210Sstevel@tonic-gate 					copy_msg(f);
16220Sstevel@tonic-gate 				if (f->f_current.flags & MARK) {
16230Sstevel@tonic-gate 					DPRINT2(2, "logit(%u): msg is "
16246358Snakanon 					    "mark - %p)\n", f->f_thread,
16256358Snakanon 					    (void *)mp);
16260Sstevel@tonic-gate 					f->f_msgflag &= ~OLD_VALID;
16270Sstevel@tonic-gate 				} else {
16280Sstevel@tonic-gate 					DPRINT2(2, "logit(%u): saving "
16296358Snakanon 					    "message - %p\n", f->f_thread,
16306358Snakanon 					    (void *)mp);
16310Sstevel@tonic-gate 				}
16320Sstevel@tonic-gate 				f->f_stat.total++;
16330Sstevel@tonic-gate 			} else { /* new message */
16340Sstevel@tonic-gate 				DPRINT2(2, "logit(%u): msg is new "
16356358Snakanon 				    "- %p\n", f->f_thread, (void *)mp);
16360Sstevel@tonic-gate 				writemsg(CURRENT, f);
16370Sstevel@tonic-gate 				if (!(mp->flags & NOCOPY))
16380Sstevel@tonic-gate 					copy_msg(f);
16390Sstevel@tonic-gate 				f->f_stat.total++;
16400Sstevel@tonic-gate 			}
16410Sstevel@tonic-gate 		}
16420Sstevel@tonic-gate 		/*
16430Sstevel@tonic-gate 		 * if message refcnt goes to zero after we decrement
16440Sstevel@tonic-gate 		 * it here, we are the last consumer of the message,
16450Sstevel@tonic-gate 		 * and we should free it.  We need to hold the lock
16460Sstevel@tonic-gate 		 * between decrementing the count and checking for
16470Sstevel@tonic-gate 		 * zero so another thread doesn't beat us to it.
16480Sstevel@tonic-gate 		 */
16490Sstevel@tonic-gate out:
16502104Sjjj 		(void) pthread_mutex_lock(&mp->msg_mutex);
16510Sstevel@tonic-gate 		refcnt = --mp->refcnt;
16522104Sjjj 		(void) pthread_mutex_unlock(&mp->msg_mutex);
16530Sstevel@tonic-gate 		if (refcnt == 0)
16540Sstevel@tonic-gate 			free_msg(mp);
16550Sstevel@tonic-gate 	}
16560Sstevel@tonic-gate 	/* register our exit */
16570Sstevel@tonic-gate 
16580Sstevel@tonic-gate 	/*
16590Sstevel@tonic-gate 	 * Pull out all pending messages, if they exist.
16600Sstevel@tonic-gate 	 */
16610Sstevel@tonic-gate 
16622104Sjjj 	(void) pthread_mutex_lock(&f->filed_mutex);
16630Sstevel@tonic-gate 
16640Sstevel@tonic-gate 	while (f->f_queue_count > 0) {
16650Sstevel@tonic-gate 		(void) dataq_dequeue(&f->f_queue, (void **)&mp, 0);
16660Sstevel@tonic-gate 		DPRINT3(5, "logit(%u): logger dequeued msg %p from queue "
16676358Snakanon 		    "%p\n",
16686358Snakanon 		    f->f_thread, (void *)mp, (void *)&f->f_queue);
16692104Sjjj 		(void) pthread_mutex_lock(&mp->msg_mutex);
16700Sstevel@tonic-gate 		refcnt = --mp->refcnt;
16712104Sjjj 		(void) pthread_mutex_unlock(&mp->msg_mutex);
16720Sstevel@tonic-gate 		if (refcnt == 0)
16730Sstevel@tonic-gate 			free_msg(mp);
16740Sstevel@tonic-gate 		f->f_queue_count--;
16750Sstevel@tonic-gate 	}
16760Sstevel@tonic-gate 
16772104Sjjj 	(void) pthread_mutex_unlock(&f->filed_mutex);
16780Sstevel@tonic-gate 
16790Sstevel@tonic-gate 	if (f->f_type != F_USERS && f->f_type != F_WALL &&
16806358Snakanon 	    f->f_type != F_UNUSED) {
16810Sstevel@tonic-gate 		if (f->f_type == F_FORW)
16820Sstevel@tonic-gate 			(void) t_close(f->f_file);
16830Sstevel@tonic-gate 		else
16840Sstevel@tonic-gate 			(void) close(f->f_file);
16850Sstevel@tonic-gate 	}
16860Sstevel@tonic-gate 
16870Sstevel@tonic-gate 	/*
16880Sstevel@tonic-gate 	 * Since f_type may have been changed before this point, we need
16890Sstevel@tonic-gate 	 * to test orig_type.
16900Sstevel@tonic-gate 	 */
16910Sstevel@tonic-gate 	if (f->f_orig_type == F_FORW) {
16920Sstevel@tonic-gate 		free(f->f_un.f_forw.f_addr.buf);
16930Sstevel@tonic-gate 	}
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 	f->f_type = F_UNUSED;
16962104Sjjj 	(void) pthread_mutex_lock(&cft);
16970Sstevel@tonic-gate 	--conf_threads;
16982104Sjjj 	(void) pthread_mutex_unlock(&cft);
16990Sstevel@tonic-gate 	DPRINT1(5, "logit(%u): logging thread exited\n", f->f_thread);
17000Sstevel@tonic-gate 	return (NULL);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate /*
17040Sstevel@tonic-gate  * change the previous message to a flush message, stating how
17050Sstevel@tonic-gate  * many repeats occurred since the last flush
17060Sstevel@tonic-gate  */
17070Sstevel@tonic-gate static void
set_flush_msg(struct filed * f)17080Sstevel@tonic-gate set_flush_msg(struct filed *f)
17090Sstevel@tonic-gate {
17100Sstevel@tonic-gate 	char tbuf[10];
17110Sstevel@tonic-gate 	int prevofst = (f->f_prevmsg.flags & ADDDATE) ? 0 : 16;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	if (f->f_prevcount == 1)
17140Sstevel@tonic-gate 		(void) strncpy(tbuf, "time", sizeof (tbuf));
17150Sstevel@tonic-gate 	else
17160Sstevel@tonic-gate 		(void) strncpy(tbuf, "times", sizeof (tbuf));
17170Sstevel@tonic-gate 
17182104Sjjj 	(void) snprintf(f->f_prevmsg.msg+prevofst,
17192104Sjjj 	    sizeof (f->f_prevmsg.msg) - prevofst,
17202104Sjjj 	    "last message repeated %d %s", f->f_prevcount, tbuf);
17210Sstevel@tonic-gate 	f->f_prevcount = 0;
17220Sstevel@tonic-gate 	f->f_msgflag |= OLD_VALID;
17230Sstevel@tonic-gate }
17240Sstevel@tonic-gate 
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate /*
17270Sstevel@tonic-gate  * the actual writing of the message is broken into a separate function
17280Sstevel@tonic-gate  * because each file has a current and saved message associated with
17290Sstevel@tonic-gate  * it (for duplicate message detection). It is necessary to be able
17300Sstevel@tonic-gate  * to write either the saved message or the current message.
17310Sstevel@tonic-gate  */
17320Sstevel@tonic-gate static void
writemsg(int selection,struct filed * f)17330Sstevel@tonic-gate writemsg(int selection, struct filed *f)
17340Sstevel@tonic-gate {
17350Sstevel@tonic-gate 	char *cp, *p;
17360Sstevel@tonic-gate 	int pri;
17370Sstevel@tonic-gate 	int flags;
17380Sstevel@tonic-gate 	int l;
17390Sstevel@tonic-gate 	time_t ts;
17400Sstevel@tonic-gate 	struct t_unitdata ud;
17410Sstevel@tonic-gate 	char *eomp, *eomp2, *from, *text, *msg;
17420Sstevel@tonic-gate 	char line[MAXLINE*2];
17430Sstevel@tonic-gate 	char head[MAXLINE+1];
17440Sstevel@tonic-gate 	char tmpbuf[MAXLINE+1];
17450Sstevel@tonic-gate 	char cbuf[30];
17460Sstevel@tonic-gate 	char *filtered;
17470Sstevel@tonic-gate 	char *msgid_start, *msgid_end;
17480Sstevel@tonic-gate 	pthread_t mythreadno;
17490Sstevel@tonic-gate 	size_t	hlen, filter_len;
17500Sstevel@tonic-gate 
17510Sstevel@tonic-gate 	if (Debug) {
17520Sstevel@tonic-gate 		mythreadno = pthread_self();
17530Sstevel@tonic-gate 	}
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 	switch (selection) {
17560Sstevel@tonic-gate 	default:
17570Sstevel@tonic-gate 	case CURRENT:		/* print current message */
17580Sstevel@tonic-gate 		msg = f->f_current.msg;
17590Sstevel@tonic-gate 		from = f->f_current.host;
17600Sstevel@tonic-gate 		pri = f->f_current.pri;
17610Sstevel@tonic-gate 		flags = f->f_current.flags;
17620Sstevel@tonic-gate 		ts = f->f_current.time;
17630Sstevel@tonic-gate 		f->f_msgflag &= ~CURRENT_VALID;
17640Sstevel@tonic-gate 		break;
17650Sstevel@tonic-gate 	case SAVED:		/* print saved message */
17660Sstevel@tonic-gate 		msg = f->f_prevmsg.msg;
17670Sstevel@tonic-gate 		from = f->f_prevmsg.host;
17680Sstevel@tonic-gate 		pri = f->f_prevmsg.pri;
17690Sstevel@tonic-gate 		flags = f->f_prevmsg.flags;
17700Sstevel@tonic-gate 		ts = f->f_prevmsg.time;
17710Sstevel@tonic-gate 		f->f_msgflag &= ~OLD_VALID;
17720Sstevel@tonic-gate 		break;
17730Sstevel@tonic-gate 	}
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 	if (msg[0] == '\0')
17760Sstevel@tonic-gate 		return;
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	cp = line;
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	if (flags & ADDDATE)
17810Sstevel@tonic-gate 		(void) strncpy(cp, ctime_r(&ts, cbuf) + 4, 15);
17820Sstevel@tonic-gate 	else
17830Sstevel@tonic-gate 		(void) strncpy(cp, msg, 15);
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate 	line[15] = '\0';
17860Sstevel@tonic-gate 	(void) strcat(cp, " ");
17870Sstevel@tonic-gate 	(void) strcat(cp, from);
17880Sstevel@tonic-gate 	(void) strcat(cp, " ");
17890Sstevel@tonic-gate 	text = cp + strlen(cp);
17900Sstevel@tonic-gate 
17910Sstevel@tonic-gate 	if (flags & ADDDATE)
17920Sstevel@tonic-gate 		(void) strcat(cp, msg);
17930Sstevel@tonic-gate 	else
17940Sstevel@tonic-gate 		(void) strcat(cp, msg+16);
17950Sstevel@tonic-gate 	DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
17960Sstevel@tonic-gate 
17970Sstevel@tonic-gate 	errno = 0;
17980Sstevel@tonic-gate 	t_errno = 0;
17990Sstevel@tonic-gate 	switch (f->f_type) {
18000Sstevel@tonic-gate 	case F_UNUSED:
18010Sstevel@tonic-gate 		DPRINT1(1, "writemsg(%u): UNUSED\n", mythreadno);
18020Sstevel@tonic-gate 		break;
18030Sstevel@tonic-gate 	case F_FORW:
18040Sstevel@tonic-gate 		DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
18056358Snakanon 		    mythreadno, msg, TypeNames[f->f_type],
18066358Snakanon 		    f->f_un.f_forw.f_hname);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 		hlen = snprintf(head, sizeof (head),
18096358Snakanon 		    "<%d>%.15s ", pri, cp);
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): head = \"%s\"\n", mythreadno, head);
18120Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): hlen = %d\n", mythreadno, hlen);
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate 		l = strlen(text);
18150Sstevel@tonic-gate 		p = text;
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): text = \"%s\"\n", mythreadno, text);
18180Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): strlen(text) = %d\n", mythreadno, l);
18190Sstevel@tonic-gate 
18200Sstevel@tonic-gate 		(void) strncpy(tmpbuf, head, hlen);
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate 		while (l > 0) {
18230Sstevel@tonic-gate 			size_t	len;
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 			len = copy_frwd(tmpbuf + hlen, sizeof (tmpbuf) - hlen,
18266358Snakanon 			    p, l);
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 			DPRINT2(5, "writemsg(%u): tmpbuf = \"%s\"\n",
18296358Snakanon 			    mythreadno, tmpbuf);
18300Sstevel@tonic-gate 			DPRINT2(5, "writemsg(%u): len = %d\n", mythreadno,
18316358Snakanon 			    len);
18320Sstevel@tonic-gate 			DPRINT2(5, "writemsg(%u): strlen(tmpbuf) = %d\n",
18336358Snakanon 			    mythreadno, strlen(tmpbuf));
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate 			ud.opt.buf = NULL;
18360Sstevel@tonic-gate 			ud.opt.len = 0;
18370Sstevel@tonic-gate 			ud.udata.buf = tmpbuf;
18380Sstevel@tonic-gate 			ud.udata.len = len + hlen;
18390Sstevel@tonic-gate 			ud.addr.maxlen = f->f_un.f_forw.f_addr.maxlen;
18400Sstevel@tonic-gate 			ud.addr.buf = f->f_un.f_forw.f_addr.buf;
18410Sstevel@tonic-gate 			ud.addr.len = f->f_un.f_forw.f_addr.len;
18420Sstevel@tonic-gate 			if (t_sndudata(f->f_file, &ud) < 0) {
18430Sstevel@tonic-gate 				if ((hup_state & HUP_INPROGRESS) &&
18446358Snakanon 				    f->f_type == F_UNUSED) {
18450Sstevel@tonic-gate 					break;
18460Sstevel@tonic-gate 				}
18470Sstevel@tonic-gate 				(void) t_close(f->f_file);
18480Sstevel@tonic-gate 				f->f_type = F_UNUSED;
18490Sstevel@tonic-gate 				logerror("t_sndudata");
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 				/*
18520Sstevel@tonic-gate 				 * Since it has already failed, it's not worth
18530Sstevel@tonic-gate 				 * continuing output from the middle of
18540Sstevel@tonic-gate 				 * message string.
18550Sstevel@tonic-gate 				 */
18560Sstevel@tonic-gate 				break;
18570Sstevel@tonic-gate 			}
18580Sstevel@tonic-gate 			p += len;
18590Sstevel@tonic-gate 			l -= len;
18600Sstevel@tonic-gate 		}
18610Sstevel@tonic-gate 		break;
18620Sstevel@tonic-gate 	case F_CONSOLE:
18630Sstevel@tonic-gate 	case F_TTY:
18640Sstevel@tonic-gate 	case F_FILE:
18650Sstevel@tonic-gate 	case F_USERS:
18660Sstevel@tonic-gate 	case F_WALL:
18670Sstevel@tonic-gate 		DPRINT4(1, "writemsg(%u): Logging msg '%s' to %s %s\n",
18686358Snakanon 		    mythreadno, msg, TypeNames[f->f_type],
18696358Snakanon 		    ((f->f_type == F_USERS) || (f->f_type == F_WALL)) ?
18706358Snakanon 		    "" : f->f_un.f_fname);
18710Sstevel@tonic-gate 		/*
18720Sstevel@tonic-gate 		 * filter the string in preparation for writing it
18730Sstevel@tonic-gate 		 * save the original for possible forwarding.
18740Sstevel@tonic-gate 		 * In case every byte in cp is a control character,
18750Sstevel@tonic-gate 		 * allocates large enough buffer for filtered.
18760Sstevel@tonic-gate 		 */
18770Sstevel@tonic-gate 
18780Sstevel@tonic-gate 		filter_len = strlen(cp) * 4 + 1;
18790Sstevel@tonic-gate 		filtered = (char *)malloc(filter_len);
18800Sstevel@tonic-gate 		if (!filtered) {
18810Sstevel@tonic-gate 			MALLOC_FAIL("dropping message");
18820Sstevel@tonic-gate 			/* seems we can just return */
18830Sstevel@tonic-gate 			return;
18840Sstevel@tonic-gate 		}
18850Sstevel@tonic-gate 		DPRINT3(5, "writemsg(%u): "
18866358Snakanon 		    "filtered allocated (%p: %d bytes)\n",
18876358Snakanon 		    mythreadno, (void *)filtered, filter_len);
18880Sstevel@tonic-gate 		/* -3 : we may add "\r\n" to ecomp(filtered) later */
18890Sstevel@tonic-gate 		filter_string(cp, filtered, filter_len - 3);
18900Sstevel@tonic-gate 
18910Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): strlen(filtered) = %d\n",
18926358Snakanon 		    mythreadno, strlen(filtered));
18930Sstevel@tonic-gate 		/*
18940Sstevel@tonic-gate 		 * If we're writing to the console, strip out the message ID
18950Sstevel@tonic-gate 		 * to reduce visual clutter.
18960Sstevel@tonic-gate 		 */
18970Sstevel@tonic-gate 		if ((msgid_start = strstr(filtered, "[ID ")) != NULL &&
18986358Snakanon 		    (msgid_end = strstr(msgid_start, "] ")) != NULL &&
18996358Snakanon 		    f->f_type == F_CONSOLE)
19000Sstevel@tonic-gate 			(void) strcpy(msgid_start, msgid_end + 2);
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 		eomp = filtered + strlen(filtered);
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 		if ((f->f_type == F_USERS) || (f->f_type == F_WALL)) {
19050Sstevel@tonic-gate 			/* CSTYLED */
19060Sstevel@tonic-gate 			(void) strcat(eomp, "\r\n"); /*lint !e669*/
19070Sstevel@tonic-gate 			/*
19080Sstevel@tonic-gate 			 * Since wallmsg messes with utmpx we need
19090Sstevel@tonic-gate 			 * to guarantee single threadedness...
19100Sstevel@tonic-gate 			 */
19110Sstevel@tonic-gate 			(void) pthread_mutex_lock(&wmp);
19120Sstevel@tonic-gate 			wallmsg(f, from, filtered);
19130Sstevel@tonic-gate 			(void) pthread_mutex_unlock(&wmp);
19140Sstevel@tonic-gate 
19150Sstevel@tonic-gate 			/*
19160Sstevel@tonic-gate 			 * The contents of filtered have been copied
19170Sstevel@tonic-gate 			 * out to the struct walldev. We should free it here.
19180Sstevel@tonic-gate 			 */
19190Sstevel@tonic-gate 
19200Sstevel@tonic-gate 			free(filtered);
19210Sstevel@tonic-gate 
19220Sstevel@tonic-gate 			/* exiting the switch */
19230Sstevel@tonic-gate 			break;
19240Sstevel@tonic-gate 		} else if (f->f_type != F_FILE) {
19250Sstevel@tonic-gate 			/* CSTYLED */
19260Sstevel@tonic-gate 			(void) strncpy(eomp, "\r\n", 3); /*lint !e669*/
19270Sstevel@tonic-gate 		} else {
19280Sstevel@tonic-gate 			if ((eomp2 = strchr(filtered, '\r')) != NULL) {
19290Sstevel@tonic-gate 				(void) strncpy(eomp2, "\n", 2);
19300Sstevel@tonic-gate 			} else {
19310Sstevel@tonic-gate 				/* CSTYLED */
19320Sstevel@tonic-gate 				(void) strncpy(eomp, "\n", 2); /*lint !e669*/
19330Sstevel@tonic-gate 			}
19340Sstevel@tonic-gate 		}
19350Sstevel@tonic-gate 		if (write(f->f_file, filtered, strlen(filtered)) < 0) {
19360Sstevel@tonic-gate 			int e = errno;
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 			if ((hup_state & HUP_INPROGRESS) &&
19396358Snakanon 			    f->f_type == F_UNUSED) {
19400Sstevel@tonic-gate 				free(filtered);
19410Sstevel@tonic-gate 				break;
19420Sstevel@tonic-gate 			}
19430Sstevel@tonic-gate 			(void) close(f->f_file);
19440Sstevel@tonic-gate 			/*
19450Sstevel@tonic-gate 			 * Check for EBADF on TTY's due
19460Sstevel@tonic-gate 			 * to vhangup() XXX
19470Sstevel@tonic-gate 			 */
19480Sstevel@tonic-gate 			if (e == EBADF && f->f_type != F_FILE) {
19490Sstevel@tonic-gate 				f->f_file = open(f->f_un.f_fname,
19506358Snakanon 				    O_WRONLY|O_APPEND|O_NOCTTY);
19510Sstevel@tonic-gate 				if (f->f_file < 0) {
19520Sstevel@tonic-gate 					f->f_type = F_UNUSED;
19530Sstevel@tonic-gate 					logerror(f->f_un.f_fname);
19540Sstevel@tonic-gate 					f->f_stat.errs++;
19550Sstevel@tonic-gate 				}
19560Sstevel@tonic-gate 				untty();
19570Sstevel@tonic-gate 			} else {
19580Sstevel@tonic-gate 				f->f_type = F_UNUSED;
19590Sstevel@tonic-gate 				f->f_stat.errs++;
19600Sstevel@tonic-gate 				errno = e;
19610Sstevel@tonic-gate 				logerror(f->f_un.f_fname);
19620Sstevel@tonic-gate 			}
19630Sstevel@tonic-gate 		} else if (flags & SYNC_FILE)
19640Sstevel@tonic-gate 			if (((pri & LOG_FACMASK) >> 3) == LOG_KERN)
19650Sstevel@tonic-gate 				(void) fsync(f->f_file);
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 		DPRINT2(5, "writemsg(%u): freeing filtered (%p)\n",
19686358Snakanon 		    mythreadno, (void *)filtered);
19690Sstevel@tonic-gate 
19700Sstevel@tonic-gate 		free(filtered);
19710Sstevel@tonic-gate 		break;
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate }
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate /*
19760Sstevel@tonic-gate  *  WALLMSG -- Write a message to the world at large
19770Sstevel@tonic-gate  *
19780Sstevel@tonic-gate  *	Write the specified message to either the entire
19790Sstevel@tonic-gate  *	world, or a list of approved users.
19800Sstevel@tonic-gate  */
19810Sstevel@tonic-gate static void
wallmsg(struct filed * f,char * from,char * msg)19820Sstevel@tonic-gate wallmsg(struct filed *f, char *from, char *msg)
19830Sstevel@tonic-gate {
19840Sstevel@tonic-gate 	int i;
19850Sstevel@tonic-gate 	size_t	len, clen;
19860Sstevel@tonic-gate 	char *buf = NULL;
19870Sstevel@tonic-gate 	struct utmpx *utxp;
19880Sstevel@tonic-gate 	time_t now;
19890Sstevel@tonic-gate 	char line[512], dev[100];
19900Sstevel@tonic-gate 	char cp[MAXLINE+1];
19910Sstevel@tonic-gate 	struct stat statbuf;
19920Sstevel@tonic-gate 	walldev_t *w;
19930Sstevel@tonic-gate 	char cbuf[30];
19940Sstevel@tonic-gate 	pthread_t mythreadno;
19950Sstevel@tonic-gate 
19960Sstevel@tonic-gate 	if (Debug) {
19970Sstevel@tonic-gate 		mythreadno = pthread_self();
19980Sstevel@tonic-gate 	}
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate 	if (access(UTMPX_FILE, R_OK) != 0 || stat(UTMPX_FILE, &statbuf) != 0) {
20010Sstevel@tonic-gate 		logerror(UTMPX_FILE);
20020Sstevel@tonic-gate 		return;
20030Sstevel@tonic-gate 	} else if (statbuf.st_uid != 0 || (statbuf.st_mode & 07777) != 0644) {
20042104Sjjj 		(void) snprintf(line, sizeof (line), "%s %s", UTMPX_FILE,
20056358Snakanon 		    "not owned by root or not mode 644.\n"
20066358Snakanon 		    "This file must be owned by root "
20076358Snakanon 		    "and not writable by\n"
20086358Snakanon 		    "anyone other than root.  This alert is being "
20096358Snakanon 		    "dropped because of\n"
20106358Snakanon 		    "this problem.");
20110Sstevel@tonic-gate 		logerror(line);
20120Sstevel@tonic-gate 		return;
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	if (f->f_type == F_WALL) {
20160Sstevel@tonic-gate 		(void) time(&now);
20170Sstevel@tonic-gate 		len = snprintf(line, sizeof (line),
20186358Snakanon 		    "\r\n\7Message from syslogd@%s "
20196358Snakanon 		    "at %.24s ...\r\n", from, ctime_r(&now, cbuf));
20200Sstevel@tonic-gate 		len += strlen(msg + 16);
20210Sstevel@tonic-gate 		buf = (char *)malloc(len + 1);
20220Sstevel@tonic-gate 		if (!buf) {
20230Sstevel@tonic-gate 			MALLOC_FAIL("dropping message");
20240Sstevel@tonic-gate 			return;
20250Sstevel@tonic-gate 		}
20260Sstevel@tonic-gate 		DPRINT3(5, "wallmsg(%u): buf allocated (%p: %d bytes)\n",
20276358Snakanon 		    mythreadno, (void *)buf, len + 1);
20280Sstevel@tonic-gate 		(void) strcpy(buf, line);
20290Sstevel@tonic-gate 		(void) strcat(buf, msg + 16);
20300Sstevel@tonic-gate 		clen = copy_frwd(cp, sizeof (cp), buf, len);
20310Sstevel@tonic-gate 		DPRINT2(5, "wallmsg(%u): clen = %d\n",
20326358Snakanon 		    mythreadno, clen);
20330Sstevel@tonic-gate 		DPRINT2(5, "wallmsg(%u): freeing buf (%p)\n",
20346358Snakanon 		    mythreadno, (void *)buf);
20350Sstevel@tonic-gate 		free(buf);
20360Sstevel@tonic-gate 	} else {
20370Sstevel@tonic-gate 		clen = copy_frwd(cp, sizeof (cp), msg, strlen(msg));
20380Sstevel@tonic-gate 		DPRINT2(5, "wallmsg(%u): clen = %d\n",
20396358Snakanon 		    mythreadno, clen);
20400Sstevel@tonic-gate 	}
20410Sstevel@tonic-gate 	/* scan the user login file */
20420Sstevel@tonic-gate 	setutxent();
20430Sstevel@tonic-gate 	while ((utxp = getutxent()) != NULL) {
20440Sstevel@tonic-gate 		/* is this slot used? */
20450Sstevel@tonic-gate 		if (utxp->ut_name[0] == '\0' ||
20466358Snakanon 		    utxp->ut_line[0] == '\0' ||
20476358Snakanon 		    utxp->ut_type != USER_PROCESS)
20480Sstevel@tonic-gate 			continue;
20490Sstevel@tonic-gate 		/* should we send the message to this user? */
20500Sstevel@tonic-gate 		if (f->f_type == F_USERS) {
20510Sstevel@tonic-gate 			for (i = 0; i < MAXUNAMES; i++) {
20520Sstevel@tonic-gate 				if (!f->f_un.f_uname[i][0]) {
20530Sstevel@tonic-gate 					i = MAXUNAMES;
20540Sstevel@tonic-gate 					break;
20550Sstevel@tonic-gate 				}
20560Sstevel@tonic-gate 				if (strncmp(f->f_un.f_uname[i],
20576358Snakanon 				    utxp->ut_name, UNAMESZ) == 0)
20580Sstevel@tonic-gate 					break;
20590Sstevel@tonic-gate 			}
20600Sstevel@tonic-gate 			if (i >= MAXUNAMES)
20610Sstevel@tonic-gate 				continue;
20620Sstevel@tonic-gate 		}
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate 		/* compute the device name */
20650Sstevel@tonic-gate 		if (utxp->ut_line[0] == '/') {
20660Sstevel@tonic-gate 			(void) strncpy(dev, utxp->ut_line, UDEVSZ);
20670Sstevel@tonic-gate 		} else {
20680Sstevel@tonic-gate 			(void) strcpy(dev, "/dev/");
20690Sstevel@tonic-gate 			(void) strncat(dev, utxp->ut_line, UDEVSZ);
20700Sstevel@tonic-gate 		}
20710Sstevel@tonic-gate 		DPRINT2(1, "wallmsg(%u): write to '%s'\n", mythreadno,
20726358Snakanon 		    dev);
20730Sstevel@tonic-gate 
20740Sstevel@tonic-gate 		if ((w = malloc(sizeof (walldev_t))) != NULL) {
20750Sstevel@tonic-gate 			int rc;
20760Sstevel@tonic-gate 			(void) pthread_attr_init(&w->thread_attr);
20770Sstevel@tonic-gate 			(void) pthread_attr_setdetachstate(&w->thread_attr,
20786358Snakanon 			    PTHREAD_CREATE_DETACHED);
20790Sstevel@tonic-gate 			(void) strncpy(w->dev, dev, PATH_MAX);
20800Sstevel@tonic-gate 			(void) strncpy(w->msg, cp, MAXLINE+1);
20810Sstevel@tonic-gate 			(void) strncpy(w->ut_name, utxp->ut_name,
20820Sstevel@tonic-gate 			    sizeof (w->ut_name));
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 			if ((rc = pthread_create(&w->thread, &w->thread_attr,
20856358Snakanon 			    writetodev, (void *) w)) != 0) {
20860Sstevel@tonic-gate 				DPRINT2(5, "wallmsg(%u): wallmsg thread "
20876358Snakanon 				    "create failed rc = %d\n",
20886358Snakanon 				    mythreadno, rc);
20890Sstevel@tonic-gate 				free(w);
20900Sstevel@tonic-gate 				break;
20910Sstevel@tonic-gate 			}
20920Sstevel@tonic-gate 		} else {
20930Sstevel@tonic-gate 			MALLOC_FAIL("dropping message to user");
20940Sstevel@tonic-gate 		}
20950Sstevel@tonic-gate 	}
20960Sstevel@tonic-gate 	/* close the user login file */
20970Sstevel@tonic-gate 	endutxent();
20980Sstevel@tonic-gate }
20990Sstevel@tonic-gate 
21000Sstevel@tonic-gate /*
21010Sstevel@tonic-gate  * Each time we need to write to a tty device (a potentially expensive
21020Sstevel@tonic-gate  * or long-running operation) this routine gets called as a new
21030Sstevel@tonic-gate  * detached, unbound thread. This allows writes to many devices
21040Sstevel@tonic-gate  * to proceed nearly in parallel, without having to resort to
21050Sstevel@tonic-gate  * asynchronous I/O or forking.
21060Sstevel@tonic-gate  */
21070Sstevel@tonic-gate static void *
writetodev(void * ap)21080Sstevel@tonic-gate writetodev(void *ap)
21090Sstevel@tonic-gate {
21100Sstevel@tonic-gate 	walldev_t *w = ap;
21110Sstevel@tonic-gate 	int ttyf;
21120Sstevel@tonic-gate 	int len;
21130Sstevel@tonic-gate 	struct stat statb;
21140Sstevel@tonic-gate 	struct passwd pw, *pwp;
21150Sstevel@tonic-gate 	char pwbuf[MAXLINE];
21160Sstevel@tonic-gate 	pthread_t mythreadno;
21170Sstevel@tonic-gate 
21180Sstevel@tonic-gate 	if (Debug) {
21190Sstevel@tonic-gate 		mythreadno = pthread_self();
21200Sstevel@tonic-gate 	}
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	DPRINT1(1, "writetodev(%u): Device writer thread started\n",
21236358Snakanon 	    mythreadno);
21240Sstevel@tonic-gate 
21250Sstevel@tonic-gate 	len = strlen(w->msg);
21260Sstevel@tonic-gate 
21270Sstevel@tonic-gate 	ttyf = open(w->dev, O_WRONLY|O_NOCTTY|O_NDELAY);
21280Sstevel@tonic-gate 	if (ttyf >= 0) {
21290Sstevel@tonic-gate 		if (fstat(ttyf, &statb) != 0) {
21300Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): Can't stat '%s'\n",
21316358Snakanon 			    mythreadno, w->dev);
21320Sstevel@tonic-gate 			errno = 0;
21330Sstevel@tonic-gate 			logerror("Can't stat '%s'", w->dev);
21340Sstevel@tonic-gate 		} else if (!(statb.st_mode & S_IWRITE)) {
21350Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): Can't write to "
21366358Snakanon 			    "'%s'\n", mythreadno, w->dev);
21370Sstevel@tonic-gate 		} else if (!isatty(ttyf)) {
21380Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): '%s' not a tty\n",
21396358Snakanon 			    mythreadno, w->dev);
21400Sstevel@tonic-gate 			/*
21410Sstevel@tonic-gate 			 * We might hit dtremote here. Don't generate
21420Sstevel@tonic-gate 			 * error message.
21430Sstevel@tonic-gate 			 */
21440Sstevel@tonic-gate 		} else if (getpwuid_r(statb.st_uid, &pw, pwbuf,
21456358Snakanon 		    sizeof (pwbuf), &pwp) != 0) {
21460Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): Can't determine owner "
21476358Snakanon 			    "of '%s'\n", mythreadno, w->dev);
21480Sstevel@tonic-gate 			errno = 0;
21490Sstevel@tonic-gate 			logerror("Can't determine owner of '%s'", w->dev);
21500Sstevel@tonic-gate 		} else if (strncmp(pw.pw_name, w->ut_name, UNAMESZ) != 0) {
21510Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): Bad terminal owner '%s'"
21526358Snakanon 			    "\n", mythreadno, w->dev);
21530Sstevel@tonic-gate 			errno = 0;
21540Sstevel@tonic-gate 			logerror("%s %s owns '%s' %s %.*s",
21556358Snakanon 			    "Bad terminal owner;", pw.pw_name, w->dev,
21566358Snakanon 			    "but utmpx says", UNAMESZ, w->ut_name);
21570Sstevel@tonic-gate 		} else if (write(ttyf, w->msg, len) != len) {
21580Sstevel@tonic-gate 			DPRINT2(1, "writetodev(%u): Write failed to "
21596358Snakanon 			    "'%s'\n", mythreadno, w->dev);
21600Sstevel@tonic-gate 			errno = 0;
21610Sstevel@tonic-gate 			logerror("Write failed to '%s'", w->dev);
21620Sstevel@tonic-gate 		}
21630Sstevel@tonic-gate 
21640Sstevel@tonic-gate 		DPRINT2(1, "writetodev(%u): write to '%s' succeeded\n",
21656358Snakanon 		    mythreadno, w->dev);
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 		(void) close(ttyf);
21680Sstevel@tonic-gate 	} else {
21690Sstevel@tonic-gate 		DPRINT2(1, "writetodev(%u): Can't open '%s'\n",
21706358Snakanon 		    mythreadno, w->dev);
21710Sstevel@tonic-gate 	}
21720Sstevel@tonic-gate 
21732104Sjjj 	(void) pthread_attr_destroy(&w->thread_attr);
21740Sstevel@tonic-gate 	free(w);
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 	DPRINT1(1, "writetodev(%u): Device writer thread exiting\n",
21776358Snakanon 	    mythreadno);
21780Sstevel@tonic-gate 
21790Sstevel@tonic-gate 	pthread_exit(0);
21800Sstevel@tonic-gate 	return (NULL);
21810Sstevel@tonic-gate 	/*NOTREACHED*/
21820Sstevel@tonic-gate }
21830Sstevel@tonic-gate 
21840Sstevel@tonic-gate /*
21850Sstevel@tonic-gate  * Return a printable representation of a host address. If unable to
21860Sstevel@tonic-gate  * look up hostname, format the numeric address for display instead.
21870Sstevel@tonic-gate  *
21880Sstevel@tonic-gate  * First calls hnc_lookup to see if there is valid cache entry for
21890Sstevel@tonic-gate  * given network address. If it failed, cvthname looks up hostname,
21900Sstevel@tonic-gate  * and push the results into the hostname cache.
21910Sstevel@tonic-gate  */
21920Sstevel@tonic-gate static host_list_t *
cvthname(struct netbuf * nbp,struct netconfig * ncp,char * failsafe_addr)21930Sstevel@tonic-gate cvthname(struct netbuf *nbp, struct netconfig *ncp, char *failsafe_addr)
21940Sstevel@tonic-gate {
21950Sstevel@tonic-gate 	int i;
21960Sstevel@tonic-gate 	host_list_t *h;
21970Sstevel@tonic-gate 	struct nd_hostservlist *hsp;
21980Sstevel@tonic-gate 	struct nd_hostserv *hspp;
21990Sstevel@tonic-gate 	pthread_t mythreadno;
2200955Spd155743 	int hindex;
22010Sstevel@tonic-gate 	char *uap;
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	if (Debug) {
22040Sstevel@tonic-gate 		mythreadno = pthread_self();
22050Sstevel@tonic-gate 	}
22060Sstevel@tonic-gate 
22070Sstevel@tonic-gate 	if (Debug)
22080Sstevel@tonic-gate 		uap = taddr2uaddr(ncp, nbp);
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	DPRINT2(2, "cvthname(%u): looking up hostname for %s\n",
22116358Snakanon 	    mythreadno, uap ? uap : "<unknown>");
22120Sstevel@tonic-gate 
2213955Spd155743 	if ((h = hnc_lookup(nbp, ncp, &hindex)) != NULL) {
22140Sstevel@tonic-gate 		DPRINT4(2, "cvthname(%u): Cache found %p for %s (%s)\n",
22156358Snakanon 		    mythreadno, (void *)h, uap ? uap : "<unknown>",
22166358Snakanon 		    h->hl_hosts[0]);
22170Sstevel@tonic-gate 		return (h);
22180Sstevel@tonic-gate 	}
22190Sstevel@tonic-gate 	DPRINT2(2, "cvthname(%u): No cache found for %s\n",
22206358Snakanon 	    mythreadno, uap ? uap : "<unknown>");
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	if (Debug)
22230Sstevel@tonic-gate 		free(uap);
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 	if (ncp->nc_semantics != NC_TPI_CLTS) {
22260Sstevel@tonic-gate 		return (NULL);
22270Sstevel@tonic-gate 	}
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 	/* memory allocation failure here is fatal */
22300Sstevel@tonic-gate 	if ((h = malloc(sizeof (host_list_t))) == NULL) {
22310Sstevel@tonic-gate 		MALLOC_FAIL("host name conversion");
22320Sstevel@tonic-gate 		return (NULL);
22330Sstevel@tonic-gate 	}
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 	if (netdir_getbyaddr(ncp, &hsp, nbp) == 0) {
22360Sstevel@tonic-gate 		if (hsp->h_cnt <= 0) {
22370Sstevel@tonic-gate out:			netdir_free((void *)hsp, ND_HOSTSERVLIST);
22380Sstevel@tonic-gate 			free(h);
22390Sstevel@tonic-gate 			return (NULL);
22400Sstevel@tonic-gate 		}
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 		hspp = hsp->h_hostservs;
22430Sstevel@tonic-gate 		h->hl_cnt = hsp->h_cnt;
22440Sstevel@tonic-gate 		h->hl_hosts = (char **)malloc(sizeof (char *) * (h->hl_cnt));
22450Sstevel@tonic-gate 		if (h->hl_hosts == NULL) {
22460Sstevel@tonic-gate 			MALLOC_FAIL("host name conversion");
22470Sstevel@tonic-gate 			goto out;
22480Sstevel@tonic-gate 		}
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 		DPRINT2(2, "cvthname(%u): Found %d hostnames\n",
22516358Snakanon 		    mythreadno, h->hl_cnt);
22520Sstevel@tonic-gate 		for (i = 0; i < h->hl_cnt; i++) {
22530Sstevel@tonic-gate 			h->hl_hosts[i] = (char *)
22540Sstevel@tonic-gate 			    malloc(sizeof (char) * (strlen(hspp->h_host) + 1));
22550Sstevel@tonic-gate 			if (h->hl_hosts[i] == NULL) {
22560Sstevel@tonic-gate 				int j;
22570Sstevel@tonic-gate 				for (j = 0; j < i; j++) {
22580Sstevel@tonic-gate 					free(h->hl_hosts[j]);
22590Sstevel@tonic-gate 				}
22600Sstevel@tonic-gate 				free(h->hl_hosts);
22610Sstevel@tonic-gate 				MALLOC_FAIL("host name conversion");
22620Sstevel@tonic-gate 				goto out;
22630Sstevel@tonic-gate 			}
22640Sstevel@tonic-gate 			(void) strcpy(h->hl_hosts[i], hspp->h_host);
22650Sstevel@tonic-gate 			hspp++;
22660Sstevel@tonic-gate 		}
22670Sstevel@tonic-gate 		netdir_free((void *)hsp, ND_HOSTSERVLIST);
22680Sstevel@tonic-gate 	} else { /* unknown address */
22690Sstevel@tonic-gate 		h->hl_cnt = 1;
22700Sstevel@tonic-gate 		h->hl_hosts = (char **)malloc(sizeof (char *));
22710Sstevel@tonic-gate 		if (h->hl_hosts == NULL) {
22720Sstevel@tonic-gate 			free(h);
22730Sstevel@tonic-gate 			MALLOC_FAIL("host name conversion");
22740Sstevel@tonic-gate 			return (NULL);
22750Sstevel@tonic-gate 		}
22760Sstevel@tonic-gate 		h->hl_hosts[0] = (char *)malloc(strlen(failsafe_addr) + 3);
22770Sstevel@tonic-gate 		if (h->hl_hosts[0] == NULL) {
22780Sstevel@tonic-gate 			free(h->hl_hosts);
22790Sstevel@tonic-gate 			free(h);
22800Sstevel@tonic-gate 			MALLOC_FAIL("host name conversion");
22810Sstevel@tonic-gate 			return (NULL);
22820Sstevel@tonic-gate 		}
22832104Sjjj 		/*LINTED*/
22840Sstevel@tonic-gate 		(void) sprintf(h->hl_hosts[0], "[%s]", failsafe_addr);
22850Sstevel@tonic-gate 		DPRINT2(1, "cvthname(%u): Hostname lookup failed "
22866358Snakanon 		    "- using address %s instead\n",
22876358Snakanon 		    mythreadno, h->hl_hosts[0]);
22880Sstevel@tonic-gate 	}
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate 	h->hl_refcnt = 1;
22910Sstevel@tonic-gate 	if (pthread_mutex_init(&h->hl_mutex, NULL) != 0) {
22920Sstevel@tonic-gate 		logerror("pthread_mutex_init failed");
22930Sstevel@tonic-gate 		/* This host_list won't be shared by the cache. */
22940Sstevel@tonic-gate 		return (h);
22950Sstevel@tonic-gate 	}
2296955Spd155743 	hnc_register(nbp, ncp, h, hindex);
22970Sstevel@tonic-gate 	DPRINT3(2, "cvthname(%u): returning %p for %s\n",
22986358Snakanon 	    mythreadno, (void *)h, h->hl_hosts[0]);
22990Sstevel@tonic-gate 	return (h);
23000Sstevel@tonic-gate }
23010Sstevel@tonic-gate 
23020Sstevel@tonic-gate /*
23030Sstevel@tonic-gate  * Print syslogd errors some place. Need to be careful here, because
23040Sstevel@tonic-gate  * this routine is called at times when we're not initialized and
23050Sstevel@tonic-gate  * ready to log messages...in this case, fall back to using the console.
23060Sstevel@tonic-gate  */
23070Sstevel@tonic-gate void
logerror(const char * type,...)23080Sstevel@tonic-gate logerror(const char *type, ...)
23090Sstevel@tonic-gate {
23100Sstevel@tonic-gate 	char buf[MAXLINE+1];
23110Sstevel@tonic-gate 	pthread_t mythreadno;
23120Sstevel@tonic-gate 	int flag;
23130Sstevel@tonic-gate 	va_list ap;
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 	if (Debug) {
23160Sstevel@tonic-gate 		mythreadno = pthread_self();
23170Sstevel@tonic-gate 	}
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 	va_start(ap, type);
23200Sstevel@tonic-gate 	logerror_format(type, buf, ap);
23210Sstevel@tonic-gate 	va_end(ap);
23220Sstevel@tonic-gate 	DPRINT2(1, "logerror(%u): %s\n", mythreadno, buf);
23230Sstevel@tonic-gate 
23242104Sjjj 	(void) pthread_mutex_lock(&logerror_lock);
23250Sstevel@tonic-gate 	if (!interrorlog) {
23260Sstevel@tonic-gate 		flag = 0;
23270Sstevel@tonic-gate 		if (logerror_to_console(1, buf) == 0) {
23280Sstevel@tonic-gate 			/* has written to the console */
23290Sstevel@tonic-gate 			flag = IGN_CONS;
23300Sstevel@tonic-gate 		}
23310Sstevel@tonic-gate 		(void) logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE|flag, 1);
23320Sstevel@tonic-gate 	} else {
23330Sstevel@tonic-gate 		if (logmymsg(LOG_SYSLOG|LOG_ERR, buf, ADDDATE, 0) == -1) {
23340Sstevel@tonic-gate 			(void) logerror_to_console(1, buf);
23350Sstevel@tonic-gate 		}
23360Sstevel@tonic-gate 	}
23372104Sjjj 	(void) pthread_mutex_unlock(&logerror_lock);
23380Sstevel@tonic-gate 
23390Sstevel@tonic-gate 	errno = 0;
23400Sstevel@tonic-gate 	t_errno = 0;
23410Sstevel@tonic-gate }
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate static void
logerror_format(const char * type,char * buf,va_list ap)23440Sstevel@tonic-gate logerror_format(const char *type, char *buf, va_list ap)
23450Sstevel@tonic-gate {
23460Sstevel@tonic-gate 	char tmpbuf[MAXLINE + 1];
23470Sstevel@tonic-gate 	pthread_t mythreadno;
23480Sstevel@tonic-gate 
23490Sstevel@tonic-gate 	if (Debug) {
23500Sstevel@tonic-gate 		mythreadno = pthread_self();
23510Sstevel@tonic-gate 	}
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	(void) vsnprintf(tmpbuf, MAXLINE, type, ap);
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	if (t_errno == 0 || t_errno == TSYSERR) {
23560Sstevel@tonic-gate 		char *errstr;
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 		if (errno == 0) {
23590Sstevel@tonic-gate 			(void) snprintf(buf, MAXLINE, "syslogd: %.*s",
23606358Snakanon 			    MAXLINE, tmpbuf);
23610Sstevel@tonic-gate 		} else if ((errstr = strerror(errno)) == (char *)NULL) {
23620Sstevel@tonic-gate 			(void) snprintf(buf, MAXLINE, "syslogd: %s: error"
23636358Snakanon 			    " %d", tmpbuf, errno);
23640Sstevel@tonic-gate 		} else {
23650Sstevel@tonic-gate 			(void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
23666358Snakanon 			    tmpbuf, errstr);
23670Sstevel@tonic-gate 		}
23680Sstevel@tonic-gate 	} else {
23690Sstevel@tonic-gate 		if (t_errno > t_nerr) {
23700Sstevel@tonic-gate 			(void) snprintf(buf, MAXLINE, "syslogd: %s:"
23716358Snakanon 			    " t_error %d", tmpbuf, t_errno);
23720Sstevel@tonic-gate 		} else {
23730Sstevel@tonic-gate 			(void) snprintf(buf, MAXLINE, "syslogd: %s: %s",
23746358Snakanon 			    tmpbuf, t_errlist[t_errno]);
23750Sstevel@tonic-gate 		}
23760Sstevel@tonic-gate 	}
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 	DPRINT2(5, "logerror_format(%u): out %s\n", mythreadno, buf);
23790Sstevel@tonic-gate }
23800Sstevel@tonic-gate 
23810Sstevel@tonic-gate static int
logerror_to_console(int nonblock,const char * buf)23820Sstevel@tonic-gate logerror_to_console(int nonblock, const char *buf)
23830Sstevel@tonic-gate {
23840Sstevel@tonic-gate 	int cfd, modes;
23850Sstevel@tonic-gate 	pthread_t mythreadno;
23860Sstevel@tonic-gate 	int ret = 0, len;
23870Sstevel@tonic-gate 	char tmpbuf[MAXLINE + 1];
23880Sstevel@tonic-gate 
23890Sstevel@tonic-gate 	if (Debug) {
23900Sstevel@tonic-gate 		mythreadno = pthread_self();
23910Sstevel@tonic-gate 	}
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	DPRINT2(1, "logerror_to_console(%u): %s\n", mythreadno, buf);
23940Sstevel@tonic-gate 
23950Sstevel@tonic-gate 	/*
23960Sstevel@tonic-gate 	 * must use open here instead of fopen, because
23970Sstevel@tonic-gate 	 * we need the O_NOCTTY behavior - otherwise we
23980Sstevel@tonic-gate 	 * could hang the console at boot time
23990Sstevel@tonic-gate 	 */
24000Sstevel@tonic-gate 
24010Sstevel@tonic-gate 	modes = (nonblock) ?
24026358Snakanon 	    O_WRONLY|O_APPEND|O_NOCTTY|O_NONBLOCK :
24036358Snakanon 	    O_WRONLY|O_APPEND|O_NOCTTY;
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 	if (((cfd = open(sysmsg, modes)) >= 0) ||
24060Sstevel@tonic-gate 	    ((cfd = open(ctty, modes)) >= 0)) {
24070Sstevel@tonic-gate 		(void) snprintf(tmpbuf, MAXLINE, "%s\n", buf);
24080Sstevel@tonic-gate 		len = strlen(tmpbuf);
24090Sstevel@tonic-gate 		if (write(cfd, tmpbuf, len) != len) {
24100Sstevel@tonic-gate 			ret = 1;
24110Sstevel@tonic-gate 		}
24120Sstevel@tonic-gate 		(void) close(cfd);
24130Sstevel@tonic-gate 	} else {
24140Sstevel@tonic-gate 		ret = 1;
24150Sstevel@tonic-gate 
24160Sstevel@tonic-gate 		/* punt */
24170Sstevel@tonic-gate 		DPRINT1(1, "logerror_console(%u): can't open console\n",
24186358Snakanon 		    mythreadno);
24190Sstevel@tonic-gate 	}
24200Sstevel@tonic-gate 	return (ret);
24210Sstevel@tonic-gate }
24220Sstevel@tonic-gate 
24230Sstevel@tonic-gate /*
24240Sstevel@tonic-gate  * copy current message to saved message in filed structure.
24250Sstevel@tonic-gate  */
24260Sstevel@tonic-gate static void
copy_msg(struct filed * f)24270Sstevel@tonic-gate copy_msg(struct filed *f)
24280Sstevel@tonic-gate {
24290Sstevel@tonic-gate 	(void) strlcpy(f->f_prevmsg.msg, f->f_current.msg, MAXLINE+1);
24300Sstevel@tonic-gate 	(void) strlcpy(f->f_prevmsg.host, f->f_current.host, SYS_NMLN);
24310Sstevel@tonic-gate 	f->f_prevmsg.pri = f->f_current.pri;
24320Sstevel@tonic-gate 	f->f_prevmsg.flags = f->f_current.flags;
24330Sstevel@tonic-gate 	f->f_prevmsg.time = f->f_current.time;
24340Sstevel@tonic-gate 	f->f_msgflag |= OLD_VALID;
24350Sstevel@tonic-gate }
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate /*
24390Sstevel@tonic-gate  * function to free a host_list_t struct that was allocated
24400Sstevel@tonic-gate  * out of cvthname(). There is a special case where we don't
24410Sstevel@tonic-gate  * free the hostname list in LocalHostName, because that's
24420Sstevel@tonic-gate  * our own addresses, and we just want to have to look it
24430Sstevel@tonic-gate  * up once and save it.  Also don't free it if it's
24440Sstevel@tonic-gate  * NullHostName, because that's a special one we use if
24450Sstevel@tonic-gate  * name service lookup fails.
24460Sstevel@tonic-gate  *
24470Sstevel@tonic-gate  * By having hostname cache, now host_list_t will be shared
24480Sstevel@tonic-gate  * by messages and hostname cache. hl_refcnt is used for
24490Sstevel@tonic-gate  * the purpose.
24500Sstevel@tonic-gate  */
24510Sstevel@tonic-gate static void
freehl(host_list_t * h)24520Sstevel@tonic-gate freehl(host_list_t *h)
24530Sstevel@tonic-gate {
24540Sstevel@tonic-gate 	int i, refcnt;
24550Sstevel@tonic-gate 	pthread_t mythreadno;
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	if (Debug) {
24580Sstevel@tonic-gate 		mythreadno = pthread_self();
24590Sstevel@tonic-gate 	}
24600Sstevel@tonic-gate 
24612104Sjjj 	DPRINT2(2, "freehl(%u): releasing %p\n", mythreadno, (void *)h);
24620Sstevel@tonic-gate 
24630Sstevel@tonic-gate 	if (h == NULL || h == &LocalHostName || h == &NullHostName) {
24640Sstevel@tonic-gate 		return;
24650Sstevel@tonic-gate 	}
24660Sstevel@tonic-gate 
24672104Sjjj 	(void) pthread_mutex_lock(&h->hl_mutex);
24680Sstevel@tonic-gate 	refcnt = --h->hl_refcnt;
24692104Sjjj 	(void) pthread_mutex_unlock(&h->hl_mutex);
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	if (refcnt != 0) {
24720Sstevel@tonic-gate 		DPRINT3(5, "freehl(%u): %p has reference %d\n",
24736358Snakanon 		    mythreadno, (void *)h, refcnt);
24740Sstevel@tonic-gate 		return;
24750Sstevel@tonic-gate 	}
24760Sstevel@tonic-gate 
24772104Sjjj 	(void) pthread_mutex_destroy(&h->hl_mutex);
24782104Sjjj 
24792104Sjjj 	DPRINT2(5, "freehl(%u): freeing %p\n", mythreadno, (void *)h);
24800Sstevel@tonic-gate 
24810Sstevel@tonic-gate 	for (i = 0; i < h->hl_cnt; i++) {
24820Sstevel@tonic-gate 		free(h->hl_hosts[i]);
24830Sstevel@tonic-gate 	}
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	free(h->hl_hosts);
24860Sstevel@tonic-gate 	free(h);
24870Sstevel@tonic-gate }
24880Sstevel@tonic-gate 
24890Sstevel@tonic-gate /*
24900Sstevel@tonic-gate  * Create the door file and the pid file in /var/run.  If the filesystem
24910Sstevel@tonic-gate  * containing /etc is writable, create symlinks /etc/.syslog_door and
24920Sstevel@tonic-gate  * /etc/syslog.pid to them.  On systems that do not support /var/run, create
24930Sstevel@tonic-gate  * /etc/.syslog_door and /etc/syslog.pid directly.
24940Sstevel@tonic-gate  *
24950Sstevel@tonic-gate  * Note: it is not considered fatal to fail to create the pid file or its
24960Sstevel@tonic-gate  * symlink.  Attempts to use them in the usual way will fail, of course, but
24970Sstevel@tonic-gate  * syslogd will function nicely without it (not so for the door file).
24980Sstevel@tonic-gate  */
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate static void
open_door(void)25010Sstevel@tonic-gate open_door(void)
25020Sstevel@tonic-gate {
25030Sstevel@tonic-gate 	struct stat buf;
25040Sstevel@tonic-gate 	door_info_t info;
25050Sstevel@tonic-gate 	char line[MAXLINE+1];
25060Sstevel@tonic-gate 	pthread_t mythreadno;
25070Sstevel@tonic-gate 	int err;
25080Sstevel@tonic-gate 
25090Sstevel@tonic-gate 	if (Debug) {
25100Sstevel@tonic-gate 		mythreadno = pthread_self();
25110Sstevel@tonic-gate 	}
25120Sstevel@tonic-gate 
25130Sstevel@tonic-gate 	/*
25140Sstevel@tonic-gate 	 * first see if another syslogd is running by trying
25150Sstevel@tonic-gate 	 * a door call - if it succeeds, there is already
25160Sstevel@tonic-gate 	 * a syslogd process active
25170Sstevel@tonic-gate 	 */
25180Sstevel@tonic-gate 
25190Sstevel@tonic-gate 	if (!DoorCreated) {
25200Sstevel@tonic-gate 		int door;
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 		if ((door = open(DoorFileName, O_RDONLY)) >= 0) {
25230Sstevel@tonic-gate 			DPRINT2(5, "open_door(%u): %s opened "
25246358Snakanon 			    "successfully\n", mythreadno, DoorFileName);
25250Sstevel@tonic-gate 
25260Sstevel@tonic-gate 			if (door_info(door, &info) >= 0) {
25270Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): "
25286358Snakanon 				    "door_info:info.di_target = %ld\n",
25296358Snakanon 				    mythreadno, info.di_target);
25300Sstevel@tonic-gate 
25310Sstevel@tonic-gate 				if (info.di_target > 0) {
25320Sstevel@tonic-gate 					(void) sprintf(line, "syslogd pid %ld"
25336358Snakanon 					    " already running. Cannot "
25346358Snakanon 					    "start another syslogd pid %ld",
25356358Snakanon 					    info.di_target, getpid());
25360Sstevel@tonic-gate 					DPRINT2(5, "open_door(%u): error: "
25376358Snakanon 					    "%s\n", mythreadno, line);
25380Sstevel@tonic-gate 					errno = 0;
25390Sstevel@tonic-gate 					logerror(line);
25400Sstevel@tonic-gate 					exit(1);
25410Sstevel@tonic-gate 				}
25420Sstevel@tonic-gate 			}
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 			(void) close(door);
25450Sstevel@tonic-gate 		} else {
25460Sstevel@tonic-gate 			if (lstat(DoorFileName, &buf) < 0) {
25470Sstevel@tonic-gate 				err = errno;
25480Sstevel@tonic-gate 
25490Sstevel@tonic-gate 				DPRINT3(5, "open_door(%u): lstat() of %s "
25506358Snakanon 				    "failed, errno=%d\n",
25516358Snakanon 				    mythreadno, DoorFileName, err);
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 				if ((door = creat(DoorFileName, 0644)) < 0) {
25540Sstevel@tonic-gate 					err = errno;
25552104Sjjj 					(void) snprintf(line, sizeof (line),
25562104Sjjj 					    "creat() of %s failed - fatal",
25572104Sjjj 					    DoorFileName);
25580Sstevel@tonic-gate 					DPRINT3(1, "open_door(%u): error: %s, "
25596358Snakanon 					    "errno=%d\n", mythreadno, line,
25606358Snakanon 					    err);
25610Sstevel@tonic-gate 					errno = err;
25620Sstevel@tonic-gate 					logerror(line);
25630Sstevel@tonic-gate 					delete_doorfiles();
25640Sstevel@tonic-gate 					exit(1);
25650Sstevel@tonic-gate 				}
25660Sstevel@tonic-gate 
25670Sstevel@tonic-gate 				(void) fchmod(door,
25686358Snakanon 				    S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): creat() of %s "
25716358Snakanon 				    "succeeded\n", mythreadno,
25726358Snakanon 				    DoorFileName);
25730Sstevel@tonic-gate 
25740Sstevel@tonic-gate 				(void) close(door);
25750Sstevel@tonic-gate 			}
25760Sstevel@tonic-gate 		}
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 		if (strcmp(DoorFileName, DOORFILE) == 0) {
25790Sstevel@tonic-gate 			if (lstat(OLD_DOORFILE, &buf) == 0) {
25800Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): lstat() of %s "
25816358Snakanon 				    "succeeded\n", mythreadno,
25826358Snakanon 				    OLD_DOORFILE);
25830Sstevel@tonic-gate 
25840Sstevel@tonic-gate 				if (S_ISDIR(buf.st_mode)) {
25852104Sjjj 					(void) snprintf(line, sizeof (line),
25862104Sjjj 					    "%s is a directory - fatal",
25872104Sjjj 					    OLD_DOORFILE);
25880Sstevel@tonic-gate 					DPRINT2(1, "open_door(%u): error: "
25896358Snakanon 					    "%s\n", mythreadno, line);
25900Sstevel@tonic-gate 					errno = 0;
25910Sstevel@tonic-gate 					logerror(line);
25920Sstevel@tonic-gate 					delete_doorfiles();
25930Sstevel@tonic-gate 					exit(1);
25940Sstevel@tonic-gate 				}
25950Sstevel@tonic-gate 
25960Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): %s is not a "
25976358Snakanon 				    "directory\n",
25986358Snakanon 				    mythreadno, OLD_DOORFILE);
25990Sstevel@tonic-gate 
26000Sstevel@tonic-gate 				if (unlink(OLD_DOORFILE) < 0) {
26010Sstevel@tonic-gate 					err = errno;
26022104Sjjj 					(void) snprintf(line, sizeof (line),
26032104Sjjj 					    "unlink() of %s failed",
26042104Sjjj 					    OLD_DOORFILE);
26050Sstevel@tonic-gate 					DPRINT2(5, "open_door(%u): %s\n",
26066358Snakanon 					    mythreadno, line);
26070Sstevel@tonic-gate 
26080Sstevel@tonic-gate 					if (err != EROFS) {
26090Sstevel@tonic-gate 						DPRINT3(1, "open_door(%u): "
26106358Snakanon 						    "error: %s, "
26116358Snakanon 						    "errno=%d\n",
26126358Snakanon 						    mythreadno, line, err);
26130Sstevel@tonic-gate 						(void) strcat(line, " - fatal");
26140Sstevel@tonic-gate 						errno = err;
26150Sstevel@tonic-gate 						logerror(line);
26160Sstevel@tonic-gate 						delete_doorfiles();
26170Sstevel@tonic-gate 						exit(1);
26180Sstevel@tonic-gate 					}
26190Sstevel@tonic-gate 
26200Sstevel@tonic-gate 					DPRINT1(5, "open_door(%u): unlink "
26216358Snakanon 					    "failure OK on RO file "
26226358Snakanon 					    "system\n", mythreadno);
26230Sstevel@tonic-gate 				}
26240Sstevel@tonic-gate 			} else {
26250Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): file %s doesn't "
26266358Snakanon 				    "exist\n", mythreadno, OLD_DOORFILE);
26270Sstevel@tonic-gate 			}
26280Sstevel@tonic-gate 
26290Sstevel@tonic-gate 			if (symlink(RELATIVE_DOORFILE, OLD_DOORFILE) < 0) {
26300Sstevel@tonic-gate 				err = errno;
26312104Sjjj 				(void) snprintf(line, sizeof (line),
26322104Sjjj 				    "symlink %s -> %s failed", OLD_DOORFILE,
26332104Sjjj 				    RELATIVE_DOORFILE);
26340Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): %s\n", mythreadno,
26356358Snakanon 				    line);
26360Sstevel@tonic-gate 
26370Sstevel@tonic-gate 				if (err != EROFS) {
26380Sstevel@tonic-gate 					DPRINT3(1, "open_door(%u): error: %s, "
26396358Snakanon 					    "errno=%d\n", mythreadno, line,
26406358Snakanon 					    err);
26410Sstevel@tonic-gate 					errno = err;
26420Sstevel@tonic-gate 					(void) strcat(line, " - fatal");
26430Sstevel@tonic-gate 					logerror(line);
26440Sstevel@tonic-gate 					delete_doorfiles();
26450Sstevel@tonic-gate 					exit(1);
26460Sstevel@tonic-gate 				}
26470Sstevel@tonic-gate 
26480Sstevel@tonic-gate 				DPRINT1(5, "open_door(%u): symlink failure OK "
26496358Snakanon 				    "on RO file system\n", mythreadno);
26500Sstevel@tonic-gate 			} else {
26510Sstevel@tonic-gate 				DPRINT3(5, "open_door(%u): symlink %s -> %s "
26526358Snakanon 				    "succeeded\n", mythreadno,
26536358Snakanon 				    OLD_DOORFILE, RELATIVE_DOORFILE);
26540Sstevel@tonic-gate 			}
26550Sstevel@tonic-gate 		}
26560Sstevel@tonic-gate 
26570Sstevel@tonic-gate 		if ((DoorFd = door_create(server, 0,
26580Sstevel@tonic-gate 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) < 0) {
26590Sstevel@tonic-gate 			err = errno;
26600Sstevel@tonic-gate 			(void) sprintf(line, "door_create() failed - fatal");
26610Sstevel@tonic-gate 			DPRINT3(1, "open_door(%u): error: %s, errno=%d\n",
26626358Snakanon 			    mythreadno, line, err);
26630Sstevel@tonic-gate 			errno = err;
26640Sstevel@tonic-gate 			logerror(line);
26650Sstevel@tonic-gate 			delete_doorfiles();
26660Sstevel@tonic-gate 			exit(1);
26670Sstevel@tonic-gate 		}
26680Sstevel@tonic-gate 		(void) door_setparam(DoorFd, DOOR_PARAM_DATA_MAX, 0);
26690Sstevel@tonic-gate 		DPRINT2(5, "open_door(%u): door_create() succeeded, "
26706358Snakanon 		    "DoorFd=%d\n", mythreadno, DoorFd);
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 		DoorCreated = 1;
26730Sstevel@tonic-gate 	}
26740Sstevel@tonic-gate 
26750Sstevel@tonic-gate 	(void) fdetach(DoorFileName);	/* just in case... */
26760Sstevel@tonic-gate 
26776358Snakanon 	(void) door_server_create(door_server_pool);
26786358Snakanon 
26790Sstevel@tonic-gate 	if (fattach(DoorFd, DoorFileName) < 0) {
26800Sstevel@tonic-gate 		err = errno;
26812104Sjjj 		(void) snprintf(line, sizeof (line), "fattach() of fd"
26826358Snakanon 		    " %d to %s failed - fatal", DoorFd, DoorFileName);
26830Sstevel@tonic-gate 		DPRINT3(1, "open_door(%u): error: %s, errno=%d\n", mythreadno,
26846358Snakanon 		    line, err);
26850Sstevel@tonic-gate 		errno = err;
26860Sstevel@tonic-gate 		logerror(line);
26870Sstevel@tonic-gate 		delete_doorfiles();
26880Sstevel@tonic-gate 		exit(1);
26890Sstevel@tonic-gate 	}
26900Sstevel@tonic-gate 
26910Sstevel@tonic-gate 	DPRINT2(5, "open_door(%u): attached server() to %s\n", mythreadno,
26926358Snakanon 	    DoorFileName);
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	/*
26950Sstevel@tonic-gate 	 * create pidfile anyway, so those using it to control
26960Sstevel@tonic-gate 	 * syslogd (with kill `cat /etc/syslog.pid` perhaps)
26970Sstevel@tonic-gate 	 * don't get broken.
26980Sstevel@tonic-gate 	 */
26990Sstevel@tonic-gate 
27000Sstevel@tonic-gate 	if (!PidfileCreated) {
27010Sstevel@tonic-gate 		int pidfd;
27020Sstevel@tonic-gate 
27030Sstevel@tonic-gate 		PidfileCreated = 1;
27040Sstevel@tonic-gate 
27050Sstevel@tonic-gate 		if ((pidfd = open(PidFileName, O_RDWR|O_CREAT|O_TRUNC, 0644))
27060Sstevel@tonic-gate 		    < 0) {
27070Sstevel@tonic-gate 			err = errno;
27082104Sjjj 			(void) snprintf(line, sizeof (line),
27092104Sjjj 			    "open() of %s failed", PidFileName);
27100Sstevel@tonic-gate 			DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
27116358Snakanon 			    mythreadno, line, err);
27120Sstevel@tonic-gate 			errno = err;
27130Sstevel@tonic-gate 			logerror(line);
27140Sstevel@tonic-gate 			return;
27150Sstevel@tonic-gate 		}
27160Sstevel@tonic-gate 
27170Sstevel@tonic-gate 		(void) fchmod(pidfd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
27180Sstevel@tonic-gate 		(void) sprintf(line, "%ld\n", getpid());
27190Sstevel@tonic-gate 
27200Sstevel@tonic-gate 		if (write(pidfd, line, strlen(line)) < 0) {
27210Sstevel@tonic-gate 			err = errno;
27222104Sjjj 			(void) snprintf(line, sizeof (line),
27232104Sjjj 			    "write to %s on fd %d failed", PidFileName, pidfd);
27240Sstevel@tonic-gate 			DPRINT3(1, "open_door(%u): warning: %s, errno=%d\n",
27256358Snakanon 			    mythreadno, line, err);
27260Sstevel@tonic-gate 			errno = err;
27270Sstevel@tonic-gate 			logerror(line);
27280Sstevel@tonic-gate 			return;
27290Sstevel@tonic-gate 		}
27300Sstevel@tonic-gate 
27310Sstevel@tonic-gate 		(void) close(pidfd);
27320Sstevel@tonic-gate 
27330Sstevel@tonic-gate 		DPRINT2(5, "open_door(%u): %s created\n",
27346358Snakanon 		    mythreadno, PidFileName);
27350Sstevel@tonic-gate 
27360Sstevel@tonic-gate 		if (strcmp(PidFileName, PIDFILE) == 0) {
27370Sstevel@tonic-gate 			if (lstat(OLD_PIDFILE, &buf) == 0) {
27380Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): lstat() of %s "
27396358Snakanon 				    "succeded\n", mythreadno, OLD_PIDFILE);
27400Sstevel@tonic-gate 
27410Sstevel@tonic-gate 				if (S_ISDIR(buf.st_mode)) {
27422104Sjjj 					(void) snprintf(line, sizeof (line),
27432104Sjjj 					    "file %s is a directory",
27442104Sjjj 					    OLD_PIDFILE);
27450Sstevel@tonic-gate 					DPRINT2(1, "open_door(%u): warning: "
27466358Snakanon 					    "%s\n", mythreadno, line);
27470Sstevel@tonic-gate 					errno = 0;
27480Sstevel@tonic-gate 					logerror(line);
27490Sstevel@tonic-gate 					return;
27500Sstevel@tonic-gate 				}
27510Sstevel@tonic-gate 
27520Sstevel@tonic-gate 				if (unlink(OLD_PIDFILE) < 0) {
27530Sstevel@tonic-gate 					err = errno;
27542104Sjjj 					(void) snprintf(line, sizeof (line),
27552104Sjjj 					    "unlink() of %s failed",
27562104Sjjj 					    OLD_PIDFILE);
27570Sstevel@tonic-gate 					DPRINT2(5, "open_door(%u): %s\n",
27586358Snakanon 					    mythreadno, line);
27590Sstevel@tonic-gate 
27600Sstevel@tonic-gate 					if (err != EROFS) {
27610Sstevel@tonic-gate 						DPRINT3(1, "open_door (%u): "
27626358Snakanon 						    "warning: %s, "
27636358Snakanon 						    "errno=%d\n",
27646358Snakanon 						    mythreadno, line, err);
27650Sstevel@tonic-gate 						errno = err;
27660Sstevel@tonic-gate 						logerror(line);
27670Sstevel@tonic-gate 						return;
27680Sstevel@tonic-gate 					}
27690Sstevel@tonic-gate 
27700Sstevel@tonic-gate 					DPRINT1(5, "open_door(%u): unlink "
27716358Snakanon 					    "failure OK on RO file "
27726358Snakanon 					    "system\n", mythreadno);
27730Sstevel@tonic-gate 				}
27740Sstevel@tonic-gate 			} else {
27750Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): file %s doesn't "
27766358Snakanon 				    "exist\n", mythreadno, OLD_PIDFILE);
27770Sstevel@tonic-gate 			}
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 			if (symlink(RELATIVE_PIDFILE, OLD_PIDFILE) < 0) {
27800Sstevel@tonic-gate 				err = errno;
27812104Sjjj 				(void) snprintf(line, sizeof (line),
27822104Sjjj 				    "symlink %s -> %s failed", OLD_PIDFILE,
27836358Snakanon 				    RELATIVE_PIDFILE);
27840Sstevel@tonic-gate 				DPRINT2(5, "open_door(%u): %s\n", mythreadno,
27856358Snakanon 				    line);
27860Sstevel@tonic-gate 
27870Sstevel@tonic-gate 				if (err != EROFS) {
27880Sstevel@tonic-gate 					DPRINT3(1, "open_door(%u): warning: "
27896358Snakanon 					    "%s, errno=%d\n", mythreadno,
27906358Snakanon 					    line, err);
27910Sstevel@tonic-gate 					errno = err;
27920Sstevel@tonic-gate 					logerror(line);
27930Sstevel@tonic-gate 					return;
27940Sstevel@tonic-gate 				}
27950Sstevel@tonic-gate 
27960Sstevel@tonic-gate 				DPRINT1(5, "open_door(%u): symlink failure OK "
27976358Snakanon 				    "on RO file system\n", mythreadno);
27980Sstevel@tonic-gate 				return;
27990Sstevel@tonic-gate 			}
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 			DPRINT3(5, "open_door(%u): symlink %s -> %s "
28026358Snakanon 			    "succeeded\n", mythreadno, OLD_PIDFILE,
28036358Snakanon 			    RELATIVE_PIDFILE);
28040Sstevel@tonic-gate 		}
28050Sstevel@tonic-gate 	}
28060Sstevel@tonic-gate }
28070Sstevel@tonic-gate 
28080Sstevel@tonic-gate /*
28090Sstevel@tonic-gate  * the 'server' function that we export via the door. It does
28100Sstevel@tonic-gate  * nothing but return.
28110Sstevel@tonic-gate  */
28120Sstevel@tonic-gate /*ARGSUSED*/
28130Sstevel@tonic-gate static void
server(void * cookie,char * argp,size_t arg_size,door_desc_t * dp,uint_t n)28140Sstevel@tonic-gate server(void *cookie, char *argp, size_t arg_size,
28150Sstevel@tonic-gate     door_desc_t *dp, uint_t n)
28160Sstevel@tonic-gate {
28170Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
28180Sstevel@tonic-gate 	/* NOTREACHED */
28190Sstevel@tonic-gate }
28200Sstevel@tonic-gate 
28216358Snakanon /*ARGSUSED*/
28226358Snakanon static void *
create_door_thr(void * arg)28236358Snakanon create_door_thr(void *arg)
28246358Snakanon {
28256358Snakanon 	(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
28266358Snakanon 	(void) door_return(NULL, 0, NULL, 0);
28276358Snakanon 
28286358Snakanon 	/*
28296358Snakanon 	 * If there is an error in door_return(), it will return here and
28306358Snakanon 	 * the thread will exit. Hence we need to decrement door_server_cnt.
28316358Snakanon 	 */
28326358Snakanon 	(void) pthread_mutex_lock(&door_server_cnt_lock);
28336358Snakanon 	door_server_cnt--;
28346358Snakanon 	(void) pthread_mutex_unlock(&door_server_cnt_lock);
28356358Snakanon 	return (NULL);
28366358Snakanon }
28376358Snakanon 
28386358Snakanon /*
28396358Snakanon  * Max number of door server threads for syslogd. Since door is used
28406358Snakanon  * to check the health of syslogd, we don't need large number of
28416358Snakanon  * server threads.
28426358Snakanon  */
28436358Snakanon #define	MAX_DOOR_SERVER_THR	3
28446358Snakanon 
28456358Snakanon /*
28466358Snakanon  * Manage door server thread pool.
28476358Snakanon  */
28486358Snakanon /*ARGSUSED*/
28496358Snakanon static void
door_server_pool(door_info_t * dip)28506358Snakanon door_server_pool(door_info_t *dip)
28516358Snakanon {
28526358Snakanon 	(void) pthread_mutex_lock(&door_server_cnt_lock);
28536358Snakanon 	if (door_server_cnt <= MAX_DOOR_SERVER_THR &&
28546358Snakanon 	    pthread_create(NULL, &door_thr_attr, create_door_thr, NULL) == 0) {
28556358Snakanon 		door_server_cnt++;
28566358Snakanon 		(void) pthread_mutex_unlock(&door_server_cnt_lock);
28576358Snakanon 		return;
28586358Snakanon 	}
28596358Snakanon 
28606358Snakanon 	(void) pthread_mutex_unlock(&door_server_cnt_lock);
28616358Snakanon }
28626358Snakanon 
28630Sstevel@tonic-gate /*
28640Sstevel@tonic-gate  * checkm4 - used to verify that the external utilities that
28650Sstevel@tonic-gate  * syslogd depends on are where we expect them to be.
28660Sstevel@tonic-gate  * Returns 0 if all utilities are found, > 0 if any are missing.
28670Sstevel@tonic-gate  * Also logs errors so user knows what's missing
28680Sstevel@tonic-gate  */
28690Sstevel@tonic-gate static int
checkm4(void)28700Sstevel@tonic-gate checkm4(void)
28710Sstevel@tonic-gate {
28720Sstevel@tonic-gate 	int notfound = 0;
28730Sstevel@tonic-gate 	int saverrno;
28740Sstevel@tonic-gate 	pthread_t mythreadno;
28750Sstevel@tonic-gate 
28760Sstevel@tonic-gate 	if (Debug) {
28770Sstevel@tonic-gate 		mythreadno = pthread_self();
28780Sstevel@tonic-gate 	}
28790Sstevel@tonic-gate 
28800Sstevel@tonic-gate 	if (access("/usr/ccs/bin/m4", X_OK) < 0) {
28810Sstevel@tonic-gate 		saverrno = errno;
28820Sstevel@tonic-gate 		logerror("/usr/ccs/bin/m4");
28830Sstevel@tonic-gate 		DPRINT2(1, "checkm4(%u): /usr/ccs/bin/m4 - access "
28846358Snakanon 		    "returned %d\n", mythreadno, saverrno);
28850Sstevel@tonic-gate 		notfound++;
28860Sstevel@tonic-gate 	}
28870Sstevel@tonic-gate 
28880Sstevel@tonic-gate 	return (notfound);
28890Sstevel@tonic-gate }
28900Sstevel@tonic-gate 
28910Sstevel@tonic-gate /*
28920Sstevel@tonic-gate  *  INIT -- Initialize syslogd from configuration table, start up
28930Sstevel@tonic-gate  *  input and logger threads. This routine is called only once.
28940Sstevel@tonic-gate  */
28950Sstevel@tonic-gate static void
init(void)28960Sstevel@tonic-gate init(void)
28970Sstevel@tonic-gate {
28980Sstevel@tonic-gate 	struct utsname *up;
28990Sstevel@tonic-gate 	pthread_attr_t sys_attr, net_attr, log_attr, hnl_attr;
29000Sstevel@tonic-gate 	int nthread;
29010Sstevel@tonic-gate 	pthread_t mythreadno;
29020Sstevel@tonic-gate 
29030Sstevel@tonic-gate 	if (Debug) {
29040Sstevel@tonic-gate 		mythreadno = pthread_self();
29050Sstevel@tonic-gate 	}
29060Sstevel@tonic-gate 
29070Sstevel@tonic-gate 	DPRINT1(2, "init(%u): initializing\n", mythreadno);
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate 	/* hand-craft a host_list_t entry for our local host name */
29100Sstevel@tonic-gate 	if ((up = malloc(sizeof (struct utsname))) == NULL) {
29110Sstevel@tonic-gate 		MALLOC_FAIL_EXIT;
29120Sstevel@tonic-gate 	}
29130Sstevel@tonic-gate 	(void) uname(up);
29140Sstevel@tonic-gate 	LocalHostName.hl_cnt = 1;
29150Sstevel@tonic-gate 	if ((LocalHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
29160Sstevel@tonic-gate 		MALLOC_FAIL_EXIT;
29170Sstevel@tonic-gate 	}
29180Sstevel@tonic-gate 	if ((LocalHostName.hl_hosts[0] = strdup(up->nodename)) == NULL) {
29190Sstevel@tonic-gate 		free(LocalHostName.hl_hosts);
29200Sstevel@tonic-gate 		MALLOC_FAIL_EXIT;
29210Sstevel@tonic-gate 	}
29220Sstevel@tonic-gate 	free(up);
29230Sstevel@tonic-gate 	/* also hand craft one for use if name resolution fails */
29240Sstevel@tonic-gate 	NullHostName.hl_cnt = 1;
29250Sstevel@tonic-gate 	if ((NullHostName.hl_hosts = malloc(sizeof (char *))) == NULL) {
29260Sstevel@tonic-gate 		MALLOC_FAIL_EXIT;
29270Sstevel@tonic-gate 	}
29280Sstevel@tonic-gate 	if ((NullHostName.hl_hosts[0] = strdup("name lookup failed")) == NULL) {
29290Sstevel@tonic-gate 		MALLOC_FAIL_EXIT;
29300Sstevel@tonic-gate 	}
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 	hnc_init(0);
29330Sstevel@tonic-gate 
29340Sstevel@tonic-gate 	/*
29350Sstevel@tonic-gate 	 * Note that getnets will allocate network resources, but won't be
29360Sstevel@tonic-gate 	 * binding UDP port. This is because, there could be a race
29370Sstevel@tonic-gate 	 * condition between door. If we bind here, one syslogd could grab
29380Sstevel@tonic-gate 	 * UDP port first, but later another syslogd could take over without
29390Sstevel@tonic-gate 	 * getting UDP port but grab the door file. The 2nd syslogd could
29400Sstevel@tonic-gate 	 * continue to run without listening network.
29410Sstevel@tonic-gate 	 * bindnet() will be called after door was successfully opened.
29420Sstevel@tonic-gate 	 */
29430Sstevel@tonic-gate 	getnets();
29440Sstevel@tonic-gate 
29450Sstevel@tonic-gate 	/*
29460Sstevel@tonic-gate 	 * Start up configured theads
29470Sstevel@tonic-gate 	 */
29480Sstevel@tonic-gate 	conf_init();
29490Sstevel@tonic-gate 
29500Sstevel@tonic-gate 	/*
29510Sstevel@tonic-gate 	 * allocate thread stacks for the persistant threads
29520Sstevel@tonic-gate 	 */
29530Sstevel@tonic-gate 	nthread = (turnoff == 0) ? 4 : 2;
29540Sstevel@tonic-gate 
29550Sstevel@tonic-gate 	if ((stack_ptr = alloc_stacks(nthread)) == NULL) {
29560Sstevel@tonic-gate 		logerror("alloc_stacks failed - fatal");
29570Sstevel@tonic-gate 		exit(1);
29580Sstevel@tonic-gate 	}
29590Sstevel@tonic-gate 
29600Sstevel@tonic-gate 	if (Debug) {
29610Sstevel@tonic-gate 		dumpstats(STDOUT_FILENO);
29620Sstevel@tonic-gate 	}
29630Sstevel@tonic-gate 
29640Sstevel@tonic-gate 	(void) dataq_init(&inputq);	/* init the input queue */
29650Sstevel@tonic-gate 
29660Sstevel@tonic-gate 	if (pthread_attr_init(&sys_attr) != 0 ||
29670Sstevel@tonic-gate 	    pthread_attr_init(&log_attr) != 0 ||
29680Sstevel@tonic-gate 	    pthread_attr_init(&net_attr) != 0 ||
29696358Snakanon 	    pthread_attr_init(&hnl_attr) != 0 ||
29706358Snakanon 	    pthread_attr_init(&door_thr_attr) != 0) {
29710Sstevel@tonic-gate 		logerror("pthread_attr_init failed - fatal");
29720Sstevel@tonic-gate 		exit(1);
29730Sstevel@tonic-gate 	}
29740Sstevel@tonic-gate 
29750Sstevel@tonic-gate 	(void) pthread_attr_setscope(&sys_attr, PTHREAD_SCOPE_PROCESS);
29760Sstevel@tonic-gate 	(void) pthread_attr_setscope(&log_attr, PTHREAD_SCOPE_PROCESS);
29770Sstevel@tonic-gate 	(void) pthread_attr_setscope(&net_attr, PTHREAD_SCOPE_PROCESS);
29780Sstevel@tonic-gate 	(void) pthread_attr_setscope(&hnl_attr, PTHREAD_SCOPE_PROCESS);
29796358Snakanon 	(void) pthread_attr_setscope(&door_thr_attr, PTHREAD_SCOPE_SYSTEM);
29806358Snakanon 	(void) pthread_attr_setdetachstate(&door_thr_attr,
29816358Snakanon 	    PTHREAD_CREATE_DETACHED);
29820Sstevel@tonic-gate 
29830Sstevel@tonic-gate 	/* 1: logmsg thread */
29840Sstevel@tonic-gate 	(void) pthread_attr_setstacksize(&log_attr, stacksize);
29850Sstevel@tonic-gate 	(void) pthread_attr_setstackaddr(&log_attr, stack_ptr);
29860Sstevel@tonic-gate 	stack_ptr += stacksize + redzonesize;
29870Sstevel@tonic-gate 	if (pthread_create(&log_thread, &log_attr, logmsg, NULL) != 0) {
29880Sstevel@tonic-gate 		logerror("pthread_create failed - fatal");
29890Sstevel@tonic-gate 		exit(1);
29900Sstevel@tonic-gate 	}
29910Sstevel@tonic-gate 
29920Sstevel@tonic-gate 	/*
29930Sstevel@tonic-gate 	 * open the log device, and pull up all pending message
29940Sstevel@tonic-gate 	 * from the log driver.
29950Sstevel@tonic-gate 	 */
29960Sstevel@tonic-gate 	prepare_sys_poll();
29970Sstevel@tonic-gate 
29980Sstevel@tonic-gate 	/*
29990Sstevel@tonic-gate 	 * Now we can deliver the pending internal error messages.
30000Sstevel@tonic-gate 	 */
30010Sstevel@tonic-gate 	enable_errorlog();
30020Sstevel@tonic-gate 
30030Sstevel@tonic-gate 	/* 2: sys_poll thread */
30040Sstevel@tonic-gate 	(void) pthread_attr_setstacksize(&sys_attr, stacksize);
30050Sstevel@tonic-gate 	(void) pthread_attr_setstackaddr(&sys_attr, stack_ptr);
30060Sstevel@tonic-gate 	stack_ptr += stacksize + redzonesize;
30070Sstevel@tonic-gate 	if (pthread_create(&sys_thread, &sys_attr, sys_poll, NULL) != 0) {
30080Sstevel@tonic-gate 		logerror("pthread_create failed - fatal");
30090Sstevel@tonic-gate 		exit(1);
30100Sstevel@tonic-gate 	}
30110Sstevel@tonic-gate 
30120Sstevel@tonic-gate 	/*
30130Sstevel@tonic-gate 	 * We've started the sys_poll() and logmsg() threads.  Now we are ready
30140Sstevel@tonic-gate 	 * to open the door.  This cannot happen before spawning sys_poll(),
30150Sstevel@tonic-gate 	 * because after opening the door, syslog() will no longer take care of
30160Sstevel@tonic-gate 	 * LOG_CONS.  Therefor, we should pull up all pending log messages and
30170Sstevel@tonic-gate 	 * activate sys_poll() before opening the door, so that log driver
30180Sstevel@tonic-gate 	 * won't drop messages.
30190Sstevel@tonic-gate 	 */
30200Sstevel@tonic-gate 	open_door();
30210Sstevel@tonic-gate 
30220Sstevel@tonic-gate 	DPRINT1(1, "init(%u): accepting messages from local system\n",
30236358Snakanon 	    mythreadno);
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	if (turnoff == 0) {
30260Sstevel@tonic-gate 		/* init the hostname lookup queue */
30270Sstevel@tonic-gate 		(void) dataq_init(&hnlq);
30280Sstevel@tonic-gate 
30290Sstevel@tonic-gate 		/* 3: hostname lookup thread */
30300Sstevel@tonic-gate 		(void) pthread_attr_setstacksize(&hnl_attr, stacksize);
30310Sstevel@tonic-gate 		(void) pthread_attr_setstackaddr(&hnl_attr, stack_ptr);
30320Sstevel@tonic-gate 		stack_ptr += stacksize + redzonesize;
30330Sstevel@tonic-gate 		if (pthread_create(&hnl_thread, &hnl_attr,
30346358Snakanon 		    hostname_lookup, NULL) != 0) {
30350Sstevel@tonic-gate 			logerror("pthread_create failed - fatal");
30360Sstevel@tonic-gate 			exit(1);
30370Sstevel@tonic-gate 		}
30380Sstevel@tonic-gate 
30390Sstevel@tonic-gate 		/* 4: net_poll thread */
30400Sstevel@tonic-gate 		(void) pthread_attr_setstacksize(&net_attr, stacksize);
30410Sstevel@tonic-gate 		(void) pthread_attr_setstackaddr(&net_attr, stack_ptr);
30420Sstevel@tonic-gate 		stack_ptr += stacksize + redzonesize;
30430Sstevel@tonic-gate 
30440Sstevel@tonic-gate 		/* grab UDP port */
30450Sstevel@tonic-gate 		bindnet();
30460Sstevel@tonic-gate 
30470Sstevel@tonic-gate 		if (pthread_create(&net_thread, &net_attr, net_poll,
30486358Snakanon 		    NULL) != 0) {
30490Sstevel@tonic-gate 			logerror("pthread_create failed - fatal");
30500Sstevel@tonic-gate 			exit(1);
30510Sstevel@tonic-gate 		}
30520Sstevel@tonic-gate 		DPRINT1(1, "init(%u): accepting messages from remote\n",
30536358Snakanon 		    mythreadno);
30540Sstevel@tonic-gate 	}
30550Sstevel@tonic-gate 
30560Sstevel@tonic-gate 	(void) pthread_attr_destroy(&sys_attr);
30570Sstevel@tonic-gate 	(void) pthread_attr_destroy(&net_attr);
30580Sstevel@tonic-gate 	(void) pthread_attr_destroy(&log_attr);
30590Sstevel@tonic-gate 	(void) pthread_attr_destroy(&hnl_attr);
30600Sstevel@tonic-gate 
30610Sstevel@tonic-gate 	curalarm = MarkInterval * 60 / MARKCOUNT;
30620Sstevel@tonic-gate 	(void) alarm((unsigned)curalarm);
30630Sstevel@tonic-gate 	DPRINT2(2, "init(%u): Next alarm in %d seconds\n",
30646358Snakanon 	    mythreadno, curalarm);
30650Sstevel@tonic-gate 	DPRINT1(1, "init(%u): syslogd: started\n", mythreadno);
30660Sstevel@tonic-gate }
30670Sstevel@tonic-gate 
30680Sstevel@tonic-gate /*
30690Sstevel@tonic-gate  * will print a bunch of debugging stats on 'fd'
30700Sstevel@tonic-gate  */
30710Sstevel@tonic-gate static void
dumpstats(int fd)30720Sstevel@tonic-gate dumpstats(int fd)
30730Sstevel@tonic-gate {
30740Sstevel@tonic-gate 	FILE *out;
30750Sstevel@tonic-gate 	struct filed *f;
30760Sstevel@tonic-gate 	int i;
30770Sstevel@tonic-gate 	char users[1024];
30780Sstevel@tonic-gate 	char cbuf[30];
30790Sstevel@tonic-gate 	char *dashes = "------------------------";
30800Sstevel@tonic-gate 	static int conversion_printed;
30810Sstevel@tonic-gate 
30820Sstevel@tonic-gate 	if ((out = fdopen(fd, "w+")) == NULL)
30830Sstevel@tonic-gate 		return;
30840Sstevel@tonic-gate 
3085*8094SVladimir.Marek@Sun.COM 	(void) fprintf(out, "\nSyslogd started: %s",
3086*8094SVladimir.Marek@Sun.COM 	    ctime_r(&start_time, cbuf));
30870Sstevel@tonic-gate 	(void) fprintf(out, "Input message count: system %d, network %d\n",
30886358Snakanon 	    sys_msg_count, net_msg_count);
30890Sstevel@tonic-gate 	(void) fprintf(out, "# Outputs: %d\n\n", nlogs);
30900Sstevel@tonic-gate 
30910Sstevel@tonic-gate 	(void) fprintf(out, "%s priority = [file, facility] %s\n\n",
30926358Snakanon 	    dashes, dashes);
30930Sstevel@tonic-gate 
30940Sstevel@tonic-gate 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
30950Sstevel@tonic-gate 		(void) fprintf(out, "%d ", i / 10);
30960Sstevel@tonic-gate 	}
30970Sstevel@tonic-gate 	(void) fprintf(out, "\n");
30980Sstevel@tonic-gate 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
30990Sstevel@tonic-gate 		(void) fprintf(out, "%d ", i % 10);
31000Sstevel@tonic-gate 	}
31010Sstevel@tonic-gate 	(void) fprintf(out, "\n");
31020Sstevel@tonic-gate 	for (i = 0; i < LOG_NFACILITIES + 1; i++) {
31030Sstevel@tonic-gate 		(void) fprintf(out, "--");
31040Sstevel@tonic-gate 	}
31050Sstevel@tonic-gate 	(void) fprintf(out, "\n");
31060Sstevel@tonic-gate 
31070Sstevel@tonic-gate 	for (f = Files; f < &Files[nlogs]; f++) {
31080Sstevel@tonic-gate 		for (i = 0; i < LOG_NFACILITIES + 1; i++) {
31090Sstevel@tonic-gate 			if (f->f_pmask[i] == NOPRI)
31100Sstevel@tonic-gate 				(void) fprintf(out, "X ");
31110Sstevel@tonic-gate 			else
31120Sstevel@tonic-gate 				(void) fprintf(out, "%d ",
31136358Snakanon 				    f->f_pmask[i]);
31140Sstevel@tonic-gate 		}
31150Sstevel@tonic-gate 		(void) fprintf(out, "%s: ", TypeNames[f->f_type]);
31160Sstevel@tonic-gate 		switch (f->f_type) {
31170Sstevel@tonic-gate 		case F_FILE:
31180Sstevel@tonic-gate 		case F_TTY:
31190Sstevel@tonic-gate 		case F_CONSOLE:
31200Sstevel@tonic-gate 			(void) fprintf(out, "%s", f->f_un.f_fname);
31210Sstevel@tonic-gate 			break;
31220Sstevel@tonic-gate 		case F_FORW:
31230Sstevel@tonic-gate 			(void) fprintf(out, "%s", f->f_un.f_forw.f_hname);
31240Sstevel@tonic-gate 			break;
31250Sstevel@tonic-gate 		case F_USERS:
31260Sstevel@tonic-gate 			for (i = 0; i < MAXUNAMES &&
31276358Snakanon 			    *f->f_un.f_uname[i]; i++) {
31280Sstevel@tonic-gate 				if (!i)
31290Sstevel@tonic-gate 					(void) fprintf(out, "%s",
31306358Snakanon 					    f->f_un.f_uname[i]);
31310Sstevel@tonic-gate 				else
31320Sstevel@tonic-gate 					(void) fprintf(out, ", %s",
31336358Snakanon 					    f->f_un.f_uname[i]);
31340Sstevel@tonic-gate 			}
31350Sstevel@tonic-gate 			break;
31360Sstevel@tonic-gate 		}
31370Sstevel@tonic-gate 		(void) fprintf(out, "\n");
31380Sstevel@tonic-gate 	}
31390Sstevel@tonic-gate 
31400Sstevel@tonic-gate 	if (!conversion_printed) {
31412104Sjjj 		(void) fprintf(out, "\nFacilities:\n");
31420Sstevel@tonic-gate 
31430Sstevel@tonic-gate 		for (i = 0; FacNames[i].c_val != -1; i++) {
31442104Sjjj 			(void) fprintf(out, "  [%02d] %s: %3d\n", i,
31456358Snakanon 			    FacNames[i].c_name, FacNames[i].c_val);
31460Sstevel@tonic-gate 		}
31470Sstevel@tonic-gate 
31482104Sjjj 		(void) fprintf(out, "\nPriorities:\n");
31490Sstevel@tonic-gate 
31500Sstevel@tonic-gate 		for (i = 0; PriNames[i].c_val != -1; i++) {
31512104Sjjj 			(void) fprintf(out, "  [%02d] %s: %3d\n", i,
31526358Snakanon 			    PriNames[i].c_name, PriNames[i].c_val);
31530Sstevel@tonic-gate 		}
31540Sstevel@tonic-gate 
31550Sstevel@tonic-gate 		conversion_printed = 1;
31560Sstevel@tonic-gate 	}
31570Sstevel@tonic-gate 
31580Sstevel@tonic-gate 	(void) fprintf(out, "\n\n\n\t\tPer File Statistics\n");
31590Sstevel@tonic-gate 	(void) fprintf(out, "%-24s\tTot\tDups\tNofwd\tErrs\n", "File");
31600Sstevel@tonic-gate 	(void) fprintf(out, "%-24s\t---\t----\t-----\t----\n", "----");
31610Sstevel@tonic-gate 	for (f = Files; f < &Files[nlogs]; f++) {
31620Sstevel@tonic-gate 		switch (f->f_type) {
31630Sstevel@tonic-gate 		case F_FILE:
31640Sstevel@tonic-gate 		case F_TTY:
31650Sstevel@tonic-gate 		case F_CONSOLE:
31660Sstevel@tonic-gate 			(void) fprintf(out, "%-24s", f->f_un.f_fname);
31670Sstevel@tonic-gate 			break;
31680Sstevel@tonic-gate 		case F_WALL:
31690Sstevel@tonic-gate 			(void) fprintf(out, "%-24s", TypeNames[f->f_type]);
31700Sstevel@tonic-gate 			break;
31710Sstevel@tonic-gate 		case F_FORW:
31720Sstevel@tonic-gate 			(void) fprintf(out, "%-24s", f->f_un.f_forw.f_hname);
31730Sstevel@tonic-gate 			break;
31740Sstevel@tonic-gate 		case F_USERS:
31750Sstevel@tonic-gate 			for (i = 0; i < MAXUNAMES &&
31766358Snakanon 			    *f->f_un.f_uname[i]; i++) {
31770Sstevel@tonic-gate 				if (!i)
31780Sstevel@tonic-gate 					(void) strcpy(users,
31796358Snakanon 					    f->f_un.f_uname[i]);
31800Sstevel@tonic-gate 				else {
31810Sstevel@tonic-gate 					(void) strcat(users, ",");
31820Sstevel@tonic-gate 					(void) strcat(users,
31836358Snakanon 					    f->f_un.f_uname[i]);
31840Sstevel@tonic-gate 				}
31850Sstevel@tonic-gate 			}
31860Sstevel@tonic-gate 			(void) fprintf(out, "%-24s", users);
31870Sstevel@tonic-gate 			break;
31880Sstevel@tonic-gate 		}
31890Sstevel@tonic-gate 		(void) fprintf(out, "\t%d\t%d\t%d\t%d\n",
31906358Snakanon 		    f->f_stat.total, f->f_stat.dups,
31916358Snakanon 		    f->f_stat.cantfwd, f->f_stat.errs);
31920Sstevel@tonic-gate 	}
31930Sstevel@tonic-gate 	(void) fprintf(out, "\n\n");
31940Sstevel@tonic-gate 	if (Debug && fd == 1)
31950Sstevel@tonic-gate 		return;
31960Sstevel@tonic-gate 	(void) fclose(out);
31970Sstevel@tonic-gate }
31980Sstevel@tonic-gate 
31990Sstevel@tonic-gate /*
32000Sstevel@tonic-gate  * conf_init - This routine is code seperated from the
32010Sstevel@tonic-gate  * init routine in order to be re-callable when we get
32020Sstevel@tonic-gate  * a SIGHUP signal.
32030Sstevel@tonic-gate  */
32040Sstevel@tonic-gate static void
conf_init(void)32050Sstevel@tonic-gate conf_init(void)
32060Sstevel@tonic-gate {
32070Sstevel@tonic-gate 	char *p;
32080Sstevel@tonic-gate 	int i;
32090Sstevel@tonic-gate 	struct filed *f;
32100Sstevel@tonic-gate 	char *m4argv[4];
32110Sstevel@tonic-gate 	int m4argc = 0;
32120Sstevel@tonic-gate 	conf_t cf;
32130Sstevel@tonic-gate 	pthread_t mythreadno;
32140Sstevel@tonic-gate 
32150Sstevel@tonic-gate 	if (Debug) {
32160Sstevel@tonic-gate 		mythreadno = pthread_self();
32170Sstevel@tonic-gate 	}
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 	DPRINT1(2, "conf_init(%u): starting logger threads\n",
32206358Snakanon 	    mythreadno);
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate 	m4argv[m4argc++] = "m4";
32230Sstevel@tonic-gate 
32240Sstevel@tonic-gate 	if (amiloghost() == 1) {
32250Sstevel@tonic-gate 		DPRINT1(1, "conf_init(%u): I am loghost\n", mythreadno);
32260Sstevel@tonic-gate 		m4argv[m4argc++] = "-DLOGHOST=1";
32270Sstevel@tonic-gate 	}
32280Sstevel@tonic-gate 
32290Sstevel@tonic-gate 	m4argv[m4argc++] = ConfFile;
32300Sstevel@tonic-gate 	m4argv[m4argc] = NULL;
32310Sstevel@tonic-gate 
32320Sstevel@tonic-gate 	/*
32330Sstevel@tonic-gate 	 * Make sure the configuration file and m4 exist, and then parse
32340Sstevel@tonic-gate 	 * the configuration file with m4.  If any of these fail, resort
32350Sstevel@tonic-gate 	 * to our hardcoded fallback configuration.
32360Sstevel@tonic-gate 	 */
32370Sstevel@tonic-gate 
32380Sstevel@tonic-gate 	if (access(ConfFile, R_OK) == -1) {
32390Sstevel@tonic-gate 		DPRINT2(1, "conf_init(%u): %s does not exist\n", mythreadno,
32406358Snakanon 		    ConfFile);
32410Sstevel@tonic-gate 		logerror("can't open configuration file");
32420Sstevel@tonic-gate 		/* CSTYLED */
32430Sstevel@tonic-gate 		Files = (struct filed *) &fallback; /*lint !e545 */
32440Sstevel@tonic-gate 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
32450Sstevel@tonic-gate 		cfline("*.PANIC\t*", 0, &Files[1]);
32460Sstevel@tonic-gate 		nlogs = 2;
32470Sstevel@tonic-gate 		goto nofile;
32480Sstevel@tonic-gate 	}
32490Sstevel@tonic-gate 
32500Sstevel@tonic-gate 	if (checkm4() != 0 || conf_open(&cf, "/usr/ccs/bin/m4", m4argv) == -1) {
32510Sstevel@tonic-gate 		DPRINT2(1, "conf_init(%u): cannot open %s\n", mythreadno,
32526358Snakanon 		    ConfFile);
32530Sstevel@tonic-gate 		/* CSTYLED */
32540Sstevel@tonic-gate 		Files = (struct filed *) &fallback; /*lint !e545 */
32550Sstevel@tonic-gate 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
32560Sstevel@tonic-gate 		cfline("*.PANIC\t*", 0, &Files[1]);
32570Sstevel@tonic-gate 		nlogs = 2;
32580Sstevel@tonic-gate 		goto nofile;
32590Sstevel@tonic-gate 	}
32600Sstevel@tonic-gate 
32610Sstevel@tonic-gate 	/* Count the number of lines which are not blanks or comments */
32620Sstevel@tonic-gate 	nlogs = 0;
32630Sstevel@tonic-gate 	while ((p = conf_read(&cf)) != NULL) {
32640Sstevel@tonic-gate 		if (p[0] != '\0' && p[0] != '#')
32650Sstevel@tonic-gate 			nlogs++;
32660Sstevel@tonic-gate 	}
32670Sstevel@tonic-gate 
32680Sstevel@tonic-gate 	Files = (struct filed *)malloc(sizeof (struct filed) * nlogs);
32690Sstevel@tonic-gate 
32700Sstevel@tonic-gate 	if (!Files) {
32710Sstevel@tonic-gate 		DPRINT1(1, "conf_init(%u): malloc failed - can't "
32726358Snakanon 		    "allocate 'Files' array\n", mythreadno);
32730Sstevel@tonic-gate 		MALLOC_FAIL("loading minimum configuration");
32740Sstevel@tonic-gate 		/* CSTYLED */
32750Sstevel@tonic-gate 		Files = (struct filed *) &fallback; /*lint !e545 */
32760Sstevel@tonic-gate 		cfline("*.ERR\t/dev/sysmsg", 0, &Files[0]);
32770Sstevel@tonic-gate 		cfline("*.PANIC\t*", 0, &Files[1]);
32780Sstevel@tonic-gate 		nlogs = 2;
32790Sstevel@tonic-gate 		conf_close(&cf);
32800Sstevel@tonic-gate 		goto nofile;
32810Sstevel@tonic-gate 	}
32820Sstevel@tonic-gate 
32830Sstevel@tonic-gate 	/*
32840Sstevel@tonic-gate 	 *  Foreach line in the conf table, open that file.
32850Sstevel@tonic-gate 	 */
32860Sstevel@tonic-gate 	conf_rewind(&cf);
32870Sstevel@tonic-gate 	f = Files;
32880Sstevel@tonic-gate 	i = 0;
32890Sstevel@tonic-gate 	while (((p = conf_read(&cf)) != NULL) && (f < &Files[nlogs])) {
32900Sstevel@tonic-gate 		i++;
32910Sstevel@tonic-gate 		/* check for end-of-section */
32920Sstevel@tonic-gate 		if (p[0] == '\0' || p[0] == '#')
32930Sstevel@tonic-gate 			continue;
32940Sstevel@tonic-gate 
32950Sstevel@tonic-gate 		cfline(p, i, f);
32960Sstevel@tonic-gate 		if (f->f_type == F_UNUSED)
32970Sstevel@tonic-gate 			nlogs--;
32980Sstevel@tonic-gate 		else
32990Sstevel@tonic-gate 			f++;
33000Sstevel@tonic-gate 	}
33010Sstevel@tonic-gate 
33020Sstevel@tonic-gate 	conf_close(&cf);
33030Sstevel@tonic-gate 
33040Sstevel@tonic-gate 	/*
33050Sstevel@tonic-gate 	 * See if marks are to be written to any files.  If so, set up a
33060Sstevel@tonic-gate 	 * timeout for marks.
33070Sstevel@tonic-gate 	 */
33080Sstevel@tonic-gate nofile:
33090Sstevel@tonic-gate 	Marking = 0;
33100Sstevel@tonic-gate 
33110Sstevel@tonic-gate 	/*
33120Sstevel@tonic-gate 	 * allocate thread stacks - one for each logger thread.
33130Sstevel@tonic-gate 	 */
33140Sstevel@tonic-gate 	if ((cstack_ptr = alloc_stacks(nlogs)) == NULL) {
33150Sstevel@tonic-gate 		logerror("alloc_stacks failed - fatal");
33160Sstevel@tonic-gate 		exit(1);
33170Sstevel@tonic-gate 	}
33180Sstevel@tonic-gate 
33190Sstevel@tonic-gate 	/* And now one thread for each configured file */
33200Sstevel@tonic-gate 	for (f = Files; f < &Files[nlogs]; f++) {
33210Sstevel@tonic-gate 		if (filed_init(f) != 0) {
33220Sstevel@tonic-gate 			logerror("pthread_create failed - fatal");
33230Sstevel@tonic-gate 			exit(1);
33240Sstevel@tonic-gate 		}
33250Sstevel@tonic-gate 
33262104Sjjj 		(void) pthread_mutex_lock(&cft);
33270Sstevel@tonic-gate 		++conf_threads;
33282104Sjjj 		(void) pthread_mutex_unlock(&cft);
33290Sstevel@tonic-gate 
33300Sstevel@tonic-gate 		if (f->f_type != F_UNUSED &&
33316358Snakanon 		    f->f_pmask[LOG_NFACILITIES] != NOPRI)
33320Sstevel@tonic-gate 			Marking = 1;
33330Sstevel@tonic-gate 	}
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate 
33360Sstevel@tonic-gate /*
33370Sstevel@tonic-gate  * filed init - initialize fields in a file descriptor struct
33380Sstevel@tonic-gate  * this is called before multiple threads are running, so no mutex
33390Sstevel@tonic-gate  * needs to be held at this time.
33400Sstevel@tonic-gate  */
3341236Schin static int
filed_init(struct filed * f)33420Sstevel@tonic-gate filed_init(struct filed *f)
33430Sstevel@tonic-gate {
33440Sstevel@tonic-gate 	pthread_attr_t stack_attr;
33450Sstevel@tonic-gate 	pthread_t mythreadno;
33460Sstevel@tonic-gate 
33470Sstevel@tonic-gate 	if (Debug) {
33480Sstevel@tonic-gate 		mythreadno = pthread_self();
33490Sstevel@tonic-gate 	}
33500Sstevel@tonic-gate 
33510Sstevel@tonic-gate 	if (pthread_mutex_init(&f->filed_mutex, NULL) != 0) {
33520Sstevel@tonic-gate 		logerror("pthread_mutex_init failed");
33530Sstevel@tonic-gate 		return (-1);
33540Sstevel@tonic-gate 	}
33550Sstevel@tonic-gate 
33560Sstevel@tonic-gate 	DPRINT2(5, "filed_init(%u): dataq_init for queue %p\n",
33576358Snakanon 	    mythreadno, (void *)&f->f_queue);
33580Sstevel@tonic-gate 	(void) dataq_init(&f->f_queue);
33590Sstevel@tonic-gate 
33600Sstevel@tonic-gate 	if (pthread_attr_init(&stack_attr) != 0) {
33610Sstevel@tonic-gate 		logerror("pthread_attr_init failed");
33620Sstevel@tonic-gate 		return (-1);
33630Sstevel@tonic-gate 	}
33640Sstevel@tonic-gate 
33650Sstevel@tonic-gate 	(void) pthread_attr_setstacksize(&stack_attr, stacksize);
33660Sstevel@tonic-gate 	(void) pthread_attr_setstackaddr(&stack_attr, cstack_ptr);
33670Sstevel@tonic-gate 	cstack_ptr += stacksize + redzonesize;
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 	f->f_msgflag = 0;
33700Sstevel@tonic-gate 	f->f_prevmsg.msg[0] = '\0';
33710Sstevel@tonic-gate 	f->f_prevmsg.flags = 0;
33720Sstevel@tonic-gate 	f->f_prevmsg.pri = 0;
33730Sstevel@tonic-gate 	f->f_prevmsg.host[0] = '\0';
33740Sstevel@tonic-gate 
33750Sstevel@tonic-gate 	f->f_current.msg[0] = '\0';
33760Sstevel@tonic-gate 	f->f_current.flags = 0;
33770Sstevel@tonic-gate 	f->f_current.pri = 0;
33780Sstevel@tonic-gate 	f->f_current.host[0] = '\0';
33790Sstevel@tonic-gate 
33800Sstevel@tonic-gate 	f->f_prevcount = 0;
33810Sstevel@tonic-gate 
33820Sstevel@tonic-gate 	f->f_stat.flag = 0;
33830Sstevel@tonic-gate 	f->f_stat.total = 0;
33840Sstevel@tonic-gate 	f->f_stat.dups = 0;
33850Sstevel@tonic-gate 	f->f_stat.cantfwd = 0;
33860Sstevel@tonic-gate 	f->f_stat.errs = 0;
33870Sstevel@tonic-gate 
33880Sstevel@tonic-gate 	if (pthread_create(&f->f_thread, NULL, logit, (void *)f) != 0) {
33890Sstevel@tonic-gate 		logerror("pthread_create failed");
33902104Sjjj 		(void) pthread_attr_destroy(&stack_attr);
33910Sstevel@tonic-gate 		return (-1);
33920Sstevel@tonic-gate 	}
33930Sstevel@tonic-gate 
33942104Sjjj 	(void) pthread_attr_destroy(&stack_attr);
33950Sstevel@tonic-gate 	return (0);
33960Sstevel@tonic-gate }
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate 
33990Sstevel@tonic-gate /*
34000Sstevel@tonic-gate  * Crack a configuration file line
34010Sstevel@tonic-gate  */
34020Sstevel@tonic-gate static void
cfline(char * line,int lineno,struct filed * f)34030Sstevel@tonic-gate cfline(char *line, int lineno, struct filed *f)
34040Sstevel@tonic-gate {
34050Sstevel@tonic-gate 	char *p;
34060Sstevel@tonic-gate 	char *q;
34070Sstevel@tonic-gate 	int i;
34080Sstevel@tonic-gate 	char *bp;
34090Sstevel@tonic-gate 	int pri;
34100Sstevel@tonic-gate 	char buf[MAXLINE];
34110Sstevel@tonic-gate 	char ebuf[SYS_NMLN+1+40];
34120Sstevel@tonic-gate 	mode_t fmode, omode = O_WRONLY|O_APPEND|O_NOCTTY;
34130Sstevel@tonic-gate 	struct stat64 sbuf;
34140Sstevel@tonic-gate 	pthread_t mythreadno;
34150Sstevel@tonic-gate 
34160Sstevel@tonic-gate 	if (Debug) {
34170Sstevel@tonic-gate 		mythreadno = pthread_self();
34180Sstevel@tonic-gate 	}
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate 	DPRINT2(1, "cfline(%u): (%s)\n", mythreadno, line);
34210Sstevel@tonic-gate 
3422634Sdp 	errno = 0;	/* keep errno related stuff out of logerror messages */
34230Sstevel@tonic-gate 
34240Sstevel@tonic-gate 	/* clear out file entry */
34250Sstevel@tonic-gate 	bzero((char *)f, sizeof (*f));
34260Sstevel@tonic-gate 	for (i = 0; i <= LOG_NFACILITIES; i++)
34270Sstevel@tonic-gate 		f->f_pmask[i] = NOPRI;
34280Sstevel@tonic-gate 
34290Sstevel@tonic-gate 	/* scan through the list of selectors */
34300Sstevel@tonic-gate 	for (p = line; *p && *p != '\t'; ) {
34310Sstevel@tonic-gate 
34320Sstevel@tonic-gate 		/* find the end of this facility name list */
34330Sstevel@tonic-gate 		for (q = p; *q && *q != '\t' && *q++ != '.'; )
34340Sstevel@tonic-gate 			continue;
34350Sstevel@tonic-gate 
34360Sstevel@tonic-gate 		/* collect priority name */
34370Sstevel@tonic-gate 		for (bp = buf; *q && !strchr("\t,;", *q); )
34380Sstevel@tonic-gate 			*bp++ = *q++;
34390Sstevel@tonic-gate 		*bp = '\0';
34400Sstevel@tonic-gate 
34410Sstevel@tonic-gate 		/* skip cruft */
34420Sstevel@tonic-gate 		while (strchr(", ;", *q))
34430Sstevel@tonic-gate 			q++;
34440Sstevel@tonic-gate 
34450Sstevel@tonic-gate 		/* decode priority name */
34460Sstevel@tonic-gate 		pri = decode(buf, PriNames);
34470Sstevel@tonic-gate 		if (pri < 0) {
34480Sstevel@tonic-gate 			logerror("line %d: unknown priority name \"%s\"",
34496358Snakanon 			    lineno, buf);
34500Sstevel@tonic-gate 			return;
34510Sstevel@tonic-gate 		}
34520Sstevel@tonic-gate 
34530Sstevel@tonic-gate 		/* scan facilities */
34540Sstevel@tonic-gate 		while (*p && !strchr("\t.;", *p)) {
34550Sstevel@tonic-gate 			for (bp = buf; *p && !strchr("\t,;.", *p); )
34560Sstevel@tonic-gate 				*bp++ = *p++;
34570Sstevel@tonic-gate 			*bp = '\0';
34580Sstevel@tonic-gate 			if (*buf == '*')
34590Sstevel@tonic-gate 				for (i = 0; i < LOG_NFACILITIES; i++)
34600Sstevel@tonic-gate 					f->f_pmask[i] = (uchar_t)pri;
34610Sstevel@tonic-gate 			else {
34620Sstevel@tonic-gate 				i = decode(buf, FacNames);
34630Sstevel@tonic-gate 				if (i < 0) {
34640Sstevel@tonic-gate 					logerror("line %d: unknown facility"
34656358Snakanon 					    " name \"%s\"", lineno, buf);
34660Sstevel@tonic-gate 					return;
34670Sstevel@tonic-gate 				}
34680Sstevel@tonic-gate 				f->f_pmask[i >> 3] = (uchar_t)pri;
34690Sstevel@tonic-gate 			}
34700Sstevel@tonic-gate 			while (*p == ',' || *p == ' ')
34710Sstevel@tonic-gate 				p++;
34720Sstevel@tonic-gate 		}
34730Sstevel@tonic-gate 
34740Sstevel@tonic-gate 		p = q;
34750Sstevel@tonic-gate 	}
34760Sstevel@tonic-gate 
34770Sstevel@tonic-gate 	/* skip to action part */
34780Sstevel@tonic-gate 	while (*p == '\t' || *p == ' ')
34790Sstevel@tonic-gate 		p++;
34800Sstevel@tonic-gate 
34810Sstevel@tonic-gate 	switch (*p) {
34820Sstevel@tonic-gate 	case '\0':
34830Sstevel@tonic-gate 		errno = 0;
34840Sstevel@tonic-gate 		logerror("line %d: no action part", lineno);
34850Sstevel@tonic-gate 		break;
34860Sstevel@tonic-gate 
34870Sstevel@tonic-gate 	case '@':
34880Sstevel@tonic-gate 		(void) strlcpy(f->f_un.f_forw.f_hname, ++p, SYS_NMLN);
34892104Sjjj 		if (logforward(f, ebuf, sizeof (ebuf)) != 0) {
34900Sstevel@tonic-gate 			logerror("line %d: %s", lineno, ebuf);
34910Sstevel@tonic-gate 			break;
34920Sstevel@tonic-gate 		}
34930Sstevel@tonic-gate 		f->f_type = F_FORW;
34940Sstevel@tonic-gate 		break;
34950Sstevel@tonic-gate 
34960Sstevel@tonic-gate 	case '/':
34970Sstevel@tonic-gate 		(void) strlcpy(f->f_un.f_fname, p, MAXPATHLEN);
34980Sstevel@tonic-gate 		if (stat64(p, &sbuf) < 0) {
34990Sstevel@tonic-gate 			logerror(p);
35000Sstevel@tonic-gate 			break;
35010Sstevel@tonic-gate 		}
35020Sstevel@tonic-gate 		/*
35030Sstevel@tonic-gate 		 * don't block trying to open a pipe
35040Sstevel@tonic-gate 		 * with no reader on the other end
35050Sstevel@tonic-gate 		 */
35060Sstevel@tonic-gate 		fmode = 0; 	/* reset each pass */
35070Sstevel@tonic-gate 		if (S_ISFIFO(sbuf.st_mode))
35080Sstevel@tonic-gate 			fmode = O_NONBLOCK;
35090Sstevel@tonic-gate 
35100Sstevel@tonic-gate 		f->f_file = open64(p, omode|fmode);
35110Sstevel@tonic-gate 		if (f->f_file < 0) {
35120Sstevel@tonic-gate 			if (fmode && errno == ENXIO) {
35130Sstevel@tonic-gate 				errno = 0;
35140Sstevel@tonic-gate 				logerror("%s - no reader", p);
35150Sstevel@tonic-gate 			} else
35160Sstevel@tonic-gate 				logerror(p);
35170Sstevel@tonic-gate 			break;
35180Sstevel@tonic-gate 		}
35190Sstevel@tonic-gate 
35200Sstevel@tonic-gate 		/*
35210Sstevel@tonic-gate 		 * Fifos are initially opened NONBLOCK
35220Sstevel@tonic-gate 		 * to insure we don't hang, but once
35230Sstevel@tonic-gate 		 * we are open, we need to change the
35240Sstevel@tonic-gate 		 * behavior back to blocking, otherwise
35250Sstevel@tonic-gate 		 * we may get write errors, and the log
35260Sstevel@tonic-gate 		 * will get closed down the line.
35270Sstevel@tonic-gate 		 */
35280Sstevel@tonic-gate 		if (S_ISFIFO(sbuf.st_mode))
35290Sstevel@tonic-gate 			(void) fcntl(f->f_file, F_SETFL, omode);
35300Sstevel@tonic-gate 
35310Sstevel@tonic-gate 		if (isatty(f->f_file)) {
35320Sstevel@tonic-gate 			f->f_type = F_TTY;
35330Sstevel@tonic-gate 			untty();
35340Sstevel@tonic-gate 		} else
35350Sstevel@tonic-gate 			f->f_type = F_FILE;
35360Sstevel@tonic-gate 
35370Sstevel@tonic-gate 		if ((strcmp(p, ctty) == 0) || (strcmp(p, sysmsg) == 0))
35380Sstevel@tonic-gate 			f->f_type = F_CONSOLE;
35390Sstevel@tonic-gate 		break;
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate 	case '*':
35420Sstevel@tonic-gate 		f->f_type = F_WALL;
35430Sstevel@tonic-gate 		break;
35440Sstevel@tonic-gate 
35450Sstevel@tonic-gate 	default:
35460Sstevel@tonic-gate 		for (i = 0; i < MAXUNAMES && *p; i++) {
35470Sstevel@tonic-gate 			for (q = p; *q && *q != ','; )
35480Sstevel@tonic-gate 				q++;
35490Sstevel@tonic-gate 			(void) strlcpy(f->f_un.f_uname[i], p, UNAMESZ);
35500Sstevel@tonic-gate 			if ((q - p) > UNAMESZ)
35510Sstevel@tonic-gate 				f->f_un.f_uname[i][UNAMESZ] = '\0';
35520Sstevel@tonic-gate 			else
35530Sstevel@tonic-gate 				f->f_un.f_uname[i][q - p] = '\0';
35540Sstevel@tonic-gate 			while (*q == ',' || *q == ' ')
35550Sstevel@tonic-gate 				q++;
35560Sstevel@tonic-gate 			p = q;
35570Sstevel@tonic-gate 		}
35580Sstevel@tonic-gate 		f->f_type = F_USERS;
35590Sstevel@tonic-gate 		break;
35600Sstevel@tonic-gate 	}
35610Sstevel@tonic-gate 	f->f_orig_type = f->f_type;
35620Sstevel@tonic-gate }
35630Sstevel@tonic-gate 
35640Sstevel@tonic-gate 
35650Sstevel@tonic-gate /*
35660Sstevel@tonic-gate  *  Decode a symbolic name to a numeric value
35670Sstevel@tonic-gate  */
35680Sstevel@tonic-gate static int
decode(char * name,struct code * codetab)35690Sstevel@tonic-gate decode(char *name, struct code *codetab)
35700Sstevel@tonic-gate {
35710Sstevel@tonic-gate 	struct code *c;
35720Sstevel@tonic-gate 	char *p;
35730Sstevel@tonic-gate 	char buf[40];
35740Sstevel@tonic-gate 
35750Sstevel@tonic-gate 	if (isdigit(*name))
35760Sstevel@tonic-gate 		return (atoi(name));
35770Sstevel@tonic-gate 
35780Sstevel@tonic-gate 	(void) strncpy(buf, name, sizeof (buf) - 1);
35790Sstevel@tonic-gate 	for (p = buf; *p; p++)
35800Sstevel@tonic-gate 		if (isupper(*p))
35810Sstevel@tonic-gate 			*p = tolower(*p);
35820Sstevel@tonic-gate 	for (c = codetab; c->c_name; c++)
35830Sstevel@tonic-gate 		if (!(strcmp(buf, c->c_name)))
35840Sstevel@tonic-gate 			return (c->c_val);
35850Sstevel@tonic-gate 
35860Sstevel@tonic-gate 	return (-1);
35870Sstevel@tonic-gate }
35880Sstevel@tonic-gate 
35890Sstevel@tonic-gate static int
ismyaddr(struct netbuf * nbp)35900Sstevel@tonic-gate ismyaddr(struct netbuf *nbp)
35910Sstevel@tonic-gate {
35920Sstevel@tonic-gate 	int i;
35930Sstevel@tonic-gate 
35940Sstevel@tonic-gate 	if (nbp == NULL)
35950Sstevel@tonic-gate 		return (0);
35960Sstevel@tonic-gate 
35970Sstevel@tonic-gate 	for (i = 1; i < Ninputs; i++) {
35980Sstevel@tonic-gate 		if (same_addr(nbp, Myaddrs[i]))
35990Sstevel@tonic-gate 			return (1);
36000Sstevel@tonic-gate 	}
36010Sstevel@tonic-gate 	return (0);
36020Sstevel@tonic-gate }
36030Sstevel@tonic-gate 
36040Sstevel@tonic-gate static void
getnets(void)36050Sstevel@tonic-gate getnets(void)
36060Sstevel@tonic-gate {
36070Sstevel@tonic-gate 	struct nd_hostserv hs;
36080Sstevel@tonic-gate 	struct netconfig *ncp;
36090Sstevel@tonic-gate 	struct nd_addrlist *nap;
36100Sstevel@tonic-gate 	struct netbuf *nbp;
36110Sstevel@tonic-gate 	int i, inputs;
36120Sstevel@tonic-gate 	void *handle;
36130Sstevel@tonic-gate 	char *uap;
36140Sstevel@tonic-gate 	pthread_t mythreadno;
36150Sstevel@tonic-gate 
36160Sstevel@tonic-gate 	if (Debug) {
36170Sstevel@tonic-gate 		mythreadno = pthread_self();
36180Sstevel@tonic-gate 	}
36190Sstevel@tonic-gate 
36200Sstevel@tonic-gate 	if (turnoff) {
36210Sstevel@tonic-gate 		DPRINT1(1, "getnets(%u): network is being turned off\n",
36226358Snakanon 		    mythreadno);
36230Sstevel@tonic-gate 		return;
36240Sstevel@tonic-gate 	}
36250Sstevel@tonic-gate 
36260Sstevel@tonic-gate 	hs.h_host = HOST_SELF;
36270Sstevel@tonic-gate 	hs.h_serv = "syslog";
36280Sstevel@tonic-gate 
36290Sstevel@tonic-gate 	if ((handle = setnetconfig()) == NULL) {
36300Sstevel@tonic-gate 		return;
36310Sstevel@tonic-gate 	}
36320Sstevel@tonic-gate 
36330Sstevel@tonic-gate 	while ((ncp = getnetconfig(handle)) != NULL) {
36340Sstevel@tonic-gate 		if (ncp->nc_semantics != NC_TPI_CLTS) {
36350Sstevel@tonic-gate 			continue;
36360Sstevel@tonic-gate 		}
36370Sstevel@tonic-gate 
36380Sstevel@tonic-gate 		if (netdir_getbyname(ncp, &hs, &nap) != 0) {
36390Sstevel@tonic-gate 			continue;
36400Sstevel@tonic-gate 		}
36410Sstevel@tonic-gate 
36420Sstevel@tonic-gate 		if (nap == NULL || nap->n_cnt <= 0) {
36430Sstevel@tonic-gate 			DPRINT1(1, "getnets(%u): found no address\n",
36446358Snakanon 			    mythreadno);
36450Sstevel@tonic-gate 			netdir_free((void *)nap, ND_ADDRLIST);
36460Sstevel@tonic-gate 			continue;
36470Sstevel@tonic-gate 		}
36480Sstevel@tonic-gate 
36490Sstevel@tonic-gate 		if (Debug) {
36500Sstevel@tonic-gate 			DPRINT2(1, "getnets(%u): found %d addresses",
36516358Snakanon 			    mythreadno, nap->n_cnt);
36520Sstevel@tonic-gate 			DPRINT0(1, ", they are: ");
36530Sstevel@tonic-gate 			nbp = nap->n_addrs;
36540Sstevel@tonic-gate 
36550Sstevel@tonic-gate 			for (i = 0; i < nap->n_cnt; i++) {
36560Sstevel@tonic-gate 				if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
36570Sstevel@tonic-gate 					DPRINT1(1, "%s ", uap);
36580Sstevel@tonic-gate 					free(uap);
36590Sstevel@tonic-gate 				}
36600Sstevel@tonic-gate 				nbp++;
36610Sstevel@tonic-gate 			}
36620Sstevel@tonic-gate 
36630Sstevel@tonic-gate 			DPRINT0(1, "\n");
36640Sstevel@tonic-gate 		}
36650Sstevel@tonic-gate 
36660Sstevel@tonic-gate 		inputs = Ninputs + nap->n_cnt;
36670Sstevel@tonic-gate 
36680Sstevel@tonic-gate 		Nfd = realloc(Nfd, inputs * sizeof (struct pollfd));
36690Sstevel@tonic-gate 		Ncf = realloc(Ncf, inputs * sizeof (struct netconfig));
36700Sstevel@tonic-gate 		Myaddrs = realloc(Myaddrs, inputs * sizeof (struct netbuf *));
36710Sstevel@tonic-gate 		Udp = realloc(Udp, inputs * sizeof (struct t_unitdata *));
36720Sstevel@tonic-gate 		Errp = realloc(Errp, inputs * sizeof (struct t_uderr *));
36730Sstevel@tonic-gate 
36740Sstevel@tonic-gate 		/*
36750Sstevel@tonic-gate 		 * all malloc failures here are fatal
36760Sstevel@tonic-gate 		 */
36770Sstevel@tonic-gate 		if (Nfd == NULL || Ncf == NULL || Myaddrs == NULL ||
36786358Snakanon 		    Udp == NULL || Errp == NULL) {
36790Sstevel@tonic-gate 			MALLOC_FAIL_EXIT;
36800Sstevel@tonic-gate 		}
36810Sstevel@tonic-gate 
36820Sstevel@tonic-gate 		nbp = nap->n_addrs;
36830Sstevel@tonic-gate 
36840Sstevel@tonic-gate 		for (i = 0; i < nap->n_cnt; i++, nbp++) {
36850Sstevel@tonic-gate 			char ebuf[128];
36860Sstevel@tonic-gate 
36870Sstevel@tonic-gate 			if (addnet(ncp, nbp) == 0) {
36880Sstevel@tonic-gate 				/* no error */
36890Sstevel@tonic-gate 				continue;
36900Sstevel@tonic-gate 			}
36910Sstevel@tonic-gate 
36920Sstevel@tonic-gate 			(void) strcpy(ebuf, "Unable to configure syslog port");
36930Sstevel@tonic-gate 
36940Sstevel@tonic-gate 			if ((uap = taddr2uaddr(ncp, nbp)) != NULL) {
36950Sstevel@tonic-gate 				size_t l = strlen(ebuf);
36960Sstevel@tonic-gate 				(void) snprintf(ebuf + l, sizeof (ebuf) - l,
36976358Snakanon 				    " for %s", uap);
36980Sstevel@tonic-gate 			}
36990Sstevel@tonic-gate 
37000Sstevel@tonic-gate 			DPRINT2(1, "getnets(%u): %s",
37016358Snakanon 			    mythreadno, ebuf);
37020Sstevel@tonic-gate 
37030Sstevel@tonic-gate 			if (uap) {
37040Sstevel@tonic-gate 				free(uap);
37050Sstevel@tonic-gate 			}
37060Sstevel@tonic-gate 
37070Sstevel@tonic-gate 			logerror(ebuf);
37080Sstevel@tonic-gate 			/*
37090Sstevel@tonic-gate 			 * Here maybe syslogd can quit. However, syslogd
37100Sstevel@tonic-gate 			 * has been ignoring this error and keep running.
37110Sstevel@tonic-gate 			 * So we won't break it.
37120Sstevel@tonic-gate 			 */
37130Sstevel@tonic-gate 		}
37140Sstevel@tonic-gate 
37150Sstevel@tonic-gate 		netdir_free((void *)nap, ND_ADDRLIST);
37160Sstevel@tonic-gate 	}
37170Sstevel@tonic-gate 
37180Sstevel@tonic-gate 	(void) endnetconfig(handle);
37190Sstevel@tonic-gate }
37200Sstevel@tonic-gate 
37210Sstevel@tonic-gate /*
37220Sstevel@tonic-gate  * Open the network device, and allocate necessary resources.
37230Sstevel@tonic-gate  * Myaddrs will also be filled, so that we can call ismyaddr() before
37240Sstevel@tonic-gate  * being bound to the network.
37250Sstevel@tonic-gate  */
37260Sstevel@tonic-gate static int
addnet(struct netconfig * ncp,struct netbuf * nbp)37270Sstevel@tonic-gate addnet(struct netconfig *ncp, struct netbuf *nbp)
37280Sstevel@tonic-gate {
37290Sstevel@tonic-gate 	int fd;
37300Sstevel@tonic-gate 	struct netbuf *bp;
37310Sstevel@tonic-gate 
37320Sstevel@tonic-gate 	fd = t_open(ncp->nc_device, O_RDWR, NULL);
37330Sstevel@tonic-gate 
37340Sstevel@tonic-gate 	if (fd < 0) {
37350Sstevel@tonic-gate 		return (1);
37360Sstevel@tonic-gate 	}
37370Sstevel@tonic-gate 
37380Sstevel@tonic-gate 	(void) memcpy(&Ncf[Ninputs], ncp, sizeof (struct netconfig));
37390Sstevel@tonic-gate 
37400Sstevel@tonic-gate 	/*LINTED*/
37410Sstevel@tonic-gate 	Udp[Ninputs] = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR);
37420Sstevel@tonic-gate 
37430Sstevel@tonic-gate 	if (Udp[Ninputs] == NULL) {
37442104Sjjj 		(void) t_close(fd);
37450Sstevel@tonic-gate 		return (1);
37460Sstevel@tonic-gate 	}
37470Sstevel@tonic-gate 
37480Sstevel@tonic-gate 	/*LINTED*/
37490Sstevel@tonic-gate 	Errp[Ninputs] = (struct t_uderr *)t_alloc(fd, T_UDERROR, T_ADDR);
37500Sstevel@tonic-gate 
37510Sstevel@tonic-gate 	if (Errp[Ninputs] == NULL) {
37522104Sjjj 		(void) t_close(fd);
37532104Sjjj 		(void) t_free((char *)Udp[Ninputs], T_UNITDATA);
37540Sstevel@tonic-gate 		return (1);
37550Sstevel@tonic-gate 	}
37560Sstevel@tonic-gate 
37570Sstevel@tonic-gate 	if ((bp = malloc(sizeof (struct netbuf))) == NULL ||
37586358Snakanon 	    (bp->buf = malloc(nbp->len)) == NULL) {
37590Sstevel@tonic-gate 		MALLOC_FAIL("allocating address buffer");
37602104Sjjj 		(void) t_close(fd);
37612104Sjjj 		(void) t_free((char *)Udp[Ninputs], T_UNITDATA);
37622104Sjjj 		(void) t_free((char *)Errp[Ninputs], T_UDERROR);
37630Sstevel@tonic-gate 
37640Sstevel@tonic-gate 		if (bp) {
37650Sstevel@tonic-gate 			free(bp);
37660Sstevel@tonic-gate 		}
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 		return (1);
37690Sstevel@tonic-gate 	}
37700Sstevel@tonic-gate 
37710Sstevel@tonic-gate 	bp->len = nbp->len;
37720Sstevel@tonic-gate 	(void) memcpy(bp->buf, nbp->buf, nbp->len);
37730Sstevel@tonic-gate 	Myaddrs[Ninputs] = bp;
37740Sstevel@tonic-gate 
37750Sstevel@tonic-gate 	Nfd[Ninputs].fd = fd;
37760Sstevel@tonic-gate 	Nfd[Ninputs].events = POLLIN;
37770Sstevel@tonic-gate 	Ninputs++;
37780Sstevel@tonic-gate 	return (0);
37790Sstevel@tonic-gate }
37800Sstevel@tonic-gate 
37810Sstevel@tonic-gate /*
37820Sstevel@tonic-gate  * Allocate UDP buffer to minimize packet loss.
37830Sstevel@tonic-gate  */
37840Sstevel@tonic-gate static void
set_udp_buffer(int fd)37850Sstevel@tonic-gate set_udp_buffer(int fd)
37860Sstevel@tonic-gate {
37870Sstevel@tonic-gate 	struct t_optmgmt req, resp;
37880Sstevel@tonic-gate 	struct opthdr *opt;
37890Sstevel@tonic-gate 	size_t optsize, bsize = 256 * 1024;
37900Sstevel@tonic-gate 	pthread_t mythreadno;
37910Sstevel@tonic-gate 
37920Sstevel@tonic-gate 	if (Debug) {
37930Sstevel@tonic-gate 		mythreadno = pthread_self();
37940Sstevel@tonic-gate 	}
37950Sstevel@tonic-gate 
37960Sstevel@tonic-gate 	optsize = sizeof (struct opthdr) + sizeof (int);
37970Sstevel@tonic-gate 	if ((opt = malloc(optsize)) == NULL) {
37980Sstevel@tonic-gate 		MALLOC_FAIL("will have no udp buffer");
37990Sstevel@tonic-gate 		return;
38000Sstevel@tonic-gate 	}
38010Sstevel@tonic-gate 	opt->level = SOL_SOCKET;
38020Sstevel@tonic-gate 	opt->name = SO_RCVBUF;
38030Sstevel@tonic-gate 	opt->len = sizeof (int);
38040Sstevel@tonic-gate 	*(int *)(opt + 1) = bsize;
38050Sstevel@tonic-gate 
38060Sstevel@tonic-gate 	req.flags = T_NEGOTIATE;
38070Sstevel@tonic-gate 	req.opt.len = optsize;
38080Sstevel@tonic-gate 	req.opt.buf = (char *)opt;
38090Sstevel@tonic-gate 
38100Sstevel@tonic-gate 	resp.flags = 0;
38110Sstevel@tonic-gate 	resp.opt.maxlen = optsize;
38120Sstevel@tonic-gate 	resp.opt.buf = (char *)opt;
38130Sstevel@tonic-gate 
38140Sstevel@tonic-gate 	while (t_optmgmt(fd, &req, &resp) == -1 || resp.flags != T_SUCCESS) {
38150Sstevel@tonic-gate 		if (t_errno != TSYSERR || errno != ENOBUFS) {
38160Sstevel@tonic-gate 			bsize = 0;
38170Sstevel@tonic-gate 			break;
38180Sstevel@tonic-gate 		}
38190Sstevel@tonic-gate 		bsize >>= 1;
38200Sstevel@tonic-gate 		if (bsize < 8192) {
38210Sstevel@tonic-gate 			break;
38220Sstevel@tonic-gate 		}
38230Sstevel@tonic-gate 		*(int *)(opt + 1) = bsize;
38240Sstevel@tonic-gate 	}
38250Sstevel@tonic-gate 	if (bsize == 0) {
38260Sstevel@tonic-gate 		logerror("failed to allocate UDP buffer");
38270Sstevel@tonic-gate 	}
38280Sstevel@tonic-gate 	DPRINT3(1, "set_udp_buffer(%u): allocate %d for fd %d\n",
38296358Snakanon 	    mythreadno, bsize, fd);
38300Sstevel@tonic-gate 	free(opt);
38310Sstevel@tonic-gate }
38320Sstevel@tonic-gate 
38330Sstevel@tonic-gate /*
38340Sstevel@tonic-gate  * Attach the network, and allocate UDP buffer for the interface.
38350Sstevel@tonic-gate  */
38360Sstevel@tonic-gate static void
bindnet(void)38370Sstevel@tonic-gate bindnet(void)
38380Sstevel@tonic-gate {
38390Sstevel@tonic-gate 	struct t_bind bind, *bound;
38400Sstevel@tonic-gate 	int cnt, i;
38410Sstevel@tonic-gate 	char *uap;
38420Sstevel@tonic-gate 	pthread_t mythreadno;
38430Sstevel@tonic-gate 
38440Sstevel@tonic-gate 	if (Debug) {
38450Sstevel@tonic-gate 		mythreadno = pthread_self();
38460Sstevel@tonic-gate 	}
38470Sstevel@tonic-gate 
38480Sstevel@tonic-gate 	cnt = 0;
38490Sstevel@tonic-gate 
38500Sstevel@tonic-gate 	while (cnt < Ninputs) {
38510Sstevel@tonic-gate 		char ebuf[128];
38520Sstevel@tonic-gate 
38530Sstevel@tonic-gate 		/*LINTED*/
38540Sstevel@tonic-gate 		bound  = (struct t_bind *)t_alloc(Nfd[cnt].fd, T_BIND, T_ADDR);
38550Sstevel@tonic-gate 		bind.addr = *Myaddrs[cnt];
38560Sstevel@tonic-gate 		bind.qlen = 0;
38570Sstevel@tonic-gate 
38580Sstevel@tonic-gate 		if (t_bind(Nfd[cnt].fd, &bind, bound) == 0) {
38590Sstevel@tonic-gate 			if (same_addr(&bind.addr, &bound->addr)) {
38602104Sjjj 				(void) t_free((char *)bound, T_BIND);
38610Sstevel@tonic-gate 				set_udp_buffer(Nfd[cnt].fd);
38620Sstevel@tonic-gate 				cnt++;
38630Sstevel@tonic-gate 				continue;
38640Sstevel@tonic-gate 			}
38650Sstevel@tonic-gate 		}
38660Sstevel@tonic-gate 
38670Sstevel@tonic-gate 		/* failed to bind port */
38682104Sjjj 		(void) t_free((char *)bound, T_BIND);
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 		(void) strcpy(ebuf, "Unable to bind syslog port");
38710Sstevel@tonic-gate 
38720Sstevel@tonic-gate 		uap = taddr2uaddr(&Ncf[cnt], Myaddrs[cnt]);
38730Sstevel@tonic-gate 		if (uap) {
38740Sstevel@tonic-gate 			i = strlen(ebuf);
38750Sstevel@tonic-gate 			(void) snprintf(ebuf + i, sizeof (ebuf) - i,
38766358Snakanon 			    " for %s", uap);
38770Sstevel@tonic-gate 		}
38780Sstevel@tonic-gate 
38790Sstevel@tonic-gate 		DPRINT2(1, "bindnet(%u): failed to bind port (%s)\n",
38806358Snakanon 		    mythreadno, uap ? uap : "<unknown>");
38810Sstevel@tonic-gate 
38820Sstevel@tonic-gate 		if (uap) {
38830Sstevel@tonic-gate 			free(uap);
38840Sstevel@tonic-gate 		}
38850Sstevel@tonic-gate 
38860Sstevel@tonic-gate 		errno = 0;
38870Sstevel@tonic-gate 		logerror(ebuf);
38880Sstevel@tonic-gate 
38892104Sjjj 		(void) t_close(Nfd[cnt].fd);
38900Sstevel@tonic-gate 		free(Myaddrs[cnt]->buf);
38910Sstevel@tonic-gate 		free(Myaddrs[cnt]);
38922104Sjjj 		(void) t_free((char *)Udp[cnt], T_UNITDATA);
38932104Sjjj 		(void) t_free((char *)Errp[cnt], T_UDERROR);
38940Sstevel@tonic-gate 
38950Sstevel@tonic-gate 		for (i = cnt; i < (Ninputs-1); i++) {
38960Sstevel@tonic-gate 			Nfd[i] = Nfd[i + 1];
38970Sstevel@tonic-gate 			Ncf[i] = Ncf[i + 1];
38980Sstevel@tonic-gate 			Myaddrs[i] = Myaddrs[i + 1];
38990Sstevel@tonic-gate 			Udp[i] = Udp[i + 1];
39000Sstevel@tonic-gate 			Errp[i] = Errp[i + 1];
39010Sstevel@tonic-gate 		}
39020Sstevel@tonic-gate 
39030Sstevel@tonic-gate 		Ninputs--;
39040Sstevel@tonic-gate 	}
39050Sstevel@tonic-gate }
39060Sstevel@tonic-gate 
39070Sstevel@tonic-gate static int
logforward(struct filed * f,char * ebuf,size_t elen)39082104Sjjj logforward(struct filed *f, char *ebuf, size_t elen)
39090Sstevel@tonic-gate {
39100Sstevel@tonic-gate 	struct nd_hostserv hs;
39110Sstevel@tonic-gate 	struct netbuf *nbp;
39120Sstevel@tonic-gate 	struct netconfig *ncp;
39130Sstevel@tonic-gate 	struct nd_addrlist *nap;
39140Sstevel@tonic-gate 	void *handle;
39150Sstevel@tonic-gate 	char *hp;
39160Sstevel@tonic-gate 
39170Sstevel@tonic-gate 	hp = f->f_un.f_forw.f_hname;
39180Sstevel@tonic-gate 	hs.h_host = hp;
39190Sstevel@tonic-gate 	hs.h_serv = "syslog";
39200Sstevel@tonic-gate 
39210Sstevel@tonic-gate 	if ((handle = setnetconfig()) == NULL) {
39222104Sjjj 		(void) strlcpy(ebuf,
39236358Snakanon 		    "unable to rewind the netconfig database", elen);
39240Sstevel@tonic-gate 		errno = 0;
39250Sstevel@tonic-gate 		return (-1);
39260Sstevel@tonic-gate 	}
39270Sstevel@tonic-gate 	nap = (struct nd_addrlist *)NULL;
39280Sstevel@tonic-gate 	while ((ncp = getnetconfig(handle)) != NULL) {
39290Sstevel@tonic-gate 		if (ncp->nc_semantics == NC_TPI_CLTS) {
39300Sstevel@tonic-gate 			if (netdir_getbyname(ncp, &hs, &nap) == 0) {
39310Sstevel@tonic-gate 				if (!nap)
39320Sstevel@tonic-gate 					continue;
39330Sstevel@tonic-gate 				nbp = nap->n_addrs;
39340Sstevel@tonic-gate 				break;
39350Sstevel@tonic-gate 			}
39360Sstevel@tonic-gate 		}
39370Sstevel@tonic-gate 	}
39380Sstevel@tonic-gate 	if (ncp == NULL) {
39392104Sjjj 		(void) endnetconfig(handle);
39402104Sjjj 		(void) snprintf(ebuf, elen,
39412104Sjjj 		    "WARNING: %s could not be resolved", hp);
39420Sstevel@tonic-gate 		errno = 0;
39430Sstevel@tonic-gate 		return (-1);
39440Sstevel@tonic-gate 	}
39450Sstevel@tonic-gate 	if (nap == (struct nd_addrlist *)NULL) {
39462104Sjjj 		(void) endnetconfig(handle);
39472104Sjjj 		(void) snprintf(ebuf, elen, "unknown host %s", hp);
39480Sstevel@tonic-gate 		errno = 0;
39490Sstevel@tonic-gate 		return (-1);
39500Sstevel@tonic-gate 	}
39510Sstevel@tonic-gate 	/* CSTYLED */
39520Sstevel@tonic-gate 	if (ismyaddr(nbp)) { /*lint !e644 */
39530Sstevel@tonic-gate 		netdir_free((void *)nap, ND_ADDRLIST);
39542104Sjjj 		(void) endnetconfig(handle);
39552104Sjjj 		(void) snprintf(ebuf, elen,
39562104Sjjj 		    "host %s is this host - logging loop", hp);
39570Sstevel@tonic-gate 		errno = 0;
39580Sstevel@tonic-gate 		return (-1);
39590Sstevel@tonic-gate 	}
39600Sstevel@tonic-gate 	f->f_un.f_forw.f_addr.buf = malloc(nbp->len);
39610Sstevel@tonic-gate 	if (f->f_un.f_forw.f_addr.buf == NULL) {
39620Sstevel@tonic-gate 		netdir_free((void *)nap, ND_ADDRLIST);
39632104Sjjj 		(void) endnetconfig(handle);
39642104Sjjj 		(void) strlcpy(ebuf, "malloc failed", elen);
39650Sstevel@tonic-gate 		return (-1);
39660Sstevel@tonic-gate 	}
39670Sstevel@tonic-gate 	bcopy(nbp->buf, f->f_un.f_forw.f_addr.buf, nbp->len);
39680Sstevel@tonic-gate 	f->f_un.f_forw.f_addr.len = nbp->len;
39690Sstevel@tonic-gate 	f->f_file = t_open(ncp->nc_device, O_RDWR, NULL);
39700Sstevel@tonic-gate 	if (f->f_file < 0) {
39710Sstevel@tonic-gate 		netdir_free((void *)nap, ND_ADDRLIST);
39722104Sjjj 		(void) endnetconfig(handle);
39730Sstevel@tonic-gate 		free(f->f_un.f_forw.f_addr.buf);
39742104Sjjj 		(void) strlcpy(ebuf, "t_open", elen);
39750Sstevel@tonic-gate 		return (-1);
39760Sstevel@tonic-gate 	}
39770Sstevel@tonic-gate 	netdir_free((void *)nap, ND_ADDRLIST);
39782104Sjjj 	(void) endnetconfig(handle);
39790Sstevel@tonic-gate 	if (t_bind(f->f_file, NULL, NULL) < 0) {
39802104Sjjj 		(void) strlcpy(ebuf, "t_bind", elen);
39810Sstevel@tonic-gate 		free(f->f_un.f_forw.f_addr.buf);
39822104Sjjj 		(void) t_close(f->f_file);
39830Sstevel@tonic-gate 		return (-1);
39840Sstevel@tonic-gate 	}
39850Sstevel@tonic-gate 	return (0);
39860Sstevel@tonic-gate }
39870Sstevel@tonic-gate 
39880Sstevel@tonic-gate static int
amiloghost(void)39890Sstevel@tonic-gate amiloghost(void)
39900Sstevel@tonic-gate {
39910Sstevel@tonic-gate 	struct nd_hostserv hs;
39920Sstevel@tonic-gate 	struct netconfig *ncp;
39930Sstevel@tonic-gate 	struct nd_addrlist *nap;
39940Sstevel@tonic-gate 	struct netbuf *nbp;
39950Sstevel@tonic-gate 	int i, fd;
39960Sstevel@tonic-gate 	void *handle;
39970Sstevel@tonic-gate 	char *uap;
39980Sstevel@tonic-gate 	struct t_bind bind, *bound;
39990Sstevel@tonic-gate 	pthread_t mythreadno;
40000Sstevel@tonic-gate 
40010Sstevel@tonic-gate 	if (Debug) {
40020Sstevel@tonic-gate 		mythreadno = pthread_self();
40030Sstevel@tonic-gate 	}
40040Sstevel@tonic-gate 
40050Sstevel@tonic-gate 	/*
40060Sstevel@tonic-gate 	 * we need to know if we are running on the loghost. This is
40070Sstevel@tonic-gate 	 * checked by binding to the address associated with "loghost"
40080Sstevel@tonic-gate 	 * and "syslogd" service over the connectionless transport
40090Sstevel@tonic-gate 	 */
40100Sstevel@tonic-gate 	hs.h_host = "loghost";
40110Sstevel@tonic-gate 	hs.h_serv = "syslog";
40120Sstevel@tonic-gate 
40130Sstevel@tonic-gate 	if ((handle = setnetconfig()) == NULL) {
40140Sstevel@tonic-gate 		return (0);
40150Sstevel@tonic-gate 	}
40160Sstevel@tonic-gate 
40170Sstevel@tonic-gate 	while ((ncp = getnetconfig(handle)) != NULL) {
40180Sstevel@tonic-gate 		if (ncp->nc_semantics != NC_TPI_CLTS) {
40190Sstevel@tonic-gate 			continue;
40200Sstevel@tonic-gate 		}
40210Sstevel@tonic-gate 
40220Sstevel@tonic-gate 		if (netdir_getbyname(ncp, &hs, &nap) != 0) {
40230Sstevel@tonic-gate 			continue;
40240Sstevel@tonic-gate 		}
40250Sstevel@tonic-gate 
40260Sstevel@tonic-gate 		if (nap == NULL) {
40270Sstevel@tonic-gate 			continue;
40280Sstevel@tonic-gate 		}
40290Sstevel@tonic-gate 
40300Sstevel@tonic-gate 		nbp = nap->n_addrs;
40310Sstevel@tonic-gate 
40320Sstevel@tonic-gate 		for (i = 0; i < nap->n_cnt; i++) {
40330Sstevel@tonic-gate 			if ((uap = taddr2uaddr(ncp, nbp)) != (char *)NULL) {
40340Sstevel@tonic-gate 				DPRINT2(1, "amiloghost(%u): testing %s\n",
40356358Snakanon 				    mythreadno, uap);
40360Sstevel@tonic-gate 			}
40370Sstevel@tonic-gate 
40380Sstevel@tonic-gate 			free(uap);
40390Sstevel@tonic-gate 
40400Sstevel@tonic-gate 			fd = t_open(ncp->nc_device, O_RDWR, NULL);
40410Sstevel@tonic-gate 
40420Sstevel@tonic-gate 			if (fd < 0) {
40430Sstevel@tonic-gate 				netdir_free((void *)nap, ND_ADDRLIST);
40442104Sjjj 				(void) endnetconfig(handle);
40450Sstevel@tonic-gate 				return (0);
40460Sstevel@tonic-gate 			}
40470Sstevel@tonic-gate 
40480Sstevel@tonic-gate 			/*LINTED*/
40490Sstevel@tonic-gate 			bound = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
40500Sstevel@tonic-gate 			bind.addr = *nbp;
40510Sstevel@tonic-gate 			bind.qlen = 0;
40520Sstevel@tonic-gate 
40530Sstevel@tonic-gate 			if (t_bind(fd, &bind, bound) == 0) {
40542104Sjjj 				(void) t_close(fd);
40552104Sjjj 				(void) t_free((char *)bound, T_BIND);
40560Sstevel@tonic-gate 				netdir_free((void *)nap, ND_ADDRLIST);
40572104Sjjj 				(void) endnetconfig(handle);
40580Sstevel@tonic-gate 				return (1);
40590Sstevel@tonic-gate 			} else {
40602104Sjjj 				(void) t_close(fd);
40612104Sjjj 				(void) t_free((char *)bound, T_BIND);
40620Sstevel@tonic-gate 			}
40630Sstevel@tonic-gate 
40640Sstevel@tonic-gate 			nbp++;
40650Sstevel@tonic-gate 		}
40660Sstevel@tonic-gate 
40670Sstevel@tonic-gate 		netdir_free((void *)nap, ND_ADDRLIST);
40680Sstevel@tonic-gate 	}
40690Sstevel@tonic-gate 
40702104Sjjj 	(void) endnetconfig(handle);
40710Sstevel@tonic-gate 	return (0);
40720Sstevel@tonic-gate }
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate int
same_addr(struct netbuf * na,struct netbuf * nb)40750Sstevel@tonic-gate same_addr(struct netbuf *na, struct netbuf *nb)
40760Sstevel@tonic-gate {
40770Sstevel@tonic-gate 	char *a, *b;
40780Sstevel@tonic-gate 	size_t n;
40790Sstevel@tonic-gate 
40802104Sjjj 	assert(na->buf != NULL && nb->buf != NULL);
40810Sstevel@tonic-gate 
40820Sstevel@tonic-gate 	if (na->len != nb->len) {
40830Sstevel@tonic-gate 		return (0);
40840Sstevel@tonic-gate 	}
40850Sstevel@tonic-gate 
40860Sstevel@tonic-gate 	a = na->buf;
40870Sstevel@tonic-gate 	b = nb->buf;
40880Sstevel@tonic-gate 	n = nb->len;
40890Sstevel@tonic-gate 
40900Sstevel@tonic-gate 	while (n-- > 0) {
40910Sstevel@tonic-gate 		if (*a++ != *b++) {
40920Sstevel@tonic-gate 			return (0);
40930Sstevel@tonic-gate 		}
40940Sstevel@tonic-gate 	}
40950Sstevel@tonic-gate 
40960Sstevel@tonic-gate 	return (1);
40970Sstevel@tonic-gate }
40980Sstevel@tonic-gate 
40990Sstevel@tonic-gate /*
41000Sstevel@tonic-gate  * allocates a new message structure, initializes it
41010Sstevel@tonic-gate  * and returns a pointer to it
41020Sstevel@tonic-gate  */
41030Sstevel@tonic-gate static log_message_t *
new_msg(void)41040Sstevel@tonic-gate new_msg(void)
41050Sstevel@tonic-gate {
41060Sstevel@tonic-gate 	log_message_t *lm;
41070Sstevel@tonic-gate 	pthread_t mythreadno;
41080Sstevel@tonic-gate 
41090Sstevel@tonic-gate 	if (Debug) {
41100Sstevel@tonic-gate 		mythreadno = pthread_self();
41110Sstevel@tonic-gate 	}
41120Sstevel@tonic-gate 
41130Sstevel@tonic-gate 	if ((lm = malloc(sizeof (log_message_t))) == NULL)
41140Sstevel@tonic-gate 		return ((log_message_t *)NULL);
41150Sstevel@tonic-gate 
41160Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*lm))
41170Sstevel@tonic-gate 
41180Sstevel@tonic-gate 	if (pthread_mutex_init(&lm->msg_mutex, NULL) != 0)
41190Sstevel@tonic-gate 		return ((log_message_t *)NULL);
41200Sstevel@tonic-gate 	lm->refcnt = 0;
41210Sstevel@tonic-gate 	lm->pri = 0;
41220Sstevel@tonic-gate 	lm->flags = 0;
41230Sstevel@tonic-gate 	lm->hlp = NULL;
41240Sstevel@tonic-gate 	lm->msg[0] = '\0';
41250Sstevel@tonic-gate 	lm->ptr = NULL;
41260Sstevel@tonic-gate 
41272104Sjjj 	DPRINT2(3, "new_msg(%u): creating msg %p\n", mythreadno, (void *)lm);
41280Sstevel@tonic-gate 	return (lm);
41290Sstevel@tonic-gate }
41300Sstevel@tonic-gate 
41310Sstevel@tonic-gate /*
41320Sstevel@tonic-gate  * frees a message structure - should only be called if
41330Sstevel@tonic-gate  * the refcount is 0
41340Sstevel@tonic-gate  */
41350Sstevel@tonic-gate static void
free_msg(log_message_t * lm)41360Sstevel@tonic-gate free_msg(log_message_t *lm)
41370Sstevel@tonic-gate {
41380Sstevel@tonic-gate 	pthread_t mythreadno;
41390Sstevel@tonic-gate 
41400Sstevel@tonic-gate 	if (Debug) {
41410Sstevel@tonic-gate 		mythreadno = pthread_self();
41420Sstevel@tonic-gate 	}
41430Sstevel@tonic-gate 
41440Sstevel@tonic-gate 	assert(lm != NULL && lm->refcnt == 0);
41450Sstevel@tonic-gate 	if (lm->hlp != NULL)
41460Sstevel@tonic-gate 		freehl(lm->hlp);
41472104Sjjj 	DPRINT2(3, "free_msg(%u): freeing msg %p\n", mythreadno, (void *)lm);
41480Sstevel@tonic-gate 	free(lm);
41490Sstevel@tonic-gate }
41500Sstevel@tonic-gate 
41510Sstevel@tonic-gate /*
41520Sstevel@tonic-gate  *  Make sure that the message makes sense in the current locale, and
41530Sstevel@tonic-gate  *  does not contain stray control characters.
41540Sstevel@tonic-gate  */
41550Sstevel@tonic-gate static void
filter_string(char * mbstr,char * filtered,size_t max)41560Sstevel@tonic-gate filter_string(char *mbstr, char *filtered, size_t max)
41570Sstevel@tonic-gate {
41580Sstevel@tonic-gate 	size_t	cs = 0;
41590Sstevel@tonic-gate 	size_t	mb_cur_max;
41600Sstevel@tonic-gate 	unsigned char	*p = (unsigned char *)mbstr;
41610Sstevel@tonic-gate 	pthread_t mythreadno = 0;
41620Sstevel@tonic-gate 
41630Sstevel@tonic-gate 	if (Debug) {
41640Sstevel@tonic-gate 		mythreadno = pthread_self();
41650Sstevel@tonic-gate 	}
41660Sstevel@tonic-gate 
41670Sstevel@tonic-gate 	assert(mbstr != NULL && filtered != NULL);
41680Sstevel@tonic-gate 
41690Sstevel@tonic-gate 	/*
41700Sstevel@tonic-gate 	 * Since the access to MB_CUR_MAX is expensive (because
41710Sstevel@tonic-gate 	 * MB_CUR_MAX lives in a global area), it should be
41720Sstevel@tonic-gate 	 * restrained for the better performance.
41730Sstevel@tonic-gate 	 */
41740Sstevel@tonic-gate 	mb_cur_max = (size_t)MB_CUR_MAX;
41750Sstevel@tonic-gate 	if (mb_cur_max > 1) {
41760Sstevel@tonic-gate 		/* multibyte locale */
41770Sstevel@tonic-gate 		int	mlen;
41780Sstevel@tonic-gate 		wchar_t	wc;
41790Sstevel@tonic-gate 
41800Sstevel@tonic-gate 		while (*p != '\0') {
41810Sstevel@tonic-gate 			if ((mlen = mbtowc(&wc, (char *)p,
41826358Snakanon 			    mb_cur_max)) == -1) {
41830Sstevel@tonic-gate 				/*
41840Sstevel@tonic-gate 				 * Invalid byte sequence found.
41850Sstevel@tonic-gate 				 *
41860Sstevel@tonic-gate 				 * try to print one byte
41870Sstevel@tonic-gate 				 * in ASCII format.
41880Sstevel@tonic-gate 				 */
41890Sstevel@tonic-gate 				DPRINT2(9, "filter_string(%u): Invalid "
41906358Snakanon 				    "MB sequence: %ld\n", mythreadno,
41916358Snakanon 				    wc);
41920Sstevel@tonic-gate 
41930Sstevel@tonic-gate 				if (!putctrlc(*p++, &filtered, &cs, max)) {
41940Sstevel@tonic-gate 					/* not enough buffer */
41950Sstevel@tonic-gate 					goto end;
41960Sstevel@tonic-gate 				} else {
41970Sstevel@tonic-gate 					continue;
41980Sstevel@tonic-gate 				}
41990Sstevel@tonic-gate 			} else {
42000Sstevel@tonic-gate 				/*
42010Sstevel@tonic-gate 				 * Since *p is not a null byte here,
42020Sstevel@tonic-gate 				 * mbtowc should have never returned 0.
42030Sstevel@tonic-gate 				 *
42040Sstevel@tonic-gate 				 * A valid wide character found.
42050Sstevel@tonic-gate 				 */
42060Sstevel@tonic-gate 
42070Sstevel@tonic-gate 				if (wc != L'\t' && iswcntrl(wc)) {
42080Sstevel@tonic-gate 					/*
42090Sstevel@tonic-gate 					 * non-tab, non-newline, and
42100Sstevel@tonic-gate 					 * control character found.
42110Sstevel@tonic-gate 					 *
42120Sstevel@tonic-gate 					 * try to print this wide character
42130Sstevel@tonic-gate 					 * in ASCII-format.
42140Sstevel@tonic-gate 					 */
42150Sstevel@tonic-gate 					char	*q = filtered;
42160Sstevel@tonic-gate 
42170Sstevel@tonic-gate 					DPRINT2(9, "filter_string(%u): MB"
42186358Snakanon 					    " control character: %ld\n",
42196358Snakanon 					    mythreadno, wc);
42200Sstevel@tonic-gate 
42210Sstevel@tonic-gate 					while (mlen--) {
42220Sstevel@tonic-gate 						if (!putctrlc(*p++, &filtered,
42236358Snakanon 						    &cs, max)) {
42240Sstevel@tonic-gate 							/*
42250Sstevel@tonic-gate 							 * not enough buffer in
42260Sstevel@tonic-gate 							 * filtered
42270Sstevel@tonic-gate 							 *
42280Sstevel@tonic-gate 							 * cancel already
42290Sstevel@tonic-gate 							 * stored bytes in
42300Sstevel@tonic-gate 							 * filtered for this
42310Sstevel@tonic-gate 							 * wide character.
42320Sstevel@tonic-gate 							 */
42330Sstevel@tonic-gate 							filtered = q;
42340Sstevel@tonic-gate 							goto end;
42350Sstevel@tonic-gate 						}
42360Sstevel@tonic-gate 					}
42370Sstevel@tonic-gate 					continue;
42380Sstevel@tonic-gate 				} else {
42390Sstevel@tonic-gate 					/*
42400Sstevel@tonic-gate 					 * tab, newline, or non-control
42410Sstevel@tonic-gate 					 * character found.
42420Sstevel@tonic-gate 					 */
42430Sstevel@tonic-gate 					if (cs + mlen < max) {
42440Sstevel@tonic-gate 						/* enough buffer */
42450Sstevel@tonic-gate 						cs += mlen;
42460Sstevel@tonic-gate 						while (mlen--) {
42470Sstevel@tonic-gate 							*filtered++ = *p++;
42480Sstevel@tonic-gate 						}
42490Sstevel@tonic-gate 						continue;
42500Sstevel@tonic-gate 					} else {
42510Sstevel@tonic-gate 						/* not enough buffer */
42520Sstevel@tonic-gate 						goto end;
42530Sstevel@tonic-gate 					}
42540Sstevel@tonic-gate 				}
42550Sstevel@tonic-gate 			}
42560Sstevel@tonic-gate 		}
42570Sstevel@tonic-gate 	} else {
42580Sstevel@tonic-gate 		/* singlebyte locale */
42590Sstevel@tonic-gate 
42600Sstevel@tonic-gate 		while (*p != '\0') {
42610Sstevel@tonic-gate 			if (*p != '\t' && iscntrl(*p)) {
42620Sstevel@tonic-gate 				/*
42630Sstevel@tonic-gate 				 * non-tab, non-newline,
42640Sstevel@tonic-gate 				 * and control character found.
42650Sstevel@tonic-gate 				 *
42660Sstevel@tonic-gate 				 * try to print this singlebyte character
42670Sstevel@tonic-gate 				 * in ASCII format.
42680Sstevel@tonic-gate 				 */
42690Sstevel@tonic-gate 				DPRINT2(9, "filter_string(%u): control "
42706358Snakanon 				    "character: %d\n", mythreadno, *p);
42710Sstevel@tonic-gate 
42720Sstevel@tonic-gate 				if (!putctrlc(*p++, &filtered, &cs, max)) {
42730Sstevel@tonic-gate 					/* not enough buffer */
42740Sstevel@tonic-gate 					goto end;
42750Sstevel@tonic-gate 				} else {
42760Sstevel@tonic-gate 					continue;
42770Sstevel@tonic-gate 				}
42780Sstevel@tonic-gate 			} else if (*p != '\t' && !isprint(*p)) {
42790Sstevel@tonic-gate 				/*
42800Sstevel@tonic-gate 				 * non-tab and non printable character found
42810Sstevel@tonic-gate 				 * this check is required for the C locale
42820Sstevel@tonic-gate 				 */
42830Sstevel@tonic-gate 				DPRINT2(9, "filter_string(%u): non-printable "
42846358Snakanon 				    "character: %d\n", mythreadno, *p);
42850Sstevel@tonic-gate 				if (!putctrlc(*p++, &filtered, &cs, max)) {
42860Sstevel@tonic-gate 					/* not enough buffer */
42870Sstevel@tonic-gate 					goto end;
42880Sstevel@tonic-gate 				} else {
42890Sstevel@tonic-gate 					continue;
42900Sstevel@tonic-gate 				}
42910Sstevel@tonic-gate 			} else {
42920Sstevel@tonic-gate 				/*
42930Sstevel@tonic-gate 				 * tab, newline, non-control character, or
42940Sstevel@tonic-gate 				 * printable found.
42950Sstevel@tonic-gate 				 */
42960Sstevel@tonic-gate 				if (cs + 1 < max) {
42970Sstevel@tonic-gate 					*filtered++ = *p++;
42980Sstevel@tonic-gate 					cs++;
42990Sstevel@tonic-gate 					continue;
43000Sstevel@tonic-gate 				} else {
43010Sstevel@tonic-gate 					/* not enough buffer */
43020Sstevel@tonic-gate 					goto end;
43030Sstevel@tonic-gate 				}
43040Sstevel@tonic-gate 			}
43050Sstevel@tonic-gate 		}
43060Sstevel@tonic-gate 	}
43070Sstevel@tonic-gate 
43080Sstevel@tonic-gate end:
43090Sstevel@tonic-gate 	*filtered = '\0';
43100Sstevel@tonic-gate 
43110Sstevel@tonic-gate 	if (cs >= 2 &&
43126358Snakanon 	    filtered[-2] == '\\' && filtered[-1] == 'n') {
43130Sstevel@tonic-gate 		filtered[-2] = '\0';
43140Sstevel@tonic-gate 	}
43150Sstevel@tonic-gate }
43160Sstevel@tonic-gate 
43170Sstevel@tonic-gate static char *
alloc_stacks(int numstacks)43180Sstevel@tonic-gate alloc_stacks(int numstacks)
43190Sstevel@tonic-gate {
43200Sstevel@tonic-gate 	size_t pagesize, mapsize;
43210Sstevel@tonic-gate 	char *stack_top;
43220Sstevel@tonic-gate 	char *addr;
43230Sstevel@tonic-gate 	int i;
43240Sstevel@tonic-gate 
43250Sstevel@tonic-gate 	pagesize = (size_t)sysconf(_SC_PAGESIZE);
43260Sstevel@tonic-gate 	/*
43270Sstevel@tonic-gate 	 * stacksize and redzonesize are global so threads
43280Sstevel@tonic-gate 	 * can be created elsewhere and refer to the sizes
43290Sstevel@tonic-gate 	 */
43300Sstevel@tonic-gate 	stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
43316358Snakanon 	    DEFAULT_STACKSIZE, pagesize);
43320Sstevel@tonic-gate 	redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
43330Sstevel@tonic-gate 
43340Sstevel@tonic-gate 	/*
43350Sstevel@tonic-gate 	 * allocate an additional "redzonesize" chunk in addition
43360Sstevel@tonic-gate 	 * to what we require, so we can create a redzone at the
43370Sstevel@tonic-gate 	 * bottom of the last stack as well.
43380Sstevel@tonic-gate 	 */
43390Sstevel@tonic-gate 	mapsize = redzonesize + numstacks * (stacksize + redzonesize);
43400Sstevel@tonic-gate 	stack_top = mmap(NULL, mapsize, PROT_READ|PROT_WRITE,
43416358Snakanon 	    MAP_PRIVATE|MAP_ANON, -1, 0);
43420Sstevel@tonic-gate 	if (stack_top == MAP_FAILED)
43430Sstevel@tonic-gate 		return (NULL);
43440Sstevel@tonic-gate 
43450Sstevel@tonic-gate 	addr = stack_top;
43460Sstevel@tonic-gate 	/*
43470Sstevel@tonic-gate 	 * this loop is intentionally <= instead of <, so we can
43480Sstevel@tonic-gate 	 * protect the redzone at the bottom of the last stack
43490Sstevel@tonic-gate 	 */
43500Sstevel@tonic-gate 	for (i = 0; i <= numstacks; i++) {
43510Sstevel@tonic-gate 		(void) mprotect(addr, redzonesize, PROT_NONE);
43520Sstevel@tonic-gate 		addr += stacksize + redzonesize;
43530Sstevel@tonic-gate 	}
43540Sstevel@tonic-gate 	return ((char *)(stack_top + redzonesize));
43550Sstevel@tonic-gate }
43560Sstevel@tonic-gate 
43570Sstevel@tonic-gate static void
dealloc_stacks(int numstacks)43580Sstevel@tonic-gate dealloc_stacks(int numstacks)
43590Sstevel@tonic-gate {
43600Sstevel@tonic-gate 	size_t pagesize, mapsize;
43610Sstevel@tonic-gate 
43620Sstevel@tonic-gate 	pagesize = (size_t)sysconf(_SC_PAGESIZE);
43630Sstevel@tonic-gate 
43640Sstevel@tonic-gate 	stacksize = (size_t)roundup(sysconf(_SC_THREAD_STACK_MIN) +
43650Sstevel@tonic-gate 	    DEFAULT_STACKSIZE, pagesize);
43660Sstevel@tonic-gate 
43670Sstevel@tonic-gate 	redzonesize = (size_t)roundup(DEFAULT_REDZONESIZE, pagesize);
43680Sstevel@tonic-gate 
43690Sstevel@tonic-gate 	mapsize = redzonesize + numstacks * (stacksize + redzonesize);
43700Sstevel@tonic-gate 	(void) munmap(cstack_ptr - mapsize, mapsize);
43710Sstevel@tonic-gate }
43720Sstevel@tonic-gate 
43730Sstevel@tonic-gate static void
filed_destroy(struct filed * f)43740Sstevel@tonic-gate filed_destroy(struct filed *f)
43750Sstevel@tonic-gate {
43760Sstevel@tonic-gate 	(void) dataq_destroy(&f->f_queue);
43772104Sjjj 	(void) pthread_mutex_destroy(&f->filed_mutex);
43780Sstevel@tonic-gate }
43790Sstevel@tonic-gate 
43800Sstevel@tonic-gate static void
close_door(void)43810Sstevel@tonic-gate close_door(void)
43820Sstevel@tonic-gate {
43830Sstevel@tonic-gate 	pthread_t mythreadno;
43840Sstevel@tonic-gate 
43850Sstevel@tonic-gate 	if (Debug) {
43860Sstevel@tonic-gate 		mythreadno = pthread_self();
43870Sstevel@tonic-gate 	}
43880Sstevel@tonic-gate 
43890Sstevel@tonic-gate 	(void) fdetach(DoorFileName);
43900Sstevel@tonic-gate 
43910Sstevel@tonic-gate 	DPRINT2(5, "close_door(%u): detached server() from %s\n",
43926358Snakanon 	    mythreadno, DoorFileName);
43930Sstevel@tonic-gate }
43940Sstevel@tonic-gate 
43950Sstevel@tonic-gate static void
delete_doorfiles(void)43960Sstevel@tonic-gate delete_doorfiles(void)
43970Sstevel@tonic-gate {
43980Sstevel@tonic-gate 	pthread_t mythreadno;
43990Sstevel@tonic-gate 	struct stat sb;
44000Sstevel@tonic-gate 	int err;
44010Sstevel@tonic-gate 	char line[MAXLINE+1];
44020Sstevel@tonic-gate 
44030Sstevel@tonic-gate 	if (Debug) {
44040Sstevel@tonic-gate 		mythreadno = pthread_self();
44050Sstevel@tonic-gate 	}
44060Sstevel@tonic-gate 
44070Sstevel@tonic-gate 
44080Sstevel@tonic-gate 	if (lstat(DoorFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
44090Sstevel@tonic-gate 		if (unlink(DoorFileName) < 0) {
44100Sstevel@tonic-gate 			err = errno;
44112104Sjjj 			(void) snprintf(line, sizeof (line),
44122104Sjjj 			    "unlink() of %s failed - fatal", DoorFileName);
44130Sstevel@tonic-gate 			errno = err;
44140Sstevel@tonic-gate 			logerror(line);
44150Sstevel@tonic-gate 			DPRINT3(1, "delete_doorfiles(%u): error: %s, "
44166358Snakanon 			    "errno=%d\n", mythreadno, line, err);
44170Sstevel@tonic-gate 			exit(1);
44180Sstevel@tonic-gate 		}
44190Sstevel@tonic-gate 
44200Sstevel@tonic-gate 		DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
44216358Snakanon 		    mythreadno, DoorFileName);
44220Sstevel@tonic-gate 	}
44230Sstevel@tonic-gate 
44240Sstevel@tonic-gate 	if (strcmp(DoorFileName, DOORFILE) == 0) {
44250Sstevel@tonic-gate 		if (lstat(OLD_DOORFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
44260Sstevel@tonic-gate 			if (unlink(OLD_DOORFILE) < 0) {
44270Sstevel@tonic-gate 				err = errno;
44282104Sjjj 				(void) snprintf(line, sizeof (line),
44292104Sjjj 				    "unlink() of %s failed", OLD_DOORFILE);
44300Sstevel@tonic-gate 				DPRINT2(5, "delete_doorfiles(%u): %s\n",
44316358Snakanon 				    mythreadno, line);
44320Sstevel@tonic-gate 
44330Sstevel@tonic-gate 				if (err != EROFS) {
44340Sstevel@tonic-gate 					errno = err;
44352104Sjjj 					(void) strlcat(line, " - fatal",
44362104Sjjj 					    sizeof (line));
44370Sstevel@tonic-gate 					logerror(line);
44380Sstevel@tonic-gate 					DPRINT3(1, "delete_doorfiles(%u): "
44396358Snakanon 					    "error: %s, errno=%d\n",
44406358Snakanon 					    mythreadno, line, err);
44410Sstevel@tonic-gate 					exit(1);
44420Sstevel@tonic-gate 				}
44430Sstevel@tonic-gate 
44440Sstevel@tonic-gate 				DPRINT1(5, "delete_doorfiles(%u): unlink() "
44456358Snakanon 				    "failure OK on RO file system\n",
44466358Snakanon 				    mythreadno);
44470Sstevel@tonic-gate 			}
44480Sstevel@tonic-gate 
44490Sstevel@tonic-gate 			DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
44506358Snakanon 			    mythreadno, OLD_DOORFILE);
44510Sstevel@tonic-gate 		}
44520Sstevel@tonic-gate 	}
44530Sstevel@tonic-gate 
44540Sstevel@tonic-gate 	if (lstat(PidFileName, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
44550Sstevel@tonic-gate 		if (unlink(PidFileName) < 0) {
44560Sstevel@tonic-gate 			err = errno;
44572104Sjjj 			(void) snprintf(line, sizeof (line),
44582104Sjjj 			    "unlink() of %s failed - fatal", PidFileName);
44590Sstevel@tonic-gate 			errno = err;
44600Sstevel@tonic-gate 			logerror(line);
44610Sstevel@tonic-gate 			DPRINT3(1, "delete_doorfiles(%u): error: %s, "
44626358Snakanon 			    "errno=%d\n", mythreadno, line, err);
44630Sstevel@tonic-gate 			exit(1);
44640Sstevel@tonic-gate 		}
44650Sstevel@tonic-gate 
44660Sstevel@tonic-gate 		DPRINT2(5, "delete_doorfiles(%u): deleted %s\n", mythreadno,
44676358Snakanon 		    PidFileName);
44680Sstevel@tonic-gate 	}
44690Sstevel@tonic-gate 
44700Sstevel@tonic-gate 	if (strcmp(PidFileName, PIDFILE) == 0) {
44710Sstevel@tonic-gate 		if (lstat(OLD_PIDFILE, &sb) == 0 && !S_ISDIR(sb.st_mode)) {
44720Sstevel@tonic-gate 			if (unlink(OLD_PIDFILE) < 0) {
44730Sstevel@tonic-gate 				err = errno;
44742104Sjjj 				(void) snprintf(line, sizeof (line),
44752104Sjjj 				    "unlink() of %s failed", OLD_PIDFILE);
44760Sstevel@tonic-gate 				DPRINT2(5, "delete_doorfiles(%u): %s, \n",
44776358Snakanon 				    mythreadno, line);
44780Sstevel@tonic-gate 
44790Sstevel@tonic-gate 				if (err != EROFS) {
44800Sstevel@tonic-gate 					errno = err;
44812104Sjjj 					(void) strlcat(line, " - fatal",
44822104Sjjj 					    sizeof (line));
44830Sstevel@tonic-gate 					logerror(line);
44840Sstevel@tonic-gate 					DPRINT3(1, "delete_doorfiles(%u): "
44856358Snakanon 					    "error: %s, errno=%d\n",
44866358Snakanon 					    mythreadno, line, err);
44870Sstevel@tonic-gate 					exit(1);
44880Sstevel@tonic-gate 				}
44890Sstevel@tonic-gate 
44900Sstevel@tonic-gate 				DPRINT1(5, "delete_doorfiles(%u): unlink "
44916358Snakanon 				    "failure OK on RO file system\n",
44926358Snakanon 				    mythreadno);
44930Sstevel@tonic-gate 			}
44940Sstevel@tonic-gate 
44950Sstevel@tonic-gate 			DPRINT2(5, "delete_doorfiles(%u): deleted %s\n",
44966358Snakanon 			    mythreadno, OLD_PIDFILE);
44970Sstevel@tonic-gate 		}
44980Sstevel@tonic-gate 	}
44990Sstevel@tonic-gate 
45000Sstevel@tonic-gate 	if (DoorFd != -1) {
45010Sstevel@tonic-gate 		(void) door_revoke(DoorFd);
45020Sstevel@tonic-gate 	}
45030Sstevel@tonic-gate 
45040Sstevel@tonic-gate 	DPRINT2(1, "delete_doorfiles(%u): revoked door: DoorFd=%d\n",
45056358Snakanon 	    mythreadno, DoorFd);
45060Sstevel@tonic-gate }
45070Sstevel@tonic-gate 
45080Sstevel@tonic-gate 
45090Sstevel@tonic-gate /*ARGSUSED*/
45100Sstevel@tonic-gate static void
signull(int sig,siginfo_t * sip,void * utp)45110Sstevel@tonic-gate signull(int sig, siginfo_t *sip, void *utp)
45120Sstevel@tonic-gate {
45130Sstevel@tonic-gate 	DPRINT1(1, "signull(%u): THIS CALL SHOULD NEVER HAPPEN\n",
45146358Snakanon 	    pthread_self());
45150Sstevel@tonic-gate 	/*
45160Sstevel@tonic-gate 	 * Do nothing, as this is a place-holder used in conjunction with
45170Sstevel@tonic-gate 	 * sigaction()/sigwait() to ensure that the proper disposition is
45180Sstevel@tonic-gate 	 * given to the signals we handle in main().
45190Sstevel@tonic-gate 	 */
45200Sstevel@tonic-gate }
45210Sstevel@tonic-gate 
45220Sstevel@tonic-gate /*
45230Sstevel@tonic-gate  * putctrlc returns zero, if failed due to not enough buffer.
45240Sstevel@tonic-gate  * Otherwise, putctrlc returns non-zero.
45250Sstevel@tonic-gate  *
45260Sstevel@tonic-gate  * c:     a byte to print in ASCII format
45270Sstevel@tonic-gate  * **buf: a pointer to the pointer to the output buffer.
45280Sstevel@tonic-gate  * *cl:   current length of characters in the output buffer
45290Sstevel@tonic-gate  * max:   maximum length of the buffer
45300Sstevel@tonic-gate  */
45310Sstevel@tonic-gate 
45320Sstevel@tonic-gate static int
putctrlc(int c,char ** buf,size_t * cl,size_t max)45330Sstevel@tonic-gate putctrlc(int c, char **buf, size_t *cl, size_t max)
45340Sstevel@tonic-gate {
45350Sstevel@tonic-gate 	char	*p = *buf;
45360Sstevel@tonic-gate 
45370Sstevel@tonic-gate 	if (c == '\n') {
45380Sstevel@tonic-gate 		if (*cl + 2 < max) {
45390Sstevel@tonic-gate 			*p++ = '\\';
45400Sstevel@tonic-gate 			*p++ = 'n';
45410Sstevel@tonic-gate 			*cl += 2;
45420Sstevel@tonic-gate 			*buf = p;
45430Sstevel@tonic-gate 			return (2);
45440Sstevel@tonic-gate 		} else {
45450Sstevel@tonic-gate 			return (0);
45460Sstevel@tonic-gate 		}
45470Sstevel@tonic-gate 	} else if (c < 0200) {
45480Sstevel@tonic-gate 		/* ascii control character */
45490Sstevel@tonic-gate 		if (*cl + 2 < max) {
45500Sstevel@tonic-gate 			*p++ = '^';
45510Sstevel@tonic-gate 			*p++ = c ^ 0100;
45520Sstevel@tonic-gate 			*cl += 2;
45530Sstevel@tonic-gate 			*buf = p;
45540Sstevel@tonic-gate 			return (2);
45550Sstevel@tonic-gate 		} else {
45560Sstevel@tonic-gate 			return (0);
45570Sstevel@tonic-gate 		}
45580Sstevel@tonic-gate 	} else {
45590Sstevel@tonic-gate 		if (*cl + 4 < max) {
45600Sstevel@tonic-gate 			*p++ = '\\';
45610Sstevel@tonic-gate 			*p++ = ((c >> 6) & 07) + '0';
45620Sstevel@tonic-gate 			*p++ = ((c >> 3) & 07) + '0';
45630Sstevel@tonic-gate 			*p++ = (c & 07) + '0';
45640Sstevel@tonic-gate 			*cl += 4;
45650Sstevel@tonic-gate 			*buf = p;
45660Sstevel@tonic-gate 			return (4);
45670Sstevel@tonic-gate 		} else {
45680Sstevel@tonic-gate 			return (0);
45690Sstevel@tonic-gate 		}
45700Sstevel@tonic-gate 	}
45710Sstevel@tonic-gate }
45720Sstevel@tonic-gate 
45730Sstevel@tonic-gate /*
45740Sstevel@tonic-gate  * findnl_bkwd:
45750Sstevel@tonic-gate  *	Scans each character in buf until it finds the last newline in buf,
45760Sstevel@tonic-gate  *	or the scanned character becomes the last COMPLETE character in buf.
45770Sstevel@tonic-gate  *	Returns the number of scanned bytes.
45780Sstevel@tonic-gate  *
45790Sstevel@tonic-gate  *	buf - pointer to a buffer containing the message string
45800Sstevel@tonic-gate  *	len - the length of the buffer
45810Sstevel@tonic-gate  */
45820Sstevel@tonic-gate size_t
findnl_bkwd(const char * buf,const size_t len)45830Sstevel@tonic-gate findnl_bkwd(const char *buf, const size_t len)
45840Sstevel@tonic-gate {
45850Sstevel@tonic-gate 	const char *p;
45860Sstevel@tonic-gate 	size_t	mb_cur_max;
45870Sstevel@tonic-gate 	pthread_t mythreadno;
45880Sstevel@tonic-gate 
45890Sstevel@tonic-gate 	if (Debug) {
45900Sstevel@tonic-gate 		mythreadno = pthread_self();
45910Sstevel@tonic-gate 	}
45920Sstevel@tonic-gate 
45930Sstevel@tonic-gate 	if (len == 0) {
45940Sstevel@tonic-gate 		return (0);
45950Sstevel@tonic-gate 	}
45960Sstevel@tonic-gate 
45970Sstevel@tonic-gate 	mb_cur_max = MB_CUR_MAX;
45980Sstevel@tonic-gate 
45990Sstevel@tonic-gate 	if (mb_cur_max == 1) {
46000Sstevel@tonic-gate 		/* single-byte locale */
46010Sstevel@tonic-gate 		for (p = buf + len - 1; p != buf; p--) {
46020Sstevel@tonic-gate 			if (*p == '\n') {
46030Sstevel@tonic-gate 				return ((size_t)(p - buf));
46040Sstevel@tonic-gate 			}
46050Sstevel@tonic-gate 		}
46060Sstevel@tonic-gate 		return ((size_t)len);
46070Sstevel@tonic-gate 	} else {
46080Sstevel@tonic-gate 		/* multi-byte locale */
46090Sstevel@tonic-gate 		int mlen;
46100Sstevel@tonic-gate 		const char *nl;
46110Sstevel@tonic-gate 		size_t	rem;
46120Sstevel@tonic-gate 
46130Sstevel@tonic-gate 		p = buf;
46140Sstevel@tonic-gate 		nl = NULL;
46150Sstevel@tonic-gate 		for (rem = len; rem >= mb_cur_max; ) {
46160Sstevel@tonic-gate 			mlen = mblen(p, mb_cur_max);
46170Sstevel@tonic-gate 			if (mlen == -1) {
46180Sstevel@tonic-gate 				/*
46190Sstevel@tonic-gate 				 * Invalid character found.
46200Sstevel@tonic-gate 				 */
46210Sstevel@tonic-gate 				DPRINT1(9, "findnl_bkwd(%u): Invalid MB "
46226358Snakanon 				    "sequence\n", mythreadno);
46230Sstevel@tonic-gate 				/*
46240Sstevel@tonic-gate 				 * handle as a single byte character.
46250Sstevel@tonic-gate 				 */
46260Sstevel@tonic-gate 				p++;
46270Sstevel@tonic-gate 				rem--;
46280Sstevel@tonic-gate 			} else {
46290Sstevel@tonic-gate 				/*
46300Sstevel@tonic-gate 				 * It's guaranteed that *p points to
46310Sstevel@tonic-gate 				 * the 1st byte of a multibyte character.
46320Sstevel@tonic-gate 				 */
46330Sstevel@tonic-gate 				if (*p == '\n') {
46340Sstevel@tonic-gate 					nl = p;
46350Sstevel@tonic-gate 				}
46360Sstevel@tonic-gate 				p += mlen;
46370Sstevel@tonic-gate 				rem -= mlen;
46380Sstevel@tonic-gate 			}
46390Sstevel@tonic-gate 		}
46400Sstevel@tonic-gate 		if (nl) {
46410Sstevel@tonic-gate 			return ((size_t)(nl - buf));
46420Sstevel@tonic-gate 		}
46430Sstevel@tonic-gate 		/*
46440Sstevel@tonic-gate 		 * no newline nor null byte found.
46450Sstevel@tonic-gate 		 * Also it's guaranteed that *p points to
46460Sstevel@tonic-gate 		 * the 1st byte of a (multibyte) character
46470Sstevel@tonic-gate 		 * at this point.
46480Sstevel@tonic-gate 		 */
46490Sstevel@tonic-gate 		return (len - rem);
46500Sstevel@tonic-gate 	}
46510Sstevel@tonic-gate }
46520Sstevel@tonic-gate 
46530Sstevel@tonic-gate /*
46540Sstevel@tonic-gate  * copynl_frwd:
46550Sstevel@tonic-gate  *	Scans each character in buf and copies the scanned character to obuf
46560Sstevel@tonic-gate  *	until it finds a null byte or a newline, or
46570Sstevel@tonic-gate  *	the number of the remaining bytes in obuf gets to exceed obuflen
46580Sstevel@tonic-gate  *	if copying the scanned character to obuf.
46590Sstevel@tonic-gate  *	Returns the number of scanned bytes.
46600Sstevel@tonic-gate  *
46610Sstevel@tonic-gate  *	obuf - buffer to be copied the scanned character
46620Sstevel@tonic-gate  *	obuflen - the size of obuf
46630Sstevel@tonic-gate  *	buf - pointer to a buffer containing the message string
46640Sstevel@tonic-gate  *	len - the length of the buffer
46650Sstevel@tonic-gate  */
46660Sstevel@tonic-gate size_t
copynl_frwd(char * obuf,const size_t obuflen,const char * buf,const size_t len)46670Sstevel@tonic-gate copynl_frwd(char *obuf, const size_t obuflen,
46680Sstevel@tonic-gate 	    const char *buf, const size_t len)
46690Sstevel@tonic-gate {
46700Sstevel@tonic-gate 	const char *p;
46710Sstevel@tonic-gate 	char	*q = obuf;
46720Sstevel@tonic-gate 	size_t	olen = 0;
46730Sstevel@tonic-gate 	size_t	mb_cur_max;
46740Sstevel@tonic-gate 	pthread_t mythreadno;
46750Sstevel@tonic-gate 
46760Sstevel@tonic-gate 	if (Debug) {
46770Sstevel@tonic-gate 		mythreadno = pthread_self();
46780Sstevel@tonic-gate 	}
46790Sstevel@tonic-gate 
46800Sstevel@tonic-gate 	if (len == 0) {
46810Sstevel@tonic-gate 		return (0);
46820Sstevel@tonic-gate 	}
46830Sstevel@tonic-gate 
46840Sstevel@tonic-gate 	mb_cur_max = MB_CUR_MAX;
46850Sstevel@tonic-gate 
46860Sstevel@tonic-gate 	if (mb_cur_max == 1) {
46870Sstevel@tonic-gate 		/* single-byte locale */
46880Sstevel@tonic-gate 		for (p = buf; *p; ) {
46890Sstevel@tonic-gate 			if (obuflen > olen + 1) {
46900Sstevel@tonic-gate 				if (*p != '\n') {
46910Sstevel@tonic-gate 					*q++ = *p++;
46920Sstevel@tonic-gate 					olen++;
46930Sstevel@tonic-gate 				} else {
46940Sstevel@tonic-gate 					*q = '\0';
46950Sstevel@tonic-gate 					return ((size_t)(p - buf));
46960Sstevel@tonic-gate 				}
46970Sstevel@tonic-gate 			} else {
46980Sstevel@tonic-gate 				*q = '\0';
46990Sstevel@tonic-gate 				return ((size_t)(p - buf));
47000Sstevel@tonic-gate 			}
47010Sstevel@tonic-gate 		}
47020Sstevel@tonic-gate 		*q = '\0';
47030Sstevel@tonic-gate 		return ((size_t)(p - buf));
47040Sstevel@tonic-gate 	} else {
47050Sstevel@tonic-gate 		/* multi-byte locale */
47060Sstevel@tonic-gate 		int mlen;
47070Sstevel@tonic-gate 
47080Sstevel@tonic-gate 		for (p = buf; *p; ) {
47090Sstevel@tonic-gate 			mlen = mblen(p, mb_cur_max);
47100Sstevel@tonic-gate 			if (mlen == -1) {
47110Sstevel@tonic-gate 				/*
47120Sstevel@tonic-gate 				 * Invalid character found.
47130Sstevel@tonic-gate 				 */
47140Sstevel@tonic-gate 				DPRINT1(9, "copynl_frwd(%u): Invalid MB "
47156358Snakanon 				    "sequence\n", mythreadno);
47160Sstevel@tonic-gate 				/*
47170Sstevel@tonic-gate 				 * handle as a single byte character.
47180Sstevel@tonic-gate 				 */
47190Sstevel@tonic-gate 				if (obuflen > olen + 1) {
47200Sstevel@tonic-gate 					*q++ = *p++;
47210Sstevel@tonic-gate 					olen++;
47220Sstevel@tonic-gate 				} else {
47230Sstevel@tonic-gate 					*q = '\0';
47240Sstevel@tonic-gate 					return ((size_t)(p - buf));
47250Sstevel@tonic-gate 				}
47260Sstevel@tonic-gate 			} else {
47270Sstevel@tonic-gate 				/*
47280Sstevel@tonic-gate 				 * It's guaranteed that *p points to
47290Sstevel@tonic-gate 				 * the 1st byte of a multibyte character.
47300Sstevel@tonic-gate 				 */
47310Sstevel@tonic-gate 				if (*p == '\n') {
47320Sstevel@tonic-gate 					*q = '\0';
47330Sstevel@tonic-gate 					return ((size_t)(p - buf));
47340Sstevel@tonic-gate 				}
47350Sstevel@tonic-gate 				if (obuflen > olen + mlen) {
47360Sstevel@tonic-gate 					int	n;
47370Sstevel@tonic-gate 					for (n = 0; n < mlen; n++) {
47380Sstevel@tonic-gate 						*q++ = *p++;
47390Sstevel@tonic-gate 					}
47400Sstevel@tonic-gate 					olen += mlen;
47410Sstevel@tonic-gate 				} else {
47420Sstevel@tonic-gate 					*q = '\0';
47430Sstevel@tonic-gate 					return ((size_t)(p - buf));
47440Sstevel@tonic-gate 				}
47450Sstevel@tonic-gate 			}
47460Sstevel@tonic-gate 		}
47470Sstevel@tonic-gate 		/*
47480Sstevel@tonic-gate 		 * no newline nor null byte found.
47490Sstevel@tonic-gate 		 * Also it's guaranteed that *p points to
47500Sstevel@tonic-gate 		 * the 1st byte of a (multibyte) character
47510Sstevel@tonic-gate 		 * at this point.
47520Sstevel@tonic-gate 		 */
47530Sstevel@tonic-gate 		*q = '\0';
47540Sstevel@tonic-gate 		return ((size_t)(p - buf));
47550Sstevel@tonic-gate 	}
47560Sstevel@tonic-gate }
47570Sstevel@tonic-gate 
47580Sstevel@tonic-gate /*
47590Sstevel@tonic-gate  * copy_frwd:
47600Sstevel@tonic-gate  *	Scans each character in buf and copies the scanned character to obuf
47610Sstevel@tonic-gate  *	until the number of the remaining bytes in obuf gets to exceed obuflen
47620Sstevel@tonic-gate  *	if copying the scanned character to obuf.
47630Sstevel@tonic-gate  *	Returns the number of scanned (copied) bytes.
47640Sstevel@tonic-gate  *
47650Sstevel@tonic-gate  *	obuf - buffer to be copied the scanned character
47660Sstevel@tonic-gate  *	obuflen - the size of obuf
47670Sstevel@tonic-gate  *	buf - pointer to a buffer containing the message string
47680Sstevel@tonic-gate  *	len - the length of the buffer
47690Sstevel@tonic-gate  */
47700Sstevel@tonic-gate size_t
copy_frwd(char * obuf,const size_t obuflen,const char * buf,const size_t len)47710Sstevel@tonic-gate copy_frwd(char *obuf, const size_t obuflen,
47720Sstevel@tonic-gate 	const char *buf, const size_t len)
47730Sstevel@tonic-gate {
47740Sstevel@tonic-gate 	const char *p;
47750Sstevel@tonic-gate 	char	*q = obuf;
47760Sstevel@tonic-gate 	size_t	olen = 0;
47770Sstevel@tonic-gate 	size_t	mb_cur_max;
47780Sstevel@tonic-gate 	pthread_t mythreadno;
47790Sstevel@tonic-gate 
47800Sstevel@tonic-gate 	if (Debug) {
47810Sstevel@tonic-gate 		mythreadno = pthread_self();
47820Sstevel@tonic-gate 	}
47830Sstevel@tonic-gate 
47840Sstevel@tonic-gate 	if (len == 0) {
47850Sstevel@tonic-gate 		return (0);
47860Sstevel@tonic-gate 	}
47870Sstevel@tonic-gate 
47880Sstevel@tonic-gate 	mb_cur_max = MB_CUR_MAX;
47890Sstevel@tonic-gate 
47900Sstevel@tonic-gate 	if (mb_cur_max == 1) {
47910Sstevel@tonic-gate 		/* single-byte locale */
47920Sstevel@tonic-gate 		if (obuflen > len) {
47930Sstevel@tonic-gate 			(void) memcpy(obuf, buf, len);
47940Sstevel@tonic-gate 			obuf[len] = '\0';
47950Sstevel@tonic-gate 			return ((size_t)len);
47960Sstevel@tonic-gate 		} else {
47970Sstevel@tonic-gate 			(void) memcpy(obuf, buf, obuflen - 1);
47980Sstevel@tonic-gate 			obuf[obuflen - 1] = '\0';
47990Sstevel@tonic-gate 			return (obuflen - 1);
48000Sstevel@tonic-gate 		}
48010Sstevel@tonic-gate 	} else {
48020Sstevel@tonic-gate 		/* multi-byte locale */
48030Sstevel@tonic-gate 		int mlen;
48040Sstevel@tonic-gate 
48050Sstevel@tonic-gate 		for (p = buf; *p; ) {
48060Sstevel@tonic-gate 			mlen = mblen(p, mb_cur_max);
48070Sstevel@tonic-gate 			if (mlen == -1) {
48080Sstevel@tonic-gate 				/*
48090Sstevel@tonic-gate 				 * Invalid character found.
48100Sstevel@tonic-gate 				 */
48110Sstevel@tonic-gate 				DPRINT1(9, "copy_frwd(%u): Invalid MB "
48126358Snakanon 				    "sequence\n", mythreadno);
48130Sstevel@tonic-gate 				/*
48140Sstevel@tonic-gate 				 * handle as a single byte character.
48150Sstevel@tonic-gate 				 */
48160Sstevel@tonic-gate 				if (obuflen > olen + 1) {
48170Sstevel@tonic-gate 					*q++ = *p++;
48180Sstevel@tonic-gate 					olen++;
48190Sstevel@tonic-gate 				} else {
48200Sstevel@tonic-gate 					*q = '\0';
48210Sstevel@tonic-gate 					return ((size_t)(p - buf));
48220Sstevel@tonic-gate 				}
48230Sstevel@tonic-gate 			} else {
48240Sstevel@tonic-gate 				if (obuflen > olen + mlen) {
48250Sstevel@tonic-gate 					int	n;
48260Sstevel@tonic-gate 					for (n = 0; n < mlen; n++) {
48270Sstevel@tonic-gate 						*q++ = *p++;
48280Sstevel@tonic-gate 					}
48290Sstevel@tonic-gate 					olen += mlen;
48300Sstevel@tonic-gate 				} else {
48310Sstevel@tonic-gate 					*q = '\0';
48320Sstevel@tonic-gate 					return ((size_t)(p - buf));
48330Sstevel@tonic-gate 				}
48340Sstevel@tonic-gate 			}
48350Sstevel@tonic-gate 		}
48360Sstevel@tonic-gate 		*q = '\0';
48370Sstevel@tonic-gate 		return ((size_t)(p - buf));
48380Sstevel@tonic-gate 	}
48390Sstevel@tonic-gate }
48400Sstevel@tonic-gate 
48410Sstevel@tonic-gate /*
48422104Sjjj  * properties:
48432104Sjjj  *	Get properties from SMF framework.
48440Sstevel@tonic-gate  */
48450Sstevel@tonic-gate static void
properties(void)48462104Sjjj properties(void)
48470Sstevel@tonic-gate {
48482104Sjjj 	scf_simple_prop_t *prop;
48492104Sjjj 	uint8_t *bool;
48502104Sjjj 
48512104Sjjj 	if ((prop = scf_simple_prop_get(NULL, NULL, "config",
48522104Sjjj 	    "log_from_remote")) != NULL) {
48532104Sjjj 		if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
48542104Sjjj 			if (*bool == 0)
48552104Sjjj 				turnoff = 1; /* log_from_remote = false */
48562104Sjjj 			else
48572104Sjjj 				turnoff = 0; /* log_from_remote = true */
48580Sstevel@tonic-gate 		}
48592104Sjjj 		scf_simple_prop_free(prop);
48602104Sjjj 		DPRINT1(1, "properties: setting turnoff to %s\n",
48612104Sjjj 		    turnoff ? "true" : "false");
48620Sstevel@tonic-gate 	}
48630Sstevel@tonic-gate }
48640Sstevel@tonic-gate 
48650Sstevel@tonic-gate /*
48660Sstevel@tonic-gate  * close all the input devices.
48670Sstevel@tonic-gate  */
48680Sstevel@tonic-gate static void
shutdown_input(void)48690Sstevel@tonic-gate shutdown_input(void)
48700Sstevel@tonic-gate {
48710Sstevel@tonic-gate 	int cnt;
48720Sstevel@tonic-gate 
48730Sstevel@tonic-gate 	shutting_down = 1;
48740Sstevel@tonic-gate 
48750Sstevel@tonic-gate 	for (cnt = 0; cnt < Ninputs; cnt++) {
48760Sstevel@tonic-gate 		(void) t_close(Nfd[cnt].fd);
48770Sstevel@tonic-gate 	}
48780Sstevel@tonic-gate 
48790Sstevel@tonic-gate 	(void) close(Pfd.fd);
48800Sstevel@tonic-gate }
48810Sstevel@tonic-gate 
48820Sstevel@tonic-gate /*
48830Sstevel@tonic-gate  * This is for the one thread that dedicates to resolve the
48840Sstevel@tonic-gate  * hostname. This will get the messages from net_poll() through
48850Sstevel@tonic-gate  * hnlq, and resolve the hostname, and push the messages back
48860Sstevel@tonic-gate  * into the inputq.
48870Sstevel@tonic-gate  */
48880Sstevel@tonic-gate /*ARGSUSED*/
48890Sstevel@tonic-gate static void *
hostname_lookup(void * ap)48900Sstevel@tonic-gate hostname_lookup(void *ap)
48910Sstevel@tonic-gate {
48920Sstevel@tonic-gate 	char *uap;
48930Sstevel@tonic-gate 	log_message_t *mp;
48940Sstevel@tonic-gate 	host_info_t *hip;
48950Sstevel@tonic-gate 	char failsafe_addr[SYS_NMLN + 1];
48960Sstevel@tonic-gate 	pthread_t mythreadno;
48970Sstevel@tonic-gate 
48980Sstevel@tonic-gate 	if (Debug) {
48990Sstevel@tonic-gate 		mythreadno = pthread_self();
49000Sstevel@tonic-gate 	}
49010Sstevel@tonic-gate 
49020Sstevel@tonic-gate 	DPRINT1(1, "hostname_lookup(%u): hostname_lookup started\n",
49036358Snakanon 	    mythreadno);
49040Sstevel@tonic-gate 
49050Sstevel@tonic-gate 	for (;;) {
49060Sstevel@tonic-gate 		(void) dataq_dequeue(&hnlq, (void **)&mp, 0);
49070Sstevel@tonic-gate 
49080Sstevel@tonic-gate 		DPRINT3(5, "hostname_lookup(%u): dequeued msg %p"
49096358Snakanon 		    " from queue %p\n", mythreadno, (void *)mp,
49106358Snakanon 		    (void *)&hnlq);
49110Sstevel@tonic-gate 
49120Sstevel@tonic-gate 		hip = (host_info_t *)mp->ptr;
49130Sstevel@tonic-gate 		if ((uap = taddr2uaddr(hip->ncp, &hip->addr)) != NULL) {
49140Sstevel@tonic-gate 			(void) strlcpy(failsafe_addr, uap, SYS_NMLN);
49150Sstevel@tonic-gate 			free(uap);
49160Sstevel@tonic-gate 		} else {
49170Sstevel@tonic-gate 			(void) strlcpy(failsafe_addr, "<unknown>", SYS_NMLN);
49180Sstevel@tonic-gate 		}
49190Sstevel@tonic-gate 
49200Sstevel@tonic-gate 		mp->hlp = cvthname(&hip->addr, hip->ncp, failsafe_addr);
49210Sstevel@tonic-gate 
49220Sstevel@tonic-gate 		if (mp->hlp == NULL) {
49230Sstevel@tonic-gate 			mp->hlp = &NullHostName;
49240Sstevel@tonic-gate 		}
49250Sstevel@tonic-gate 
49260Sstevel@tonic-gate 		free(hip->addr.buf);
49270Sstevel@tonic-gate 		free(hip);
49280Sstevel@tonic-gate 		mp->ptr = NULL;
49290Sstevel@tonic-gate 
49300Sstevel@tonic-gate 		if (dataq_enqueue(&inputq, (void *)mp) == -1) {
49310Sstevel@tonic-gate 			MALLOC_FAIL("dropping message from remote");
49320Sstevel@tonic-gate 			free_msg(mp);
49330Sstevel@tonic-gate 			continue;
49340Sstevel@tonic-gate 		}
49350Sstevel@tonic-gate 
49362104Sjjj 		DPRINT3(5, "hostname_lookup(%u): enqueued msg %p on queue "
49376358Snakanon 		    "%p\n", mythreadno, (void *)mp, (void *)&inputq);
49380Sstevel@tonic-gate 	}
49390Sstevel@tonic-gate 
49400Sstevel@tonic-gate 	/*NOTREACHED*/
49410Sstevel@tonic-gate 	return (NULL);
49420Sstevel@tonic-gate }
49430Sstevel@tonic-gate 
49440Sstevel@tonic-gate /*
49450Sstevel@tonic-gate  * Does all HUP(re-configuration) process.
49460Sstevel@tonic-gate  */
49470Sstevel@tonic-gate static void
reconfigure()49480Sstevel@tonic-gate reconfigure()
49490Sstevel@tonic-gate {
49500Sstevel@tonic-gate 	int cnt, loop, drops;
49510Sstevel@tonic-gate 	int really_stuck;
49520Sstevel@tonic-gate 	int console_stuck = 0;
49530Sstevel@tonic-gate 	struct filed *f;
49540Sstevel@tonic-gate 	char buf[LINE_MAX];
49550Sstevel@tonic-gate 	struct utsname up;
49560Sstevel@tonic-gate 	char cbuf[30];
49570Sstevel@tonic-gate 	time_t tim;
49580Sstevel@tonic-gate 	pthread_t mythreadno;
49590Sstevel@tonic-gate 
49600Sstevel@tonic-gate 	if (Debug) {
49610Sstevel@tonic-gate 		mythreadno = pthread_self();
49620Sstevel@tonic-gate 	}
49630Sstevel@tonic-gate 
49640Sstevel@tonic-gate 	/* If we get here then we must need to regen */
49650Sstevel@tonic-gate 	flushmsg(0);
49660Sstevel@tonic-gate 
49670Sstevel@tonic-gate 	if (logmymsg(LOG_SYSLOG|LOG_INFO, "syslogd: configuration restart",
49686358Snakanon 	    ADDDATE, 0) == -1) {
49690Sstevel@tonic-gate 		MALLOC_FAIL("dropping message");
49700Sstevel@tonic-gate 	}
49710Sstevel@tonic-gate 
49720Sstevel@tonic-gate 	/*
49730Sstevel@tonic-gate 	 * make sure the logmsg thread is not in the waiting state.
49740Sstevel@tonic-gate 	 * Otherwise, changing hup_state will prevent the logmsg thread
49750Sstevel@tonic-gate 	 * getting out from the waiting loop.
49760Sstevel@tonic-gate 	 */
49770Sstevel@tonic-gate 
49780Sstevel@tonic-gate 	if (Debug) {
49790Sstevel@tonic-gate 		tim = time(NULL);
49800Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: awaiting logmsg()"
49816358Snakanon 		    " moving to the safe place\n",
49826358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
49830Sstevel@tonic-gate 	}
49840Sstevel@tonic-gate 
49850Sstevel@tonic-gate 	for (loop = 0; loop < LOOP_MAX; loop++) {
49860Sstevel@tonic-gate 		/* we don't need the mutex to read */
49870Sstevel@tonic-gate 		if (hup_state == HUP_ACCEPTABLE)
49880Sstevel@tonic-gate 			break;
49890Sstevel@tonic-gate 		(void) sleep(1);
49900Sstevel@tonic-gate 	}
49910Sstevel@tonic-gate 	if (hup_state != HUP_ACCEPTABLE) {
49920Sstevel@tonic-gate 		goto thread_stuck;
49930Sstevel@tonic-gate 	}
49940Sstevel@tonic-gate 
49950Sstevel@tonic-gate 	if (Debug) {
49960Sstevel@tonic-gate 		tim = time(NULL);
49970Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: logmsg() will accept HUP\n",
49986358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
49990Sstevel@tonic-gate 	}
50000Sstevel@tonic-gate 
50010Sstevel@tonic-gate 	/*
50020Sstevel@tonic-gate 	 * Prevent logging until we are truly done processing the HUP
50030Sstevel@tonic-gate 	 */
50040Sstevel@tonic-gate 	(void) pthread_mutex_lock(&hup_lock);
50050Sstevel@tonic-gate 	hup_state = HUP_INPROGRESS;
50060Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&hup_lock);
50070Sstevel@tonic-gate 
50080Sstevel@tonic-gate 	/*
50090Sstevel@tonic-gate 	 * We will be going into a critical state. Any error message
50100Sstevel@tonic-gate 	 * from syslogd needs to be dumped to the console by default
50110Sstevel@tonic-gate 	 * immediately. Also, those error messages are quened in a temporary
50120Sstevel@tonic-gate 	 * queue to be able to post into the regular stream later.
50130Sstevel@tonic-gate 	 */
50140Sstevel@tonic-gate 	disable_errorlog();
50150Sstevel@tonic-gate 
50160Sstevel@tonic-gate 	if (Debug) {
50170Sstevel@tonic-gate 		tim = time(NULL);
50180Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: sending SHUTDOWN\n",
50196358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
50200Sstevel@tonic-gate 	}
50210Sstevel@tonic-gate 
50220Sstevel@tonic-gate 	/* stop configured threads */
50230Sstevel@tonic-gate 	if (shutdown_msg() == -1) {
50240Sstevel@tonic-gate 		/*
50250Sstevel@tonic-gate 		 * No memory, message will be dumped to the console.
50260Sstevel@tonic-gate 		 */
50270Sstevel@tonic-gate 		MALLOC_FAIL("unable to restart syslogd");
50280Sstevel@tonic-gate 		goto out;
50290Sstevel@tonic-gate 	}
50300Sstevel@tonic-gate 
50310Sstevel@tonic-gate 	/* make sure logmsg() is in suspended state */
50320Sstevel@tonic-gate 	for (loop = 0; loop < LOOP_INTERVAL; loop++) {
50330Sstevel@tonic-gate 		if (hup_state & HUP_LOGMSG_SUSPENDED)
50340Sstevel@tonic-gate 			break;
50350Sstevel@tonic-gate 		(void) sleep(1);
50360Sstevel@tonic-gate 	}
50370Sstevel@tonic-gate 
50380Sstevel@tonic-gate 	if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
50390Sstevel@tonic-gate 		if (Debug) {
50400Sstevel@tonic-gate 			tim = time(NULL);
50410Sstevel@tonic-gate 			DPRINT2(3, "reconfigure(%u): %.15s: logmsg() does not "
50426358Snakanon 			    "stop. enforcing\n",
50436358Snakanon 			    mythreadno, ctime_r(&tim, cbuf)+4);
50440Sstevel@tonic-gate 		}
50450Sstevel@tonic-gate 
50460Sstevel@tonic-gate 		/* probably we have too long input queue, or really stuck */
50470Sstevel@tonic-gate 		(void) pthread_mutex_lock(&hup_lock);
50480Sstevel@tonic-gate 		hup_state |= HUP_SUSP_LOGMSG_REQD;
50490Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&hup_lock);
50500Sstevel@tonic-gate 
50510Sstevel@tonic-gate 		for (loop = 0; loop < LOOP_MAX; loop++) {
50520Sstevel@tonic-gate 			if (hup_state & HUP_LOGMSG_SUSPENDED)
50530Sstevel@tonic-gate 				break;
50540Sstevel@tonic-gate 			(void) sleep(1);
50550Sstevel@tonic-gate 		}
50560Sstevel@tonic-gate 		if ((hup_state & HUP_LOGMSG_SUSPENDED) == 0) {
50570Sstevel@tonic-gate 			if (Debug) {
50580Sstevel@tonic-gate 				tim = time(NULL);
50590Sstevel@tonic-gate 				DPRINT2(3, "reconfigure(%u): %.15s: logmsg()"
50606358Snakanon 				    " does not stop. give up\n",
50616358Snakanon 				    mythreadno, ctime_r(&tim, cbuf)+4);
50620Sstevel@tonic-gate 			}
50630Sstevel@tonic-gate 			logerror("could not suspend logmsg - fatal");
50640Sstevel@tonic-gate 			goto thread_stuck;
50650Sstevel@tonic-gate 		}
50660Sstevel@tonic-gate 	}
50670Sstevel@tonic-gate 
50680Sstevel@tonic-gate 	if (Debug) {
50690Sstevel@tonic-gate 		tim = time(NULL);
50700Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: logmsg() suspended\n",
50716358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
50720Sstevel@tonic-gate 	}
50730Sstevel@tonic-gate 
50740Sstevel@tonic-gate 	/*
50750Sstevel@tonic-gate 	 * Will wait for LOOP_MAX secs with watching queue lengths for the
50760Sstevel@tonic-gate 	 * each logger threads. If they have backlogs, and no change in the
50770Sstevel@tonic-gate 	 * length of queue found in 30 seconds, those will be counted as
50780Sstevel@tonic-gate 	 * "really stuck".
50790Sstevel@tonic-gate 	 * If all running logger threads become "really stuck" state, there
50800Sstevel@tonic-gate 	 * should be no worth waiting for them to quit.
50810Sstevel@tonic-gate 	 * In that case, we will go ahead and close out file descriptors to
50820Sstevel@tonic-gate 	 * have them pull out from hanging system call, and give them a last
50830Sstevel@tonic-gate 	 * chance(LOOP_INTERVAL sec) to quit.
50840Sstevel@tonic-gate 	 */
50850Sstevel@tonic-gate 
50860Sstevel@tonic-gate 	if (Debug) {
50870Sstevel@tonic-gate 		tim = time(NULL);
50880Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: awaiting logit() to be"
50896358Snakanon 		    " shutdown\n", mythreadno, ctime_r(&tim, cbuf)+4);
50900Sstevel@tonic-gate 	}
50910Sstevel@tonic-gate 
50920Sstevel@tonic-gate 	cnt = 0;
50930Sstevel@tonic-gate 	really_stuck = 0;
50940Sstevel@tonic-gate 	while (cnt < (LOOP_MAX/LOOP_INTERVAL) &&
50956358Snakanon 	    conf_threads > really_stuck) {
50960Sstevel@tonic-gate 
50970Sstevel@tonic-gate 		/* save initial queue count */
50980Sstevel@tonic-gate 		for (f = Files; f < &Files[nlogs]; f++) {
50990Sstevel@tonic-gate 			f->f_prev_queue_count = (f->f_type == F_UNUSED) ?
51006358Snakanon 			    -1 : f->f_queue_count;
51010Sstevel@tonic-gate 		}
51020Sstevel@tonic-gate 
51030Sstevel@tonic-gate 		for (loop = 0; loop < LOOP_INTERVAL; loop++) {
51040Sstevel@tonic-gate 			if (conf_threads == 0)
51050Sstevel@tonic-gate 				break;
51060Sstevel@tonic-gate 			(void) sleep(1);
51070Sstevel@tonic-gate 		}
51080Sstevel@tonic-gate 
51090Sstevel@tonic-gate 		if (conf_threads == 0)
51100Sstevel@tonic-gate 			break;
51110Sstevel@tonic-gate 
51120Sstevel@tonic-gate 		if (Debug) {
51130Sstevel@tonic-gate 			tim = time(NULL);
51140Sstevel@tonic-gate 			DPRINT3(3, "reconfigure(%u): %.15s: "
51156358Snakanon 			    "%d threads are still alive.\n",
51166358Snakanon 			    mythreadno, ctime_r(&tim, cbuf)+4,
51176358Snakanon 			    conf_threads);
51180Sstevel@tonic-gate 		}
51190Sstevel@tonic-gate 
51200Sstevel@tonic-gate 		really_stuck = 0;
51210Sstevel@tonic-gate 		for (f = Files; f < &Files[nlogs]; f++) {
51220Sstevel@tonic-gate 			if (f->f_type == F_UNUSED) {
51230Sstevel@tonic-gate 				f->f_prev_queue_count = -1;
51240Sstevel@tonic-gate 				continue;
51250Sstevel@tonic-gate 			}
51260Sstevel@tonic-gate 			if (f->f_prev_queue_count == f->f_queue_count) {
51270Sstevel@tonic-gate 				really_stuck++;
51280Sstevel@tonic-gate 				f->f_prev_queue_count = 1;
51290Sstevel@tonic-gate 				DPRINT2(3, "reconfigure(%u): "
51306358Snakanon 				    "tid=%d is really stuck.\n",
51316358Snakanon 				    mythreadno, f->f_thread);
51320Sstevel@tonic-gate 			} else {
51330Sstevel@tonic-gate 				f->f_prev_queue_count = 0;
51340Sstevel@tonic-gate 				DPRINT2(3, "reconfigure(%u): "
51356358Snakanon 				    "tid=%d is still active.\n",
51366358Snakanon 				    mythreadno, f->f_thread);
51370Sstevel@tonic-gate 			}
51380Sstevel@tonic-gate 		}
51390Sstevel@tonic-gate 		/*
51400Sstevel@tonic-gate 		 * Here we have one of following values in the
51410Sstevel@tonic-gate 		 * f_prev_queue_count:
51420Sstevel@tonic-gate 		 *  0: logger thread is still actively working.
51430Sstevel@tonic-gate 		 *  1: logger thread is really stuck.
51440Sstevel@tonic-gate 		 * -1: logger thread has already died.
51450Sstevel@tonic-gate 		 */
51460Sstevel@tonic-gate 
51470Sstevel@tonic-gate 		cnt++;
51480Sstevel@tonic-gate 	}
51490Sstevel@tonic-gate 
51500Sstevel@tonic-gate 	if (Debug) {
51510Sstevel@tonic-gate 		tim = time(NULL);
51520Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s:"
51536358Snakanon 		    " complete awaiting logit()\n",
51546358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
51550Sstevel@tonic-gate 		DPRINT3(3, "reconfigure(%u): %d threads alive."
51566358Snakanon 		    " %d threads stuck\n",
51576358Snakanon 		    mythreadno, conf_threads, really_stuck);
51580Sstevel@tonic-gate 	}
51590Sstevel@tonic-gate 
51600Sstevel@tonic-gate 	/*
51610Sstevel@tonic-gate 	 * Still running? If so, mark it as UNUSED, and close
51620Sstevel@tonic-gate 	 * the fd so that logger threads can bail out from the loop.
51630Sstevel@tonic-gate 	 */
51640Sstevel@tonic-gate 	drops = 0;
51650Sstevel@tonic-gate 	if (conf_threads) {
51660Sstevel@tonic-gate 		for (f = Files; f < &Files[nlogs]; f++) {
51670Sstevel@tonic-gate 			if (f->f_type == F_CONSOLE &&
51686358Snakanon 			    f->f_prev_queue_count == 1) {
51690Sstevel@tonic-gate 				/* console is really stuck */
51700Sstevel@tonic-gate 				console_stuck = 1;
51710Sstevel@tonic-gate 			}
51720Sstevel@tonic-gate 			if (f->f_type == F_USERS || f->f_type == F_WALL ||
51736358Snakanon 			    f->f_type == F_UNUSED)
51740Sstevel@tonic-gate 				continue;
51750Sstevel@tonic-gate 			cnt = f->f_queue_count;
51760Sstevel@tonic-gate 			drops += (cnt > 0) ? cnt - 1: 0;
51770Sstevel@tonic-gate 			f->f_type = F_UNUSED;
51780Sstevel@tonic-gate 
51790Sstevel@tonic-gate 			if (f->f_orig_type == F_FORW)
51802104Sjjj 				(void) t_close(f->f_file);
51810Sstevel@tonic-gate 			else
51822104Sjjj 				(void) close(f->f_file);
51830Sstevel@tonic-gate 		}
51840Sstevel@tonic-gate 
51850Sstevel@tonic-gate 		if (Debug) {
51860Sstevel@tonic-gate 			tim = time(NULL);
51870Sstevel@tonic-gate 			DPRINT1(3, "reconfigure(%u): terminating logit()\n",
51886358Snakanon 			    mythreadno);
51890Sstevel@tonic-gate 		}
51900Sstevel@tonic-gate 
51910Sstevel@tonic-gate 		/* last chance to exit */
51920Sstevel@tonic-gate 		for (loop = 0; loop < LOOP_MAX; loop++) {
51930Sstevel@tonic-gate 			if (conf_threads == 0)
51940Sstevel@tonic-gate 				break;
51950Sstevel@tonic-gate 			(void) sleep(1);
51960Sstevel@tonic-gate 		}
51970Sstevel@tonic-gate 
51980Sstevel@tonic-gate 		if (Debug) {
51990Sstevel@tonic-gate 			tim = time(NULL);
52000Sstevel@tonic-gate 			DPRINT3(3, "reconfigure(%u): %.15s: %d alive\n",
52016358Snakanon 			    mythreadno, ctime_r(&tim, cbuf)+4,
52026358Snakanon 			    conf_threads);
52030Sstevel@tonic-gate 		}
52040Sstevel@tonic-gate 	}
52050Sstevel@tonic-gate 
52060Sstevel@tonic-gate 	if (conf_threads == 0 && drops) {
52070Sstevel@tonic-gate 		errno = 0;
52080Sstevel@tonic-gate 		logerror("Could not completely output pending messages"
52096358Snakanon 		    " while preparing re-configuration");
52100Sstevel@tonic-gate 		logerror("discarded %d messages and restart configuration.",
52116358Snakanon 		    drops);
52120Sstevel@tonic-gate 		if (Debug) {
52130Sstevel@tonic-gate 			tim = time(NULL);
52140Sstevel@tonic-gate 			DPRINT3(3, "reconfigure(%u): %.15s: "
52156358Snakanon 			    "discarded %d messages\n",
52166358Snakanon 			    mythreadno, ctime_r(&tim, cbuf)+4, drops);
52170Sstevel@tonic-gate 		}
52180Sstevel@tonic-gate 	}
52190Sstevel@tonic-gate 
52200Sstevel@tonic-gate 	/*
52210Sstevel@tonic-gate 	 * If all threads still haven't exited
52220Sstevel@tonic-gate 	 * something is stuck or hosed. We just
52230Sstevel@tonic-gate 	 * have no option but to exit.
52240Sstevel@tonic-gate 	 */
52250Sstevel@tonic-gate 	if (conf_threads) {
52260Sstevel@tonic-gate thread_stuck:
52270Sstevel@tonic-gate 		if (Debug) {
52280Sstevel@tonic-gate 			tim = time(NULL);
52290Sstevel@tonic-gate 			DPRINT2(3, "reconfigure(%u): %.15s: really stuck\n",
52306358Snakanon 			    mythreadno, ctime_r(&tim, cbuf)+4);
52310Sstevel@tonic-gate 		}
52320Sstevel@tonic-gate 
52330Sstevel@tonic-gate 		shutdown_input();
52340Sstevel@tonic-gate 		delete_doorfiles();
52352104Sjjj 		(void) uname(&up);
52362104Sjjj 
52372104Sjjj 		(void) snprintf(buf, sizeof (buf),
52386358Snakanon 		    "syslogd(%s): some logger thread(s) "
52396358Snakanon 		    "are stuck%s; syslogd is shutting down.",
52406358Snakanon 		    up.nodename,
52416358Snakanon 		    console_stuck ? " (including the console)" : "");
52420Sstevel@tonic-gate 
52430Sstevel@tonic-gate 		if (console_stuck) {
52440Sstevel@tonic-gate 			FILE *m = popen(MAILCMD, "w");
52450Sstevel@tonic-gate 
52460Sstevel@tonic-gate 			if (m != NULL) {
52472104Sjjj 				(void) fprintf(m, "%s\n", buf);
52482104Sjjj 				(void) pclose(m);
52490Sstevel@tonic-gate 			}
52500Sstevel@tonic-gate 		}
52510Sstevel@tonic-gate 
52520Sstevel@tonic-gate 		disable_errorlog();
52530Sstevel@tonic-gate 		logerror(buf);
52540Sstevel@tonic-gate 		exit(1);
52550Sstevel@tonic-gate 	}
52560Sstevel@tonic-gate 
52570Sstevel@tonic-gate 	/* Free up some resources */
52580Sstevel@tonic-gate 	if (Files != (struct filed *)&fallback) {
52590Sstevel@tonic-gate 		for (f = Files; f < &Files[nlogs]; f++) {
52600Sstevel@tonic-gate 			(void) pthread_join(f->f_thread, NULL);
52610Sstevel@tonic-gate 			filed_destroy(f);
52620Sstevel@tonic-gate 		}
52630Sstevel@tonic-gate 		free(Files);
52640Sstevel@tonic-gate 	}
52650Sstevel@tonic-gate 
52660Sstevel@tonic-gate 	dealloc_stacks(nlogs);
52670Sstevel@tonic-gate 
52680Sstevel@tonic-gate 	if (Debug) {
52690Sstevel@tonic-gate 		tim = time(NULL);
52700Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: cleanup complete\n",
52716358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
52720Sstevel@tonic-gate 	}
52730Sstevel@tonic-gate 
52740Sstevel@tonic-gate 	hnc_init(1);	/* purge hostname cache */
52750Sstevel@tonic-gate 	conf_init();	/* start reconfigure */
52760Sstevel@tonic-gate 
52770Sstevel@tonic-gate out:;
52780Sstevel@tonic-gate 	/* Now should be ready to dispatch error messages from syslogd. */
52790Sstevel@tonic-gate 	enable_errorlog();
52800Sstevel@tonic-gate 
52810Sstevel@tonic-gate 	/* Wake up the log thread */
52820Sstevel@tonic-gate 
52830Sstevel@tonic-gate 	if (Debug) {
52840Sstevel@tonic-gate 		tim = time(NULL);
52850Sstevel@tonic-gate 		DPRINT2(3, "reconfigure(%u): %.15s: resuming logmsg()\n",
52866358Snakanon 		    mythreadno, ctime_r(&tim, cbuf)+4);
52870Sstevel@tonic-gate 	}
52880Sstevel@tonic-gate 
52890Sstevel@tonic-gate 	(void) pthread_mutex_lock(&hup_lock);
52900Sstevel@tonic-gate 	hup_state = HUP_COMPLETED;
52910Sstevel@tonic-gate 	(void) pthread_cond_signal(&hup_done);
52920Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&hup_lock);
52930Sstevel@tonic-gate }
52940Sstevel@tonic-gate 
52950Sstevel@tonic-gate /*
52960Sstevel@tonic-gate  * The following function implements simple hostname cache mechanism.
5297955Spd155743  * Host name cache is implemented through hash table bucket chaining method.
5298955Spd155743  * Collisions are handled by bucket chaining.
52990Sstevel@tonic-gate  *
53000Sstevel@tonic-gate  * hnc_init():
53010Sstevel@tonic-gate  * 	allocate and initialize the cache. If reinit is set,
53020Sstevel@tonic-gate  *	invalidate all cache entries.
53030Sstevel@tonic-gate  * hnc_look():
5304955Spd155743  *	It hashes the ipaddress gets the index and walks thru the
5305955Spd155743  *	single linked list. if cached entry was found, it will
5306955Spd155743  *	put in the head of the list, and return.While going through
53070Sstevel@tonic-gate  *	the entries, an entry which has already expired will be invalidated.
53080Sstevel@tonic-gate  * hnc_register():
5309955Spd155743  *	Hashes the ipaddress finds the index and puts current entry to the list.
53100Sstevel@tonic-gate  * hnc_unreg():
5311955Spd155743  *	invalidate the cachep.
53120Sstevel@tonic-gate  */
53130Sstevel@tonic-gate 
53140Sstevel@tonic-gate static void
hnc_init(int reinit)53150Sstevel@tonic-gate hnc_init(int reinit)
53160Sstevel@tonic-gate {
53170Sstevel@tonic-gate 	struct hostname_cache **hpp;
53180Sstevel@tonic-gate 	pthread_t mythreadno;
5319955Spd155743 	int i;
53200Sstevel@tonic-gate 
53210Sstevel@tonic-gate 	if (Debug) {
53220Sstevel@tonic-gate 		mythreadno = pthread_self();
53230Sstevel@tonic-gate 	}
53240Sstevel@tonic-gate 
53250Sstevel@tonic-gate 	if (reinit) {
53262104Sjjj 		(void) pthread_mutex_lock(&hnc_mutex);
53270Sstevel@tonic-gate 
5328955Spd155743 		for (i = 0; i < hnc_size; i++) {
5329955Spd155743 			for (hpp = &hnc_cache[i]; *hpp != NULL; ) {
5330955Spd155743 				hnc_unreg(hpp);
5331955Spd155743 			}
53320Sstevel@tonic-gate 		}
53330Sstevel@tonic-gate 
53342104Sjjj 		(void) pthread_mutex_unlock(&hnc_mutex);
53350Sstevel@tonic-gate 		DPRINT1(2, "hnc_init(%u): hostname cache re-configured\n",
53366358Snakanon 		    mythreadno);
53370Sstevel@tonic-gate 	} else {
5338955Spd155743 
5339955Spd155743 		hnc_cache = calloc(hnc_size, sizeof (struct hostname_cache *));
53400Sstevel@tonic-gate 
53410Sstevel@tonic-gate 		if (hnc_cache == NULL) {
53420Sstevel@tonic-gate 			MALLOC_FAIL("hostname cache");
53430Sstevel@tonic-gate 			logerror("hostname cache disabled");
53440Sstevel@tonic-gate 			return;
53450Sstevel@tonic-gate 		}
53460Sstevel@tonic-gate 
53470Sstevel@tonic-gate 		DPRINT3(1, "hnc_init(%u): hostname cache configured %d entry"
53486358Snakanon 		    " ttl:%d\n", mythreadno, hnc_size, hnc_ttl);
53490Sstevel@tonic-gate 	}
53500Sstevel@tonic-gate }
53510Sstevel@tonic-gate 
53520Sstevel@tonic-gate static host_list_t *
hnc_lookup(struct netbuf * nbp,struct netconfig * ncp,int * hindex)5353955Spd155743 hnc_lookup(struct netbuf *nbp, struct netconfig *ncp, int *hindex)
53540Sstevel@tonic-gate {
53550Sstevel@tonic-gate 	struct hostname_cache **hpp, *hp;
53560Sstevel@tonic-gate 	time_t now;
53570Sstevel@tonic-gate 	pthread_t mythreadno;
5358955Spd155743 	int index;
53590Sstevel@tonic-gate 
53600Sstevel@tonic-gate 	if (Debug) {
53610Sstevel@tonic-gate 		mythreadno = pthread_self();
53620Sstevel@tonic-gate 	}
53630Sstevel@tonic-gate 
53640Sstevel@tonic-gate 	if (hnc_cache == NULL) {
53650Sstevel@tonic-gate 		return (NULL);
53660Sstevel@tonic-gate 	}
53670Sstevel@tonic-gate 
53682104Sjjj 	(void) pthread_mutex_lock(&hnc_mutex);
53690Sstevel@tonic-gate 	now = time(0);
53700Sstevel@tonic-gate 
5371955Spd155743 	*hindex = index = addr_hash(nbp);
5372955Spd155743 
5373955Spd155743 	for (hpp = &hnc_cache[index]; (hp = *hpp) != NULL; ) {
53740Sstevel@tonic-gate 		DPRINT4(10, "hnc_lookup(%u): check %p on %p for %s\n",
53756358Snakanon 		    mythreadno, (void *)hp->h, (void *)hp,
53766358Snakanon 		    hp->h->hl_hosts[0]);
53770Sstevel@tonic-gate 
53780Sstevel@tonic-gate 		if (hp->expire < now) {
53790Sstevel@tonic-gate 			DPRINT2(9, "hnc_lookup(%u): purge %p\n",
53806358Snakanon 			    mythreadno, (void *)hp);
53810Sstevel@tonic-gate 			hnc_unreg(hpp);
53820Sstevel@tonic-gate 			continue;
53830Sstevel@tonic-gate 		}
53840Sstevel@tonic-gate 
53850Sstevel@tonic-gate 		if (ncp == hp->ncp && same_addr(&hp->addr, nbp)) {
53860Sstevel@tonic-gate 			/*
53870Sstevel@tonic-gate 			 * found!
53880Sstevel@tonic-gate 			 * Put the entry at the top.
53890Sstevel@tonic-gate 			 */
53900Sstevel@tonic-gate 
5391955Spd155743 			if (hp != hnc_cache[index]) {
53920Sstevel@tonic-gate 				/* unlink from active list */
53930Sstevel@tonic-gate 				*hpp = (*hpp)->next;
53940Sstevel@tonic-gate 				/* push it onto the top */
5395955Spd155743 				hp->next = hnc_cache[index];
5396955Spd155743 				hnc_cache[index] = hp;
53970Sstevel@tonic-gate 			}
53980Sstevel@tonic-gate 
53992104Sjjj 			(void) pthread_mutex_lock(&hp->h->hl_mutex);
54000Sstevel@tonic-gate 			hp->h->hl_refcnt++;
54012104Sjjj 			(void) pthread_mutex_unlock(&hp->h->hl_mutex);
54020Sstevel@tonic-gate 
54030Sstevel@tonic-gate 			DPRINT4(9, "hnc_lookup(%u): found %p on %p for %s\n",
54046358Snakanon 			    mythreadno, (void *)hp->h, (void *)hp,
54056358Snakanon 			    hp->h->hl_hosts[0]);
54062104Sjjj 
54072104Sjjj 			(void) pthread_mutex_unlock(&hnc_mutex);
54080Sstevel@tonic-gate 			return (hp->h);
54090Sstevel@tonic-gate 		}
54100Sstevel@tonic-gate 
54110Sstevel@tonic-gate 		hpp = &hp->next;
54120Sstevel@tonic-gate 	}
54130Sstevel@tonic-gate 
54142104Sjjj 	(void) pthread_mutex_unlock(&hnc_mutex);
54150Sstevel@tonic-gate 	return (NULL);
54160Sstevel@tonic-gate }
54170Sstevel@tonic-gate 
54180Sstevel@tonic-gate static void
hnc_register(struct netbuf * nbp,struct netconfig * ncp,host_list_t * h,int hindex)5419955Spd155743 hnc_register(struct netbuf *nbp, struct netconfig *ncp,
5420955Spd155743 		    host_list_t *h, int hindex)
54210Sstevel@tonic-gate {
5422955Spd155743 	struct hostname_cache **hpp, **tailp, *hp, *entry;
54230Sstevel@tonic-gate 	void *addrbuf;
54240Sstevel@tonic-gate 	time_t now;
54250Sstevel@tonic-gate 	pthread_t mythreadno;
5426955Spd155743 	int i;
54270Sstevel@tonic-gate 
54280Sstevel@tonic-gate 	if (Debug) {
54290Sstevel@tonic-gate 		mythreadno = pthread_self();
54300Sstevel@tonic-gate 	}
54310Sstevel@tonic-gate 
54320Sstevel@tonic-gate 	if (hnc_cache == NULL) {
54330Sstevel@tonic-gate 		return;
54340Sstevel@tonic-gate 	}
54350Sstevel@tonic-gate 
54360Sstevel@tonic-gate 	if ((addrbuf = malloc(nbp->len)) == NULL) {
54370Sstevel@tonic-gate 		MALLOC_FAIL("pushing hostname cache");
54380Sstevel@tonic-gate 		return;
54390Sstevel@tonic-gate 	}
54400Sstevel@tonic-gate 
5441955Spd155743 	if ((entry = malloc(sizeof (struct hostname_cache))) == NULL) {
5442955Spd155743 		MALLOC_FAIL("pushing hostname entry");
5443955Spd155743 		free(addrbuf);
5444955Spd155743 		return;
5445955Spd155743 	}
5446955Spd155743 
54472104Sjjj 	(void) pthread_mutex_lock(&hnc_mutex);
54480Sstevel@tonic-gate 
5449955Spd155743 	i = 0;
5450955Spd155743 
5451955Spd155743 	now = time(0);
5452955Spd155743 	/*
5453955Spd155743 	 * first go through active list, and discard the
5454955Spd155743 	 * caches which has been invalid. Count number of
5455955Spd155743 	 * non-expired buckets.
5456955Spd155743 	 */
5457955Spd155743 
5458955Spd155743 	for (hpp = &hnc_cache[hindex]; (hp = *hpp) != NULL; ) {
5459955Spd155743 		tailp = hpp;
5460955Spd155743 
5461955Spd155743 		if (hp->expire < now) {
5462955Spd155743 			DPRINT2(9, "hnc_register(%u): discard %p\n",
54636358Snakanon 			    mythreadno, (void *)hp);
5464955Spd155743 			hnc_unreg(hpp);
5465955Spd155743 		} else {
5466955Spd155743 			i++;
5467955Spd155743 			hpp = &hp->next;
54680Sstevel@tonic-gate 		}
5469955Spd155743 	}
5470955Spd155743 
5471955Spd155743 	/*
5472955Spd155743 	 * If max limit of chained hash buckets has been used up
5473955Spd155743 	 * delete the least active element in the chain.
5474955Spd155743 	 */
5475955Spd155743 	if (i == MAX_BUCKETS) {
5476955Spd155743 		hnc_unreg(tailp);
5477955Spd155743 	}
54780Sstevel@tonic-gate 
54790Sstevel@tonic-gate 	(void) memcpy(addrbuf, nbp->buf, nbp->len);
5480955Spd155743 	entry->addr.len = nbp->len;
5481955Spd155743 	entry->addr.buf = addrbuf;
5482955Spd155743 	entry->ncp = ncp;
5483955Spd155743 	entry->h = h;
5484955Spd155743 	entry->expire = time(NULL) + hnc_ttl;
5485955Spd155743 
5486955Spd155743 	/* insert it at the top */
5487955Spd155743 	entry->next = hnc_cache[hindex];
5488955Spd155743 	hnc_cache[hindex] = entry;
54890Sstevel@tonic-gate 
54900Sstevel@tonic-gate 	/*
54910Sstevel@tonic-gate 	 * As far as cache is valid, corresponding host_list must
54920Sstevel@tonic-gate 	 * also be valid. Increments the refcnt to avoid freeing
54930Sstevel@tonic-gate 	 * host_list.
54940Sstevel@tonic-gate 	 */
54950Sstevel@tonic-gate 	h->hl_refcnt++;
54960Sstevel@tonic-gate 	DPRINT4(9, "hnc_register(%u): reg %p onto %p for %s\n",
5497*8094SVladimir.Marek@Sun.COM 	    mythreadno, (void *)entry->h, (void *)entry, entry->h->hl_hosts[0]);
54982104Sjjj 	(void) pthread_mutex_unlock(&hnc_mutex);
54990Sstevel@tonic-gate }
55000Sstevel@tonic-gate 
55010Sstevel@tonic-gate static void
hnc_unreg(struct hostname_cache ** hpp)55020Sstevel@tonic-gate hnc_unreg(struct hostname_cache **hpp)
55030Sstevel@tonic-gate {
55040Sstevel@tonic-gate 	struct hostname_cache *hp = *hpp;
55050Sstevel@tonic-gate 	pthread_t mythreadno;
55060Sstevel@tonic-gate 
55070Sstevel@tonic-gate 	if (Debug) {
55080Sstevel@tonic-gate 		mythreadno = pthread_self();
55090Sstevel@tonic-gate 	}
55100Sstevel@tonic-gate 
55110Sstevel@tonic-gate 	DPRINT4(9, "hnc_unreg(%u): unreg %p on %p for %s\n",
55126358Snakanon 	    mythreadno, (void *)hp->h, (void *)hp, hp->h->hl_hosts[0]);
55130Sstevel@tonic-gate 	free(hp->addr.buf);
55140Sstevel@tonic-gate 	freehl(hp->h);
55150Sstevel@tonic-gate 
55160Sstevel@tonic-gate 	/* unlink from active list */
55170Sstevel@tonic-gate 	*hpp = (*hpp)->next;
55180Sstevel@tonic-gate 
5519955Spd155743 	free(hp);
55200Sstevel@tonic-gate }
55210Sstevel@tonic-gate 
55220Sstevel@tonic-gate /*
55230Sstevel@tonic-gate  * Once this is called, error messages through logerror() will go to
55240Sstevel@tonic-gate  * the console immediately. Also, messages are queued into the tmpq
55250Sstevel@tonic-gate  * to be able to later put them into inputq.
55260Sstevel@tonic-gate  */
55270Sstevel@tonic-gate static void
disable_errorlog()55280Sstevel@tonic-gate disable_errorlog()
55290Sstevel@tonic-gate {
55302104Sjjj 	(void) dataq_init(&tmpq);
55312104Sjjj 
55322104Sjjj 	(void) pthread_mutex_lock(&logerror_lock);
55330Sstevel@tonic-gate 	interrorlog = 0;
55342104Sjjj 	(void) pthread_mutex_unlock(&logerror_lock);
55350Sstevel@tonic-gate }
55360Sstevel@tonic-gate 
55370Sstevel@tonic-gate /*
55380Sstevel@tonic-gate  * Turn internal error messages to regular input stream.
55390Sstevel@tonic-gate  * All pending messages are pulled and pushed into the regular
55400Sstevel@tonic-gate  * input queue.
55410Sstevel@tonic-gate  */
55420Sstevel@tonic-gate static void
enable_errorlog()55430Sstevel@tonic-gate enable_errorlog()
55440Sstevel@tonic-gate {
55450Sstevel@tonic-gate 	log_message_t *mp;
55460Sstevel@tonic-gate 
55472104Sjjj 	(void) pthread_mutex_lock(&logerror_lock);
55480Sstevel@tonic-gate 	interrorlog = 1;
55492104Sjjj 	(void) pthread_mutex_unlock(&logerror_lock);
55500Sstevel@tonic-gate 
55510Sstevel@tonic-gate 	/*
55520Sstevel@tonic-gate 	 * push all the pending messages into inputq.
55530Sstevel@tonic-gate 	 */
55540Sstevel@tonic-gate 	while (dataq_dequeue(&tmpq, (void **)&mp, 1) == 0) {
55550Sstevel@tonic-gate 		(void) dataq_enqueue(&inputq, mp);
55560Sstevel@tonic-gate 	}
55572104Sjjj 	(void) dataq_destroy(&tmpq);
55580Sstevel@tonic-gate }
5559955Spd155743 
5560955Spd155743 /*
5561955Spd155743  * Generate a hash value of the given address and derive
5562955Spd155743  * an index into the hnc_cache hashtable.
5563955Spd155743  * The hashing method is similar to what Java does for strings.
5564955Spd155743  */
5565955Spd155743 static int
addr_hash(struct netbuf * nbp)5566955Spd155743 addr_hash(struct netbuf *nbp)
5567955Spd155743 {
5568955Spd155743 	char *uap;
5569955Spd155743 	int i;
5570955Spd155743 	unsigned long hcode = 0;
5571955Spd155743 
5572955Spd155743 	uap = nbp->buf;
5573955Spd155743 
5574955Spd155743 	if (uap == NULL) {
5575955Spd155743 		return (0);
5576955Spd155743 	}
5577955Spd155743 
5578955Spd155743 	/*
5579955Spd155743 	 * Compute a hashcode of the address string
5580955Spd155743 	 */
5581955Spd155743 	for (i = 0; i < nbp->len; i++)
5582955Spd155743 		hcode = (31 * hcode) + uap[i];
5583955Spd155743 
5584955Spd155743 	/*
5585955Spd155743 	 * Scramble the hashcode for better distribution
5586955Spd155743 	 */
5587955Spd155743 	hcode += ~(hcode << 9);
5588955Spd155743 	hcode ^=  (hcode >> 14);
5589955Spd155743 	hcode +=  (hcode << 4);
5590955Spd155743 	hcode ^=  (hcode >> 10);
5591955Spd155743 
5592955Spd155743 	return ((int)(hcode % hnc_size));
5593955Spd155743 }
5594