17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
580ab886dSwesolows  * Common Development and Distribution License (the "License").
680ab886dSwesolows  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2180ab886dSwesolows 
227c478bd9Sstevel@tonic-gate /*
235ad1f010SStephen Hanson  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  *	syseventd - The system event daemon
297c478bd9Sstevel@tonic-gate  *
307c478bd9Sstevel@tonic-gate  *		This daemon dispatches event buffers received from the
317c478bd9Sstevel@tonic-gate  *		kernel to all interested SLM clients.  SLMs in turn
327c478bd9Sstevel@tonic-gate  *		deliver the buffers to their particular application
337c478bd9Sstevel@tonic-gate  *		clients.
347c478bd9Sstevel@tonic-gate  */
357c478bd9Sstevel@tonic-gate #include <stdio.h>
367c478bd9Sstevel@tonic-gate #include <sys/types.h>
377c478bd9Sstevel@tonic-gate #include <dirent.h>
387c478bd9Sstevel@tonic-gate #include <stdarg.h>
397c478bd9Sstevel@tonic-gate #include <stddef.h>
407c478bd9Sstevel@tonic-gate #include <stdlib.h>
417c478bd9Sstevel@tonic-gate #include <dlfcn.h>
427c478bd9Sstevel@tonic-gate #include <door.h>
437c478bd9Sstevel@tonic-gate #include <errno.h>
447c478bd9Sstevel@tonic-gate #include <fcntl.h>
457c478bd9Sstevel@tonic-gate #include <signal.h>
467c478bd9Sstevel@tonic-gate #include <strings.h>
477c478bd9Sstevel@tonic-gate #include <unistd.h>
487c478bd9Sstevel@tonic-gate #include <synch.h>
497c478bd9Sstevel@tonic-gate #include <syslog.h>
507c478bd9Sstevel@tonic-gate #include <thread.h>
517c478bd9Sstevel@tonic-gate #include <libsysevent.h>
527c478bd9Sstevel@tonic-gate #include <limits.h>
537c478bd9Sstevel@tonic-gate #include <locale.h>
547c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
557c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
567c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
577c478bd9Sstevel@tonic-gate #include <sys/stat.h>
587c478bd9Sstevel@tonic-gate #include <sys/systeminfo.h>
597c478bd9Sstevel@tonic-gate #include <sys/wait.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #include "sysevent_signal.h"
627c478bd9Sstevel@tonic-gate #include "syseventd.h"
637c478bd9Sstevel@tonic-gate #include "message.h"
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate extern int insert_client(void *client, int client_type, int retry_limit);
667c478bd9Sstevel@tonic-gate extern void delete_client(int id);
677c478bd9Sstevel@tonic-gate extern void initialize_client_tbl(void);
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate extern struct sysevent_client *sysevent_client_tbl[];
707c478bd9Sstevel@tonic-gate extern mutex_t client_tbl_lock;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	DEBUG_LEVEL_FORK	9	/* will run in background at all */
737c478bd9Sstevel@tonic-gate 					/* levels less than DEBUG_LEVEL_FORK */
747c478bd9Sstevel@tonic-gate 
757c478bd9Sstevel@tonic-gate int debug_level = 0;
767c478bd9Sstevel@tonic-gate char *root_dir = "";			/* Relative root for lock and door */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /* Maximum number of outstanding events dispatched */
797c478bd9Sstevel@tonic-gate #define	SE_EVENT_DISPATCH_CNT	100
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate static int upcall_door;			/* Kernel event door */
827c478bd9Sstevel@tonic-gate static int door_upcall_retval;		/* Kernel event posting return value */
837c478bd9Sstevel@tonic-gate static int fini_pending = 0;		/* fini pending flag */
847c478bd9Sstevel@tonic-gate static int deliver_buf = 0;		/* Current event buffer from kernel */
857c478bd9Sstevel@tonic-gate static int dispatch_buf = 0;		/* Current event buffer dispatched */
86c7cb3c8bSToomas Soome static sysevent_t **eventbuf;		/* Global array of event buffers */
877c478bd9Sstevel@tonic-gate static struct ev_completion *event_compq;	/* Event completion queue */
887c478bd9Sstevel@tonic-gate static mutex_t ev_comp_lock;		/* Event completion queue lock */
897c478bd9Sstevel@tonic-gate static mutex_t err_mutex;		/* error logging lock */
907c478bd9Sstevel@tonic-gate static mutex_t door_lock;		/* sync door return access */
917c478bd9Sstevel@tonic-gate static rwlock_t mod_unload_lock;		/* sync module unloading */
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate /* declarations and definitions for avoiding multiple daemons running */
94c6fc6dddSEric Schrock #define	DAEMON_LOCK_FILE "/var/run/syseventd.lock"
957c478bd9Sstevel@tonic-gate char local_lock_file[PATH_MAX + 1];
967c478bd9Sstevel@tonic-gate static int hold_daemon_lock;
977c478bd9Sstevel@tonic-gate static int daemon_lock_fd;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate  * sema_eventbuf - guards against the global buffer eventbuf
1017c478bd9Sstevel@tonic-gate  *	being written to before it has been dispatched to clients
1027c478bd9Sstevel@tonic-gate  *
1037c478bd9Sstevel@tonic-gate  * sema_dispatch - synchronizes between the kernel uploading thread
1047c478bd9Sstevel@tonic-gate  *	(producer) and the userland dispatch_message thread (consumer).
1057c478bd9Sstevel@tonic-gate  *
1067c478bd9Sstevel@tonic-gate  * sema_resource - throttles outstanding event consumption.
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  * event_comp_cv - synchronizes threads waiting for the event completion queue
1097c478bd9Sstevel@tonic-gate  *			to empty or become active.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate static sema_t sema_eventbuf, sema_dispatch, sema_resource;
1127c478bd9Sstevel@tonic-gate static cond_t event_comp_cv;
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /* Self-tuning concurrency level */
1157c478bd9Sstevel@tonic-gate #define	MIN_CONCURRENCY_LEVEL	4
1167c478bd9Sstevel@tonic-gate static int concurrency_level = MIN_CONCURRENCY_LEVEL;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate /* SLM defines */
1207c478bd9Sstevel@tonic-gate #define	MODULE_SUFFIX	".so"
1217c478bd9Sstevel@tonic-gate #define	EVENT_FINI	"slm_fini"
1227c478bd9Sstevel@tonic-gate #define	EVENT_INIT	"slm_init"
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #define	SE_TIMEOUT	60	/* Client dispatch timeout (seconds) */
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /* syslog message related */
1277c478bd9Sstevel@tonic-gate static int logflag = 0;
1287c478bd9Sstevel@tonic-gate static char *prog;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate /* function prototypes */
1317c478bd9Sstevel@tonic-gate static void door_upcall(void *cookie, char *args, size_t alen, door_desc_t *ddp,
1327c478bd9Sstevel@tonic-gate 	uint_t ndid);
1337c478bd9Sstevel@tonic-gate static void dispatch_message(void);
1347c478bd9Sstevel@tonic-gate static int dispatch(void);
1357c478bd9Sstevel@tonic-gate static void event_completion_thr(void);
1367c478bd9Sstevel@tonic-gate static void usage(void);
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate static void syseventd_init(void);
1397c478bd9Sstevel@tonic-gate static void syseventd_fini(int sig);
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static pid_t enter_daemon_lock(void);
1427c478bd9Sstevel@tonic-gate static void exit_daemon_lock(void);
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate static void
usage()145*30699046SRichard Lowe usage()
146*30699046SRichard Lowe {
1477c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "usage: syseventd [-d <debug_level>] "
1487c478bd9Sstevel@tonic-gate 	    "[-r <root_dir>]\n");
1497c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "higher debug levels get progressively ");
1507c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "more detailed debug information.\n");
1517c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "syseventd will run in background if ");
1527c478bd9Sstevel@tonic-gate 	(void) fprintf(stderr, "run with a debug_level less than %d.\n",
1537c478bd9Sstevel@tonic-gate 	    DEBUG_LEVEL_FORK);
1547c478bd9Sstevel@tonic-gate 	exit(2);
1557c478bd9Sstevel@tonic-gate }
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate /* common exit function which ensures releasing locks */
1597c478bd9Sstevel@tonic-gate void
syseventd_exit(int status)1607c478bd9Sstevel@tonic-gate syseventd_exit(int status)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	syseventd_print(1, "exit status = %d\n", status);
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (hold_daemon_lock) {
1657c478bd9Sstevel@tonic-gate 		exit_daemon_lock();
1667c478bd9Sstevel@tonic-gate 	}
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	exit(status);
1697c478bd9Sstevel@tonic-gate }
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * hup_handler - SIGHUP handler.  SIGHUP is used to force a reload of
1747c478bd9Sstevel@tonic-gate  *		 all SLMs.  During fini, events are drained from all
1757c478bd9Sstevel@tonic-gate  *		 client event queues.  The events that have been consumed
1767c478bd9Sstevel@tonic-gate  *		 by all clients are freed from the kernel event queue.
1777c478bd9Sstevel@tonic-gate  *
1787c478bd9Sstevel@tonic-gate  *		 Events that have not yet been delivered to all clients
1797c478bd9Sstevel@tonic-gate  *		 are not freed and will be replayed after all SLMs have
1807c478bd9Sstevel@tonic-gate  *		 been (re)loaded.
1817c478bd9Sstevel@tonic-gate  *
1827c478bd9Sstevel@tonic-gate  *		 After all client event queues have been drained, each
1837c478bd9Sstevel@tonic-gate  *		 SLM client is unloaded.  The init phase will (re)load
1847c478bd9Sstevel@tonic-gate  *		 each SLM and initiate event replay and delivery from
1857c478bd9Sstevel@tonic-gate  *		 the kernel.
1867c478bd9Sstevel@tonic-gate  *
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1897c478bd9Sstevel@tonic-gate static void
hup_handler(int sig)1907c478bd9Sstevel@tonic-gate hup_handler(int sig)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	syseventd_err_print(SIGHUP_CAUGHT);
1937c478bd9Sstevel@tonic-gate 	(void) fflush(0);
1947c478bd9Sstevel@tonic-gate 	syseventd_fini(sig);
1957c478bd9Sstevel@tonic-gate 	syseventd_init();
1967c478bd9Sstevel@tonic-gate 	syseventd_err_print(DAEMON_RESTARTED);
1977c478bd9Sstevel@tonic-gate 	(void) fflush(0);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Fault handler for other signals caught
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2047c478bd9Sstevel@tonic-gate static void
flt_handler(int sig)2057c478bd9Sstevel@tonic-gate flt_handler(int sig)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	char signame[SIG2STR_MAX];
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	if (sig2str(sig, signame) == -1) {
2107c478bd9Sstevel@tonic-gate 		syseventd_err_print(UNKNOWN_SIGNAL_CAUGHT, sig);
2117c478bd9Sstevel@tonic-gate 	}
2127c478bd9Sstevel@tonic-gate 
213*30699046SRichard Lowe 	(void) se_signal_sethandler(sig, SE_SIG_DFL, NULL);
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	switch (sig) {
2167c478bd9Sstevel@tonic-gate 		case SIGINT:
2177c478bd9Sstevel@tonic-gate 		case SIGSTOP:
2187c478bd9Sstevel@tonic-gate 		case SIGTERM:
2197c478bd9Sstevel@tonic-gate 			/* Close kernel door */
2207c478bd9Sstevel@tonic-gate 			(void) door_revoke(upcall_door);
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 			/* Gracefully exit current event delivery threads */
2237c478bd9Sstevel@tonic-gate 			syseventd_fini(sig);
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 			(void) fflush(0);
2267c478bd9Sstevel@tonic-gate 			(void) se_signal_unblockall();
2277c478bd9Sstevel@tonic-gate 			syseventd_exit(1);
2287c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
2295ad1f010SStephen Hanson 		case SIGCLD:
230b0daa853SStephen Hanson 		case SIGPWR:
231b0daa853SStephen Hanson 		case SIGWINCH:
232b0daa853SStephen Hanson 		case SIGURG:
233b0daa853SStephen Hanson 		case SIGCONT:
234b0daa853SStephen Hanson 		case SIGWAITING:
235b0daa853SStephen Hanson 		case SIGLWP:
236b0daa853SStephen Hanson 		case SIGFREEZE:
237b0daa853SStephen Hanson 		case SIGTHAW:
238b0daa853SStephen Hanson 		case SIGCANCEL:
239b0daa853SStephen Hanson 		case SIGXRES:
240b0daa853SStephen Hanson 		case SIGJVM1:
241b0daa853SStephen Hanson 		case SIGJVM2:
24219d32b9aSRobert Mustacchi 		case SIGINFO:
243b0daa853SStephen Hanson 			/* No need to abort */
2445ad1f010SStephen Hanson 			break;
2457c478bd9Sstevel@tonic-gate 		default:
2467c478bd9Sstevel@tonic-gate 			syseventd_err_print(FATAL_ERROR);
2475ad1f010SStephen Hanson 			abort();
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	}
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
252b3a85157Sjg /*
253b3a85157Sjg  * Daemon parent process only.
254b3a85157Sjg  * Child process signal to indicate successful daemon initialization.
255b3a85157Sjg  * This is the normal and expected exit path of the daemon parent.
256b3a85157Sjg  */
257b3a85157Sjg /*ARGSUSED*/
258b3a85157Sjg static void
sigusr1(int sig)259b3a85157Sjg sigusr1(int sig)
260b3a85157Sjg {
261b3a85157Sjg 	syseventd_exit(0);
262b3a85157Sjg }
263b3a85157Sjg 
2645b784b07SToomas Soome static void *
sigwait_thr(void * arg __unused)2655b784b07SToomas Soome sigwait_thr(void *arg __unused)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	int	sig;
2687c478bd9Sstevel@tonic-gate 	int	err;
2697c478bd9Sstevel@tonic-gate 	sigset_t signal_set;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	for (;;) {
2727c478bd9Sstevel@tonic-gate 		syseventd_print(3, "sigwait thread waiting for signal\n");
2737c478bd9Sstevel@tonic-gate 		(void) sigfillset(&signal_set);
2747c478bd9Sstevel@tonic-gate 		err = sigwait(&signal_set, &sig);
2757c478bd9Sstevel@tonic-gate 		if (err) {
2767c478bd9Sstevel@tonic-gate 			syseventd_exit(2);
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 		/*
2807c478bd9Sstevel@tonic-gate 		 * Block all signals until the signal handler completes
2817c478bd9Sstevel@tonic-gate 		 */
2827c478bd9Sstevel@tonic-gate 		if (sig == SIGHUP) {
2837c478bd9Sstevel@tonic-gate 			hup_handler(sig);
2847c478bd9Sstevel@tonic-gate 		} else {
2857c478bd9Sstevel@tonic-gate 			flt_handler(sig);
2867c478bd9Sstevel@tonic-gate 		}
2877c478bd9Sstevel@tonic-gate 	}
2885b784b07SToomas Soome 	return (NULL);
2897c478bd9Sstevel@tonic-gate }
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate static void
set_root_dir(char * dir)2927c478bd9Sstevel@tonic-gate set_root_dir(char *dir)
2937c478bd9Sstevel@tonic-gate {
2947c478bd9Sstevel@tonic-gate 	root_dir = malloc(strlen(dir) + 1);
2957c478bd9Sstevel@tonic-gate 	if (root_dir == NULL) {
2967c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_ROOT_DIR_ERR, strerror(errno));
2977c478bd9Sstevel@tonic-gate 		syseventd_exit(2);
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 	(void) strcpy(root_dir, dir);
3007c478bd9Sstevel@tonic-gate }
3017c478bd9Sstevel@tonic-gate 
30280ab886dSwesolows int
main(int argc,char ** argv)3037c478bd9Sstevel@tonic-gate main(int argc, char **argv)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	int i, c;
3067c478bd9Sstevel@tonic-gate 	int fd;
3077c478bd9Sstevel@tonic-gate 	pid_t pid;
308b3a85157Sjg 	int has_forked = 0;
3097c478bd9Sstevel@tonic-gate 	extern char *optarg;
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
3127c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
3157c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "Must be root to run syseventd\n");
3167c478bd9Sstevel@tonic-gate 		syseventd_exit(1);
3177c478bd9Sstevel@tonic-gate 	}
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if (argc > 5) {
3207c478bd9Sstevel@tonic-gate 		usage();
3217c478bd9Sstevel@tonic-gate 	}
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate 	if ((prog = strrchr(argv[0], '/')) == NULL) {
3247c478bd9Sstevel@tonic-gate 		prog = argv[0];
3257c478bd9Sstevel@tonic-gate 	} else {
3267c478bd9Sstevel@tonic-gate 		prog++;
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 
3295ad1f010SStephen Hanson 	while ((c = getopt(argc, argv, "d:r:")) != EOF) {
3307c478bd9Sstevel@tonic-gate 		switch (c) {
3317c478bd9Sstevel@tonic-gate 		case 'd':
3327c478bd9Sstevel@tonic-gate 			debug_level = atoi(optarg);
3337c478bd9Sstevel@tonic-gate 			break;
3347c478bd9Sstevel@tonic-gate 		case 'r':
3357c478bd9Sstevel@tonic-gate 			/*
3367c478bd9Sstevel@tonic-gate 			 * Private flag for suninstall to run
3377c478bd9Sstevel@tonic-gate 			 * daemon during install.
3387c478bd9Sstevel@tonic-gate 			 */
3397c478bd9Sstevel@tonic-gate 			set_root_dir(optarg);
3407c478bd9Sstevel@tonic-gate 			break;
3417c478bd9Sstevel@tonic-gate 		case '?':
3427c478bd9Sstevel@tonic-gate 		default:
3437c478bd9Sstevel@tonic-gate 			usage();
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 	}
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/* demonize ourselves */
3487c478bd9Sstevel@tonic-gate 	if (debug_level < DEBUG_LEVEL_FORK) {
3497c478bd9Sstevel@tonic-gate 
350b3a85157Sjg 		sigset_t mask;
351b3a85157Sjg 
352b3a85157Sjg 		(void) sigset(SIGUSR1, sigusr1);
353b3a85157Sjg 
354b3a85157Sjg 		(void) sigemptyset(&mask);
355b3a85157Sjg 		(void) sigaddset(&mask, SIGUSR1);
356b3a85157Sjg 		(void) sigprocmask(SIG_BLOCK, &mask, NULL);
357b3a85157Sjg 
358b3a85157Sjg 		if ((pid = fork()) == (pid_t)-1) {
359b3a85157Sjg 			(void) fprintf(stderr,
360b3a85157Sjg 			    "syseventd: fork failed - %s\n", strerror(errno));
361b3a85157Sjg 			syseventd_exit(1);
362b3a85157Sjg 		}
363b3a85157Sjg 
364b3a85157Sjg 		if (pid != 0) {
365b3a85157Sjg 			/*
366b3a85157Sjg 			 * parent
367b3a85157Sjg 			 * handshake with the daemon so that dependents
368b3a85157Sjg 			 * of the syseventd service don't start up until
369b3a85157Sjg 			 * the service is actually functional
370b3a85157Sjg 			 */
371b3a85157Sjg 			int status;
372b3a85157Sjg 			(void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
373b3a85157Sjg 
374b3a85157Sjg 			if (waitpid(pid, &status, 0) != pid) {
375b3a85157Sjg 				/*
376b3a85157Sjg 				 * child process signal indicating
377b3a85157Sjg 				 * successful daemon initialization
378b3a85157Sjg 				 */
379b3a85157Sjg 				syseventd_exit(0);
380b3a85157Sjg 			}
381b3a85157Sjg 			/* child exited implying unsuccessful startup */
382b3a85157Sjg 			syseventd_exit(1);
3837c478bd9Sstevel@tonic-gate 		}
3847c478bd9Sstevel@tonic-gate 
3857c478bd9Sstevel@tonic-gate 		/* child */
3867c478bd9Sstevel@tonic-gate 
387b3a85157Sjg 		has_forked = 1;
388b3a85157Sjg 		(void) sigset(SIGUSR1, SIG_DFL);
389b3a85157Sjg 		(void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
390b3a85157Sjg 
3917c478bd9Sstevel@tonic-gate 		(void) chdir("/");
3927c478bd9Sstevel@tonic-gate 		(void) setsid();
3937c478bd9Sstevel@tonic-gate 		if (debug_level <= 1) {
3947c478bd9Sstevel@tonic-gate 			closefrom(0);
3957c478bd9Sstevel@tonic-gate 			fd = open("/dev/null", 0);
3967c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 1);
3977c478bd9Sstevel@tonic-gate 			(void) dup2(fd, 2);
3987c478bd9Sstevel@tonic-gate 			logflag = 1;
3997c478bd9Sstevel@tonic-gate 		}
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate 	openlog("syseventd", LOG_PID, LOG_DAEMON);
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	(void) mutex_init(&err_mutex, USYNC_THREAD, NULL);
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	syseventd_print(8,
4077c478bd9Sstevel@tonic-gate 	    "syseventd started, debug level = %d\n", debug_level);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/* only one instance of syseventd can run at a time */
4107c478bd9Sstevel@tonic-gate 	if ((pid = enter_daemon_lock()) != getpid()) {
4117c478bd9Sstevel@tonic-gate 		syseventd_print(1,
4127c478bd9Sstevel@tonic-gate 		    "event daemon pid %ld already running\n", pid);
4137c478bd9Sstevel@tonic-gate 		exit(3);
4147c478bd9Sstevel@tonic-gate 	}
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	/* initialize semaphores and eventbuf */
4177c478bd9Sstevel@tonic-gate 	(void) sema_init(&sema_eventbuf, SE_EVENT_DISPATCH_CNT,
4187c478bd9Sstevel@tonic-gate 	    USYNC_THREAD, NULL);
4197c478bd9Sstevel@tonic-gate 	(void) sema_init(&sema_dispatch, 0, USYNC_THREAD, NULL);
4207c478bd9Sstevel@tonic-gate 	(void) sema_init(&sema_resource, SE_EVENT_DISPATCH_CNT,
421b3a85157Sjg 	    USYNC_THREAD, NULL);
4227c478bd9Sstevel@tonic-gate 	(void) cond_init(&event_comp_cv, USYNC_THREAD, NULL);
4237c478bd9Sstevel@tonic-gate 	eventbuf = (sysevent_t **)calloc(SE_EVENT_DISPATCH_CNT,
4247c478bd9Sstevel@tonic-gate 	    sizeof (sysevent_t *));
4257c478bd9Sstevel@tonic-gate 	if (eventbuf == NULL) {
4267c478bd9Sstevel@tonic-gate 		syseventd_print(1, "Unable to allocate event buffer array\n");
4277c478bd9Sstevel@tonic-gate 		exit(2);
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 	for (i = 0; i < SE_EVENT_DISPATCH_CNT; ++i) {
4307c478bd9Sstevel@tonic-gate 		eventbuf[i] = malloc(LOGEVENT_BUFSIZE);
4317c478bd9Sstevel@tonic-gate 		if (eventbuf[i] == NULL) {
4327c478bd9Sstevel@tonic-gate 			syseventd_print(1, "Unable to allocate event "
4337c478bd9Sstevel@tonic-gate 			    "buffers\n");
4347c478bd9Sstevel@tonic-gate 			exit(2);
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 	}
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate 	(void) mutex_init(&client_tbl_lock, USYNC_THREAD, NULL);
4397c478bd9Sstevel@tonic-gate 	(void) mutex_init(&ev_comp_lock, USYNC_THREAD, NULL);
4407c478bd9Sstevel@tonic-gate 	(void) mutex_init(&door_lock, USYNC_THREAD, NULL);
4417c478bd9Sstevel@tonic-gate 	(void) rwlock_init(&mod_unload_lock, USYNC_THREAD, NULL);
4427c478bd9Sstevel@tonic-gate 
4437c478bd9Sstevel@tonic-gate 	event_compq = NULL;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	syseventd_print(8, "start the message thread running\n");
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	/*
4487c478bd9Sstevel@tonic-gate 	 * Block all signals to all threads include the main thread.
4497c478bd9Sstevel@tonic-gate 	 * The sigwait_thr thread will process any signals and initiate
4507c478bd9Sstevel@tonic-gate 	 * a graceful recovery if possible.
4517c478bd9Sstevel@tonic-gate 	 */
4527c478bd9Sstevel@tonic-gate 	if (se_signal_blockall() < 0) {
4537c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_SIG_BLOCK_ERR);
4547c478bd9Sstevel@tonic-gate 		syseventd_exit(2);
4557c478bd9Sstevel@tonic-gate 	}
4567c478bd9Sstevel@tonic-gate 
457c7cb3c8bSToomas Soome 	if (thr_create(NULL, 0, (void *(*)(void *))dispatch_message,
458b3a85157Sjg 	    (void *)0, 0, NULL) < 0) {
4597c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
4607c478bd9Sstevel@tonic-gate 		syseventd_exit(2);
4617c478bd9Sstevel@tonic-gate 	}
462c7cb3c8bSToomas Soome 	if (thr_create(NULL, 0,
463b3a85157Sjg 	    (void *(*)(void *))event_completion_thr, NULL,
464b3a85157Sjg 	    THR_BOUND, NULL) != 0) {
4657c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
4667c478bd9Sstevel@tonic-gate 		syseventd_exit(2);
4677c478bd9Sstevel@tonic-gate 	}
4687c478bd9Sstevel@tonic-gate 	/* Create signal catching thread */
4695b784b07SToomas Soome 	if (thr_create(NULL, 0, sigwait_thr, NULL, 0, NULL) < 0) {
4707c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_THR_CREATE_ERR, strerror(errno));
4717c478bd9Sstevel@tonic-gate 		syseventd_exit(2);
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	setbuf(stdout, (char *)NULL);
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 	/* Initialize and load SLM clients */
4777c478bd9Sstevel@tonic-gate 	initialize_client_tbl();
4787c478bd9Sstevel@tonic-gate 	syseventd_init();
4797c478bd9Sstevel@tonic-gate 
480b3a85157Sjg 	/* signal parent to indicate successful daemon initialization */
481b3a85157Sjg 	if (has_forked) {
482b3a85157Sjg 		if (kill(getppid(), SIGUSR1) != 0) {
483b3a85157Sjg 			syseventd_err_print(
484b3a85157Sjg 			    "signal to the parent failed - %s\n",
485b3a85157Sjg 			    strerror(errno));
486b3a85157Sjg 			syseventd_exit(2);
487b3a85157Sjg 		}
488b3a85157Sjg 	}
489b3a85157Sjg 
4907c478bd9Sstevel@tonic-gate 	syseventd_print(8, "Pausing\n");
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	for (;;) {
4937c478bd9Sstevel@tonic-gate 		(void) pause();
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
49680ab886dSwesolows 	return (0);
4977c478bd9Sstevel@tonic-gate }
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate /*
5007c478bd9Sstevel@tonic-gate  * door_upcall - called from the kernel via kernel sysevent door
5017c478bd9Sstevel@tonic-gate  *		to upload event(s).
5027c478bd9Sstevel@tonic-gate  *
5037c478bd9Sstevel@tonic-gate  *		This routine should never block.  If resources are
5047c478bd9Sstevel@tonic-gate  *		not available to immediately accept the event buffer
5057c478bd9Sstevel@tonic-gate  *		EAGAIN is returned to the kernel.
5067c478bd9Sstevel@tonic-gate  *
5077c478bd9Sstevel@tonic-gate  *		Once resources are available, the kernel is notified
5087c478bd9Sstevel@tonic-gate  *		via a modctl interface to resume event delivery to
5097c478bd9Sstevel@tonic-gate  *		syseventd.
5107c478bd9Sstevel@tonic-gate  *
5117c478bd9Sstevel@tonic-gate  */
5127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5137c478bd9Sstevel@tonic-gate static void
door_upcall(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)5147c478bd9Sstevel@tonic-gate door_upcall(void *cookie, char *args, size_t alen,
5157c478bd9Sstevel@tonic-gate     door_desc_t *ddp, uint_t ndid)
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
5187c478bd9Sstevel@tonic-gate 	int rval;
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&door_lock);
5227c478bd9Sstevel@tonic-gate 	if (args == NULL) {
5237c478bd9Sstevel@tonic-gate 		rval = EINVAL;
5247c478bd9Sstevel@tonic-gate 	} else if (sema_trywait(&sema_eventbuf)) {
5257c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)
5267c478bd9Sstevel@tonic-gate 		    &((log_event_upcall_arg_t *)(void *)args)->buf;
5277c478bd9Sstevel@tonic-gate 		syseventd_print(2, "door_upcall: busy event %llx "
528b3a85157Sjg 		    "retry\n", sysevent_get_seq(ev));
5297c478bd9Sstevel@tonic-gate 		rval = door_upcall_retval = EAGAIN;
5307c478bd9Sstevel@tonic-gate 	} else {
5317c478bd9Sstevel@tonic-gate 		/*
5327c478bd9Sstevel@tonic-gate 		 * Copy received message to local buffer.
5337c478bd9Sstevel@tonic-gate 		 */
5347c478bd9Sstevel@tonic-gate 		size_t size;
5357c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)
5367c478bd9Sstevel@tonic-gate 		    &((log_event_upcall_arg_t *)(void *)args)->buf;
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		syseventd_print(2, "door_upcall: event %llx in eventbuf %d\n",
5397c478bd9Sstevel@tonic-gate 		    sysevent_get_seq(ev), deliver_buf);
5407c478bd9Sstevel@tonic-gate 		size = sysevent_get_size(ev) > LOGEVENT_BUFSIZE ?
5417c478bd9Sstevel@tonic-gate 		    LOGEVENT_BUFSIZE : sysevent_get_size(ev);
5427c478bd9Sstevel@tonic-gate 		(void) bcopy(ev, eventbuf[deliver_buf], size);
5437c478bd9Sstevel@tonic-gate 		deliver_buf = (deliver_buf + 1) % SE_EVENT_DISPATCH_CNT;
5447c478bd9Sstevel@tonic-gate 		rval = 0;
5457c478bd9Sstevel@tonic-gate 		(void) sema_post(&sema_dispatch);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&door_lock);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	/*
5517c478bd9Sstevel@tonic-gate 	 * Filling in return values for door_return
5527c478bd9Sstevel@tonic-gate 	 */
5537c478bd9Sstevel@tonic-gate 	(void) door_return((void *)&rval, sizeof (rval), NULL, 0);
5547c478bd9Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate 
5577c478bd9Sstevel@tonic-gate /*
5587c478bd9Sstevel@tonic-gate  * dispatch_message - dispatch message thread
5597c478bd9Sstevel@tonic-gate  *			This thread spins until an event buffer is delivered
5607c478bd9Sstevel@tonic-gate  *			delivered from the kernel.
5617c478bd9Sstevel@tonic-gate  *
5627c478bd9Sstevel@tonic-gate  *			It will wait to dispatch an event to any clients
5637c478bd9Sstevel@tonic-gate  *			until adequate resources are available to process
5647c478bd9Sstevel@tonic-gate  *			the event buffer.
5657c478bd9Sstevel@tonic-gate  */
5667c478bd9Sstevel@tonic-gate static void
dispatch_message(void)5677c478bd9Sstevel@tonic-gate dispatch_message(void)
5687c478bd9Sstevel@tonic-gate {
5697c478bd9Sstevel@tonic-gate 	int error;
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	for (;;) {
5727c478bd9Sstevel@tonic-gate 		syseventd_print(3, "dispatch_message: thread started\n");
5737c478bd9Sstevel@tonic-gate 		/*
5747c478bd9Sstevel@tonic-gate 		 * Spin till a message comes
5757c478bd9Sstevel@tonic-gate 		 */
5767c478bd9Sstevel@tonic-gate 		while (sema_wait(&sema_dispatch) != 0) {
5777c478bd9Sstevel@tonic-gate 			syseventd_print(1,
5787c478bd9Sstevel@tonic-gate 			    "dispatch_message: sema_wait failed\n");
5797c478bd9Sstevel@tonic-gate 			(void) sleep(1);
5807c478bd9Sstevel@tonic-gate 		}
5817c478bd9Sstevel@tonic-gate 
5827c478bd9Sstevel@tonic-gate 		syseventd_print(3, "dispatch_message: sema_dispatch\n");
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 		/*
5857c478bd9Sstevel@tonic-gate 		 * Wait for available resources
5867c478bd9Sstevel@tonic-gate 		 */
5877c478bd9Sstevel@tonic-gate 		while (sema_wait(&sema_resource) != 0) {
5887c478bd9Sstevel@tonic-gate 			syseventd_print(1, "dispatch_message: sema_wait "
589b3a85157Sjg 			    "failed\n");
5907c478bd9Sstevel@tonic-gate 			(void) sleep(1);
5917c478bd9Sstevel@tonic-gate 		}
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 		syseventd_print(2, "dispatch_message: eventbuf %d\n",
5947c478bd9Sstevel@tonic-gate 		    dispatch_buf);
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 		/*
5977c478bd9Sstevel@tonic-gate 		 * Client dispatch
5987c478bd9Sstevel@tonic-gate 		 */
5997c478bd9Sstevel@tonic-gate 		do {
6007c478bd9Sstevel@tonic-gate 			error = dispatch();
6017c478bd9Sstevel@tonic-gate 		} while (error == EAGAIN);
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 		syseventd_print(2, "eventbuf %d dispatched\n", dispatch_buf);
6047c478bd9Sstevel@tonic-gate 		dispatch_buf = (dispatch_buf + 1) % SE_EVENT_DISPATCH_CNT;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate 		/*
6077c478bd9Sstevel@tonic-gate 		 * kernel received a busy signal -
6087c478bd9Sstevel@tonic-gate 		 * kickstart the kernel delivery thread
6097c478bd9Sstevel@tonic-gate 		 * door_lock blocks the kernel so we hold it for the
6107c478bd9Sstevel@tonic-gate 		 * shortest time possible.
6117c478bd9Sstevel@tonic-gate 		 */
6127c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&door_lock);
6137c478bd9Sstevel@tonic-gate 		if (door_upcall_retval == EAGAIN && !fini_pending) {
6147c478bd9Sstevel@tonic-gate 			syseventd_print(3, "dispatch_message: retrigger "
615b3a85157Sjg 			    "door_upcall_retval = %d\n",
616b3a85157Sjg 			    door_upcall_retval);
6177c478bd9Sstevel@tonic-gate 			(void) modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH,
618b3a85157Sjg 			    NULL, NULL, NULL, 0);
6197c478bd9Sstevel@tonic-gate 			door_upcall_retval = 0;
6207c478bd9Sstevel@tonic-gate 		}
6217c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&door_lock);
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
6247c478bd9Sstevel@tonic-gate }
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate /*
6277c478bd9Sstevel@tonic-gate  * drain_eventq - Called to drain all pending events from the client's
6287c478bd9Sstevel@tonic-gate  *		event queue.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate static void
drain_eventq(struct sysevent_client * scp,int status)6317c478bd9Sstevel@tonic-gate drain_eventq(struct sysevent_client *scp, int status)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	struct event_dispatch_pkg *d_pkg;
6347c478bd9Sstevel@tonic-gate 	struct event_dispatchq *eventq, *eventq_next;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	syseventd_print(3, "Draining eventq for client %d\n",
637b3a85157Sjg 	    scp->client_num);
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	eventq = scp->eventq;
6407c478bd9Sstevel@tonic-gate 	while (eventq) {
6417c478bd9Sstevel@tonic-gate 		/*
6427c478bd9Sstevel@tonic-gate 		 * Mark all dispatched events as completed, but indicate the
6437c478bd9Sstevel@tonic-gate 		 * error status
6447c478bd9Sstevel@tonic-gate 		 */
6457c478bd9Sstevel@tonic-gate 		d_pkg = eventq->d_pkg;
6467c478bd9Sstevel@tonic-gate 
6477c478bd9Sstevel@tonic-gate 		syseventd_print(4, "drain event 0X%llx for client %d\n",
6487c478bd9Sstevel@tonic-gate 		    sysevent_get_seq(d_pkg->ev), scp->client_num);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 		if (d_pkg->completion_state == SE_NOT_DISPATCHED) {
6517c478bd9Sstevel@tonic-gate 			d_pkg->completion_status = status;
6527c478bd9Sstevel@tonic-gate 			d_pkg->completion_state = SE_COMPLETE;
6537c478bd9Sstevel@tonic-gate 			(void) sema_post(d_pkg->completion_sema);
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		eventq_next = eventq->next;
6577c478bd9Sstevel@tonic-gate 		free(eventq);
6587c478bd9Sstevel@tonic-gate 		eventq = eventq_next;
6597c478bd9Sstevel@tonic-gate 		scp->eventq = eventq;
6607c478bd9Sstevel@tonic-gate 	}
6617c478bd9Sstevel@tonic-gate }
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate /*
6647c478bd9Sstevel@tonic-gate  * client_deliver_event_thr - Client delivery thread
6657c478bd9Sstevel@tonic-gate  *				This thread will process any events on this
6667c478bd9Sstevel@tonic-gate  *				client's eventq.
6677c478bd9Sstevel@tonic-gate  */
6685b784b07SToomas Soome static void *
client_deliver_event_thr(void * arg)6697c478bd9Sstevel@tonic-gate client_deliver_event_thr(void *arg)
6707c478bd9Sstevel@tonic-gate {
6717c478bd9Sstevel@tonic-gate 	int flag, error, i;
6727c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
6737c478bd9Sstevel@tonic-gate 	hrtime_t now;
6747c478bd9Sstevel@tonic-gate 	module_t *mod;
6757c478bd9Sstevel@tonic-gate 	struct event_dispatchq *eventq;
6767c478bd9Sstevel@tonic-gate 	struct sysevent_client *scp;
6777c478bd9Sstevel@tonic-gate 	struct event_dispatch_pkg *d_pkg;
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate 	scp = (struct sysevent_client *)arg;
6807c478bd9Sstevel@tonic-gate 	mod = (module_t *)scp->client_data;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&scp->client_lock);
6837c478bd9Sstevel@tonic-gate 	for (;;) {
6847c478bd9Sstevel@tonic-gate 		while (scp->eventq == NULL) {
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 			/*
6877c478bd9Sstevel@tonic-gate 			 * Client has been suspended or unloaded, go no further.
6887c478bd9Sstevel@tonic-gate 			 */
6897c478bd9Sstevel@tonic-gate 			if (fini_pending) {
6907c478bd9Sstevel@tonic-gate 				scp->client_flags &= ~SE_CLIENT_THR_RUNNING;
6917c478bd9Sstevel@tonic-gate 				syseventd_print(3, "Client %d delivery thread "
692b3a85157Sjg 				    "exiting flags: 0X%x\n",
693b3a85157Sjg 				    scp->client_num, scp->client_flags);
6947c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&scp->client_lock);
6955b784b07SToomas Soome 				return (NULL);
6967c478bd9Sstevel@tonic-gate 			}
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 			(void) cond_wait(&scp->client_cv, &scp->client_lock);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		}
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		/*
7037c478bd9Sstevel@tonic-gate 		 * Process events from the head of the eventq, eventq is locked
7047c478bd9Sstevel@tonic-gate 		 * going into the processing.
7057c478bd9Sstevel@tonic-gate 		 */
7067c478bd9Sstevel@tonic-gate 		eventq = scp->eventq;
7077c478bd9Sstevel@tonic-gate 		while (eventq != NULL) {
7087c478bd9Sstevel@tonic-gate 			d_pkg = eventq->d_pkg;
7097c478bd9Sstevel@tonic-gate 			d_pkg->completion_state = SE_OUTSTANDING;
7105ad1f010SStephen Hanson 			scp->eventq = eventq->next;
7115ad1f010SStephen Hanson 			free(eventq);
7127c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&scp->client_lock);
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate 			flag = error = 0;
7167c478bd9Sstevel@tonic-gate 			ev = d_pkg->ev;
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 			syseventd_print(3, "Start delivery for client %d "
7197c478bd9Sstevel@tonic-gate 			    "with retry count %d\n",
7207c478bd9Sstevel@tonic-gate 			    scp->client_num, d_pkg->retry_count);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 			/*
7237c478bd9Sstevel@tonic-gate 			 * Retry limit has been reached by this client, indicate
7247c478bd9Sstevel@tonic-gate 			 * that no further retries are allowed
7257c478bd9Sstevel@tonic-gate 			 */
7267c478bd9Sstevel@tonic-gate 			for (i = 0; i <= scp->retry_limit; ++i) {
7277c478bd9Sstevel@tonic-gate 				if (i == scp->retry_limit)
7287c478bd9Sstevel@tonic-gate 					flag = SE_NO_RETRY;
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 				/* Start the clock for the event delivery */
7317c478bd9Sstevel@tonic-gate 				d_pkg->start_time = gethrtime();
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 				syseventd_print(9, "Deliver to module client "
7347c478bd9Sstevel@tonic-gate 				    "%s\n", mod->name);
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 				error = mod->deliver_event(ev, flag);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 				/* Can not allow another retry */
7397c478bd9Sstevel@tonic-gate 				if (i == scp->retry_limit)
7407c478bd9Sstevel@tonic-gate 					error = 0;
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 				/* Stop the clock */
7437c478bd9Sstevel@tonic-gate 				now = gethrtime();
7447c478bd9Sstevel@tonic-gate 
7457c478bd9Sstevel@tonic-gate 				/*
7467c478bd9Sstevel@tonic-gate 				 * Suspend event processing and drain the
7477c478bd9Sstevel@tonic-gate 				 * event q for latent clients
7487c478bd9Sstevel@tonic-gate 				 */
7497c478bd9Sstevel@tonic-gate 				if (now - d_pkg->start_time >
7507c478bd9Sstevel@tonic-gate 				    ((hrtime_t)SE_TIMEOUT * NANOSEC)) {
7517c478bd9Sstevel@tonic-gate 					syseventd_print(1, "Unresponsive "
7527c478bd9Sstevel@tonic-gate 					    "client %d: Draining eventq and "
7537c478bd9Sstevel@tonic-gate 					    "suspending event delivery\n",
7547c478bd9Sstevel@tonic-gate 					    scp->client_num);
7557c478bd9Sstevel@tonic-gate 					(void) mutex_lock(&scp->client_lock);
7567c478bd9Sstevel@tonic-gate 					scp->client_flags &=
7577c478bd9Sstevel@tonic-gate 					    ~SE_CLIENT_THR_RUNNING;
7587c478bd9Sstevel@tonic-gate 					scp->client_flags |=
7597c478bd9Sstevel@tonic-gate 					    SE_CLIENT_SUSPENDED;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 					/* Cleanup current event */
7627c478bd9Sstevel@tonic-gate 					d_pkg->completion_status = EFAULT;
7637c478bd9Sstevel@tonic-gate 					d_pkg->completion_state = SE_COMPLETE;
7647c478bd9Sstevel@tonic-gate 					(void) sema_post(
7657c478bd9Sstevel@tonic-gate 					    d_pkg->completion_sema);
7667c478bd9Sstevel@tonic-gate 
7677c478bd9Sstevel@tonic-gate 					/*
7687c478bd9Sstevel@tonic-gate 					 * Drain the remaining events from the
7697c478bd9Sstevel@tonic-gate 					 * queue.
7707c478bd9Sstevel@tonic-gate 					 */
7717c478bd9Sstevel@tonic-gate 					drain_eventq(scp, EINVAL);
7727c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&scp->client_lock);
7735b784b07SToomas Soome 					return (NULL);
7747c478bd9Sstevel@tonic-gate 				}
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 				/* Event delivery retry requested */
7777c478bd9Sstevel@tonic-gate 				if (fini_pending || error != EAGAIN) {
7787c478bd9Sstevel@tonic-gate 					break;
7797c478bd9Sstevel@tonic-gate 				} else {
7807c478bd9Sstevel@tonic-gate 					(void) sleep(SE_RETRY_TIME);
7817c478bd9Sstevel@tonic-gate 				}
7827c478bd9Sstevel@tonic-gate 			}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&scp->client_lock);
7857c478bd9Sstevel@tonic-gate 			d_pkg->completion_status = error;
7867c478bd9Sstevel@tonic-gate 			d_pkg->completion_state = SE_COMPLETE;
7877c478bd9Sstevel@tonic-gate 			(void) sema_post(d_pkg->completion_sema);
7887c478bd9Sstevel@tonic-gate 			syseventd_print(3, "Completed delivery with "
7897c478bd9Sstevel@tonic-gate 			    "error %d\n", error);
790540db9a9SStephen Hanson 			eventq = scp->eventq;
7917c478bd9Sstevel@tonic-gate 		}
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 		syseventd_print(3, "No more events to process for client %d\n",
794b3a85157Sjg 		    scp->client_num);
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 		/* Return if this was a synchronous delivery */
7977c478bd9Sstevel@tonic-gate 		if (!SE_CLIENT_IS_THR_RUNNING(scp)) {
7987c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&scp->client_lock);
7995b784b07SToomas Soome 			return (NULL);
8007c478bd9Sstevel@tonic-gate 		}
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	}
8037c478bd9Sstevel@tonic-gate }
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate /*
8067c478bd9Sstevel@tonic-gate  * client_deliver_event - Client specific event delivery
8077c478bd9Sstevel@tonic-gate  *			This routine will allocate and initialize the
8087c478bd9Sstevel@tonic-gate  *			neccessary per-client dispatch data.
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  *			If the eventq is not empty, it may be assumed that
8117c478bd9Sstevel@tonic-gate  *			a delivery thread exists for this client and the
8127c478bd9Sstevel@tonic-gate  *			dispatch data is appended to the eventq.
8137c478bd9Sstevel@tonic-gate  *
8147c478bd9Sstevel@tonic-gate  *			The dispatch package is freed by the event completion
8157c478bd9Sstevel@tonic-gate  *			thread (event_completion_thr) and the eventq entry
8167c478bd9Sstevel@tonic-gate  *			is freed by the event delivery thread.
8177c478bd9Sstevel@tonic-gate  */
8187c478bd9Sstevel@tonic-gate static struct event_dispatch_pkg *
client_deliver_event(struct sysevent_client * scp,sysevent_t * ev,sema_t * completion_sema)8197c478bd9Sstevel@tonic-gate client_deliver_event(struct sysevent_client *scp, sysevent_t *ev,
820*30699046SRichard Lowe     sema_t *completion_sema)
8217c478bd9Sstevel@tonic-gate {
8227c478bd9Sstevel@tonic-gate 	size_t ev_sz = sysevent_get_size(ev);
8237c478bd9Sstevel@tonic-gate 	struct event_dispatchq *newq, *tmp;
8247c478bd9Sstevel@tonic-gate 	struct event_dispatch_pkg *d_pkg;
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	syseventd_print(3, "client_deliver_event: id 0x%llx size %d\n",
827b3a85157Sjg 	    (longlong_t)sysevent_get_seq(ev), ev_sz);
8287c478bd9Sstevel@tonic-gate 	if (debug_level == 9) {
8297c478bd9Sstevel@tonic-gate 		se_print(stdout, ev);
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	/*
8337c478bd9Sstevel@tonic-gate 	 * Check for suspended client
8347c478bd9Sstevel@tonic-gate 	 */
8357c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&scp->client_lock);
8367c478bd9Sstevel@tonic-gate 	if (SE_CLIENT_IS_SUSPENDED(scp) || !SE_CLIENT_IS_THR_RUNNING(scp)) {
8377c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&scp->client_lock);
8387c478bd9Sstevel@tonic-gate 		return (NULL);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 
8417c478bd9Sstevel@tonic-gate 	/*
8427c478bd9Sstevel@tonic-gate 	 * Allocate a new dispatch package and eventq entry
8437c478bd9Sstevel@tonic-gate 	 */
8447c478bd9Sstevel@tonic-gate 	newq = (struct event_dispatchq *)malloc(
845b3a85157Sjg 	    sizeof (struct event_dispatchq));
8467c478bd9Sstevel@tonic-gate 	if (newq == NULL) {
8477c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&scp->client_lock);
8487c478bd9Sstevel@tonic-gate 		return (NULL);
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	d_pkg = (struct event_dispatch_pkg *)malloc(
852b3a85157Sjg 	    sizeof (struct event_dispatch_pkg));
8537c478bd9Sstevel@tonic-gate 	if (d_pkg == NULL) {
8547c478bd9Sstevel@tonic-gate 		free(newq);
8557c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&scp->client_lock);
8567c478bd9Sstevel@tonic-gate 		return (NULL);
8577c478bd9Sstevel@tonic-gate 	}
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	/* Initialize the dispatch package */
8607c478bd9Sstevel@tonic-gate 	d_pkg->scp = scp;
8617c478bd9Sstevel@tonic-gate 	d_pkg->retry_count = 0;
8627c478bd9Sstevel@tonic-gate 	d_pkg->completion_status = 0;
8637c478bd9Sstevel@tonic-gate 	d_pkg->completion_state = SE_NOT_DISPATCHED;
8647c478bd9Sstevel@tonic-gate 	d_pkg->completion_sema = completion_sema;
8657c478bd9Sstevel@tonic-gate 	d_pkg->ev = ev;
8667c478bd9Sstevel@tonic-gate 	newq->d_pkg = d_pkg;
8677c478bd9Sstevel@tonic-gate 	newq->next = NULL;
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 	if (scp->eventq != NULL) {
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		/* Add entry to the end of the eventq */
8727c478bd9Sstevel@tonic-gate 		tmp = scp->eventq;
8737c478bd9Sstevel@tonic-gate 		while (tmp->next != NULL)
8747c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
8757c478bd9Sstevel@tonic-gate 		tmp->next = newq;
8767c478bd9Sstevel@tonic-gate 	} else {
8777c478bd9Sstevel@tonic-gate 		/* event queue empty, wakeup delivery thread */
8787c478bd9Sstevel@tonic-gate 		scp->eventq = newq;
8797c478bd9Sstevel@tonic-gate 		(void) cond_signal(&scp->client_cv);
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&scp->client_lock);
8827c478bd9Sstevel@tonic-gate 
8837c478bd9Sstevel@tonic-gate 	return (d_pkg);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate  * event_completion_thr - Event completion thread.  This thread routine
8887c478bd9Sstevel@tonic-gate  *			waits for all client delivery thread to complete
8897c478bd9Sstevel@tonic-gate  *			delivery of a particular event.
8907c478bd9Sstevel@tonic-gate  */
8917c478bd9Sstevel@tonic-gate static void
event_completion_thr()8927c478bd9Sstevel@tonic-gate event_completion_thr()
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	int ret, i, client_count, ok_to_free;
8957c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
8967c478bd9Sstevel@tonic-gate 	struct sysevent_client *scp;
8977c478bd9Sstevel@tonic-gate 	struct ev_completion *ev_comp;
8987c478bd9Sstevel@tonic-gate 	struct event_dispatchq *dispatchq;
8997c478bd9Sstevel@tonic-gate 	struct event_dispatch_pkg *d_pkg;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&ev_comp_lock);
9027c478bd9Sstevel@tonic-gate 	for (;;) {
9037c478bd9Sstevel@tonic-gate 		while (event_compq == NULL) {
9047c478bd9Sstevel@tonic-gate 			(void) cond_wait(&event_comp_cv, &ev_comp_lock);
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 		/*
9087c478bd9Sstevel@tonic-gate 		 * Process event completions from the head of the
9097c478bd9Sstevel@tonic-gate 		 * completion queue
9107c478bd9Sstevel@tonic-gate 		 */
9117c478bd9Sstevel@tonic-gate 		ev_comp = event_compq;
9127c478bd9Sstevel@tonic-gate 		while (ev_comp) {
9137c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&ev_comp_lock);
9147c478bd9Sstevel@tonic-gate 			eid.eid_seq = sysevent_get_seq(ev_comp->ev);
9157c478bd9Sstevel@tonic-gate 			sysevent_get_time(ev_comp->ev, &eid.eid_ts);
9167c478bd9Sstevel@tonic-gate 			client_count = ev_comp->client_count;
9177c478bd9Sstevel@tonic-gate 			ok_to_free = 1;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 			syseventd_print(3, "Wait for event completion of "
9207c478bd9Sstevel@tonic-gate 			    "event 0X%llx on %d clients\n",
9217c478bd9Sstevel@tonic-gate 			    eid.eid_seq, client_count);
9227c478bd9Sstevel@tonic-gate 
9237c478bd9Sstevel@tonic-gate 			while (client_count) {
9247c478bd9Sstevel@tonic-gate 				syseventd_print(9, "Waiting for %d clients on "
925b3a85157Sjg 				    "event id 0X%llx\n", client_count,
926b3a85157Sjg 				    eid.eid_seq);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 				(void) sema_wait(&ev_comp->client_sema);
9297c478bd9Sstevel@tonic-gate 				--client_count;
9307c478bd9Sstevel@tonic-gate 			}
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 			syseventd_print(3, "Cleaning up clients for event "
9337c478bd9Sstevel@tonic-gate 			    "0X%llx\n", eid.eid_seq);
9347c478bd9Sstevel@tonic-gate 			dispatchq = ev_comp->dispatch_list;
9357c478bd9Sstevel@tonic-gate 			while (dispatchq != NULL) {
9367c478bd9Sstevel@tonic-gate 				d_pkg = dispatchq->d_pkg;
9377c478bd9Sstevel@tonic-gate 				scp = d_pkg->scp;
9387c478bd9Sstevel@tonic-gate 
9397c478bd9Sstevel@tonic-gate 				if (d_pkg->completion_status == EAGAIN)
9407c478bd9Sstevel@tonic-gate 					ok_to_free = 0;
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 				syseventd_print(4, "Delivery of 0X%llx "
9437c478bd9Sstevel@tonic-gate 				    "complete for client %d retry count %d "
9447c478bd9Sstevel@tonic-gate 				    "status %d\n", eid.eid_seq,
9457c478bd9Sstevel@tonic-gate 				    scp->client_num,
9467c478bd9Sstevel@tonic-gate 				    d_pkg->retry_count,
9477c478bd9Sstevel@tonic-gate 				    d_pkg->completion_status);
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 				free(d_pkg);
9507c478bd9Sstevel@tonic-gate 				ev_comp->dispatch_list = dispatchq->next;
9517c478bd9Sstevel@tonic-gate 				free(dispatchq);
9527c478bd9Sstevel@tonic-gate 				dispatchq = ev_comp->dispatch_list;
9537c478bd9Sstevel@tonic-gate 			}
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 			if (ok_to_free) {
9567c478bd9Sstevel@tonic-gate 				for (i = 0; i < MAX_MODCTL_RETRY; ++i) {
9577c478bd9Sstevel@tonic-gate 					if ((ret = modctl(MODEVENTS,
958b3a85157Sjg 					    (uintptr_t)MODEVENTS_FREEDATA,
959b3a85157Sjg 					    (uintptr_t)&eid, NULL,
960b3a85157Sjg 					    NULL, 0)) != 0) {
9617c478bd9Sstevel@tonic-gate 						syseventd_print(1, "attempting "
9627c478bd9Sstevel@tonic-gate 						    "to free event 0X%llx\n",
9637c478bd9Sstevel@tonic-gate 						    eid.eid_seq);
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 						/*
9667c478bd9Sstevel@tonic-gate 						 * Kernel may need time to
9677c478bd9Sstevel@tonic-gate 						 * move this event buffer to
9687c478bd9Sstevel@tonic-gate 						 * the sysevent sent queue
9697c478bd9Sstevel@tonic-gate 						 */
9707c478bd9Sstevel@tonic-gate 						(void) sleep(1);
9717c478bd9Sstevel@tonic-gate 					} else {
9727c478bd9Sstevel@tonic-gate 						break;
9737c478bd9Sstevel@tonic-gate 					}
9747c478bd9Sstevel@tonic-gate 				}
9757c478bd9Sstevel@tonic-gate 				if (ret) {
9767c478bd9Sstevel@tonic-gate 					syseventd_print(1, "Unable to free "
977b3a85157Sjg 					    "event 0X%llx from the "
978b3a85157Sjg 					    "kernel\n", eid.eid_seq);
9797c478bd9Sstevel@tonic-gate 				}
9807c478bd9Sstevel@tonic-gate 			} else {
9817c478bd9Sstevel@tonic-gate 				syseventd_print(1, "Not freeing event 0X%llx\n",
982b3a85157Sjg 				    eid.eid_seq);
9837c478bd9Sstevel@tonic-gate 			}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 			syseventd_print(2, "Event delivery complete for id "
986b3a85157Sjg 			    "0X%llx\n", eid.eid_seq);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&ev_comp_lock);
9897c478bd9Sstevel@tonic-gate 			event_compq = ev_comp->next;
9907c478bd9Sstevel@tonic-gate 			free(ev_comp->ev);
9917c478bd9Sstevel@tonic-gate 			free(ev_comp);
9927c478bd9Sstevel@tonic-gate 			ev_comp = event_compq;
9937c478bd9Sstevel@tonic-gate 			(void) sema_post(&sema_resource);
9947c478bd9Sstevel@tonic-gate 		}
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 		/*
9977c478bd9Sstevel@tonic-gate 		 * Event completion queue is empty, signal possible unload
9987c478bd9Sstevel@tonic-gate 		 * operation
9997c478bd9Sstevel@tonic-gate 		 */
10007c478bd9Sstevel@tonic-gate 		(void) cond_signal(&event_comp_cv);
10017c478bd9Sstevel@tonic-gate 
10027c478bd9Sstevel@tonic-gate 		syseventd_print(3, "No more events\n");
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate }
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate /*
10077c478bd9Sstevel@tonic-gate  * dispatch - Dispatch the current event buffer to all valid SLM clients.
10087c478bd9Sstevel@tonic-gate  */
10097c478bd9Sstevel@tonic-gate static int
dispatch(void)10107c478bd9Sstevel@tonic-gate dispatch(void)
10117c478bd9Sstevel@tonic-gate {
10127c478bd9Sstevel@tonic-gate 	int ev_sz, i, client_count = 0;
10137c478bd9Sstevel@tonic-gate 	sysevent_t *new_ev;
10147c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
10157c478bd9Sstevel@tonic-gate 	struct ev_completion *ev_comp, *tmp;
10167c478bd9Sstevel@tonic-gate 	struct event_dispatchq *dispatchq, *client_list;
10177c478bd9Sstevel@tonic-gate 	struct event_dispatch_pkg *d_pkg;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/* Check for module unload operation */
10207c478bd9Sstevel@tonic-gate 	if (rw_tryrdlock(&mod_unload_lock) != 0) {
10217c478bd9Sstevel@tonic-gate 		syseventd_print(2, "unload in progress abort delivery\n");
10227c478bd9Sstevel@tonic-gate 		(void) sema_post(&sema_eventbuf);
10237c478bd9Sstevel@tonic-gate 		(void) sema_post(&sema_resource);
10247c478bd9Sstevel@tonic-gate 		return (0);
10257c478bd9Sstevel@tonic-gate 	}
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	syseventd_print(3, "deliver dispatch buffer %d", dispatch_buf);
10287c478bd9Sstevel@tonic-gate 	eid.eid_seq = sysevent_get_seq(eventbuf[dispatch_buf]);
10297c478bd9Sstevel@tonic-gate 	sysevent_get_time(eventbuf[dispatch_buf], &eid.eid_ts);
10307c478bd9Sstevel@tonic-gate 	syseventd_print(3, "deliver msg id: 0x%llx\n", eid.eid_seq);
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	/*
10337c478bd9Sstevel@tonic-gate 	 * ev_comp is used to hold event completion data.  It is freed
10347c478bd9Sstevel@tonic-gate 	 * by the event completion thread (event_completion_thr).
10357c478bd9Sstevel@tonic-gate 	 */
10367c478bd9Sstevel@tonic-gate 	ev_comp = (struct ev_completion *)
1037b3a85157Sjg 	    malloc(sizeof (struct ev_completion));
10387c478bd9Sstevel@tonic-gate 	if (ev_comp == NULL) {
10397c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&mod_unload_lock);
10407c478bd9Sstevel@tonic-gate 		syseventd_print(1, "Can not allocate event completion buffer "
1041b3a85157Sjg 		    "for event id 0X%llx\n", eid.eid_seq);
10427c478bd9Sstevel@tonic-gate 		return (EAGAIN);
10437c478bd9Sstevel@tonic-gate 	}
10447c478bd9Sstevel@tonic-gate 	ev_comp->dispatch_list = NULL;
10457c478bd9Sstevel@tonic-gate 	ev_comp->next = NULL;
10467c478bd9Sstevel@tonic-gate 	(void) sema_init(&ev_comp->client_sema, 0, USYNC_THREAD, NULL);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	ev_sz = sysevent_get_size(eventbuf[dispatch_buf]);
10497c478bd9Sstevel@tonic-gate 	new_ev = calloc(1, ev_sz);
10507c478bd9Sstevel@tonic-gate 	if (new_ev == NULL) {
10517c478bd9Sstevel@tonic-gate 		free(ev_comp);
10527c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&mod_unload_lock);
10537c478bd9Sstevel@tonic-gate 		syseventd_print(1, "Can not allocate new event buffer "
10547c478bd9Sstevel@tonic-gate 		"for event id 0X%llx\n", eid.eid_seq);
10557c478bd9Sstevel@tonic-gate 		return (EAGAIN);
10567c478bd9Sstevel@tonic-gate 	}
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/*
10607c478bd9Sstevel@tonic-gate 	 * For long messages, copy additional data from kernel
10617c478bd9Sstevel@tonic-gate 	 */
10627c478bd9Sstevel@tonic-gate 	if (ev_sz > LOGEVENT_BUFSIZE) {
10637c478bd9Sstevel@tonic-gate 		int ret = 0;
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		/* Ok to release eventbuf for next event buffer from kernel */
10667c478bd9Sstevel@tonic-gate 		(void) sema_post(&sema_eventbuf);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_MODCTL_RETRY; ++i) {
10697c478bd9Sstevel@tonic-gate 			if ((ret = modctl(MODEVENTS,
1070b3a85157Sjg 			    (uintptr_t)MODEVENTS_GETDATA,
1071b3a85157Sjg 			    (uintptr_t)&eid,
1072b3a85157Sjg 			    (uintptr_t)ev_sz,
1073b3a85157Sjg 			    (uintptr_t)new_ev, 0))
1074b3a85157Sjg 			    == 0)
10757c478bd9Sstevel@tonic-gate 				break;
10767c478bd9Sstevel@tonic-gate 			else
10777c478bd9Sstevel@tonic-gate 				(void) sleep(1);
10787c478bd9Sstevel@tonic-gate 		}
10797c478bd9Sstevel@tonic-gate 		if (ret) {
10807c478bd9Sstevel@tonic-gate 			syseventd_print(1, "GET_DATA failed for 0X%llx:%llx\n",
10817c478bd9Sstevel@tonic-gate 			    eid.eid_ts, eid.eid_seq);
10827c478bd9Sstevel@tonic-gate 			free(new_ev);
10837c478bd9Sstevel@tonic-gate 			free(ev_comp);
10847c478bd9Sstevel@tonic-gate 			(void) rw_unlock(&mod_unload_lock);
10857c478bd9Sstevel@tonic-gate 			return (EAGAIN);
10867c478bd9Sstevel@tonic-gate 		}
10877c478bd9Sstevel@tonic-gate 	} else {
10887c478bd9Sstevel@tonic-gate 		(void) bcopy(eventbuf[dispatch_buf], new_ev, ev_sz);
10897c478bd9Sstevel@tonic-gate 		/* Ok to release eventbuf for next event buffer from kernel */
10907c478bd9Sstevel@tonic-gate 		(void) sema_post(&sema_eventbuf);
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 	/*
10957c478bd9Sstevel@tonic-gate 	 * Deliver a copy of eventbuf to clients so
10967c478bd9Sstevel@tonic-gate 	 * eventbuf can be used for the next message
10977c478bd9Sstevel@tonic-gate 	 */
10987c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_SLM; ++i) {
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		/* Don't bother for suspended or unloaded clients */
11017c478bd9Sstevel@tonic-gate 		if (!SE_CLIENT_IS_LOADED(sysevent_client_tbl[i]) ||
11027c478bd9Sstevel@tonic-gate 		    SE_CLIENT_IS_SUSPENDED(sysevent_client_tbl[i]))
11037c478bd9Sstevel@tonic-gate 			continue;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 		/*
11067c478bd9Sstevel@tonic-gate 		 * Allocate event dispatch queue entry.  All queue entries
11077c478bd9Sstevel@tonic-gate 		 * are freed by the event completion thread as client
11087c478bd9Sstevel@tonic-gate 		 * delivery completes.
11097c478bd9Sstevel@tonic-gate 		 */
11107c478bd9Sstevel@tonic-gate 		dispatchq = (struct event_dispatchq *)malloc(
1111b3a85157Sjg 		    sizeof (struct event_dispatchq));
11127c478bd9Sstevel@tonic-gate 		if (dispatchq == NULL) {
11137c478bd9Sstevel@tonic-gate 			syseventd_print(1, "Can not allocate dispatch q "
11147c478bd9Sstevel@tonic-gate 			"for event id 0X%llx client %d\n", eid.eid_seq, i);
11157c478bd9Sstevel@tonic-gate 			continue;
11167c478bd9Sstevel@tonic-gate 		}
11177c478bd9Sstevel@tonic-gate 		dispatchq->next = NULL;
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		/* Initiate client delivery */
11207c478bd9Sstevel@tonic-gate 		d_pkg = client_deliver_event(sysevent_client_tbl[i],
1121b3a85157Sjg 		    new_ev, &ev_comp->client_sema);
11227c478bd9Sstevel@tonic-gate 		if (d_pkg == NULL) {
11237c478bd9Sstevel@tonic-gate 			syseventd_print(1, "Can not allocate dispatch "
1124b3a85157Sjg 			    "package for event id 0X%llx client %d\n",
1125b3a85157Sjg 			    eid.eid_seq, i);
11267c478bd9Sstevel@tonic-gate 			free(dispatchq);
11277c478bd9Sstevel@tonic-gate 			continue;
11287c478bd9Sstevel@tonic-gate 		}
11297c478bd9Sstevel@tonic-gate 		dispatchq->d_pkg = d_pkg;
11307c478bd9Sstevel@tonic-gate 		++client_count;
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		if (ev_comp->dispatch_list == NULL) {
11337c478bd9Sstevel@tonic-gate 			ev_comp->dispatch_list = dispatchq;
11347c478bd9Sstevel@tonic-gate 			client_list = dispatchq;
11357c478bd9Sstevel@tonic-gate 		} else {
11367c478bd9Sstevel@tonic-gate 			client_list->next = dispatchq;
11377c478bd9Sstevel@tonic-gate 			client_list = client_list->next;
11387c478bd9Sstevel@tonic-gate 		}
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate 
11417c478bd9Sstevel@tonic-gate 	ev_comp->client_count = client_count;
11427c478bd9Sstevel@tonic-gate 	ev_comp->ev = new_ev;
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&ev_comp_lock);
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	if (event_compq == NULL) {
11477c478bd9Sstevel@tonic-gate 		syseventd_print(3, "Wakeup event completion thread for "
11487c478bd9Sstevel@tonic-gate 		    "id 0X%llx\n", eid.eid_seq);
11497c478bd9Sstevel@tonic-gate 		event_compq = ev_comp;
11507c478bd9Sstevel@tonic-gate 		(void) cond_signal(&event_comp_cv);
11517c478bd9Sstevel@tonic-gate 	} else {
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate 		/* Add entry to the end of the event completion queue */
11547c478bd9Sstevel@tonic-gate 		tmp = event_compq;
11557c478bd9Sstevel@tonic-gate 		while (tmp->next != NULL)
11567c478bd9Sstevel@tonic-gate 			tmp = tmp->next;
11577c478bd9Sstevel@tonic-gate 		tmp->next = ev_comp;
11587c478bd9Sstevel@tonic-gate 		syseventd_print(3, "event added to completion queue for "
11597c478bd9Sstevel@tonic-gate 		    "id 0X%llx\n", eid.eid_seq);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&ev_comp_lock);
11627c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&mod_unload_lock);
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	return (0);
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate #define	MODULE_DIR_HW	"/usr/platform/%s/lib/sysevent/modules/"
11687c478bd9Sstevel@tonic-gate #define	MODULE_DIR_GEN	"/usr/lib/sysevent/modules/"
11697c478bd9Sstevel@tonic-gate #define	MOD_DIR_NUM	3
11707c478bd9Sstevel@tonic-gate static char dirname[MOD_DIR_NUM][MAXPATHLEN];
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate static char *
dir_num2name(int dirnum)11737c478bd9Sstevel@tonic-gate dir_num2name(int dirnum)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	char infobuf[MAXPATHLEN];
11767c478bd9Sstevel@tonic-gate 
11777c478bd9Sstevel@tonic-gate 	if (dirnum >= MOD_DIR_NUM)
11787c478bd9Sstevel@tonic-gate 		return (NULL);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 	if (dirname[0][0] == '\0') {
11817c478bd9Sstevel@tonic-gate 		if (sysinfo(SI_PLATFORM, infobuf, MAXPATHLEN) == -1) {
11827c478bd9Sstevel@tonic-gate 			syseventd_print(1, "dir_num2name: "
1183b3a85157Sjg 			    "sysinfo error %s\n", strerror(errno));
11847c478bd9Sstevel@tonic-gate 			return (NULL);
11857c478bd9Sstevel@tonic-gate 		} else if (snprintf(dirname[0], sizeof (dirname[0]),
11867c478bd9Sstevel@tonic-gate 		    MODULE_DIR_HW, infobuf) >= sizeof (dirname[0])) {
11877c478bd9Sstevel@tonic-gate 			syseventd_print(1, "dir_num2name: "
1188b3a85157Sjg 			    "platform name too long: %s\n",
1189b3a85157Sjg 			    infobuf);
11907c478bd9Sstevel@tonic-gate 			return (NULL);
11917c478bd9Sstevel@tonic-gate 		}
11927c478bd9Sstevel@tonic-gate 		if (sysinfo(SI_MACHINE, infobuf, MAXPATHLEN) == -1) {
11937c478bd9Sstevel@tonic-gate 			syseventd_print(1, "dir_num2name: "
1194b3a85157Sjg 			    "sysinfo error %s\n", strerror(errno));
11957c478bd9Sstevel@tonic-gate 			return (NULL);
11967c478bd9Sstevel@tonic-gate 		} else if (snprintf(dirname[1], sizeof (dirname[1]),
11977c478bd9Sstevel@tonic-gate 		    MODULE_DIR_HW, infobuf) >= sizeof (dirname[1])) {
11987c478bd9Sstevel@tonic-gate 			syseventd_print(1, "dir_num2name: "
1199b3a85157Sjg 			    "machine name too long: %s\n",
1200b3a85157Sjg 			    infobuf);
12017c478bd9Sstevel@tonic-gate 			return (NULL);
12027c478bd9Sstevel@tonic-gate 		}
12037c478bd9Sstevel@tonic-gate 		(void) strcpy(dirname[2], MODULE_DIR_GEN);
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	return (dirname[dirnum]);
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate /*
12117c478bd9Sstevel@tonic-gate  * load_modules - Load modules found in the common syseventd module directories
12127c478bd9Sstevel@tonic-gate  *		Modules that do not provide valid interfaces are rejected.
12137c478bd9Sstevel@tonic-gate  */
12147c478bd9Sstevel@tonic-gate static void
load_modules(char * dirname)12157c478bd9Sstevel@tonic-gate load_modules(char *dirname)
12167c478bd9Sstevel@tonic-gate {
12177c478bd9Sstevel@tonic-gate 	int client_id;
12187c478bd9Sstevel@tonic-gate 	DIR *mod_dir;
12197c478bd9Sstevel@tonic-gate 	module_t *mod;
12204bc0a2efScasper 	struct dirent *entp;
12217c478bd9Sstevel@tonic-gate 	struct slm_mod_ops *mod_ops;
12227c478bd9Sstevel@tonic-gate 	struct sysevent_client *scp;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	if (dirname == NULL)
12257c478bd9Sstevel@tonic-gate 		return;
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	/* Return silently if module directory does not exist */
12287c478bd9Sstevel@tonic-gate 	if ((mod_dir = opendir(dirname)) == NULL) {
12297c478bd9Sstevel@tonic-gate 		syseventd_print(1, "Unable to open module directory %s: %s\n",
1230b3a85157Sjg 		    dirname, strerror(errno));
12317c478bd9Sstevel@tonic-gate 		return;
12327c478bd9Sstevel@tonic-gate 	}
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 	syseventd_print(3, "loading modules from %s\n", dirname);
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 	/*
12377c478bd9Sstevel@tonic-gate 	 * Go through directory, looking for files ending with .so
12387c478bd9Sstevel@tonic-gate 	 */
12394bc0a2efScasper 	while ((entp = readdir(mod_dir)) != NULL) {
12407c478bd9Sstevel@tonic-gate 		void *dlh, *f;
12417c478bd9Sstevel@tonic-gate 		char *tmp, modpath[MAXPATHLEN];
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 		if (((tmp = strstr(entp->d_name, MODULE_SUFFIX)) == NULL) ||
12447c478bd9Sstevel@tonic-gate 		    (tmp[strlen(MODULE_SUFFIX)] != '\0')) {
12457c478bd9Sstevel@tonic-gate 			continue;
12467c478bd9Sstevel@tonic-gate 		}
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 		if (snprintf(modpath, sizeof (modpath), "%s%s",
12497c478bd9Sstevel@tonic-gate 		    dirname, entp->d_name) >= sizeof (modpath)) {
12507c478bd9Sstevel@tonic-gate 			syseventd_err_print(INIT_PATH_ERR, modpath);
12517c478bd9Sstevel@tonic-gate 			continue;
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 		if ((dlh = dlopen(modpath, RTLD_LAZY)) == NULL) {
12547c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_DLOPEN_ERR,
1255b3a85157Sjg 			    modpath, dlerror());
12567c478bd9Sstevel@tonic-gate 			continue;
12577c478bd9Sstevel@tonic-gate 		} else if ((f = dlsym(dlh, EVENT_INIT)) == NULL) {
12587c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_NO_INIT,
1259b3a85157Sjg 			    modpath, dlerror());
12607c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
12617c478bd9Sstevel@tonic-gate 			continue;
12627c478bd9Sstevel@tonic-gate 		}
12637c478bd9Sstevel@tonic-gate 
12647c478bd9Sstevel@tonic-gate 		mod = malloc(sizeof (*mod));
12657c478bd9Sstevel@tonic-gate 		if (mod == NULL) {
12667c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod",
1267b3a85157Sjg 			    strerror(errno));
12687c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
12697c478bd9Sstevel@tonic-gate 			continue;
12707c478bd9Sstevel@tonic-gate 		}
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 		mod->name = strdup(entp->d_name);
12737c478bd9Sstevel@tonic-gate 		if (mod->name == NULL) {
12747c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_ALLOC_ERR, "mod->name",
1275b3a85157Sjg 			    strerror(errno));
12767c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
12777c478bd9Sstevel@tonic-gate 			free(mod);
12787c478bd9Sstevel@tonic-gate 			continue;
12797c478bd9Sstevel@tonic-gate 		}
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate 		mod->dlhandle = dlh;
12827c478bd9Sstevel@tonic-gate 		mod->event_mod_init = (struct slm_mod_ops *(*)())f;
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 		/* load in other module functions */
12857c478bd9Sstevel@tonic-gate 		mod->event_mod_fini = (void (*)())dlsym(dlh, EVENT_FINI);
12867c478bd9Sstevel@tonic-gate 		if (mod->event_mod_fini == NULL) {
12877c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_DLSYM_ERR, mod->name,
1288b3a85157Sjg 			    dlerror());
12897c478bd9Sstevel@tonic-gate 			free(mod->name);
12907c478bd9Sstevel@tonic-gate 			free(mod);
12917c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
12927c478bd9Sstevel@tonic-gate 			continue;
12937c478bd9Sstevel@tonic-gate 		}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 		/* Call module init routine */
12967c478bd9Sstevel@tonic-gate 		if ((mod_ops = mod->event_mod_init()) == NULL) {
12977c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_EINVAL, mod->name);
12987c478bd9Sstevel@tonic-gate 			free(mod->name);
12997c478bd9Sstevel@tonic-gate 			free(mod);
13007c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
13017c478bd9Sstevel@tonic-gate 			continue;
13027c478bd9Sstevel@tonic-gate 		}
13037c478bd9Sstevel@tonic-gate 		if (mod_ops->major_version != SE_MAJOR_VERSION) {
13047c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_VERSION_MISMATCH,
1305b3a85157Sjg 			    mod->name, SE_MAJOR_VERSION,
1306b3a85157Sjg 			    mod_ops->major_version);
13077c478bd9Sstevel@tonic-gate 			mod->event_mod_fini();
13087c478bd9Sstevel@tonic-gate 			free(mod->name);
13097c478bd9Sstevel@tonic-gate 			free(mod);
13107c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
13117c478bd9Sstevel@tonic-gate 			continue;
13127c478bd9Sstevel@tonic-gate 		}
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 		mod->deliver_event = mod_ops->deliver_event;
13157c478bd9Sstevel@tonic-gate 		/* Add module entry to client list */
13167c478bd9Sstevel@tonic-gate 		if ((client_id = insert_client((void *)mod, SLM_CLIENT,
1317b3a85157Sjg 		    (mod_ops->retry_limit <= SE_MAX_RETRY_LIMIT ?
1318b3a85157Sjg 		    mod_ops->retry_limit : SE_MAX_RETRY_LIMIT))) < 0) {
13197c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client",
1320b3a85157Sjg 			    strerror(errno));
13217c478bd9Sstevel@tonic-gate 			mod->event_mod_fini();
13227c478bd9Sstevel@tonic-gate 			free(mod->name);
13237c478bd9Sstevel@tonic-gate 			free(mod);
13247c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
13257c478bd9Sstevel@tonic-gate 			continue;
13267c478bd9Sstevel@tonic-gate 		}
13277c478bd9Sstevel@tonic-gate 
13287c478bd9Sstevel@tonic-gate 		scp = sysevent_client_tbl[client_id];
13297c478bd9Sstevel@tonic-gate 		++concurrency_level;
13307c478bd9Sstevel@tonic-gate 		(void) thr_setconcurrency(concurrency_level);
13315b784b07SToomas Soome 		if (thr_create(NULL, 0, client_deliver_event_thr,
13325b784b07SToomas Soome 		    scp, THR_BOUND, &scp->tid) != 0) {
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 			syseventd_err_print(LOAD_MOD_ALLOC_ERR, "insert_client",
1335b3a85157Sjg 			    strerror(errno));
13367c478bd9Sstevel@tonic-gate 			mod->event_mod_fini();
13377c478bd9Sstevel@tonic-gate 			free(mod->name);
13387c478bd9Sstevel@tonic-gate 			free(mod);
13397c478bd9Sstevel@tonic-gate 			(void) dlclose(dlh);
13407c478bd9Sstevel@tonic-gate 			continue;
13417c478bd9Sstevel@tonic-gate 		}
13427c478bd9Sstevel@tonic-gate 		scp->client_flags |= SE_CLIENT_THR_RUNNING;
13437c478bd9Sstevel@tonic-gate 
13447c478bd9Sstevel@tonic-gate 		syseventd_print(3, "loaded module %s\n", entp->d_name);
13457c478bd9Sstevel@tonic-gate 	}
13467c478bd9Sstevel@tonic-gate 
13477c478bd9Sstevel@tonic-gate 	(void) closedir(mod_dir);
13487c478bd9Sstevel@tonic-gate 	syseventd_print(3, "modules loaded\n");
13497c478bd9Sstevel@tonic-gate }
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate /*
13527c478bd9Sstevel@tonic-gate  * unload_modules - modules are unloaded prior to graceful shutdown or
13537c478bd9Sstevel@tonic-gate  *			before restarting the daemon upon receipt of
13547c478bd9Sstevel@tonic-gate  *			SIGHUP.
13557c478bd9Sstevel@tonic-gate  */
13567c478bd9Sstevel@tonic-gate static void
unload_modules(int sig)13577c478bd9Sstevel@tonic-gate unload_modules(int sig)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate 	int			i, count, done;
13607c478bd9Sstevel@tonic-gate 	module_t		*mod;
13617c478bd9Sstevel@tonic-gate 	struct sysevent_client	*scp;
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	/*
13647c478bd9Sstevel@tonic-gate 	 * unload modules that are ready, skip those that have not
13657c478bd9Sstevel@tonic-gate 	 * drained their event queues.
13667c478bd9Sstevel@tonic-gate 	 */
13677c478bd9Sstevel@tonic-gate 	count = done = 0;
13687c478bd9Sstevel@tonic-gate 	while (done < MAX_SLM) {
13697c478bd9Sstevel@tonic-gate 		/* Don't wait indefinitely for unresponsive clients */
13707c478bd9Sstevel@tonic-gate 		if (sig != SIGHUP && count > SE_TIMEOUT) {
13717c478bd9Sstevel@tonic-gate 			break;
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 		done = 0;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 		/* Shutdown clients */
13777c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_SLM; ++i) {
13787c478bd9Sstevel@tonic-gate 			scp = sysevent_client_tbl[i];
13797c478bd9Sstevel@tonic-gate 			if (mutex_trylock(&scp->client_lock) == 0) {
13807c478bd9Sstevel@tonic-gate 				if (scp->client_type != SLM_CLIENT ||
1381b3a85157Sjg 				    scp->client_data == NULL) {
13827c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&scp->client_lock);
13837c478bd9Sstevel@tonic-gate 					done++;
13847c478bd9Sstevel@tonic-gate 					continue;
13857c478bd9Sstevel@tonic-gate 				}
13867c478bd9Sstevel@tonic-gate 			} else {
13877c478bd9Sstevel@tonic-gate 				syseventd_print(3, "Skipping unload of "
1388b3a85157Sjg 				    "client %d: client locked\n",
1389b3a85157Sjg 				    scp->client_num);
13907c478bd9Sstevel@tonic-gate 				continue;
13917c478bd9Sstevel@tonic-gate 			}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 			/*
13947c478bd9Sstevel@tonic-gate 			 * Drain the eventq and wait for delivery thread to
13957c478bd9Sstevel@tonic-gate 			 * cleanly exit
13967c478bd9Sstevel@tonic-gate 			 */
13977c478bd9Sstevel@tonic-gate 			drain_eventq(scp, EAGAIN);
13987c478bd9Sstevel@tonic-gate 			(void) cond_signal(&scp->client_cv);
13997c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&scp->client_lock);
14007c478bd9Sstevel@tonic-gate 			(void) thr_join(scp->tid, NULL, NULL);
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate 			/*
14037c478bd9Sstevel@tonic-gate 			 * It is now safe to unload the module
14047c478bd9Sstevel@tonic-gate 			 */
14057c478bd9Sstevel@tonic-gate 			mod = (module_t *)scp->client_data;
14067c478bd9Sstevel@tonic-gate 			syseventd_print(2, "Unload %s\n", mod->name);
14077c478bd9Sstevel@tonic-gate 			mod->event_mod_fini();
14087c478bd9Sstevel@tonic-gate 			(void) dlclose(mod->dlhandle);
14097c478bd9Sstevel@tonic-gate 			free(mod->name);
14107c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&client_tbl_lock);
14117c478bd9Sstevel@tonic-gate 			delete_client(i);
14127c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&client_tbl_lock);
14137c478bd9Sstevel@tonic-gate 			++done;
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 		}
14167c478bd9Sstevel@tonic-gate 		++count;
14177c478bd9Sstevel@tonic-gate 		(void) sleep(1);
14187c478bd9Sstevel@tonic-gate 	}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	/*
14217c478bd9Sstevel@tonic-gate 	 * Wait for event completions
14227c478bd9Sstevel@tonic-gate 	 */
14237c478bd9Sstevel@tonic-gate 	syseventd_print(2, "waiting for event completions\n");
14247c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&ev_comp_lock);
14257c478bd9Sstevel@tonic-gate 	while (event_compq != NULL) {
14267c478bd9Sstevel@tonic-gate 		(void) cond_wait(&event_comp_cv, &ev_comp_lock);
14277c478bd9Sstevel@tonic-gate 	}
14287c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&ev_comp_lock);
14297c478bd9Sstevel@tonic-gate }
14307c478bd9Sstevel@tonic-gate 
14317c478bd9Sstevel@tonic-gate /*
14327c478bd9Sstevel@tonic-gate  * syseventd_init - Called at daemon (re)start-up time to load modules
14337c478bd9Sstevel@tonic-gate  *			and kickstart the kernel delivery engine.
14347c478bd9Sstevel@tonic-gate  */
14357c478bd9Sstevel@tonic-gate static void
syseventd_init()14367c478bd9Sstevel@tonic-gate syseventd_init()
14377c478bd9Sstevel@tonic-gate {
14387c478bd9Sstevel@tonic-gate 	int i, fd;
14397c478bd9Sstevel@tonic-gate 	char local_door_file[PATH_MAX + 1];
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	fini_pending = 0;
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	concurrency_level = MIN_CONCURRENCY_LEVEL;
14447c478bd9Sstevel@tonic-gate 	(void) thr_setconcurrency(concurrency_level);
14457c478bd9Sstevel@tonic-gate 
14467c478bd9Sstevel@tonic-gate 	/*
14477c478bd9Sstevel@tonic-gate 	 * Load client modules for event delivering
14487c478bd9Sstevel@tonic-gate 	 */
14497c478bd9Sstevel@tonic-gate 	for (i = 0; i < MOD_DIR_NUM; ++i) {
14507c478bd9Sstevel@tonic-gate 		load_modules(dir_num2name(i));
14517c478bd9Sstevel@tonic-gate 	}
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate 	/*
14547c478bd9Sstevel@tonic-gate 	 * Create kernel delivery door service
14557c478bd9Sstevel@tonic-gate 	 */
14567c478bd9Sstevel@tonic-gate 	syseventd_print(8, "Create a door for kernel upcalls\n");
14577c478bd9Sstevel@tonic-gate 	if (snprintf(local_door_file, sizeof (local_door_file), "%s%s",
14587c478bd9Sstevel@tonic-gate 	    root_dir, LOGEVENT_DOOR_UPCALL) >= sizeof (local_door_file)) {
14597c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_PATH_ERR, local_door_file);
14607c478bd9Sstevel@tonic-gate 		syseventd_exit(5);
14617c478bd9Sstevel@tonic-gate 	}
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	/*
14647c478bd9Sstevel@tonic-gate 	 * Remove door file for robustness.
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 	if (unlink(local_door_file) != 0)
14677c478bd9Sstevel@tonic-gate 		syseventd_print(8, "Unlink of %s failed.\n", local_door_file);
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	fd = open(local_door_file, O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
14707c478bd9Sstevel@tonic-gate 	if ((fd == -1) && (errno != EEXIST)) {
14717c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_OPEN_DOOR_ERR, strerror(errno));
14727c478bd9Sstevel@tonic-gate 		syseventd_exit(5);
14737c478bd9Sstevel@tonic-gate 	}
14747c478bd9Sstevel@tonic-gate 	(void) close(fd);
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	upcall_door = door_create(door_upcall, NULL,
14777c478bd9Sstevel@tonic-gate 	    DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
14787c478bd9Sstevel@tonic-gate 	if (upcall_door == -1) {
14797c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_CREATE_DOOR_ERR, strerror(errno));
14807c478bd9Sstevel@tonic-gate 		syseventd_exit(5);
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	(void) fdetach(local_door_file);
14847c478bd9Sstevel@tonic-gate retry:
14857c478bd9Sstevel@tonic-gate 	if (fattach(upcall_door, local_door_file) != 0) {
14867c478bd9Sstevel@tonic-gate 		if (errno == EBUSY)
14877c478bd9Sstevel@tonic-gate 			goto retry;
14887c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_FATTACH_ERR, strerror(errno));
14897c478bd9Sstevel@tonic-gate 		(void) door_revoke(upcall_door);
14907c478bd9Sstevel@tonic-gate 		syseventd_exit(5);
14917c478bd9Sstevel@tonic-gate 	}
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate 	/*
14947c478bd9Sstevel@tonic-gate 	 * Tell kernel the door name and start delivery
14957c478bd9Sstevel@tonic-gate 	 */
14967c478bd9Sstevel@tonic-gate 	syseventd_print(2,
14977c478bd9Sstevel@tonic-gate 	    "local_door_file = %s\n", local_door_file);
14987c478bd9Sstevel@tonic-gate 	if (modctl(MODEVENTS,
14997c478bd9Sstevel@tonic-gate 	    (uintptr_t)MODEVENTS_SET_DOOR_UPCALL_FILENAME,
15007c478bd9Sstevel@tonic-gate 	    (uintptr_t)local_door_file, NULL, NULL, 0) < 0) {
15017c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_DOOR_NAME_ERR, strerror(errno));
15027c478bd9Sstevel@tonic-gate 		syseventd_exit(6);
15037c478bd9Sstevel@tonic-gate 	}
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	door_upcall_retval = 0;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 	if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_FLUSH, NULL, NULL, NULL, 0)
1508b3a85157Sjg 	    < 0) {
15097c478bd9Sstevel@tonic-gate 		syseventd_err_print(KERNEL_REPLAY_ERR, strerror(errno));
15107c478bd9Sstevel@tonic-gate 		syseventd_exit(7);
15117c478bd9Sstevel@tonic-gate 	}
15127c478bd9Sstevel@tonic-gate }
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate /*
15157c478bd9Sstevel@tonic-gate  * syseventd_fini - shut down daemon, but do not exit
15167c478bd9Sstevel@tonic-gate  */
15177c478bd9Sstevel@tonic-gate static void
syseventd_fini(int sig)15187c478bd9Sstevel@tonic-gate syseventd_fini(int sig)
15197c478bd9Sstevel@tonic-gate {
15207c478bd9Sstevel@tonic-gate 	/*
15217c478bd9Sstevel@tonic-gate 	 * Indicate that event queues should be drained and no
15227c478bd9Sstevel@tonic-gate 	 * additional events be accepted
15237c478bd9Sstevel@tonic-gate 	 */
15247c478bd9Sstevel@tonic-gate 	fini_pending = 1;
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	/* Close the kernel event door to halt delivery */
15277c478bd9Sstevel@tonic-gate 	(void) door_revoke(upcall_door);
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	syseventd_print(1, "Unloading modules\n");
15307c478bd9Sstevel@tonic-gate 	(void) rw_wrlock(&mod_unload_lock);
15317c478bd9Sstevel@tonic-gate 	unload_modules(sig);
15327c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&mod_unload_lock);
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate }
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate  * enter_daemon_lock - lock the daemon file lock
15387c478bd9Sstevel@tonic-gate  *
15397c478bd9Sstevel@tonic-gate  * Use an advisory lock to ensure that only one daemon process is active
15407c478bd9Sstevel@tonic-gate  * in the system at any point in time.	If the lock is held by another
15417c478bd9Sstevel@tonic-gate  * process, do not block but return the pid owner of the lock to the
15427c478bd9Sstevel@tonic-gate  * caller immediately.	The lock is cleared if the holding daemon process
15437c478bd9Sstevel@tonic-gate  * exits for any reason even if the lock file remains, so the daemon can
15447c478bd9Sstevel@tonic-gate  * be restarted if necessary.  The lock file is DAEMON_LOCK_FILE.
15457c478bd9Sstevel@tonic-gate  */
15467c478bd9Sstevel@tonic-gate static pid_t
enter_daemon_lock(void)15477c478bd9Sstevel@tonic-gate enter_daemon_lock(void)
15487c478bd9Sstevel@tonic-gate {
15497c478bd9Sstevel@tonic-gate 	struct flock	lock;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	syseventd_print(8, "enter_daemon_lock: lock file = %s\n",
1552b3a85157Sjg 	    DAEMON_LOCK_FILE);
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	if (snprintf(local_lock_file, sizeof (local_lock_file), "%s%s",
15557c478bd9Sstevel@tonic-gate 	    root_dir, DAEMON_LOCK_FILE) >= sizeof (local_lock_file)) {
15567c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_PATH_ERR, local_lock_file);
15577c478bd9Sstevel@tonic-gate 		syseventd_exit(8);
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 	daemon_lock_fd = open(local_lock_file, O_CREAT|O_RDWR, 0644);
15607c478bd9Sstevel@tonic-gate 	if (daemon_lock_fd < 0) {
15617c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_LOCK_OPEN_ERR,
1562b3a85157Sjg 		    local_lock_file, strerror(errno));
15637c478bd9Sstevel@tonic-gate 		syseventd_exit(8);
15647c478bd9Sstevel@tonic-gate 	}
15657c478bd9Sstevel@tonic-gate 
15667c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
15677c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
15687c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
15697c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
15727c478bd9Sstevel@tonic-gate 		if (fcntl(daemon_lock_fd, F_GETLK, &lock) == -1) {
15737c478bd9Sstevel@tonic-gate 			syseventd_err_print(INIT_LOCK_ERR,
1574b3a85157Sjg 			    local_lock_file, strerror(errno));
15757c478bd9Sstevel@tonic-gate 			exit(2);
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 		return (lock.l_pid);
15787c478bd9Sstevel@tonic-gate 	}
15797c478bd9Sstevel@tonic-gate 	hold_daemon_lock = 1;
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	return (getpid());
15827c478bd9Sstevel@tonic-gate }
15837c478bd9Sstevel@tonic-gate 
15847c478bd9Sstevel@tonic-gate /*
15857c478bd9Sstevel@tonic-gate  * exit_daemon_lock - release the daemon file lock
15867c478bd9Sstevel@tonic-gate  */
15877c478bd9Sstevel@tonic-gate static void
exit_daemon_lock(void)15887c478bd9Sstevel@tonic-gate exit_daemon_lock(void)
15897c478bd9Sstevel@tonic-gate {
15907c478bd9Sstevel@tonic-gate 	struct flock lock;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
15937c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
15947c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
15957c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	if (fcntl(daemon_lock_fd, F_SETLK, &lock) == -1) {
15987c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_UNLOCK_ERR,
1599b3a85157Sjg 		    local_lock_file, strerror(errno));
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	if (close(daemon_lock_fd) == -1) {
16037c478bd9Sstevel@tonic-gate 		syseventd_err_print(INIT_LOCK_CLOSE_ERR,
1604b3a85157Sjg 		    local_lock_file, strerror(errno));
16057c478bd9Sstevel@tonic-gate 		exit(-1);
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate }
16087c478bd9Sstevel@tonic-gate 
16097c478bd9Sstevel@tonic-gate /*
16107c478bd9Sstevel@tonic-gate  * syseventd_err_print - print error messages to the terminal if not
16117c478bd9Sstevel@tonic-gate  *			yet daemonized or to syslog.
16127c478bd9Sstevel@tonic-gate  */
16137c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
16147c478bd9Sstevel@tonic-gate void
syseventd_err_print(char * message,...)16157c478bd9Sstevel@tonic-gate syseventd_err_print(char *message, ...)
16167c478bd9Sstevel@tonic-gate {
16177c478bd9Sstevel@tonic-gate 	va_list ap;
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&err_mutex);
16207c478bd9Sstevel@tonic-gate 	va_start(ap, message);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	if (logflag) {
16237c478bd9Sstevel@tonic-gate 		(void) vsyslog(LOG_ERR, message, ap);
16247c478bd9Sstevel@tonic-gate 	} else {
16257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", prog);
16267c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, message, ap);
16277c478bd9Sstevel@tonic-gate 	}
16287c478bd9Sstevel@tonic-gate 	va_end(ap);
16297c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&err_mutex);
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate  * syseventd_print -  print messages to the terminal or to syslog
16347c478bd9Sstevel@tonic-gate  *			the following levels are implemented:
16357c478bd9Sstevel@tonic-gate  *
16367c478bd9Sstevel@tonic-gate  * 1 - transient errors that does not affect normal program flow
16377c478bd9Sstevel@tonic-gate  * 2 - upcall/dispatch interaction
16387c478bd9Sstevel@tonic-gate  * 3 - program flow trace as each message goes through the daemon
16397c478bd9Sstevel@tonic-gate  * 8 - all the nit-gritty details of startup and shutdown
16407c478bd9Sstevel@tonic-gate  * 9 - very verbose event flow tracing (no daemonization of syseventd)
16417c478bd9Sstevel@tonic-gate  *
16427c478bd9Sstevel@tonic-gate  */
16437c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
16447c478bd9Sstevel@tonic-gate void
syseventd_print(int level,char * message,...)16457c478bd9Sstevel@tonic-gate syseventd_print(int level, char *message, ...)
16467c478bd9Sstevel@tonic-gate {
16477c478bd9Sstevel@tonic-gate 	va_list ap;
16487c478bd9Sstevel@tonic-gate 	static int newline = 1;
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate 	if (level > debug_level) {
16517c478bd9Sstevel@tonic-gate 		return;
16527c478bd9Sstevel@tonic-gate 	}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&err_mutex);
16557c478bd9Sstevel@tonic-gate 	va_start(ap, message);
16567c478bd9Sstevel@tonic-gate 	if (logflag) {
16577c478bd9Sstevel@tonic-gate 		(void) syslog(LOG_DEBUG, "%s[%ld]: ",
1658b3a85157Sjg 		    prog, getpid());
16597c478bd9Sstevel@tonic-gate 		(void) vsyslog(LOG_DEBUG, message, ap);
16607c478bd9Sstevel@tonic-gate 	} else {
16617c478bd9Sstevel@tonic-gate 		if (newline) {
16627c478bd9Sstevel@tonic-gate 			(void) fprintf(stdout, "%s[%ld]: ",
1663b3a85157Sjg 			    prog, getpid());
16647c478bd9Sstevel@tonic-gate 			(void) vfprintf(stdout, message, ap);
16657c478bd9Sstevel@tonic-gate 		} else {
16667c478bd9Sstevel@tonic-gate 			(void) vfprintf(stdout, message, ap);
16677c478bd9Sstevel@tonic-gate 		}
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 	if (message[strlen(message)-1] == '\n') {
16707c478bd9Sstevel@tonic-gate 		newline = 1;
16717c478bd9Sstevel@tonic-gate 	} else {
16727c478bd9Sstevel@tonic-gate 		newline = 0;
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 	va_end(ap);
16757c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&err_mutex);
16767c478bd9Sstevel@tonic-gate }
1677