xref: /illumos-gate/usr/src/cmd/syseventd/modules/sysevent_conf_mod/sysevent_conf_mod.c (revision 4bc0a2ef2b7ba50a7a717e7ddbf31472ad28e358)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*4bc0a2efScasper  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * sysevent_conf_mod - syseventd daemon sysevent.conf module
317c478bd9Sstevel@tonic-gate  *
327c478bd9Sstevel@tonic-gate  *	This module provides a configuration file registration
337c478bd9Sstevel@tonic-gate  *	mechanism whereby event producers can define an event
347c478bd9Sstevel@tonic-gate  *	specification to be matched against events, with an
357c478bd9Sstevel@tonic-gate  *	associated command line to be invoked for each matching event.
367c478bd9Sstevel@tonic-gate  *	It includes a simple macro capability for flexibility in
377c478bd9Sstevel@tonic-gate  *	generating arbitrary command line formats from event-associated
387c478bd9Sstevel@tonic-gate  *	data, and a user specification so that commands can be invoked
397c478bd9Sstevel@tonic-gate  *	with reduced privileges to eliminate a security risk.
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  *	sysevent.conf files contain event specifications and associated
427c478bd9Sstevel@tonic-gate  *	command path and optional arguments.  System events received
437c478bd9Sstevel@tonic-gate  *	from the kernel by the sysevent daemon, syseventd, are
447c478bd9Sstevel@tonic-gate  *	compared against the event specifications in the sysevent.conf
457c478bd9Sstevel@tonic-gate  *	files.  The command as specified by pathname and arguments
467c478bd9Sstevel@tonic-gate  *	is invoked for each matching event.
477c478bd9Sstevel@tonic-gate  *
487c478bd9Sstevel@tonic-gate  *	All sysevent.conf files reside in /etc/sysevent/config.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <stdio.h>
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate #include <unistd.h>
567c478bd9Sstevel@tonic-gate #include <stdarg.h>
577c478bd9Sstevel@tonic-gate #include <stdlib.h>
587c478bd9Sstevel@tonic-gate #include <string.h>
597c478bd9Sstevel@tonic-gate #include <strings.h>
607c478bd9Sstevel@tonic-gate #include <limits.h>
617c478bd9Sstevel@tonic-gate #include <thread.h>
627c478bd9Sstevel@tonic-gate #include <synch.h>
637c478bd9Sstevel@tonic-gate #include <errno.h>
647c478bd9Sstevel@tonic-gate #include <fcntl.h>
657c478bd9Sstevel@tonic-gate #include <ctype.h>
667c478bd9Sstevel@tonic-gate #include <pwd.h>
677c478bd9Sstevel@tonic-gate #include <syslog.h>
687c478bd9Sstevel@tonic-gate #include <sys/types.h>
697c478bd9Sstevel@tonic-gate #include <sys/stat.h>
707c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
717c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
727c478bd9Sstevel@tonic-gate #include <libsysevent.h>
737c478bd9Sstevel@tonic-gate #include <libnvpair.h>
747c478bd9Sstevel@tonic-gate #include <dirent.h>
757c478bd9Sstevel@tonic-gate #include <locale.h>
767c478bd9Sstevel@tonic-gate #include <signal.h>
777c478bd9Sstevel@tonic-gate #include <wait.h>
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate #include "syseventd.h"
807c478bd9Sstevel@tonic-gate #include "syseventconfd_door.h"
817c478bd9Sstevel@tonic-gate #include "sysevent_conf_mod.h"
827c478bd9Sstevel@tonic-gate #include "message_conf_mod.h"
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate static char	*whoami = "sysevent_conf_mod";
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /*
887c478bd9Sstevel@tonic-gate  * Event sequencing, time stamp and retry count
897c478bd9Sstevel@tonic-gate  */
907c478bd9Sstevel@tonic-gate static int	ev_nretries;		/* retry count per event */
917c478bd9Sstevel@tonic-gate static uint64_t	ev_seq;			/* current event sequencing number */
927c478bd9Sstevel@tonic-gate static hrtime_t ev_ts;			/* current event timestamp */
937c478bd9Sstevel@tonic-gate static int	first_event;		/* first event since init */
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * State of the sysevent conf table, derived from
977c478bd9Sstevel@tonic-gate  * the /etc/sysevent/config files
987c478bd9Sstevel@tonic-gate  */
997c478bd9Sstevel@tonic-gate static conftab_t		*conftab		= NULL;
1007c478bd9Sstevel@tonic-gate static syseventtab_t		*syseventtab		= NULL;
1017c478bd9Sstevel@tonic-gate static syseventtab_t		*syseventtab_tail	= NULL;
1027c478bd9Sstevel@tonic-gate static sysevent_handle_t	*confd_handle 		= NULL;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * The cmd queue is a queue of commands ready to be sent
1067c478bd9Sstevel@tonic-gate  * to syseventconfd.  Each command consists of the path
1077c478bd9Sstevel@tonic-gate  * and arguments to be fork/exec'ed.  The daemon is unable
1087c478bd9Sstevel@tonic-gate  * to handle events during an active fork/exec and returns
1097c478bd9Sstevel@tonic-gate  * EAGAIN as a result.  It is grossly inefficient to bounce
1107c478bd9Sstevel@tonic-gate  * these events back to syseventd, so we queue them here for delivery.
1117c478bd9Sstevel@tonic-gate  */
1127c478bd9Sstevel@tonic-gate static cmdqueue_t		*cmdq		= NULL;
1137c478bd9Sstevel@tonic-gate static cmdqueue_t		*cmdq_tail	= NULL;
1147c478bd9Sstevel@tonic-gate static mutex_t			cmdq_lock;
1157c478bd9Sstevel@tonic-gate static cond_t			cmdq_cv;
1167c478bd9Sstevel@tonic-gate static int			cmdq_cnt;
1177c478bd9Sstevel@tonic-gate static thread_t			cmdq_thr_id;
1187c478bd9Sstevel@tonic-gate static cond_t			cmdq_thr_cv;
1197c478bd9Sstevel@tonic-gate static int			want_fini;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * State of the door channel to syseventconfd
1237c478bd9Sstevel@tonic-gate  */
1247c478bd9Sstevel@tonic-gate static int	confd_state	= CONFD_STATE_NOT_RUNNING;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate /*
1277c478bd9Sstevel@tonic-gate  * Number of times to retry event after restarting syeventconfd
1287c478bd9Sstevel@tonic-gate  */
1297c478bd9Sstevel@tonic-gate static int	confd_retries;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate /*
1327c478bd9Sstevel@tonic-gate  * Number of times to retry a failed transport
1337c478bd9Sstevel@tonic-gate  */
1347c478bd9Sstevel@tonic-gate static int	transport_retries;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate /*
1377c478bd9Sstevel@tonic-gate  * Normal sleep time when syseventconfd returns EAGAIN
1387c478bd9Sstevel@tonic-gate  * is one second but to avoid thrashing, sleep for
1397c478bd9Sstevel@tonic-gate  * something larger when syseventconfd not responding.
1407c478bd9Sstevel@tonic-gate  * This should never happen of course but it seems better
1417c478bd9Sstevel@tonic-gate  * to attempt to handle possible errors gracefully.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate static int	confd_err_msg_emitted;
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate static int sysevent_conf_dummy_event(sysevent_t *, int);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * External references
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate extern int	debug_level;
1527c478bd9Sstevel@tonic-gate extern char	*root_dir;
1537c478bd9Sstevel@tonic-gate extern void	syseventd_print(int level, char *format, ...);
1547c478bd9Sstevel@tonic-gate extern void	syseventd_err_print(char *format, ...);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate static struct slm_mod_ops sysevent_conf_mod_ops = {
1597c478bd9Sstevel@tonic-gate 	SE_MAJOR_VERSION,		/* syseventd module major version */
1607c478bd9Sstevel@tonic-gate 	SE_MINOR_VERSION,		/* syseventd module minor version */
1617c478bd9Sstevel@tonic-gate 	SE_MAX_RETRY_LIMIT,		/* max retry if EAGAIN */
1627c478bd9Sstevel@tonic-gate 	&sysevent_conf_event		/* event handler */
1637c478bd9Sstevel@tonic-gate };
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate static struct slm_mod_ops sysevent_conf_dummy_mod_ops = {
1667c478bd9Sstevel@tonic-gate 	SE_MAJOR_VERSION,		/* syseventd module major version */
1677c478bd9Sstevel@tonic-gate 	SE_MINOR_VERSION,		/* syseventd module minor version */
1687c478bd9Sstevel@tonic-gate 	0,				/* no retries, always succeeds */
1697c478bd9Sstevel@tonic-gate 	&sysevent_conf_dummy_event	/* dummy event handler */
1707c478bd9Sstevel@tonic-gate };
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate /*
1757c478bd9Sstevel@tonic-gate  * skip_spaces() - skip to next non-space character
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate static char *
1787c478bd9Sstevel@tonic-gate skip_spaces(char **cpp)
1797c478bd9Sstevel@tonic-gate {
1807c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
1837c478bd9Sstevel@tonic-gate 		cp++;
1847c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
1857c478bd9Sstevel@tonic-gate 		*cpp = 0;
1867c478bd9Sstevel@tonic-gate 		return (NULL);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 	return (cp);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate /*
1937c478bd9Sstevel@tonic-gate  * Get next white-space separated field.
1947c478bd9Sstevel@tonic-gate  * next_field() will not check any characters on next line.
1957c478bd9Sstevel@tonic-gate  * Each entry is composed of a single line.
1967c478bd9Sstevel@tonic-gate  */
1977c478bd9Sstevel@tonic-gate static char *
1987c478bd9Sstevel@tonic-gate next_field(char **cpp)
1997c478bd9Sstevel@tonic-gate {
2007c478bd9Sstevel@tonic-gate 	char *cp = *cpp;
2017c478bd9Sstevel@tonic-gate 	char *start;
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	while (*cp == ' ' || *cp == '\t')
2047c478bd9Sstevel@tonic-gate 		cp++;
2057c478bd9Sstevel@tonic-gate 	if (*cp == 0) {
2067c478bd9Sstevel@tonic-gate 		*cpp = 0;
2077c478bd9Sstevel@tonic-gate 		return (NULL);
2087c478bd9Sstevel@tonic-gate 	}
2097c478bd9Sstevel@tonic-gate 	start = cp;
2107c478bd9Sstevel@tonic-gate 	while (*cp && *cp != ' ' && *cp != '\t')
2117c478bd9Sstevel@tonic-gate 		cp++;
2127c478bd9Sstevel@tonic-gate 	if (*cp != 0)
2137c478bd9Sstevel@tonic-gate 		*cp++ = 0;
2147c478bd9Sstevel@tonic-gate 	*cpp = cp;
2157c478bd9Sstevel@tonic-gate 	return (start);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate /*
2217c478bd9Sstevel@tonic-gate  * The following functions are simple wrappers/equivalents
2227c478bd9Sstevel@tonic-gate  * for malloc, realloc, free, strdup and a special free
2237c478bd9Sstevel@tonic-gate  * for strdup.
2247c478bd9Sstevel@tonic-gate  *
2257c478bd9Sstevel@tonic-gate  * These functions ensure that any failed mallocs are
2267c478bd9Sstevel@tonic-gate  * reported via syslog() so if a command is not evoked
2277c478bd9Sstevel@tonic-gate  * in response to an event, the reason should be logged.
2287c478bd9Sstevel@tonic-gate  * These functions also provide a convenient place for
2297c478bd9Sstevel@tonic-gate  * hooks for checking for memory leaks.
2307c478bd9Sstevel@tonic-gate  */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate static void *
2337c478bd9Sstevel@tonic-gate sc_malloc(size_t n)
2347c478bd9Sstevel@tonic-gate {
2357c478bd9Sstevel@tonic-gate 	void *p;
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate 	p = malloc(n);
2387c478bd9Sstevel@tonic-gate 	if (p == NULL) {
2397c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
2407c478bd9Sstevel@tonic-gate 	}
2417c478bd9Sstevel@tonic-gate 	return (p);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2457c478bd9Sstevel@tonic-gate static void *
2467c478bd9Sstevel@tonic-gate sc_realloc(void *p, size_t current, size_t n)
2477c478bd9Sstevel@tonic-gate {
2487c478bd9Sstevel@tonic-gate 	p = realloc(p, n);
2497c478bd9Sstevel@tonic-gate 	if (p == NULL) {
2507c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
2517c478bd9Sstevel@tonic-gate 	}
2527c478bd9Sstevel@tonic-gate 	return (p);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2577c478bd9Sstevel@tonic-gate static void
2587c478bd9Sstevel@tonic-gate sc_free(void *p, size_t n)
2597c478bd9Sstevel@tonic-gate {
2607c478bd9Sstevel@tonic-gate 	free(p);
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate static char *
2657c478bd9Sstevel@tonic-gate sc_strdup(char *cp)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	char *new;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	new = malloc((unsigned)(strlen(cp) + 1));
2707c478bd9Sstevel@tonic-gate 	if (new == NULL) {
2717c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, OUT_OF_MEMORY_ERR);
2727c478bd9Sstevel@tonic-gate 		return (NULL);
2737c478bd9Sstevel@tonic-gate 	}
2747c478bd9Sstevel@tonic-gate 	(void) strcpy(new, cp);
2757c478bd9Sstevel@tonic-gate 	return (new);
2767c478bd9Sstevel@tonic-gate }
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate static void
2807c478bd9Sstevel@tonic-gate sc_strfree(char *s)
2817c478bd9Sstevel@tonic-gate {
2827c478bd9Sstevel@tonic-gate 	if (s)
2837c478bd9Sstevel@tonic-gate 		free(s);
2847c478bd9Sstevel@tonic-gate }
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate /*
2887c478bd9Sstevel@tonic-gate  * The following functions provide some simple dynamic string
2897c478bd9Sstevel@tonic-gate  * capability.  This module has no hard-coded maximum string
2907c478bd9Sstevel@tonic-gate  * lengths and should be able to parse and generate arbitrarily
2917c478bd9Sstevel@tonic-gate  * long strings, macro expansion and command lines.
2927c478bd9Sstevel@tonic-gate  *
2937c478bd9Sstevel@tonic-gate  * Each string must be explicitly allocated and freed.
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  * Allocate a dynamic string, with a hint to indicate how
2987c478bd9Sstevel@tonic-gate  * much memory to dynamically add to the string as it grows
2997c478bd9Sstevel@tonic-gate  * beyond its existing bounds, so as to avoid excessive
3007c478bd9Sstevel@tonic-gate  * reallocs as a string grows.
3017c478bd9Sstevel@tonic-gate  */
3027c478bd9Sstevel@tonic-gate static str_t *
3037c478bd9Sstevel@tonic-gate initstr(int hint)
3047c478bd9Sstevel@tonic-gate {
3057c478bd9Sstevel@tonic-gate 	str_t	*str;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate 	if ((str = sc_malloc(sizeof (str_t))) == NULL)
3087c478bd9Sstevel@tonic-gate 		return (NULL);
3097c478bd9Sstevel@tonic-gate 	str->s_str = NULL;
3107c478bd9Sstevel@tonic-gate 	str->s_len = 0;
3117c478bd9Sstevel@tonic-gate 	str->s_alloc = 0;
3127c478bd9Sstevel@tonic-gate 	str->s_hint = hint;
3137c478bd9Sstevel@tonic-gate 	return (str);
3147c478bd9Sstevel@tonic-gate }
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate /*
3187c478bd9Sstevel@tonic-gate  * Free a dynamically-allocated string
3197c478bd9Sstevel@tonic-gate  */
3207c478bd9Sstevel@tonic-gate static void
3217c478bd9Sstevel@tonic-gate freestr(str_t *str)
3227c478bd9Sstevel@tonic-gate {
3237c478bd9Sstevel@tonic-gate 	if (str->s_str) {
3247c478bd9Sstevel@tonic-gate 		sc_free(str->s_str, str->s_alloc);
3257c478bd9Sstevel@tonic-gate 	}
3267c478bd9Sstevel@tonic-gate 	sc_free(str, sizeof (str_t));
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Reset a dynamically-allocated string, allows reuse
3327c478bd9Sstevel@tonic-gate  * rather than freeing the old and allocating a new one.
3337c478bd9Sstevel@tonic-gate  */
3347c478bd9Sstevel@tonic-gate static void
3357c478bd9Sstevel@tonic-gate resetstr(str_t *str)
3367c478bd9Sstevel@tonic-gate {
3377c478bd9Sstevel@tonic-gate 	str->s_len = 0;
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate /*
3427c478bd9Sstevel@tonic-gate  * Copy a (simple) string onto a dynamically-allocated string
3437c478bd9Sstevel@tonic-gate  */
3447c478bd9Sstevel@tonic-gate static int
3457c478bd9Sstevel@tonic-gate strcopys(str_t *str, char *s)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	char	*new_str;
3487c478bd9Sstevel@tonic-gate 	int	len = strlen(s) + 1;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
3517c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ?
3527c478bd9Sstevel@tonic-gate 			sc_malloc(len+str->s_hint) :
3537c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
3547c478bd9Sstevel@tonic-gate 		if (new_str == NULL) {
3557c478bd9Sstevel@tonic-gate 			return (1);
3567c478bd9Sstevel@tonic-gate 		}
3577c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
3587c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	(void) strcpy(str->s_str, s);
3617c478bd9Sstevel@tonic-gate 	str->s_len = len - 1;
3627c478bd9Sstevel@tonic-gate 	return (0);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * Concatenate a (simple) string onto a dynamically-allocated string
3687c478bd9Sstevel@tonic-gate  */
3697c478bd9Sstevel@tonic-gate static int
3707c478bd9Sstevel@tonic-gate strcats(str_t *str, char *s)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	char	*new_str;
3737c478bd9Sstevel@tonic-gate 	int	len = str->s_len + strlen(s) + 1;
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
3767c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
3777c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
3787c478bd9Sstevel@tonic-gate 		if (new_str == NULL) {
3797c478bd9Sstevel@tonic-gate 			return (1);
3807c478bd9Sstevel@tonic-gate 		}
3817c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
3827c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
3837c478bd9Sstevel@tonic-gate 	}
3847c478bd9Sstevel@tonic-gate 	(void) strcpy(str->s_str + str->s_len, s);
3857c478bd9Sstevel@tonic-gate 	str->s_len = len - 1;
3867c478bd9Sstevel@tonic-gate 	return (0);
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * Concatenate a character onto a dynamically-allocated string
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static int
3947c478bd9Sstevel@tonic-gate strcatc(str_t *str, int c)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	char	*new_str;
3977c478bd9Sstevel@tonic-gate 	int	len = str->s_len + 2;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	if (str->s_alloc < len) {
4007c478bd9Sstevel@tonic-gate 		new_str = (str->s_str == NULL) ? sc_malloc(len+str->s_hint) :
4017c478bd9Sstevel@tonic-gate 			sc_realloc(str->s_str, str->s_alloc, len+str->s_hint);
4027c478bd9Sstevel@tonic-gate 		if (new_str == NULL) {
4037c478bd9Sstevel@tonic-gate 			return (1);
4047c478bd9Sstevel@tonic-gate 		}
4057c478bd9Sstevel@tonic-gate 		str->s_str = new_str;
4067c478bd9Sstevel@tonic-gate 		str->s_alloc = len + str->s_hint;
4077c478bd9Sstevel@tonic-gate 	}
4087c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len) = (char)c;
4097c478bd9Sstevel@tonic-gate 	*(str->s_str + str->s_len + 1) = 0;
4107c478bd9Sstevel@tonic-gate 	str->s_len++;
4117c478bd9Sstevel@tonic-gate 	return (0);
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate /*
4157c478bd9Sstevel@tonic-gate  * fgets() equivalent using a dynamically-allocated string
4167c478bd9Sstevel@tonic-gate  */
4177c478bd9Sstevel@tonic-gate static char *
4187c478bd9Sstevel@tonic-gate fstrgets(str_t *line, FILE *fp)
4197c478bd9Sstevel@tonic-gate {
4207c478bd9Sstevel@tonic-gate 	int	c;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	resetstr(line);
4237c478bd9Sstevel@tonic-gate 	while ((c = fgetc(fp)) != EOF) {
4247c478bd9Sstevel@tonic-gate 		if (strcatc(line, c))
4257c478bd9Sstevel@tonic-gate 			return (NULL);
4267c478bd9Sstevel@tonic-gate 		if (c == '\n')
4277c478bd9Sstevel@tonic-gate 			break;
4287c478bd9Sstevel@tonic-gate 	}
4297c478bd9Sstevel@tonic-gate 	if (line->s_len == 0)
4307c478bd9Sstevel@tonic-gate 		return (NULL);
4317c478bd9Sstevel@tonic-gate 	return (line->s_str);
4327c478bd9Sstevel@tonic-gate }
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate /*
4357c478bd9Sstevel@tonic-gate  * Truncate a dynamically-allocated string at index position 'pos'
4367c478bd9Sstevel@tonic-gate  */
4377c478bd9Sstevel@tonic-gate static void
4387c478bd9Sstevel@tonic-gate strtrunc(str_t *str, int pos)
4397c478bd9Sstevel@tonic-gate {
4407c478bd9Sstevel@tonic-gate 	if (str->s_len > pos) {
4417c478bd9Sstevel@tonic-gate 		str->s_len = pos;
4427c478bd9Sstevel@tonic-gate 		*(str->s_str + pos) = 0;
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate }
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Parse a sysevent.conf file, adding each entry spec to the event table.
4507c478bd9Sstevel@tonic-gate  *
4517c478bd9Sstevel@tonic-gate  * The format of an entry in a sysevent.conf file is:
4527c478bd9Sstevel@tonic-gate  *
4537c478bd9Sstevel@tonic-gate  *    class subclass vendor publisher user reserved1 reserved path arguments
4547c478bd9Sstevel@tonic-gate  *
4557c478bd9Sstevel@tonic-gate  * Fields are separated by either SPACE or TAB characters.  A
4567c478bd9Sstevel@tonic-gate  * '#' (number sign) at the beginning of a line indicates a
4577c478bd9Sstevel@tonic-gate  * comment.  Comment lines and blank lines are ignored.
4587c478bd9Sstevel@tonic-gate  *
4597c478bd9Sstevel@tonic-gate  * class
4607c478bd9Sstevel@tonic-gate  *    The class of the event.
4617c478bd9Sstevel@tonic-gate  *
4627c478bd9Sstevel@tonic-gate  * subclass
4637c478bd9Sstevel@tonic-gate  *    The subclass of the event.
4647c478bd9Sstevel@tonic-gate  *
4657c478bd9Sstevel@tonic-gate  * vendor
4667c478bd9Sstevel@tonic-gate  *    The name of the vendor defining the event, usually the
4677c478bd9Sstevel@tonic-gate  *    stock symbol.  Events generated by system components
4687c478bd9Sstevel@tonic-gate  *    provided by Sun Microsystems, Inc.  always define vendor
4697c478bd9Sstevel@tonic-gate  *    as 'SUNW'.
4707c478bd9Sstevel@tonic-gate  *
4717c478bd9Sstevel@tonic-gate  * publisher
4727c478bd9Sstevel@tonic-gate  *    The name of the application, driver or system module
4737c478bd9Sstevel@tonic-gate  *    producing the event.
4747c478bd9Sstevel@tonic-gate  *
4757c478bd9Sstevel@tonic-gate  * user
4767c478bd9Sstevel@tonic-gate  *    The name of the user under which the command should be
4777c478bd9Sstevel@tonic-gate  *    run.  This allows commands to run with access privileges
4787c478bd9Sstevel@tonic-gate  *    other than those for root.  The user field should be '-'
4797c478bd9Sstevel@tonic-gate  *    for commands to be run as root.
4807c478bd9Sstevel@tonic-gate  *
4817c478bd9Sstevel@tonic-gate  * reserved1
4827c478bd9Sstevel@tonic-gate  *    Must be '-'.
4837c478bd9Sstevel@tonic-gate  *
4847c478bd9Sstevel@tonic-gate  * reserved2
4857c478bd9Sstevel@tonic-gate  *    Must be '-'.
4867c478bd9Sstevel@tonic-gate  *
4877c478bd9Sstevel@tonic-gate  * path
4887c478bd9Sstevel@tonic-gate  *    Pathname of the command to be invoked for matching events.
4897c478bd9Sstevel@tonic-gate  *
4907c478bd9Sstevel@tonic-gate  * arguments
4917c478bd9Sstevel@tonic-gate  *    Optional argument with possible macro substitution to permit
4927c478bd9Sstevel@tonic-gate  *    arbitrary command line construction with event-specific data.
4937c478bd9Sstevel@tonic-gate  */
4947c478bd9Sstevel@tonic-gate static void
4957c478bd9Sstevel@tonic-gate parse_conf_file(char *conf_file)
4967c478bd9Sstevel@tonic-gate {
4977c478bd9Sstevel@tonic-gate 	char	conf_path[PATH_MAX];
4987c478bd9Sstevel@tonic-gate 	FILE	*fp;
4997c478bd9Sstevel@tonic-gate 	char	*lp;
5007c478bd9Sstevel@tonic-gate 	str_t	*line;
5017c478bd9Sstevel@tonic-gate 	int	lineno = 0;
5027c478bd9Sstevel@tonic-gate 	char	*vendor, *publisher;
5037c478bd9Sstevel@tonic-gate 	char	*class, *subclass;
5047c478bd9Sstevel@tonic-gate 	char	*user;
5057c478bd9Sstevel@tonic-gate 	char	*reserved1, *reserved2;
5067c478bd9Sstevel@tonic-gate 	char	*path, *args;
5077c478bd9Sstevel@tonic-gate 	syseventtab_t *sep;
5087c478bd9Sstevel@tonic-gate 	struct passwd pwd;
5097c478bd9Sstevel@tonic-gate 	struct passwd *pwdp;
5107c478bd9Sstevel@tonic-gate 	char	pwdbuf[1024];
5117c478bd9Sstevel@tonic-gate 	int	do_setuid;
5127c478bd9Sstevel@tonic-gate 	pid_t	saved_uid;
5137c478bd9Sstevel@tonic-gate 	gid_t	saved_gid;
5147c478bd9Sstevel@tonic-gate 	int	i, err;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 	(void) snprintf(conf_path, PATH_MAX, "%s/%s",
5177c478bd9Sstevel@tonic-gate 		SYSEVENT_CONFIG_DIR, conf_file);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	syseventd_print(DBG_CONF_FILE, "%s: reading %s\n", whoami, conf_path);
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if ((fp = fopen(conf_path, "r")) == NULL) {
5227c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, CANNOT_OPEN_ERR, conf_file, strerror(errno));
5237c478bd9Sstevel@tonic-gate 		return;
5247c478bd9Sstevel@tonic-gate 	}
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	if ((line = initstr(128)) == NULL)
5277c478bd9Sstevel@tonic-gate 		return;
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	while ((lp = fstrgets(line, fp)) != NULL) {
5307c478bd9Sstevel@tonic-gate 		lineno++;
5317c478bd9Sstevel@tonic-gate 		if (*lp == '\n' || *lp == '#')
5327c478bd9Sstevel@tonic-gate 			continue;
5337c478bd9Sstevel@tonic-gate 		*(lp + strlen(lp)-1) = 0;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_CONF_FILE, "[%d]: %s\n",
5367c478bd9Sstevel@tonic-gate 			lineno, lp);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 		if ((class = next_field(&lp)) != NULL) {
5397c478bd9Sstevel@tonic-gate 			subclass = next_field(&lp);
5407c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5417c478bd9Sstevel@tonic-gate 				goto mal_formed;
5427c478bd9Sstevel@tonic-gate 			vendor = next_field(&lp);
5437c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5447c478bd9Sstevel@tonic-gate 				goto mal_formed;
5457c478bd9Sstevel@tonic-gate 			publisher = next_field(&lp);
5467c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5477c478bd9Sstevel@tonic-gate 				goto mal_formed;
5487c478bd9Sstevel@tonic-gate 			user = next_field(&lp);
5497c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5507c478bd9Sstevel@tonic-gate 				goto mal_formed;
5517c478bd9Sstevel@tonic-gate 			reserved1 = next_field(&lp);
5527c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5537c478bd9Sstevel@tonic-gate 				goto mal_formed;
5547c478bd9Sstevel@tonic-gate 			reserved2 = next_field(&lp);
5557c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5567c478bd9Sstevel@tonic-gate 				goto mal_formed;
5577c478bd9Sstevel@tonic-gate 			path = next_field(&lp);
5587c478bd9Sstevel@tonic-gate 			if (lp == NULL)
5597c478bd9Sstevel@tonic-gate 				goto mal_formed;
5607c478bd9Sstevel@tonic-gate 			args = skip_spaces(&lp);
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		/*
5647c478bd9Sstevel@tonic-gate 		 * validate user
5657c478bd9Sstevel@tonic-gate 		 */
5667c478bd9Sstevel@tonic-gate 		do_setuid = 0;
5677c478bd9Sstevel@tonic-gate 		if ((strcmp(user, "-") != 0) && (strcmp(user, "root") != 0)) {
5687c478bd9Sstevel@tonic-gate 			i = getpwnam_r(user, &pwd, pwdbuf,
5697c478bd9Sstevel@tonic-gate 					sizeof (pwdbuf), &pwdp);
5707c478bd9Sstevel@tonic-gate 			if (i != 0 || pwdp == NULL) {
5717c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, NO_USER_ERR,
5727c478bd9Sstevel@tonic-gate 					conf_file, lineno, user);
5737c478bd9Sstevel@tonic-gate 				continue;
5747c478bd9Sstevel@tonic-gate 			}
5757c478bd9Sstevel@tonic-gate 			do_setuid = 1;
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 		/*
5797c478bd9Sstevel@tonic-gate 		 * validate reserved fields
5807c478bd9Sstevel@tonic-gate 		 */
5817c478bd9Sstevel@tonic-gate 		if (strcmp(reserved1, "-") != 0) {
5827c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, RESERVED_FIELD_ERR,
5837c478bd9Sstevel@tonic-gate 				conf_file, lineno, reserved1);
5847c478bd9Sstevel@tonic-gate 			continue;
5857c478bd9Sstevel@tonic-gate 		}
5867c478bd9Sstevel@tonic-gate 		if (strcmp(reserved2, "-") != 0) {
5877c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, RESERVED_FIELD_ERR,
5887c478bd9Sstevel@tonic-gate 				conf_file, lineno, reserved2);
5897c478bd9Sstevel@tonic-gate 			continue;
5907c478bd9Sstevel@tonic-gate 		}
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 		/*
5937c478bd9Sstevel@tonic-gate 		 * ensure path is executable by user
5947c478bd9Sstevel@tonic-gate 		 */
5957c478bd9Sstevel@tonic-gate 		err = 0;
5967c478bd9Sstevel@tonic-gate 		if (do_setuid) {
5977c478bd9Sstevel@tonic-gate 			saved_uid = getuid();
5987c478bd9Sstevel@tonic-gate 			saved_gid = getgid();
5997c478bd9Sstevel@tonic-gate 			if (setregid(pwdp->pw_gid, -1) == -1) {
6007c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, SETREGID_ERR,
6017c478bd9Sstevel@tonic-gate 					whoami, pwdp->pw_gid, strerror(errno));
6027c478bd9Sstevel@tonic-gate 				err = -1;
6037c478bd9Sstevel@tonic-gate 			}
6047c478bd9Sstevel@tonic-gate 			if (setreuid(pwdp->pw_uid, -1) == -1) {
6057c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, SETREUID_ERR,
6067c478bd9Sstevel@tonic-gate 					whoami, pwdp->pw_uid, strerror(errno));
6077c478bd9Sstevel@tonic-gate 				err = -1;
6087c478bd9Sstevel@tonic-gate 			}
6097c478bd9Sstevel@tonic-gate 		}
6107c478bd9Sstevel@tonic-gate 		if ((i = access(path, X_OK)) == -1) {
6117c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, CANNOT_EXECUTE_ERR,
6127c478bd9Sstevel@tonic-gate 				conf_file, lineno, path, strerror(errno));
6137c478bd9Sstevel@tonic-gate 		}
6147c478bd9Sstevel@tonic-gate 		if (do_setuid) {
6157c478bd9Sstevel@tonic-gate 			if (setreuid(saved_uid, -1) == -1) {
6167c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, SETREUID_ERR,
6177c478bd9Sstevel@tonic-gate 					whoami, saved_uid, strerror(errno));
6187c478bd9Sstevel@tonic-gate 				err = -1;
6197c478bd9Sstevel@tonic-gate 			}
6207c478bd9Sstevel@tonic-gate 			if (setregid(saved_gid, -1) == -1) {
6217c478bd9Sstevel@tonic-gate 				syslog(LOG_ERR, SETREGID_ERR,
6227c478bd9Sstevel@tonic-gate 					whoami, saved_gid, strerror(errno));
6237c478bd9Sstevel@tonic-gate 				err = -1;
6247c478bd9Sstevel@tonic-gate 			}
6257c478bd9Sstevel@tonic-gate 		}
6267c478bd9Sstevel@tonic-gate 		if (i == -1 || err == -1)
6277c478bd9Sstevel@tonic-gate 			continue;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 		/*
6307c478bd9Sstevel@tonic-gate 		 * all sanity tests successful - perform allocations
6317c478bd9Sstevel@tonic-gate 		 * to add entry to table
6327c478bd9Sstevel@tonic-gate 		 */
6337c478bd9Sstevel@tonic-gate 		if ((sep = sc_malloc(sizeof (syseventtab_t))) == NULL)
6347c478bd9Sstevel@tonic-gate 			break;
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 		sep->se_conf_file = conf_file;
6377c478bd9Sstevel@tonic-gate 		sep->se_lineno = lineno;
6387c478bd9Sstevel@tonic-gate 		sep->se_vendor = sc_strdup(vendor);
6397c478bd9Sstevel@tonic-gate 		sep->se_publisher = sc_strdup(publisher);
6407c478bd9Sstevel@tonic-gate 		sep->se_class = sc_strdup(class);
6417c478bd9Sstevel@tonic-gate 		sep->se_subclass = sc_strdup(subclass);
6427c478bd9Sstevel@tonic-gate 		sep->se_user = sc_strdup(user);
6437c478bd9Sstevel@tonic-gate 		if (do_setuid) {
6447c478bd9Sstevel@tonic-gate 			sep->se_uid = pwdp->pw_uid;
6457c478bd9Sstevel@tonic-gate 			sep->se_gid = pwdp->pw_gid;
6467c478bd9Sstevel@tonic-gate 		} else {
6477c478bd9Sstevel@tonic-gate 			sep->se_uid = 0;
6487c478bd9Sstevel@tonic-gate 			sep->se_gid = 0;
6497c478bd9Sstevel@tonic-gate 		}
6507c478bd9Sstevel@tonic-gate 		sep->se_reserved1 = sc_strdup(reserved1);
6517c478bd9Sstevel@tonic-gate 		sep->se_reserved2 = sc_strdup(reserved2);
6527c478bd9Sstevel@tonic-gate 		sep->se_path = sc_strdup(path);
6537c478bd9Sstevel@tonic-gate 		sep->se_args = (args == NULL) ? NULL : sc_strdup(args);
6547c478bd9Sstevel@tonic-gate 		sep->se_next = NULL;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 		if (sep->se_vendor == NULL || sep->se_publisher == NULL ||
6577c478bd9Sstevel@tonic-gate 		    sep->se_class == NULL || sep->se_subclass == NULL ||
6587c478bd9Sstevel@tonic-gate 		    sep->se_user == NULL || sep->se_reserved1 == NULL ||
6597c478bd9Sstevel@tonic-gate 		    sep->se_reserved2 == NULL || sep->se_path == NULL ||
6607c478bd9Sstevel@tonic-gate 		    (args && sep->se_args == NULL)) {
6617c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_vendor);
6627c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_publisher);
6637c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_class);
6647c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_subclass);
6657c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_user);
6667c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_reserved1);
6677c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_reserved2);
6687c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_path);
6697c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_args);
6707c478bd9Sstevel@tonic-gate 			sc_free(sep, sizeof (syseventtab_t));
6717c478bd9Sstevel@tonic-gate 			break;
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		/*
6757c478bd9Sstevel@tonic-gate 		 * link new entry into the table
6767c478bd9Sstevel@tonic-gate 		 */
6777c478bd9Sstevel@tonic-gate 		if (syseventtab == NULL) {
6787c478bd9Sstevel@tonic-gate 			syseventtab = sep;
6797c478bd9Sstevel@tonic-gate 			syseventtab_tail = sep;
6807c478bd9Sstevel@tonic-gate 		} else {
6817c478bd9Sstevel@tonic-gate 			syseventtab_tail->se_next = sep;
6827c478bd9Sstevel@tonic-gate 			syseventtab_tail = sep;
6837c478bd9Sstevel@tonic-gate 		}
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 		if (debug_level >= DBG_DETAILED) {
6867c478bd9Sstevel@tonic-gate 			syseventtab_t *sp;
6877c478bd9Sstevel@tonic-gate 			for (sp = syseventtab; sp; sp = sp->se_next) {
6887c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
6897c478bd9Sstevel@tonic-gate 					"    vendor=%s\n", sp->se_vendor);
6907c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
6917c478bd9Sstevel@tonic-gate 					"    publisher=%s\n", sp->se_publisher);
6927c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
6937c478bd9Sstevel@tonic-gate 					"    class=%s\n", sp->se_class);
6947c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
6957c478bd9Sstevel@tonic-gate 					"    subclass=%s\n", sp->se_subclass);
6967c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
6977c478bd9Sstevel@tonic-gate 					"    user=%s uid=%d gid=%d\n",
6987c478bd9Sstevel@tonic-gate 					sp->se_user, sp->se_uid, sp->se_gid);
6997c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
7007c478bd9Sstevel@tonic-gate 					"    reserved1=%s\n", sp->se_reserved1);
7017c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
7027c478bd9Sstevel@tonic-gate 					"    reserved2=%s\n", sp->se_reserved2);
7037c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
7047c478bd9Sstevel@tonic-gate 					"    path=%s\n", sp->se_path);
7057c478bd9Sstevel@tonic-gate 				if (sp->se_args != NULL) {
7067c478bd9Sstevel@tonic-gate 					syseventd_print(DBG_DETAILED,
7077c478bd9Sstevel@tonic-gate 						"    args=%s\n", sp->se_args);
7087c478bd9Sstevel@tonic-gate 				}
7097c478bd9Sstevel@tonic-gate 			}
7107c478bd9Sstevel@tonic-gate 		}
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate 		continue;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate mal_formed:
7157c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, SYNTAX_ERR, conf_file, lineno);
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate 
7187c478bd9Sstevel@tonic-gate 	freestr(line);
7197c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
7207c478bd9Sstevel@tonic-gate }
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * Build the events specification table, a summation of all
7257c478bd9Sstevel@tonic-gate  * event specification found in the installed sysevent.conf
7267c478bd9Sstevel@tonic-gate  * configuration files.
7277c478bd9Sstevel@tonic-gate  *
7287c478bd9Sstevel@tonic-gate  * All sysevent.conf files reside in the /etc/sysevent/config
7297c478bd9Sstevel@tonic-gate  * and may contain zero or more event/command specifications.
7307c478bd9Sstevel@tonic-gate  * A sysevent.conf file should be named as follows:
7317c478bd9Sstevel@tonic-gate  *
7327c478bd9Sstevel@tonic-gate  *        <vendor>,[<publisher>,][<class>,]sysevent.conf
7337c478bd9Sstevel@tonic-gate  *
7347c478bd9Sstevel@tonic-gate  * Event/command specifications delivered by the base Solaris
7357c478bd9Sstevel@tonic-gate  * system are provided in /etc/sysevent/config/SUNW,sysevent.conf.
7367c478bd9Sstevel@tonic-gate  * Event/command specifications delivered by optional
7377c478bd9Sstevel@tonic-gate  * Sun-supplied packages may install additional sysevent.conf
7387c478bd9Sstevel@tonic-gate  * files in /etc/sysevent/config using vendor SUNW, and additional
7397c478bd9Sstevel@tonic-gate  * publisher and/or event class naming to distinguish the
7407c478bd9Sstevel@tonic-gate  * events required for those products.  Products provided
7417c478bd9Sstevel@tonic-gate  * by third-party hardware or software companies may
7427c478bd9Sstevel@tonic-gate  * distinguish their sysevent.conf files by vendor, and
7437c478bd9Sstevel@tonic-gate  * by publisher and/or event class within vendor.
7447c478bd9Sstevel@tonic-gate  *
7457c478bd9Sstevel@tonic-gate  * Files residing in /etc/sysevent/config with a '.' (period)
7467c478bd9Sstevel@tonic-gate  * as the first character of the name and files with a suffix
7477c478bd9Sstevel@tonic-gate  * of other than "sysevent.conf" are ignored.
7487c478bd9Sstevel@tonic-gate  */
7497c478bd9Sstevel@tonic-gate static void
7507c478bd9Sstevel@tonic-gate build_event_table()
7517c478bd9Sstevel@tonic-gate {
7527c478bd9Sstevel@tonic-gate 	conftab_t	*cfp = NULL;
7537c478bd9Sstevel@tonic-gate 	DIR		*dir;
7547c478bd9Sstevel@tonic-gate 	struct dirent	*result;
7557c478bd9Sstevel@tonic-gate 	conftab_t	*new_cfp;
7567c478bd9Sstevel@tonic-gate 	char		*str;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if ((dir = opendir(SYSEVENT_CONFIG_DIR)) == NULL) {
7597c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, CANNOT_OPEN_ERR,
7607c478bd9Sstevel@tonic-gate 			SYSEVENT_CONFIG_DIR, strerror(errno));
7617c478bd9Sstevel@tonic-gate 		return;
7627c478bd9Sstevel@tonic-gate 	}
7637c478bd9Sstevel@tonic-gate 
764*4bc0a2efScasper 	while ((result = readdir(dir)) != NULL) {
7657c478bd9Sstevel@tonic-gate 		if (result->d_name[0] == '.')
7667c478bd9Sstevel@tonic-gate 			continue;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 		/*
7697c478bd9Sstevel@tonic-gate 		 * file must have extension "sysevent.conf"
7707c478bd9Sstevel@tonic-gate 		 */
7717c478bd9Sstevel@tonic-gate 		if ((str = strrchr(result->d_name, ',')) != NULL) {
7727c478bd9Sstevel@tonic-gate 			str++;
7737c478bd9Sstevel@tonic-gate 		} else {
7747c478bd9Sstevel@tonic-gate 			str = result->d_name;
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 		if (strcmp(str, "sysevent.conf") != 0) {
7777c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_CONF_FILE,
7787c478bd9Sstevel@tonic-gate 				"%s: ignoring %s\n", whoami, str);
7797c478bd9Sstevel@tonic-gate 			continue;
7807c478bd9Sstevel@tonic-gate 		}
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 		/*
7837c478bd9Sstevel@tonic-gate 		 * Add to file table and parse this conf file
7847c478bd9Sstevel@tonic-gate 		 */
7857c478bd9Sstevel@tonic-gate 		if ((str = sc_strdup(result->d_name)) == NULL)
7867c478bd9Sstevel@tonic-gate 			goto err;
7877c478bd9Sstevel@tonic-gate 		if ((new_cfp = sc_malloc(sizeof (conftab_t))) == NULL) {
7887c478bd9Sstevel@tonic-gate 			sc_strfree(str);
7897c478bd9Sstevel@tonic-gate 			goto err;
7907c478bd9Sstevel@tonic-gate 		}
7917c478bd9Sstevel@tonic-gate 		if (conftab == NULL) {
7927c478bd9Sstevel@tonic-gate 			conftab = new_cfp;
7937c478bd9Sstevel@tonic-gate 		} else {
7947c478bd9Sstevel@tonic-gate 			for (cfp = conftab; cfp->cf_next; cfp = cfp->cf_next)
7957c478bd9Sstevel@tonic-gate 				;
7967c478bd9Sstevel@tonic-gate 			cfp->cf_next = new_cfp;
7977c478bd9Sstevel@tonic-gate 		}
7987c478bd9Sstevel@tonic-gate 		cfp = new_cfp;
7997c478bd9Sstevel@tonic-gate 		cfp->cf_conf_file = str;
8007c478bd9Sstevel@tonic-gate 		cfp->cf_next = NULL;
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 		parse_conf_file(cfp->cf_conf_file);
8037c478bd9Sstevel@tonic-gate 	}
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate err:
8067c478bd9Sstevel@tonic-gate 	if (closedir(dir) == -1) {
8077c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN)
8087c478bd9Sstevel@tonic-gate 			goto err;
8097c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, CLOSEDIR_ERR,
8107c478bd9Sstevel@tonic-gate 			SYSEVENT_CONFIG_DIR, strerror(errno));
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate }
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate static int
8167c478bd9Sstevel@tonic-gate enter_lock(char *lock_file)
8177c478bd9Sstevel@tonic-gate {
8187c478bd9Sstevel@tonic-gate 	struct flock	lock;
8197c478bd9Sstevel@tonic-gate 	int		lock_fd;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	(void) snprintf(lock_file, PATH_MAX, "%s/%s",
8227c478bd9Sstevel@tonic-gate 		SYSEVENT_CONFIG_DIR, LOCK_FILENAME);
8237c478bd9Sstevel@tonic-gate 	lock_fd = open(lock_file, O_CREAT|O_RDWR, 0644);
8247c478bd9Sstevel@tonic-gate 	if (lock_fd < 0) {
8257c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MSG_LOCK_CREATE_ERR,
8267c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
8277c478bd9Sstevel@tonic-gate 		return (-1);
8287c478bd9Sstevel@tonic-gate 	}
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
8317c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
8327c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
8337c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate retry:
8367c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
8377c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR)
8387c478bd9Sstevel@tonic-gate 			goto retry;
8397c478bd9Sstevel@tonic-gate 		(void) close(lock_fd);
8407c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MSG_LOCK_SET_ERR,
8417c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
8427c478bd9Sstevel@tonic-gate 		return (-1);
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	return (lock_fd);
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate static void
8507c478bd9Sstevel@tonic-gate exit_lock(int lock_fd, char *lock_file)
8517c478bd9Sstevel@tonic-gate {
8527c478bd9Sstevel@tonic-gate 	struct flock	lock;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
8557c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
8567c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
8577c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLK, &lock) == -1) {
8607c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MSG_LOCK_CLR_ERR,
8617c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
8627c478bd9Sstevel@tonic-gate 	}
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate 	if (close(lock_fd) == -1) {
8657c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MSG_LOCK_CLOSE_ERR,
8667c478bd9Sstevel@tonic-gate 			whoami, lock_file, strerror(errno));
8677c478bd9Sstevel@tonic-gate 	}
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate /*
8727c478bd9Sstevel@tonic-gate  * Free the events specification table, constructed by
8737c478bd9Sstevel@tonic-gate  * parsing all the sysevent.conf files found.
8747c478bd9Sstevel@tonic-gate  *
8757c478bd9Sstevel@tonic-gate  * The free of this table is in response to a HUP
8767c478bd9Sstevel@tonic-gate  * given to the syseventd daemon, permitting the
8777c478bd9Sstevel@tonic-gate  * table to be rebuilt after adding a new sysevent.conf
8787c478bd9Sstevel@tonic-gate  * file or changing an existing one without shutting
8797c478bd9Sstevel@tonic-gate  * down the daemon.
8807c478bd9Sstevel@tonic-gate  */
8817c478bd9Sstevel@tonic-gate static void
8827c478bd9Sstevel@tonic-gate free_event_table()
8837c478bd9Sstevel@tonic-gate {
8847c478bd9Sstevel@tonic-gate 	syseventtab_t *sep;
8857c478bd9Sstevel@tonic-gate 	syseventtab_t *sep_next;
8867c478bd9Sstevel@tonic-gate 	conftab_t *cfp;
8877c478bd9Sstevel@tonic-gate 	conftab_t *cfp_next;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	sep = syseventtab;
8907c478bd9Sstevel@tonic-gate 	while (sep) {
8917c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_vendor);
8927c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_publisher);
8937c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_class);
8947c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_subclass);
8957c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_user);
8967c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_reserved1);
8977c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_reserved2);
8987c478bd9Sstevel@tonic-gate 		sc_strfree(sep->se_path);
8997c478bd9Sstevel@tonic-gate 		if (sep->se_args)
9007c478bd9Sstevel@tonic-gate 			sc_strfree(sep->se_args);
9017c478bd9Sstevel@tonic-gate 		sep_next = sep->se_next;
9027c478bd9Sstevel@tonic-gate 		sc_free(sep, sizeof (syseventtab_t));
9037c478bd9Sstevel@tonic-gate 		sep = sep_next;
9047c478bd9Sstevel@tonic-gate 	}
9057c478bd9Sstevel@tonic-gate 	syseventtab = NULL;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	cfp = conftab;
9087c478bd9Sstevel@tonic-gate 	while (cfp) {
9097c478bd9Sstevel@tonic-gate 		sc_strfree(cfp->cf_conf_file);
9107c478bd9Sstevel@tonic-gate 		cfp_next = cfp->cf_next;
9117c478bd9Sstevel@tonic-gate 		sc_free(cfp, sizeof (conftab_t));
9127c478bd9Sstevel@tonic-gate 		cfp = cfp_next;
9137c478bd9Sstevel@tonic-gate 	}
9147c478bd9Sstevel@tonic-gate 	conftab = NULL;
9157c478bd9Sstevel@tonic-gate }
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate static char ident_chars[] = "_";
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate /*
9227c478bd9Sstevel@tonic-gate  * Return a dynamically-allocated string containing the
9237c478bd9Sstevel@tonic-gate  * the next identifier in the string being parsed, pointed
9247c478bd9Sstevel@tonic-gate  * at by 'id'.  'end' returns a pointer to the character
9257c478bd9Sstevel@tonic-gate  * after the identifier.
9267c478bd9Sstevel@tonic-gate  *
9277c478bd9Sstevel@tonic-gate  * Identifiers are all alphanumeric ascii characters and
9287c478bd9Sstevel@tonic-gate  * those contained in ident_chars.
9297c478bd9Sstevel@tonic-gate  *
9307c478bd9Sstevel@tonic-gate  * The returned string must be explicitly freed via
9317c478bd9Sstevel@tonic-gate  * freestr().
9327c478bd9Sstevel@tonic-gate  */
9337c478bd9Sstevel@tonic-gate static str_t *
9347c478bd9Sstevel@tonic-gate snip_identifier(char *id, char **end)
9357c478bd9Sstevel@tonic-gate {
9367c478bd9Sstevel@tonic-gate 	str_t	*token;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	if ((token = initstr(32)) == NULL)
9397c478bd9Sstevel@tonic-gate 		return (NULL);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	while (*id != 0) {
9427c478bd9Sstevel@tonic-gate 		if (isascii(*id) &&
9437c478bd9Sstevel@tonic-gate 		    (isalnum(*id) || strchr(ident_chars, *id) != NULL)) {
9447c478bd9Sstevel@tonic-gate 			if (strcatc(token, *id++)) {
9457c478bd9Sstevel@tonic-gate 				freestr(token);
9467c478bd9Sstevel@tonic-gate 				return (NULL);
9477c478bd9Sstevel@tonic-gate 			}
9487c478bd9Sstevel@tonic-gate 		} else {
9497c478bd9Sstevel@tonic-gate 			*end = id;
9507c478bd9Sstevel@tonic-gate 			return (token);
9517c478bd9Sstevel@tonic-gate 		}
9527c478bd9Sstevel@tonic-gate 	}
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	*end = id;
9557c478bd9Sstevel@tonic-gate 	return (token);
9567c478bd9Sstevel@tonic-gate }
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate /*
9607c478bd9Sstevel@tonic-gate  * Identical to snip_identifier(), but the identifier
9617c478bd9Sstevel@tonic-gate  * is delimited by the characters { and }.
9627c478bd9Sstevel@tonic-gate  */
9637c478bd9Sstevel@tonic-gate static str_t *
9647c478bd9Sstevel@tonic-gate snip_delimited_identifier(char *id, char **end)
9657c478bd9Sstevel@tonic-gate {
9667c478bd9Sstevel@tonic-gate 	str_t	*token;
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	if ((token = initstr(32)) == NULL)
9697c478bd9Sstevel@tonic-gate 		return (NULL);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	while (*id != 0) {
9727c478bd9Sstevel@tonic-gate 		if (*id == '}') {
9737c478bd9Sstevel@tonic-gate 			*end = id+1;
9747c478bd9Sstevel@tonic-gate 			return (token);
9757c478bd9Sstevel@tonic-gate 		}
9767c478bd9Sstevel@tonic-gate 		if (strcatc(token, *id++)) {
9777c478bd9Sstevel@tonic-gate 			freestr(token);
9787c478bd9Sstevel@tonic-gate 			return (NULL);
9797c478bd9Sstevel@tonic-gate 		}
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	if (*id == 0) {
9837c478bd9Sstevel@tonic-gate 		freestr(token);
9847c478bd9Sstevel@tonic-gate 		return (NULL);
9857c478bd9Sstevel@tonic-gate 	}
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	*end = id;
9887c478bd9Sstevel@tonic-gate 	return (token);
9897c478bd9Sstevel@tonic-gate }
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 
9927c478bd9Sstevel@tonic-gate /*
9937c478bd9Sstevel@tonic-gate  * Return a string with the name of the attribute type
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static char *nv_attr_type_strings[] = {
9967c478bd9Sstevel@tonic-gate 	"unknown",
9977c478bd9Sstevel@tonic-gate 	"boolean",
9987c478bd9Sstevel@tonic-gate 	"byte",
9997c478bd9Sstevel@tonic-gate 	"int16",
10007c478bd9Sstevel@tonic-gate 	"uint16",
10017c478bd9Sstevel@tonic-gate 	"int32",
10027c478bd9Sstevel@tonic-gate 	"uint32",
10037c478bd9Sstevel@tonic-gate 	"int64",
10047c478bd9Sstevel@tonic-gate 	"uint64",
10057c478bd9Sstevel@tonic-gate 	"string",
10067c478bd9Sstevel@tonic-gate 	"byte-array",
10077c478bd9Sstevel@tonic-gate 	"int16-array",
10087c478bd9Sstevel@tonic-gate 	"uint16-array",
10097c478bd9Sstevel@tonic-gate 	"int32-array",
10107c478bd9Sstevel@tonic-gate 	"uint32-array",
10117c478bd9Sstevel@tonic-gate 	"int64-array",
10127c478bd9Sstevel@tonic-gate 	"uint64-array",
10137c478bd9Sstevel@tonic-gate 	"string-array",
10147c478bd9Sstevel@tonic-gate 	"hrtime"
10157c478bd9Sstevel@tonic-gate };
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate static char *
10187c478bd9Sstevel@tonic-gate se_attr_type_to_str(int se_attr_type)
10197c478bd9Sstevel@tonic-gate {
10207c478bd9Sstevel@tonic-gate 	if (se_attr_type >= 0 &&
10217c478bd9Sstevel@tonic-gate 	    se_attr_type < sizeof (nv_attr_type_strings) / sizeof (char *)) {
10227c478bd9Sstevel@tonic-gate 		return (nv_attr_type_strings[se_attr_type]);
10237c478bd9Sstevel@tonic-gate 	}
10247c478bd9Sstevel@tonic-gate 	return (nv_attr_type_strings[DATA_TYPE_UNKNOWN]);
10257c478bd9Sstevel@tonic-gate }
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate  * Find and return the data matching the macro name 'token'
10307c478bd9Sstevel@tonic-gate  *
10317c478bd9Sstevel@tonic-gate  * Predefined macros are simply substituted with the
10327c478bd9Sstevel@tonic-gate  * data from the event header:
10337c478bd9Sstevel@tonic-gate  *
10347c478bd9Sstevel@tonic-gate  *	$vendor - the vendor string defining the event.
10357c478bd9Sstevel@tonic-gate  *
10367c478bd9Sstevel@tonic-gate  *	$publisher - the publisher string defining the event.
10377c478bd9Sstevel@tonic-gate  *
10387c478bd9Sstevel@tonic-gate  *	$class - the class string defining the event.
10397c478bd9Sstevel@tonic-gate  *
10407c478bd9Sstevel@tonic-gate  *	$subclass - the subclass string defining the event.
10417c478bd9Sstevel@tonic-gate  *
10427c478bd9Sstevel@tonic-gate  *	$sequence - the sequence number of the event.
10437c478bd9Sstevel@tonic-gate  *
10447c478bd9Sstevel@tonic-gate  *	$timestamp - the timestamp of the event.
10457c478bd9Sstevel@tonic-gate  *
10467c478bd9Sstevel@tonic-gate  * Attributes with signed data types (DATA_TYPE_INT16,
10477c478bd9Sstevel@tonic-gate  * DATA_TYPE_INT32 and DATA_TYPE_INT64) are expanded
10487c478bd9Sstevel@tonic-gate  * as decimal digits.
10497c478bd9Sstevel@tonic-gate  *
10507c478bd9Sstevel@tonic-gate  * Attributes with unsigned data types (DATA_TYPE_BYTE,
10517c478bd9Sstevel@tonic-gate  * DATA_TYPE_UINT16, DATA_TYPE_UINT32, DATA_TYPE_UINT64 and
10527c478bd9Sstevel@tonic-gate  * DATA_TYPE_HTTIME) are expanded as hexadecimal digits
10537c478bd9Sstevel@tonic-gate  * with a "0x" prefix.
10547c478bd9Sstevel@tonic-gate  *
10557c478bd9Sstevel@tonic-gate  * Attributes with string data type (DATA_TYPE_STRING)
10567c478bd9Sstevel@tonic-gate  * are expanded with the string data.  The data is
10577c478bd9Sstevel@tonic-gate  * not quoted.  If if it desired that the quoted strings
10587c478bd9Sstevel@tonic-gate  * be generated on the command line, put quotes around
10597c478bd9Sstevel@tonic-gate  * the macro call in the arguments.
10607c478bd9Sstevel@tonic-gate  *
10617c478bd9Sstevel@tonic-gate  * Array types are expanded with each element expanded
10627c478bd9Sstevel@tonic-gate  * as defined for that scalar type, with a space separating
10637c478bd9Sstevel@tonic-gate  * each element substitution.
10647c478bd9Sstevel@tonic-gate  */
10657c478bd9Sstevel@tonic-gate 
10667c478bd9Sstevel@tonic-gate static str_t *
10677c478bd9Sstevel@tonic-gate find_macro_definition(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep,
10687c478bd9Sstevel@tonic-gate 	char *token, sysevent_hdr_info_t *hdr)
10697c478bd9Sstevel@tonic-gate {
10707c478bd9Sstevel@tonic-gate 	nvpair_t		*nvp;
10717c478bd9Sstevel@tonic-gate 	int			nmatches;
10727c478bd9Sstevel@tonic-gate 	char			num[64];
10737c478bd9Sstevel@tonic-gate 	str_t			*replacement;
10747c478bd9Sstevel@tonic-gate 	int			i;
10757c478bd9Sstevel@tonic-gate 	uint_t			nelems;
10767c478bd9Sstevel@tonic-gate 	union {
10777c478bd9Sstevel@tonic-gate 		uchar_t		x_byte;
10787c478bd9Sstevel@tonic-gate 		int16_t		x_int16;
10797c478bd9Sstevel@tonic-gate 		uint16_t	x_uint16;
10807c478bd9Sstevel@tonic-gate 		int32_t		x_int32;
10817c478bd9Sstevel@tonic-gate 		uint32_t	x_uint32;
10827c478bd9Sstevel@tonic-gate 		int64_t		x_int64;
10837c478bd9Sstevel@tonic-gate 		uint64_t	x_uint64;
10847c478bd9Sstevel@tonic-gate 		hrtime_t	x_time;
10857c478bd9Sstevel@tonic-gate 		char		*x_string;
10867c478bd9Sstevel@tonic-gate 		uchar_t		*x_byte_array;
10877c478bd9Sstevel@tonic-gate 		int16_t		*x_int16_array;
10887c478bd9Sstevel@tonic-gate 		int32_t		*x_int32_array;
10897c478bd9Sstevel@tonic-gate 		int64_t		*x_int64_array;
10907c478bd9Sstevel@tonic-gate 		uint16_t	*x_uint16_array;
10917c478bd9Sstevel@tonic-gate 		uint32_t	*x_uint32_array;
10927c478bd9Sstevel@tonic-gate 		uint64_t	*x_uint64_array;
10937c478bd9Sstevel@tonic-gate 		char		**x_string_array;
10947c478bd9Sstevel@tonic-gate 	} x;
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate 	if ((replacement = initstr(128)) == NULL) {
10987c478bd9Sstevel@tonic-gate 		return (NULL);
10997c478bd9Sstevel@tonic-gate 	}
11007c478bd9Sstevel@tonic-gate 
11017c478bd9Sstevel@tonic-gate 	if (strcmp(token, "vendor") == 0) {
11027c478bd9Sstevel@tonic-gate 		if (strcopys(replacement, hdr->vendor)) {
11037c478bd9Sstevel@tonic-gate 			freestr(replacement);
11047c478bd9Sstevel@tonic-gate 			return (NULL);
11057c478bd9Sstevel@tonic-gate 		}
11067c478bd9Sstevel@tonic-gate 		return (replacement);
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if (strcmp(token, "publisher") == 0) {
11107c478bd9Sstevel@tonic-gate 		if (strcopys(replacement, hdr->publisher)) {
11117c478bd9Sstevel@tonic-gate 			freestr(replacement);
11127c478bd9Sstevel@tonic-gate 			return (NULL);
11137c478bd9Sstevel@tonic-gate 		}
11147c478bd9Sstevel@tonic-gate 		return (replacement);
11157c478bd9Sstevel@tonic-gate 	}
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	if (strcmp(token, "class") == 0) {
11187c478bd9Sstevel@tonic-gate 		if (strcopys(replacement, hdr->class)) {
11197c478bd9Sstevel@tonic-gate 			freestr(replacement);
11207c478bd9Sstevel@tonic-gate 			return (NULL);
11217c478bd9Sstevel@tonic-gate 		}
11227c478bd9Sstevel@tonic-gate 		return (replacement);
11237c478bd9Sstevel@tonic-gate 	}
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	if (strcmp(token, "subclass") == 0) {
11267c478bd9Sstevel@tonic-gate 		if (strcopys(replacement, hdr->subclass)) {
11277c478bd9Sstevel@tonic-gate 			freestr(replacement);
11287c478bd9Sstevel@tonic-gate 			return (NULL);
11297c478bd9Sstevel@tonic-gate 		}
11307c478bd9Sstevel@tonic-gate 		return (replacement);
11317c478bd9Sstevel@tonic-gate 	}
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate 	if ((strcmp(token, "sequence") == 0) ||
11347c478bd9Sstevel@tonic-gate 	    (strcmp(token, "timestamp") == 0)) {
11357c478bd9Sstevel@tonic-gate 		if (strcmp(token, "sequence") == 0) {
11367c478bd9Sstevel@tonic-gate 			(void) snprintf(num, sizeof (num),
11377c478bd9Sstevel@tonic-gate 				"0x%llx", sysevent_get_seq(ev));
11387c478bd9Sstevel@tonic-gate 		} else {
11397c478bd9Sstevel@tonic-gate 			hrtime_t ts;
11407c478bd9Sstevel@tonic-gate 			sysevent_get_time(ev, &ts);
11417c478bd9Sstevel@tonic-gate 			(void) snprintf(num, sizeof (num), "0x%llx", ts);
11427c478bd9Sstevel@tonic-gate 		}
11437c478bd9Sstevel@tonic-gate 		if (strcopys(replacement, num)) {
11447c478bd9Sstevel@tonic-gate 			freestr(replacement);
11457c478bd9Sstevel@tonic-gate 			return (NULL);
11467c478bd9Sstevel@tonic-gate 		}
11477c478bd9Sstevel@tonic-gate 		return (replacement);
11487c478bd9Sstevel@tonic-gate 	}
11497c478bd9Sstevel@tonic-gate 
11507c478bd9Sstevel@tonic-gate 	nmatches = 0;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	if (nvlist) {
11537c478bd9Sstevel@tonic-gate 		nvpair_t *nvp_match;
11547c478bd9Sstevel@tonic-gate 		nvp = NULL;
11557c478bd9Sstevel@tonic-gate 		while ((nvp = nvlist_next_nvpair(nvlist, nvp)) != NULL) {
11567c478bd9Sstevel@tonic-gate 			if (debug_level >= DBG_DETAILED) {
11577c478bd9Sstevel@tonic-gate 				syseventd_print(DBG_DETAILED,
11587c478bd9Sstevel@tonic-gate 				"    attribute: %s %s\n", nvpair_name(nvp),
11597c478bd9Sstevel@tonic-gate 				se_attr_type_to_str(nvpair_type(nvp)));
11607c478bd9Sstevel@tonic-gate 			}
11617c478bd9Sstevel@tonic-gate 			if (strcmp(token, nvpair_name(nvp)) == 0) {
11627c478bd9Sstevel@tonic-gate 				nmatches++;
11637c478bd9Sstevel@tonic-gate 				nvp_match = nvp;
11647c478bd9Sstevel@tonic-gate 			}
11657c478bd9Sstevel@tonic-gate 		}
11667c478bd9Sstevel@tonic-gate 		nvp = nvp_match;
11677c478bd9Sstevel@tonic-gate 	}
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	if (nmatches == 0) {
11707c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MACRO_UNDEF_ERR,
11717c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno, token);
11727c478bd9Sstevel@tonic-gate 		freestr(replacement);
11737c478bd9Sstevel@tonic-gate 		return (NULL);
11747c478bd9Sstevel@tonic-gate 	} else if (nmatches > 1) {
11757c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, MACRO_MULT_DEF_ERR,
11767c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno, token);
11777c478bd9Sstevel@tonic-gate 		freestr(replacement);
11787c478bd9Sstevel@tonic-gate 		return (NULL);
11797c478bd9Sstevel@tonic-gate 	}
11807c478bd9Sstevel@tonic-gate 
11817c478bd9Sstevel@tonic-gate 	switch (nvpair_type(nvp)) {
11827c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
11837c478bd9Sstevel@tonic-gate 		(void) nvpair_value_byte(nvp, &x.x_byte);
11847c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "0x%x", x.x_byte);
11857c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
11867c478bd9Sstevel@tonic-gate 			freestr(replacement);
11877c478bd9Sstevel@tonic-gate 			return (NULL);
11887c478bd9Sstevel@tonic-gate 		}
11897c478bd9Sstevel@tonic-gate 		break;
11907c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
11917c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int16(nvp, &x.x_int16);
11927c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "%d", x.x_int16);
11937c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
11947c478bd9Sstevel@tonic-gate 			freestr(replacement);
11957c478bd9Sstevel@tonic-gate 			return (NULL);
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 		break;
11987c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
11997c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint16(nvp, &x.x_uint16);
12007c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "0x%x", x.x_uint16);
12017c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
12027c478bd9Sstevel@tonic-gate 			freestr(replacement);
12037c478bd9Sstevel@tonic-gate 			return (NULL);
12047c478bd9Sstevel@tonic-gate 		}
12057c478bd9Sstevel@tonic-gate 		break;
12067c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
12077c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int32(nvp, &x.x_int32);
12087c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "%d", x.x_int32);
12097c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
12107c478bd9Sstevel@tonic-gate 			freestr(replacement);
12117c478bd9Sstevel@tonic-gate 			return (NULL);
12127c478bd9Sstevel@tonic-gate 		}
12137c478bd9Sstevel@tonic-gate 		break;
12147c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
12157c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint32(nvp, &x.x_uint32);
12167c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "0x%x", x.x_uint32);
12177c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
12187c478bd9Sstevel@tonic-gate 			freestr(replacement);
12197c478bd9Sstevel@tonic-gate 			return (NULL);
12207c478bd9Sstevel@tonic-gate 		}
12217c478bd9Sstevel@tonic-gate 		break;
12227c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
12237c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int64(nvp, &x.x_int64);
12247c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "%lld", x.x_int64);
12257c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
12267c478bd9Sstevel@tonic-gate 			freestr(replacement);
12277c478bd9Sstevel@tonic-gate 			return (NULL);
12287c478bd9Sstevel@tonic-gate 		}
12297c478bd9Sstevel@tonic-gate 		break;
12307c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
12317c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint64(nvp, &x.x_uint64);
12327c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "0x%llx", x.x_uint64);
12337c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
12347c478bd9Sstevel@tonic-gate 			freestr(replacement);
12357c478bd9Sstevel@tonic-gate 			return (NULL);
12367c478bd9Sstevel@tonic-gate 		}
12377c478bd9Sstevel@tonic-gate 		break;
12387c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
12397c478bd9Sstevel@tonic-gate 		(void) nvpair_value_string(nvp, &x.x_string);
12407c478bd9Sstevel@tonic-gate 		if (strcats(replacement, x.x_string)) {
12417c478bd9Sstevel@tonic-gate 			freestr(replacement);
12427c478bd9Sstevel@tonic-gate 			return (NULL);
12437c478bd9Sstevel@tonic-gate 		}
12447c478bd9Sstevel@tonic-gate 		break;
12457c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY: {
12467c478bd9Sstevel@tonic-gate 			uchar_t	*p;
12477c478bd9Sstevel@tonic-gate 			(void) nvpair_value_byte_array(nvp,
12487c478bd9Sstevel@tonic-gate 				&x.x_byte_array, &nelems);
12497c478bd9Sstevel@tonic-gate 			p = x.x_byte_array;
12507c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
12517c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num),
12527c478bd9Sstevel@tonic-gate 					"0x%x ", *p++ & 0xff);
12537c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
12547c478bd9Sstevel@tonic-gate 					freestr(replacement);
12557c478bd9Sstevel@tonic-gate 					return (NULL);
12567c478bd9Sstevel@tonic-gate 				}
12577c478bd9Sstevel@tonic-gate 			}
12587c478bd9Sstevel@tonic-gate 		}
12597c478bd9Sstevel@tonic-gate 		break;
12607c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16_ARRAY: {
12617c478bd9Sstevel@tonic-gate 			int16_t *p;
12627c478bd9Sstevel@tonic-gate 			(void) nvpair_value_int16_array(nvp,
12637c478bd9Sstevel@tonic-gate 				&x.x_int16_array, &nelems);
12647c478bd9Sstevel@tonic-gate 			p = x.x_int16_array;
12657c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
12667c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num), "%d ", *p++);
12677c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
12687c478bd9Sstevel@tonic-gate 					freestr(replacement);
12697c478bd9Sstevel@tonic-gate 					return (NULL);
12707c478bd9Sstevel@tonic-gate 				}
12717c478bd9Sstevel@tonic-gate 			}
12727c478bd9Sstevel@tonic-gate 		}
12737c478bd9Sstevel@tonic-gate 		break;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16_ARRAY: {
12767c478bd9Sstevel@tonic-gate 			uint16_t *p;
12777c478bd9Sstevel@tonic-gate 			(void) nvpair_value_uint16_array(nvp,
12787c478bd9Sstevel@tonic-gate 				&x.x_uint16_array, &nelems);
12797c478bd9Sstevel@tonic-gate 			p = x.x_uint16_array;
12807c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
12817c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num),
12827c478bd9Sstevel@tonic-gate 					"0x%x ", *p++);
12837c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
12847c478bd9Sstevel@tonic-gate 					freestr(replacement);
12857c478bd9Sstevel@tonic-gate 					return (NULL);
12867c478bd9Sstevel@tonic-gate 				}
12877c478bd9Sstevel@tonic-gate 			}
12887c478bd9Sstevel@tonic-gate 		}
12897c478bd9Sstevel@tonic-gate 		break;
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32_ARRAY: {
12927c478bd9Sstevel@tonic-gate 			int32_t *p;
12937c478bd9Sstevel@tonic-gate 			(void) nvpair_value_int32_array(nvp,
12947c478bd9Sstevel@tonic-gate 				&x.x_int32_array, &nelems);
12957c478bd9Sstevel@tonic-gate 			p = x.x_int32_array;
12967c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
12977c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num), "%d ", *p++);
12987c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
12997c478bd9Sstevel@tonic-gate 					freestr(replacement);
13007c478bd9Sstevel@tonic-gate 					return (NULL);
13017c478bd9Sstevel@tonic-gate 				}
13027c478bd9Sstevel@tonic-gate 			}
13037c478bd9Sstevel@tonic-gate 		}
13047c478bd9Sstevel@tonic-gate 		break;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32_ARRAY: {
13077c478bd9Sstevel@tonic-gate 			uint32_t *p;
13087c478bd9Sstevel@tonic-gate 			(void) nvpair_value_uint32_array(nvp,
13097c478bd9Sstevel@tonic-gate 				&x.x_uint32_array, &nelems);
13107c478bd9Sstevel@tonic-gate 			p = x.x_uint32_array;
13117c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
13127c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num),
13137c478bd9Sstevel@tonic-gate 					"0x%x ", *p++);
13147c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
13157c478bd9Sstevel@tonic-gate 					freestr(replacement);
13167c478bd9Sstevel@tonic-gate 					return (NULL);
13177c478bd9Sstevel@tonic-gate 				}
13187c478bd9Sstevel@tonic-gate 			}
13197c478bd9Sstevel@tonic-gate 		}
13207c478bd9Sstevel@tonic-gate 		break;
13217c478bd9Sstevel@tonic-gate 
13227c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64_ARRAY: {
13237c478bd9Sstevel@tonic-gate 			int64_t *p;
13247c478bd9Sstevel@tonic-gate 			(void) nvpair_value_int64_array(nvp,
13257c478bd9Sstevel@tonic-gate 				&x.x_int64_array, &nelems);
13267c478bd9Sstevel@tonic-gate 			p = x.x_int64_array;
13277c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
13287c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num),
13297c478bd9Sstevel@tonic-gate 					"%lld ", *p++);
13307c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
13317c478bd9Sstevel@tonic-gate 					freestr(replacement);
13327c478bd9Sstevel@tonic-gate 					return (NULL);
13337c478bd9Sstevel@tonic-gate 				}
13347c478bd9Sstevel@tonic-gate 			}
13357c478bd9Sstevel@tonic-gate 		}
13367c478bd9Sstevel@tonic-gate 		break;
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64_ARRAY: {
13397c478bd9Sstevel@tonic-gate 			uint64_t *p;
13407c478bd9Sstevel@tonic-gate 			(void) nvpair_value_uint64_array(nvp,
13417c478bd9Sstevel@tonic-gate 				&x.x_uint64_array, &nelems);
13427c478bd9Sstevel@tonic-gate 			p = x.x_uint64_array;
13437c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
13447c478bd9Sstevel@tonic-gate 				(void) snprintf(num, sizeof (num),
13457c478bd9Sstevel@tonic-gate 					"0x%llx ", *p++);
13467c478bd9Sstevel@tonic-gate 				if (strcats(replacement, num)) {
13477c478bd9Sstevel@tonic-gate 					freestr(replacement);
13487c478bd9Sstevel@tonic-gate 					return (NULL);
13497c478bd9Sstevel@tonic-gate 				}
13507c478bd9Sstevel@tonic-gate 			}
13517c478bd9Sstevel@tonic-gate 		}
13527c478bd9Sstevel@tonic-gate 		break;
13537c478bd9Sstevel@tonic-gate 
13547c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING_ARRAY: {
13557c478bd9Sstevel@tonic-gate 			char **p;
13567c478bd9Sstevel@tonic-gate 			(void) nvpair_value_string_array(nvp,
13577c478bd9Sstevel@tonic-gate 				&x.x_string_array, &nelems);
13587c478bd9Sstevel@tonic-gate 			p = x.x_string_array;
13597c478bd9Sstevel@tonic-gate 			for (i = 0; i < nelems; i++) {
13607c478bd9Sstevel@tonic-gate 				if (strcats(replacement, *p++) ||
13617c478bd9Sstevel@tonic-gate 				    strcats(replacement, " ")) {
13627c478bd9Sstevel@tonic-gate 					freestr(replacement);
13637c478bd9Sstevel@tonic-gate 					return (NULL);
13647c478bd9Sstevel@tonic-gate 				}
13657c478bd9Sstevel@tonic-gate 			}
13667c478bd9Sstevel@tonic-gate 		}
13677c478bd9Sstevel@tonic-gate 		break;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
13707c478bd9Sstevel@tonic-gate 		(void) nvpair_value_hrtime(nvp, &x.x_time);
13717c478bd9Sstevel@tonic-gate 		(void) snprintf(num, sizeof (num), "0x%llx", x.x_time);
13727c478bd9Sstevel@tonic-gate 		if (strcats(replacement, num)) {
13737c478bd9Sstevel@tonic-gate 			freestr(replacement);
13747c478bd9Sstevel@tonic-gate 			return (NULL);
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 		break;
13777c478bd9Sstevel@tonic-gate 	default:
13787c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, ATTR_UNSUPPORTED_ERR,
13797c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno,
13807c478bd9Sstevel@tonic-gate 			nvpair_type(nvp), token);
13817c478bd9Sstevel@tonic-gate 		freestr(replacement);
13827c478bd9Sstevel@tonic-gate 		return (NULL);
13837c478bd9Sstevel@tonic-gate 	}
13847c478bd9Sstevel@tonic-gate 
13857c478bd9Sstevel@tonic-gate 	return (replacement);
13867c478bd9Sstevel@tonic-gate }
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate  * Expand macros in the command template provided in an event
13907c478bd9Sstevel@tonic-gate  * specification with the data from the event or event attributes.
13917c478bd9Sstevel@tonic-gate  *
13927c478bd9Sstevel@tonic-gate  * Macros are introduced by the '$' character, with the macro
13937c478bd9Sstevel@tonic-gate  * name being the following token separated by a SPACE or
13947c478bd9Sstevel@tonic-gate  * TAB character.  If the macro name is embedded in text,
13957c478bd9Sstevel@tonic-gate  * it may be delineated by '${' and "}'.  A backslash before
13967c478bd9Sstevel@tonic-gate  * the '$' causes macro expansion not to occur.
13977c478bd9Sstevel@tonic-gate  *
13987c478bd9Sstevel@tonic-gate  * The following predefined macros are defined for each event:
13997c478bd9Sstevel@tonic-gate  *
14007c478bd9Sstevel@tonic-gate  *	$vendor - the vendor string defining the event.
14017c478bd9Sstevel@tonic-gate  *
14027c478bd9Sstevel@tonic-gate  *	$publisher - the publisher string defining the event.
14037c478bd9Sstevel@tonic-gate  *
14047c478bd9Sstevel@tonic-gate  *	$class - the class string defining the event.
14057c478bd9Sstevel@tonic-gate  *
14067c478bd9Sstevel@tonic-gate  *	$subclass - the subclass string defining the event.
14077c478bd9Sstevel@tonic-gate  *
14087c478bd9Sstevel@tonic-gate  *	$sequence - the sequence number of the event.
14097c478bd9Sstevel@tonic-gate  *
14107c478bd9Sstevel@tonic-gate  *	$timestamp - the timestamp of the event.
14117c478bd9Sstevel@tonic-gate  *
14127c478bd9Sstevel@tonic-gate  *
14137c478bd9Sstevel@tonic-gate  * Macro names other than those predefined are compared against
14147c478bd9Sstevel@tonic-gate  * the attribute list provided with the event.  An attribute
14157c478bd9Sstevel@tonic-gate  * with name matching the macro name causes the value of
14167c478bd9Sstevel@tonic-gate  * of the attribute to be substituted as ASCII text on the
14177c478bd9Sstevel@tonic-gate  * generated command line.
14187c478bd9Sstevel@tonic-gate  *
14197c478bd9Sstevel@tonic-gate  * Use of a macro for which no attribute with that name
14207c478bd9Sstevel@tonic-gate  * is defined, or for which multiple attributes with that
14217c478bd9Sstevel@tonic-gate  * name are provided, cause an error and the command is
14227c478bd9Sstevel@tonic-gate  * not invoked.
14237c478bd9Sstevel@tonic-gate  */
14247c478bd9Sstevel@tonic-gate static int
14257c478bd9Sstevel@tonic-gate expand_macros(sysevent_t *ev, nvlist_t *nvlist, syseventtab_t *sep,
14267c478bd9Sstevel@tonic-gate 	str_t *line, sysevent_hdr_info_t *hdr)
14277c478bd9Sstevel@tonic-gate {
14287c478bd9Sstevel@tonic-gate 	char	*p;
14297c478bd9Sstevel@tonic-gate 	int	state;
14307c478bd9Sstevel@tonic-gate 	char	*end;
14317c478bd9Sstevel@tonic-gate 	str_t	*token;
14327c478bd9Sstevel@tonic-gate 	str_t	*remainder;
14337c478bd9Sstevel@tonic-gate 	str_t	*replacement;
14347c478bd9Sstevel@tonic-gate 	int	count;
14357c478bd9Sstevel@tonic-gate 	int	dollar_position;
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	syseventd_print(DBG_MACRO, "    expanding macros: '%s'\n", line->s_str);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate reset:
14407c478bd9Sstevel@tonic-gate 	state = 0;
14417c478bd9Sstevel@tonic-gate 	count = 0;
14427c478bd9Sstevel@tonic-gate 	for (p = line->s_str; *p != 0; p++, count++) {
14437c478bd9Sstevel@tonic-gate 		switch (state) {
14447c478bd9Sstevel@tonic-gate 		case 0:				/* initial state */
14457c478bd9Sstevel@tonic-gate 			if (*p == '\\') {
14467c478bd9Sstevel@tonic-gate 				state = 1;
14477c478bd9Sstevel@tonic-gate 			} else if (*p == '$') {
14487c478bd9Sstevel@tonic-gate 				dollar_position = count;
14497c478bd9Sstevel@tonic-gate 				state = 2;
14507c478bd9Sstevel@tonic-gate 			}
14517c478bd9Sstevel@tonic-gate 			break;
14527c478bd9Sstevel@tonic-gate 		case 1:				/* skip characters */
14537c478bd9Sstevel@tonic-gate 			state = 0;		/* after backslash */
14547c478bd9Sstevel@tonic-gate 			break;
14557c478bd9Sstevel@tonic-gate 		case 2:				/* character after $ */
14567c478bd9Sstevel@tonic-gate 			if (*p == '{') {
14577c478bd9Sstevel@tonic-gate 				token = snip_delimited_identifier(p+1, &end);
14587c478bd9Sstevel@tonic-gate 			} else {
14597c478bd9Sstevel@tonic-gate 				token = snip_identifier(p, &end);
14607c478bd9Sstevel@tonic-gate 			}
14617c478bd9Sstevel@tonic-gate 			if (token == NULL)
14627c478bd9Sstevel@tonic-gate 				goto failed;
14637c478bd9Sstevel@tonic-gate 
14647c478bd9Sstevel@tonic-gate 			if ((remainder = initstr(128)) == NULL) {
14657c478bd9Sstevel@tonic-gate 				freestr(token);
14667c478bd9Sstevel@tonic-gate 				return (1);
14677c478bd9Sstevel@tonic-gate 			}
14687c478bd9Sstevel@tonic-gate 			if (strcopys(remainder, end)) {
14697c478bd9Sstevel@tonic-gate 				freestr(token);
14707c478bd9Sstevel@tonic-gate 				freestr(remainder);
14717c478bd9Sstevel@tonic-gate 				return (1);
14727c478bd9Sstevel@tonic-gate 			}
14737c478bd9Sstevel@tonic-gate 			replacement = find_macro_definition(ev, nvlist,
14747c478bd9Sstevel@tonic-gate 				sep, token->s_str, hdr);
14757c478bd9Sstevel@tonic-gate 			if (replacement == NULL) {
14767c478bd9Sstevel@tonic-gate 				freestr(token);
14777c478bd9Sstevel@tonic-gate 				freestr(remainder);
14787c478bd9Sstevel@tonic-gate 				return (1);
14797c478bd9Sstevel@tonic-gate 			}
14807c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_MACRO,
14817c478bd9Sstevel@tonic-gate 				"    '%s' expands to '%s'\n",
14827c478bd9Sstevel@tonic-gate 				token->s_str, replacement->s_str);
14837c478bd9Sstevel@tonic-gate 
14847c478bd9Sstevel@tonic-gate 			strtrunc(line, dollar_position);
14857c478bd9Sstevel@tonic-gate 			if (strcats(line, replacement->s_str)) {
14867c478bd9Sstevel@tonic-gate 				freestr(token);
14877c478bd9Sstevel@tonic-gate 				freestr(replacement);
14887c478bd9Sstevel@tonic-gate 				freestr(remainder);
14897c478bd9Sstevel@tonic-gate 				return (1);
14907c478bd9Sstevel@tonic-gate 			}
14917c478bd9Sstevel@tonic-gate 			if (strcats(line, remainder->s_str)) {
14927c478bd9Sstevel@tonic-gate 				freestr(token);
14937c478bd9Sstevel@tonic-gate 				freestr(replacement);
14947c478bd9Sstevel@tonic-gate 				freestr(remainder);
14957c478bd9Sstevel@tonic-gate 				return (1);
14967c478bd9Sstevel@tonic-gate 			}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_MACRO,
14997c478bd9Sstevel@tonic-gate 				"    with macro expanded: '%s'\n", line->s_str);
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 			freestr(token);
15027c478bd9Sstevel@tonic-gate 			freestr(replacement);
15037c478bd9Sstevel@tonic-gate 			freestr(remainder);
15047c478bd9Sstevel@tonic-gate 			goto reset;
15057c478bd9Sstevel@tonic-gate 		}
15067c478bd9Sstevel@tonic-gate 	}
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate failed:
15097c478bd9Sstevel@tonic-gate 	if (state != 0) {
15107c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, SYNTAX_ERR, sep->se_conf_file, sep->se_lineno);
15117c478bd9Sstevel@tonic-gate 		return (1);
15127c478bd9Sstevel@tonic-gate 	}
15137c478bd9Sstevel@tonic-gate 
15147c478bd9Sstevel@tonic-gate 	return (0);
15157c478bd9Sstevel@tonic-gate }
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate static void
15197c478bd9Sstevel@tonic-gate start_syseventconfd()
15207c478bd9Sstevel@tonic-gate {
15217c478bd9Sstevel@tonic-gate 	int	err;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 	err = system1("/usr/lib/sysevent/syseventconfd",
15247c478bd9Sstevel@tonic-gate 		"/usr/lib/sysevent/syseventconfd");
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	if (err != 0 && confd_err_msg_emitted == 0) {
15277c478bd9Sstevel@tonic-gate 		if (confd_state == CONFD_STATE_NOT_RUNNING) {
15287c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, SYSEVENTCONFD_START_ERR,
15297c478bd9Sstevel@tonic-gate 				strerror(errno));
15307c478bd9Sstevel@tonic-gate 		} else {
15317c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, SYSEVENTCONFD_RESTART_ERR,
15327c478bd9Sstevel@tonic-gate 				strerror(errno));
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 	}
15357c478bd9Sstevel@tonic-gate }
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate static int
15397c478bd9Sstevel@tonic-gate system1(const char *s_path, const char *s)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate 	struct sigaction cbuf, ibuf, qbuf, ignore, dfl;
15427c478bd9Sstevel@tonic-gate 	sigset_t mask;
15437c478bd9Sstevel@tonic-gate 	sigset_t savemask;
15447c478bd9Sstevel@tonic-gate 	struct stat st;
15457c478bd9Sstevel@tonic-gate 	pid_t pid;
15467c478bd9Sstevel@tonic-gate 	int status, w;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	/* Check the requested command */
15497c478bd9Sstevel@tonic-gate 	if (s == NULL) {
15507c478bd9Sstevel@tonic-gate 		errno = EINVAL;
15517c478bd9Sstevel@tonic-gate 		return (-1);
15527c478bd9Sstevel@tonic-gate 	}
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 	/* Check the ability to execute devfsadmd from this process */
15557c478bd9Sstevel@tonic-gate 	if (stat(s_path, &st) < 0) {
15567c478bd9Sstevel@tonic-gate 		return (-1);
15577c478bd9Sstevel@tonic-gate 	}
15587c478bd9Sstevel@tonic-gate 	if (((geteuid() == st.st_uid) && ((st.st_mode & S_IXUSR) == 0)) ||
15597c478bd9Sstevel@tonic-gate 		((getegid() == st.st_gid) && ((st.st_mode & S_IXGRP) == 0)) ||
15607c478bd9Sstevel@tonic-gate 		((st.st_mode & S_IXOTH) == 0)) {
15617c478bd9Sstevel@tonic-gate 		errno = EPERM;
15627c478bd9Sstevel@tonic-gate 		return (-1);
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	/*
15667c478bd9Sstevel@tonic-gate 	 * Block SIGCHLD and set up a default handler for the duration of the
15677c478bd9Sstevel@tonic-gate 	 * system1 call.
15687c478bd9Sstevel@tonic-gate 	 */
15697c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&mask);
15707c478bd9Sstevel@tonic-gate 	(void) sigaddset(&mask, SIGCHLD);
15717c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_BLOCK, &mask, &savemask);
15727c478bd9Sstevel@tonic-gate 	(void) memset(&dfl, 0, sizeof (dfl));
15737c478bd9Sstevel@tonic-gate 	dfl.sa_handler = SIG_DFL;
15747c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCHLD, &dfl, &cbuf);
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	/* Fork off the child process (using fork1(), because it's MT-safe) */
15777c478bd9Sstevel@tonic-gate 	switch (pid = fork1()) {
15787c478bd9Sstevel@tonic-gate 		case -1:
15797c478bd9Sstevel@tonic-gate 			/* Error */
15807c478bd9Sstevel@tonic-gate 			(void) sigaction(SIGCHLD, &cbuf, NULL);
15817c478bd9Sstevel@tonic-gate 			(void) sigprocmask(SIG_SETMASK, &savemask, NULL);
15827c478bd9Sstevel@tonic-gate 			return (-1);
15837c478bd9Sstevel@tonic-gate 		case 0:
15847c478bd9Sstevel@tonic-gate 			/* Set-up an initial signal mask for the child */
15857c478bd9Sstevel@tonic-gate 			(void) sigemptyset(&mask);
15867c478bd9Sstevel@tonic-gate 			(void) sigprocmask(SIG_SETMASK, &mask, NULL);
15877c478bd9Sstevel@tonic-gate 			(void) execl(s_path, s, (char *)0);
15887c478bd9Sstevel@tonic-gate 			_exit(-1);
15897c478bd9Sstevel@tonic-gate 			break;
15907c478bd9Sstevel@tonic-gate 		default:
15917c478bd9Sstevel@tonic-gate 			/* Parent */
15927c478bd9Sstevel@tonic-gate 			break;
15937c478bd9Sstevel@tonic-gate 	}
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	(void) memset(&ignore, 0, sizeof (ignore));
15967c478bd9Sstevel@tonic-gate 	ignore.sa_handler = SIG_IGN;
15977c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGINT, &ignore, &ibuf);
15987c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &ignore, &qbuf);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	do {
16017c478bd9Sstevel@tonic-gate 		w = waitpid(pid, &status, 0);
16027c478bd9Sstevel@tonic-gate 	} while (w == -1 && errno == EINTR);
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGINT, &ibuf, NULL);
16057c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGQUIT, &qbuf, NULL);
16067c478bd9Sstevel@tonic-gate 
16077c478bd9Sstevel@tonic-gate 	(void) sigaction(SIGCHLD, &cbuf, NULL);
16087c478bd9Sstevel@tonic-gate 	(void) sigprocmask(SIG_SETMASK, &savemask, NULL);
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	return ((w == -1)? w: status);
16117c478bd9Sstevel@tonic-gate }
16127c478bd9Sstevel@tonic-gate 
16137c478bd9Sstevel@tonic-gate /*
16147c478bd9Sstevel@tonic-gate  * Free all commands on the cmd queue
16157c478bd9Sstevel@tonic-gate  */
16167c478bd9Sstevel@tonic-gate static void
16177c478bd9Sstevel@tonic-gate abort_cmd_queue()
16187c478bd9Sstevel@tonic-gate {
16197c478bd9Sstevel@tonic-gate 	cmdqueue_t	*cmd;
16207c478bd9Sstevel@tonic-gate 	cmdqueue_t	*next;
16217c478bd9Sstevel@tonic-gate 	int		nevents = 0;
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	while ((cmd = cmdq) != NULL) {
16247c478bd9Sstevel@tonic-gate 		next = cmd->next;
16257c478bd9Sstevel@tonic-gate 		cmdq_cnt--;
16267c478bd9Sstevel@tonic-gate 		sysevent_free(cmd->event);
16277c478bd9Sstevel@tonic-gate 		sc_free(cmd, sizeof (cmdqueue_t));
16287c478bd9Sstevel@tonic-gate 		cmdq = next;
16297c478bd9Sstevel@tonic-gate 		nevents++;
16307c478bd9Sstevel@tonic-gate 	}
16317c478bd9Sstevel@tonic-gate 	cmdq_tail = NULL;
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	/*
16347c478bd9Sstevel@tonic-gate 	 * Generate error msgs if events were discarded or
16357c478bd9Sstevel@tonic-gate 	 * we are entering the disabled state.
16367c478bd9Sstevel@tonic-gate 	 */
16377c478bd9Sstevel@tonic-gate 	if (nevents > 0) {
16387c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, N_EVENTS_DISCARDED_ERR, nevents);
16397c478bd9Sstevel@tonic-gate 	}
16407c478bd9Sstevel@tonic-gate 	if (want_fini == 0) {
16417c478bd9Sstevel@tonic-gate 		confd_state = CONFD_STATE_DISABLED;
16427c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, SERVICE_DISABLED_MSG);
16437c478bd9Sstevel@tonic-gate 	}
16447c478bd9Sstevel@tonic-gate }
16457c478bd9Sstevel@tonic-gate 
16467c478bd9Sstevel@tonic-gate /*
16477c478bd9Sstevel@tonic-gate  * For a matching event specification, build the command to be
16487c478bd9Sstevel@tonic-gate  * invoked in response to the event.  Building the command involves
16497c478bd9Sstevel@tonic-gate  * expanding macros supplied in the event specification command
16507c478bd9Sstevel@tonic-gate  * with values from the actual event.  These macros can be
16517c478bd9Sstevel@tonic-gate  * the class/subclass/vendor/publisher strings, or arbitrary
16527c478bd9Sstevel@tonic-gate  * attribute data attached to the event.
16537c478bd9Sstevel@tonic-gate  *
16547c478bd9Sstevel@tonic-gate  * This module does not invoke (fork/exec) the command itself,
16557c478bd9Sstevel@tonic-gate  * since this module is running in the context of the syseventd
16567c478bd9Sstevel@tonic-gate  * daemon, and fork/exec's done here interfere with the door
16577c478bd9Sstevel@tonic-gate  * upcall delivering events from the kernel to the daemon.
16587c478bd9Sstevel@tonic-gate  * Instead, we build a separate event and nvlist with the
16597c478bd9Sstevel@tonic-gate  * attributes of the command to be invoked, and pass that on
16607c478bd9Sstevel@tonic-gate  * to the syseventconfd daemon, which is basically a fork/exec
16617c478bd9Sstevel@tonic-gate  * server on our behalf.
16627c478bd9Sstevel@tonic-gate  *
16637c478bd9Sstevel@tonic-gate  * Errors queuing the event are returned to syseventd with
16647c478bd9Sstevel@tonic-gate  * EAGAIN, allowing syseventd to manage a limited number of
16657c478bd9Sstevel@tonic-gate  * retries after a short delay.
16667c478bd9Sstevel@tonic-gate  */
16677c478bd9Sstevel@tonic-gate static int
16687c478bd9Sstevel@tonic-gate queue_event(sysevent_t *ev, syseventtab_t *sep, sysevent_hdr_info_t *hdr)
16697c478bd9Sstevel@tonic-gate {
16707c478bd9Sstevel@tonic-gate 	str_t		*line;
16717c478bd9Sstevel@tonic-gate 	nvlist_t	*nvlist;
16727c478bd9Sstevel@tonic-gate 	char 		*argv0;
16737c478bd9Sstevel@tonic-gate 	sysevent_t	*cmd_event;
16747c478bd9Sstevel@tonic-gate 	nvlist_t	*cmd_nvlist;
16757c478bd9Sstevel@tonic-gate 	cmdqueue_t	*new_cmd;
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	if ((line = initstr(128)) == NULL)
16787c478bd9Sstevel@tonic-gate 		return (1);
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	if ((argv0 = strrchr(sep->se_path, '/')) == NULL) {
16817c478bd9Sstevel@tonic-gate 		argv0 = sep->se_path;
16827c478bd9Sstevel@tonic-gate 	} else {
16837c478bd9Sstevel@tonic-gate 		argv0++;
16847c478bd9Sstevel@tonic-gate 	}
16857c478bd9Sstevel@tonic-gate 	if (strcopys(line, argv0)) {
16867c478bd9Sstevel@tonic-gate 		freestr(line);
16877c478bd9Sstevel@tonic-gate 		return (1);
16887c478bd9Sstevel@tonic-gate 	}
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	if (sep->se_args) {
16917c478bd9Sstevel@tonic-gate 		if (strcats(line, " ")) {
16927c478bd9Sstevel@tonic-gate 			freestr(line);
16937c478bd9Sstevel@tonic-gate 			return (1);
16947c478bd9Sstevel@tonic-gate 		}
16957c478bd9Sstevel@tonic-gate 		if (strcats(line, sep->se_args)) {
16967c478bd9Sstevel@tonic-gate 			freestr(line);
16977c478bd9Sstevel@tonic-gate 			return (1);
16987c478bd9Sstevel@tonic-gate 		}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 		if (sysevent_get_attr_list(ev, &nvlist) != 0) {
17017c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, GET_ATTR_LIST_ERR,
17027c478bd9Sstevel@tonic-gate 				sep->se_conf_file, sep->se_lineno,
17037c478bd9Sstevel@tonic-gate 				strerror(errno));
17047c478bd9Sstevel@tonic-gate 			freestr(line);
17057c478bd9Sstevel@tonic-gate 			return (1);
17067c478bd9Sstevel@tonic-gate 		}
17077c478bd9Sstevel@tonic-gate 		if (expand_macros(ev, nvlist, sep, line, hdr)) {
17087c478bd9Sstevel@tonic-gate 			freestr(line);
17097c478bd9Sstevel@tonic-gate 			if (nvlist)
17107c478bd9Sstevel@tonic-gate 				nvlist_free(nvlist);
17117c478bd9Sstevel@tonic-gate 			return (1);
17127c478bd9Sstevel@tonic-gate 		}
17137c478bd9Sstevel@tonic-gate 		if (nvlist)
17147c478bd9Sstevel@tonic-gate 			nvlist_free(nvlist);
17157c478bd9Sstevel@tonic-gate 	}
17167c478bd9Sstevel@tonic-gate 
17177c478bd9Sstevel@tonic-gate 	if (debug_level >= DBG_EXEC) {
17187c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_EXEC, "%s, line %d: path = %s\n",
17197c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno, sep->se_path);
17207c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_EXEC, "    cmd = %s\n", line->s_str);
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 	cmd_nvlist = NULL;
17247c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_alloc(&cmd_nvlist, NV_UNIQUE_NAME, 0)) != 0) {
17257c478bd9Sstevel@tonic-gate 		freestr(line);
17267c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, NVLIST_ALLOC_ERR,
17277c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno,
17287c478bd9Sstevel@tonic-gate 			strerror(errno));
17297c478bd9Sstevel@tonic-gate 		return (1);
17307c478bd9Sstevel@tonic-gate 	}
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(cmd_nvlist, "path", sep->se_path)) != 0)
17337c478bd9Sstevel@tonic-gate 		goto err;
17347c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(cmd_nvlist, "cmd", line->s_str)) != 0)
17357c478bd9Sstevel@tonic-gate 		goto err;
17367c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(cmd_nvlist, "file",
17377c478bd9Sstevel@tonic-gate 	    sep->se_conf_file)) != 0)
17387c478bd9Sstevel@tonic-gate 		goto err;
17397c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_int32(cmd_nvlist, "line", sep->se_lineno)) != 0)
17407c478bd9Sstevel@tonic-gate 		goto err;
17417c478bd9Sstevel@tonic-gate 	if ((errno = nvlist_add_string(cmd_nvlist, "user", sep->se_user)) != 0)
17427c478bd9Sstevel@tonic-gate 		goto err;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	if (sep->se_uid != (uid_t)0) {
17457c478bd9Sstevel@tonic-gate 		if ((errno = nvlist_add_int32(cmd_nvlist, "uid",
17467c478bd9Sstevel@tonic-gate 		    sep->se_uid)) != 0)
17477c478bd9Sstevel@tonic-gate 			goto err;
17487c478bd9Sstevel@tonic-gate 		if ((errno = nvlist_add_int32(cmd_nvlist, "gid",
17497c478bd9Sstevel@tonic-gate 		    sep->se_gid)) != 0)
17507c478bd9Sstevel@tonic-gate 			goto err;
17517c478bd9Sstevel@tonic-gate 	}
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 	cmd_event = sysevent_alloc_event(hdr->class, hdr->subclass, hdr->vendor,
17547c478bd9Sstevel@tonic-gate 		hdr->publisher, cmd_nvlist);
17557c478bd9Sstevel@tonic-gate 	if (cmd_event == NULL) {
17567c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, SYSEVENT_ALLOC_ERR,
17577c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno,
17587c478bd9Sstevel@tonic-gate 			strerror(errno));
17597c478bd9Sstevel@tonic-gate 		nvlist_free(cmd_nvlist);
17607c478bd9Sstevel@tonic-gate 		freestr(line);
17617c478bd9Sstevel@tonic-gate 		return (1);
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	nvlist_free(cmd_nvlist);
17657c478bd9Sstevel@tonic-gate 	freestr(line);
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate 	/*
17687c478bd9Sstevel@tonic-gate 	 * Place cmd_event on queue to be transported to syseventconfd
17697c478bd9Sstevel@tonic-gate 	 */
17707c478bd9Sstevel@tonic-gate 	if ((new_cmd = sc_malloc(sizeof (cmdqueue_t))) == NULL) {
17717c478bd9Sstevel@tonic-gate 		sysevent_free(cmd_event);
17727c478bd9Sstevel@tonic-gate 		return (1);
17737c478bd9Sstevel@tonic-gate 	}
17747c478bd9Sstevel@tonic-gate 	new_cmd->event = cmd_event;
17757c478bd9Sstevel@tonic-gate 	new_cmd->next = NULL;
17767c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cmdq_lock);
17777c478bd9Sstevel@tonic-gate 	if (cmdq == NULL) {
17787c478bd9Sstevel@tonic-gate 		cmdq = new_cmd;
17797c478bd9Sstevel@tonic-gate 	} else {
17807c478bd9Sstevel@tonic-gate 		cmdq_tail->next = new_cmd;
17817c478bd9Sstevel@tonic-gate 	}
17827c478bd9Sstevel@tonic-gate 	cmdq_cnt++;
17837c478bd9Sstevel@tonic-gate 	cmdq_tail = new_cmd;
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate 	/*
17867c478bd9Sstevel@tonic-gate 	 * signal queue flush thread
17877c478bd9Sstevel@tonic-gate 	 */
17887c478bd9Sstevel@tonic-gate 	(void) cond_signal(&cmdq_cv);
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cmdq_lock);
17917c478bd9Sstevel@tonic-gate 
17927c478bd9Sstevel@tonic-gate 	return (0);
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate err:
17957c478bd9Sstevel@tonic-gate 	syslog(LOG_ERR, NVLIST_BUILD_ERR,
17967c478bd9Sstevel@tonic-gate 		sep->se_conf_file, sep->se_lineno, strerror(errno));
17977c478bd9Sstevel@tonic-gate 	nvlist_free(cmd_nvlist);
17987c478bd9Sstevel@tonic-gate 	freestr(line);
17997c478bd9Sstevel@tonic-gate 	return (1);
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate static int
18047c478bd9Sstevel@tonic-gate transport_event(sysevent_t *event)
18057c478bd9Sstevel@tonic-gate {
18067c478bd9Sstevel@tonic-gate 	int	rval;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 	rval = sysevent_send_event(confd_handle, event);
18097c478bd9Sstevel@tonic-gate 	if (rval != 0) {
18107c478bd9Sstevel@tonic-gate 		switch (errno) {
18117c478bd9Sstevel@tonic-gate 		case EAGAIN:
18127c478bd9Sstevel@tonic-gate 		case EINTR:
18137c478bd9Sstevel@tonic-gate 			/*
18147c478bd9Sstevel@tonic-gate 			 * syseventconfd daemon may be forking, stop
18157c478bd9Sstevel@tonic-gate 			 * attempting to empty the queue momentarily.
18167c478bd9Sstevel@tonic-gate 			 */
18177c478bd9Sstevel@tonic-gate 			rval = errno;
18187c478bd9Sstevel@tonic-gate 			break;
18197c478bd9Sstevel@tonic-gate 		case ENOENT:
18207c478bd9Sstevel@tonic-gate 		case EBADF:
18217c478bd9Sstevel@tonic-gate 			/*
18227c478bd9Sstevel@tonic-gate 			 * start/restart the syseventconfd daemon,
18237c478bd9Sstevel@tonic-gate 			 * allowing for some delay when starting
18247c478bd9Sstevel@tonic-gate 			 * up before it begins to reply.
18257c478bd9Sstevel@tonic-gate 			 */
18267c478bd9Sstevel@tonic-gate 			if (confd_state == CONFD_STATE_NOT_RUNNING ||
18277c478bd9Sstevel@tonic-gate 			    confd_state == CONFD_STATE_OK) {
18287c478bd9Sstevel@tonic-gate 				confd_state = CONFD_STATE_STARTED;
18297c478bd9Sstevel@tonic-gate 				start_syseventconfd();
18307c478bd9Sstevel@tonic-gate 				confd_retries = 0;
18317c478bd9Sstevel@tonic-gate 				rval = EAGAIN;
18327c478bd9Sstevel@tonic-gate 			} else if (confd_state == CONFD_STATE_STARTED &&
18337c478bd9Sstevel@tonic-gate 			    confd_retries < 16) {
18347c478bd9Sstevel@tonic-gate 				if (++confd_retries == 16) {
18357c478bd9Sstevel@tonic-gate 					confd_state = CONFD_STATE_ERR;
18367c478bd9Sstevel@tonic-gate 					if (confd_err_msg_emitted == 0) {
18377c478bd9Sstevel@tonic-gate 						syslog(LOG_ERR,
18387c478bd9Sstevel@tonic-gate 						    SYSEVENTCONFD_ERR);
18397c478bd9Sstevel@tonic-gate 						confd_err_msg_emitted = 1;
18407c478bd9Sstevel@tonic-gate 					}
18417c478bd9Sstevel@tonic-gate 				}
18427c478bd9Sstevel@tonic-gate 				rval = EAGAIN;
18437c478bd9Sstevel@tonic-gate 			} else {
18447c478bd9Sstevel@tonic-gate 				rval = errno;
18457c478bd9Sstevel@tonic-gate 			}
18467c478bd9Sstevel@tonic-gate 			break;
18477c478bd9Sstevel@tonic-gate 		default:
18487c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, SYSEVENTCONFD_TRAN_ERR,
18497c478bd9Sstevel@tonic-gate 				strerror(errno));
18507c478bd9Sstevel@tonic-gate 			rval = errno;
18517c478bd9Sstevel@tonic-gate 			break;
18527c478bd9Sstevel@tonic-gate 		}
18537c478bd9Sstevel@tonic-gate 	} else if (confd_state != CONFD_STATE_OK) {
18547c478bd9Sstevel@tonic-gate 		if (confd_state == CONFD_STATE_ERR) {
18557c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, SYSEVENTCONFD_OK);
18567c478bd9Sstevel@tonic-gate 			confd_err_msg_emitted = 0;
18577c478bd9Sstevel@tonic-gate 		}
18587c478bd9Sstevel@tonic-gate 		confd_state = CONFD_STATE_OK;
18597c478bd9Sstevel@tonic-gate 		confd_retries = 0;
18607c478bd9Sstevel@tonic-gate 		confd_err_msg_emitted = 0;
18617c478bd9Sstevel@tonic-gate 	}
18627c478bd9Sstevel@tonic-gate 	return (rval);
18637c478bd9Sstevel@tonic-gate }
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate /*
18677c478bd9Sstevel@tonic-gate  * Send events on queue to syseventconfd daemon.  We queue events
18687c478bd9Sstevel@tonic-gate  * here since the daemon is unable to handle events during an
18697c478bd9Sstevel@tonic-gate  * active fork/exec, returning EAGAIN as a result.  It is grossly
18707c478bd9Sstevel@tonic-gate  * inefficient to bounce these events back to syseventd, so
18717c478bd9Sstevel@tonic-gate  * we queue them here for delivery.
18727c478bd9Sstevel@tonic-gate  *
18737c478bd9Sstevel@tonic-gate  * EAGAIN/EINTR don't indicate errors with the transport to
18747c478bd9Sstevel@tonic-gate  * syseventconfd itself, just the daemon is busy or some
18757c478bd9Sstevel@tonic-gate  * other transient difficulty.  We retry EBADF and other errors
18767c478bd9Sstevel@tonic-gate  * for some time, then eventually give up - something's broken.
18777c478bd9Sstevel@tonic-gate  *
18787c478bd9Sstevel@tonic-gate  * Error handling strategy:
18797c478bd9Sstevel@tonic-gate  * If we're trying to shut down and the syseventconfd daemon isn't
18807c478bd9Sstevel@tonic-gate  * responding, abort the queue so we don't cause the fini to hang
18817c478bd9Sstevel@tonic-gate  * forever.  Otherwise, EAGAIN/EINTR are retried forever, as
18827c478bd9Sstevel@tonic-gate  * we presume the daemon is active but either busy or some transient
18837c478bd9Sstevel@tonic-gate  * state is preventing the transport.  We make considerable effort
18847c478bd9Sstevel@tonic-gate  * to retry EBADF since the daemon may take some time to come up when
18857c478bd9Sstevel@tonic-gate  * restarted so don't want to give up too easily.  Once we enter
18867c478bd9Sstevel@tonic-gate  * the DISABLED state, we stop handling events altogther to
18877c478bd9Sstevel@tonic-gate  * avoid thrashing the system if the syseventconfd binary is
18887c478bd9Sstevel@tonic-gate  * corrupted or missing.  This state can be cleared by issuing
18897c478bd9Sstevel@tonic-gate  * a HUP signal to the syseventd daemon.  For errors other than
18907c478bd9Sstevel@tonic-gate  * EAGAIN/EINTR/EBADF, we just drop the event and if we get
18917c478bd9Sstevel@tonic-gate  * a certain number of these in a row, we enter the DISABLED
18927c478bd9Sstevel@tonic-gate  * state.
18937c478bd9Sstevel@tonic-gate  */
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate static void
18967c478bd9Sstevel@tonic-gate transport_queued_events()
18977c478bd9Sstevel@tonic-gate {
18987c478bd9Sstevel@tonic-gate 	int		rval;
18997c478bd9Sstevel@tonic-gate 	cmdqueue_t	*cmd;
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cmdq_lock);
19027c478bd9Sstevel@tonic-gate 	while (cmdq != NULL) {
19037c478bd9Sstevel@tonic-gate 		cmd = cmdq;
19047c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cmdq_lock);
19057c478bd9Sstevel@tonic-gate 		rval = transport_event(cmd->event);
19067c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&cmdq_lock);
19077c478bd9Sstevel@tonic-gate 		if (rval != 0) {
19087c478bd9Sstevel@tonic-gate 			switch (rval) {
19097c478bd9Sstevel@tonic-gate 			case EAGAIN:
19107c478bd9Sstevel@tonic-gate 			case EINTR:
19117c478bd9Sstevel@tonic-gate 				/*
19127c478bd9Sstevel@tonic-gate 				 * Limit retries in the case of fini
19137c478bd9Sstevel@tonic-gate 				 */
19147c478bd9Sstevel@tonic-gate 				if (want_fini) {
19157c478bd9Sstevel@tonic-gate 					if (++transport_retries == 16) {
19167c478bd9Sstevel@tonic-gate 						abort_cmd_queue();
19177c478bd9Sstevel@tonic-gate 					}
19187c478bd9Sstevel@tonic-gate 				}
19197c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&cmdq_lock);
19207c478bd9Sstevel@tonic-gate 				return;
19217c478bd9Sstevel@tonic-gate 			case EBADF:
19227c478bd9Sstevel@tonic-gate 				/*
19237c478bd9Sstevel@tonic-gate 				 * retry up to 16 times
19247c478bd9Sstevel@tonic-gate 				 */
19257c478bd9Sstevel@tonic-gate 				if (want_fini || ++transport_retries == 16) {
19267c478bd9Sstevel@tonic-gate 					abort_cmd_queue();
19277c478bd9Sstevel@tonic-gate 				}
19287c478bd9Sstevel@tonic-gate 				(void) mutex_unlock(&cmdq_lock);
19297c478bd9Sstevel@tonic-gate 				return;
19307c478bd9Sstevel@tonic-gate 			default:
19317c478bd9Sstevel@tonic-gate 				/*
19327c478bd9Sstevel@tonic-gate 				 * After 16 sequential errors, give up
19337c478bd9Sstevel@tonic-gate 				 */
19347c478bd9Sstevel@tonic-gate 				if (++transport_retries == 16) {
19357c478bd9Sstevel@tonic-gate 					abort_cmd_queue();
19367c478bd9Sstevel@tonic-gate 					(void) mutex_unlock(&cmdq_lock);
19377c478bd9Sstevel@tonic-gate 					return;
19387c478bd9Sstevel@tonic-gate 				}
19397c478bd9Sstevel@tonic-gate 				/*
19407c478bd9Sstevel@tonic-gate 				 * We don't retry these errors, we
19417c478bd9Sstevel@tonic-gate 				 * fall through to remove this event
19427c478bd9Sstevel@tonic-gate 				 * from the queue.
19437c478bd9Sstevel@tonic-gate 				 */
19447c478bd9Sstevel@tonic-gate 				break;
19457c478bd9Sstevel@tonic-gate 			}
19467c478bd9Sstevel@tonic-gate 		} else {
19477c478bd9Sstevel@tonic-gate 			transport_retries = 0;
19487c478bd9Sstevel@tonic-gate 		}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 		/*
19517c478bd9Sstevel@tonic-gate 		 * Take completed event off queue
19527c478bd9Sstevel@tonic-gate 		 */
19537c478bd9Sstevel@tonic-gate 		cmdq_cnt--;
19547c478bd9Sstevel@tonic-gate 		cmdq = cmdq->next;
19557c478bd9Sstevel@tonic-gate 		if (cmdq == NULL) {
19567c478bd9Sstevel@tonic-gate 			cmdq_tail = NULL;
19577c478bd9Sstevel@tonic-gate 		}
19587c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cmdq_lock);
19597c478bd9Sstevel@tonic-gate 		sysevent_free(cmd->event);
19607c478bd9Sstevel@tonic-gate 		sc_free(cmd, sizeof (cmdqueue_t));
19617c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&cmdq_lock);
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cmdq_lock);
19657c478bd9Sstevel@tonic-gate }
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate static void
19697c478bd9Sstevel@tonic-gate queue_flush_thr()
19707c478bd9Sstevel@tonic-gate {
19717c478bd9Sstevel@tonic-gate 	int	n;
19727c478bd9Sstevel@tonic-gate 
19737c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cmdq_lock);
19747c478bd9Sstevel@tonic-gate 	for (;;) {
19757c478bd9Sstevel@tonic-gate 		while (cmdq_cnt == 0 && want_fini == 0) {
19767c478bd9Sstevel@tonic-gate 			(void) cond_wait(&cmdq_cv, &cmdq_lock);
19777c478bd9Sstevel@tonic-gate 		}
19787c478bd9Sstevel@tonic-gate 		if (cmdq_cnt == 0 && want_fini) {
19797c478bd9Sstevel@tonic-gate 			(void) cond_signal(&cmdq_thr_cv);
19807c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cmdq_lock);
19817c478bd9Sstevel@tonic-gate 			thr_exit(NULL);
19827c478bd9Sstevel@tonic-gate 			/*NOTREACHED*/
19837c478bd9Sstevel@tonic-gate 		}
19847c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(&cmdq_lock);
19857c478bd9Sstevel@tonic-gate 		transport_queued_events();
19867c478bd9Sstevel@tonic-gate 		(void) mutex_lock(&cmdq_lock);
19877c478bd9Sstevel@tonic-gate 		if (cmdq_cnt != 0) {
19887c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&cmdq_lock);
19897c478bd9Sstevel@tonic-gate 			if (want_fini == 0 && confd_err_msg_emitted) {
19907c478bd9Sstevel@tonic-gate 				for (n = 0; n < 60; n++) {
19917c478bd9Sstevel@tonic-gate 					(void) sleep(1);
19927c478bd9Sstevel@tonic-gate 					if (want_fini)
19937c478bd9Sstevel@tonic-gate 						break;
19947c478bd9Sstevel@tonic-gate 				}
19957c478bd9Sstevel@tonic-gate 			} else {
19967c478bd9Sstevel@tonic-gate 				(void) sleep(1);
19977c478bd9Sstevel@tonic-gate 			}
19987c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&cmdq_lock);
19997c478bd9Sstevel@tonic-gate 		}
20007c478bd9Sstevel@tonic-gate 	}
20017c478bd9Sstevel@tonic-gate }
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 
20047c478bd9Sstevel@tonic-gate /*
20057c478bd9Sstevel@tonic-gate  * syseventd daemon module event handler
20067c478bd9Sstevel@tonic-gate  *
20077c478bd9Sstevel@tonic-gate  * The syseventd daemon calls this handler with each event
20087c478bd9Sstevel@tonic-gate  * for this module to handle the event as appropriate.
20097c478bd9Sstevel@tonic-gate  * The task of this module is to compare the event's
20107c478bd9Sstevel@tonic-gate  * class/subclass/publisher/vendor against the list of
20117c478bd9Sstevel@tonic-gate  * event specifications provided in the installed
20127c478bd9Sstevel@tonic-gate  * sysevent.conf files.  Build and execute the
20137c478bd9Sstevel@tonic-gate  * defined command for that event specification
20147c478bd9Sstevel@tonic-gate  * for each match.
20157c478bd9Sstevel@tonic-gate  *
20167c478bd9Sstevel@tonic-gate  * Events are matched against the class, subclass, vendor
20177c478bd9Sstevel@tonic-gate  * and publisher specifications.  Any field not to be matched
20187c478bd9Sstevel@tonic-gate  * against an event should be set to '-'.  A specification
20197c478bd9Sstevel@tonic-gate  * of '- - - -' generates a match against every event.
20207c478bd9Sstevel@tonic-gate  */
20217c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20227c478bd9Sstevel@tonic-gate static int
20237c478bd9Sstevel@tonic-gate sysevent_conf_event(sysevent_t *ev, int flag)
20247c478bd9Sstevel@tonic-gate {
20257c478bd9Sstevel@tonic-gate 	int	ret = 0;
20267c478bd9Sstevel@tonic-gate 	char	*vendor;
20277c478bd9Sstevel@tonic-gate 	char	*publisher;
20287c478bd9Sstevel@tonic-gate 	char	*class;
20297c478bd9Sstevel@tonic-gate 	char	*subclass;
20307c478bd9Sstevel@tonic-gate 	syseventtab_t *sep;
20317c478bd9Sstevel@tonic-gate 	sysevent_hdr_info_t hdr;
20327c478bd9Sstevel@tonic-gate 	uint64_t seq;
20337c478bd9Sstevel@tonic-gate 	hrtime_t ts;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	/*
20367c478bd9Sstevel@tonic-gate 	 * If we've been completely unable to communicate with
20377c478bd9Sstevel@tonic-gate 	 * syseventconfd, there's not much we can do.
20387c478bd9Sstevel@tonic-gate 	 */
20397c478bd9Sstevel@tonic-gate 	if (confd_state == CONFD_STATE_DISABLED) {
20407c478bd9Sstevel@tonic-gate 		return (0);
20417c478bd9Sstevel@tonic-gate 	}
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate 	/*
20447c478bd9Sstevel@tonic-gate 	 * sysevent_get_seq(ev) < ev_seq):
20457c478bd9Sstevel@tonic-gate 	 *	an event we have played before, ignore it
20467c478bd9Sstevel@tonic-gate 	 * sysevent_get_seq(ev) == ev_seq):
20477c478bd9Sstevel@tonic-gate 	 *	ev_nretries > 0, an event being retried
20487c478bd9Sstevel@tonic-gate 	 * sysevent_get_seq(ev) > ev_seq):
20497c478bd9Sstevel@tonic-gate 	 *	a new event
20507c478bd9Sstevel@tonic-gate 	 */
20517c478bd9Sstevel@tonic-gate 	if (debug_level >= DBG_EVENTS) {
20527c478bd9Sstevel@tonic-gate 		if (sysevent_get_seq(ev) == ev_seq && ev_nretries > 0) {
20537c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_EVENTS,
20547c478bd9Sstevel@tonic-gate 			    "sequence: %lld/%lld, retry %d\n",
20557c478bd9Sstevel@tonic-gate 			    sysevent_get_seq(ev), ev_seq, ev_nretries);
20567c478bd9Sstevel@tonic-gate 		} else if (sysevent_get_seq(ev) > ev_seq) {
20577c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_EVENTS,
20587c478bd9Sstevel@tonic-gate 			    "sequence: %lld/%lld\n",
20597c478bd9Sstevel@tonic-gate 			    sysevent_get_seq(ev), ev_seq);
20607c478bd9Sstevel@tonic-gate 		}
20617c478bd9Sstevel@tonic-gate 	}
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	seq = sysevent_get_seq(ev);
20647c478bd9Sstevel@tonic-gate 	sysevent_get_time(ev, &ts);
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	if (seq > ev_seq || ts > ev_ts) {
20677c478bd9Sstevel@tonic-gate 		ev_nretries = 0;
20687c478bd9Sstevel@tonic-gate 	} else if (first_event == 0 &&
20697c478bd9Sstevel@tonic-gate 	    (((seq < ev_seq) || (seq == 0 && ts > ev_ts)) ||
20707c478bd9Sstevel@tonic-gate 	    (seq == ev_seq && ev_nretries == 0))) {
20717c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_TEST,
20727c478bd9Sstevel@tonic-gate 		    "out-of-order sequence: received %lld/0x%llx, "
20737c478bd9Sstevel@tonic-gate 		    "expected %lld/0x%llx\n", seq, ts, ev_seq+1, ev_ts);
20747c478bd9Sstevel@tonic-gate 		return (ret);
20757c478bd9Sstevel@tonic-gate 	}
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	ev_ts = ts;
20787c478bd9Sstevel@tonic-gate 	ev_seq = seq;
20797c478bd9Sstevel@tonic-gate 	first_event = 0;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	/*
20827c478bd9Sstevel@tonic-gate 	 * sysevent_get_vendor_name() and sysevent_get_pub_name()
20837c478bd9Sstevel@tonic-gate 	 * allocate strings which must be freed.
20847c478bd9Sstevel@tonic-gate 	 */
20857c478bd9Sstevel@tonic-gate 	vendor = sysevent_get_vendor_name(ev);
20867c478bd9Sstevel@tonic-gate 	publisher = sysevent_get_pub_name(ev);
20877c478bd9Sstevel@tonic-gate 	class = sysevent_get_class_name(ev);
20887c478bd9Sstevel@tonic-gate 	subclass = sysevent_get_subclass_name(ev);
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate 	if (vendor == NULL || publisher == NULL) {
20917c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_EVENTS, "Short on memory with vendor "
20927c478bd9Sstevel@tonic-gate 		    "and/or publisher string generation\n");
20937c478bd9Sstevel@tonic-gate 		/* Temporary short on memory */
20947c478bd9Sstevel@tonic-gate 		ev_nretries++;
20957c478bd9Sstevel@tonic-gate 		free(publisher);
20967c478bd9Sstevel@tonic-gate 		free(vendor);
20977c478bd9Sstevel@tonic-gate 		return (EAGAIN);
20987c478bd9Sstevel@tonic-gate 	}
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 	syseventd_print(DBG_EVENTS,
21017c478bd9Sstevel@tonic-gate 		"%s event %lld: vendor='%s' publisher='%s' class='%s' "
21027c478bd9Sstevel@tonic-gate 		"subclass='%s'\n", whoami, sysevent_get_seq(ev), vendor,
21037c478bd9Sstevel@tonic-gate 		publisher, class, subclass);
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 	for (sep = syseventtab; sep; sep = sep->se_next) {
21067c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_vendor, "-") != 0) {
21077c478bd9Sstevel@tonic-gate 			if (strcmp(sep->se_vendor, vendor) != 0)
21087c478bd9Sstevel@tonic-gate 				continue;
21097c478bd9Sstevel@tonic-gate 		}
21107c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_publisher, "-") != 0) {
21117c478bd9Sstevel@tonic-gate 			if (strcmp(sep->se_publisher, publisher) != 0)
21127c478bd9Sstevel@tonic-gate 				continue;
21137c478bd9Sstevel@tonic-gate 		}
21147c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_class, "-") != 0) {
21157c478bd9Sstevel@tonic-gate 			if (strcmp(sep->se_class, class) != 0)
21167c478bd9Sstevel@tonic-gate 				continue;
21177c478bd9Sstevel@tonic-gate 		}
21187c478bd9Sstevel@tonic-gate 		if (strcmp(sep->se_subclass, "-") != 0) {
21197c478bd9Sstevel@tonic-gate 			if (strcmp(sep->se_subclass, subclass) != 0)
21207c478bd9Sstevel@tonic-gate 				continue;
21217c478bd9Sstevel@tonic-gate 		}
21227c478bd9Sstevel@tonic-gate 		syseventd_print(DBG_MATCHES, "    event match: %s, line %d\n",
21237c478bd9Sstevel@tonic-gate 			sep->se_conf_file, sep->se_lineno);
21247c478bd9Sstevel@tonic-gate 		hdr.class = class;
21257c478bd9Sstevel@tonic-gate 		hdr.subclass = subclass;
21267c478bd9Sstevel@tonic-gate 		hdr.vendor = vendor;
21277c478bd9Sstevel@tonic-gate 		hdr.publisher = publisher;
21287c478bd9Sstevel@tonic-gate 		if ((ret = queue_event(ev, sep, &hdr)) != 0)
21297c478bd9Sstevel@tonic-gate 			break;
21307c478bd9Sstevel@tonic-gate 	}
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	if (ret == 0) {
21337c478bd9Sstevel@tonic-gate 		ev_nretries = 0;
21347c478bd9Sstevel@tonic-gate 	} else {
21357c478bd9Sstevel@tonic-gate 		/*
21367c478bd9Sstevel@tonic-gate 		 * Ask syseventd to retry any failed event.  If we have
21377c478bd9Sstevel@tonic-gate 		 * reached the limit on retries, emit a msg that we're
21387c478bd9Sstevel@tonic-gate 		 * not going to be able to service it.
21397c478bd9Sstevel@tonic-gate 		 */
21407c478bd9Sstevel@tonic-gate 		if (ev_nretries == SE_MAX_RETRY_LIMIT) {
21417c478bd9Sstevel@tonic-gate 			syslog(LOG_ERR, SYSEVENT_SEND_ERR,
21427c478bd9Sstevel@tonic-gate 				sep->se_conf_file, sep->se_lineno, errno);
21437c478bd9Sstevel@tonic-gate 		} else {
21447c478bd9Sstevel@tonic-gate 			syseventd_print(DBG_TEST, "%s event %lld: "
21457c478bd9Sstevel@tonic-gate 			    "'%s' '%s' '%s' '%s - errno %d, retry %d\n",
21467c478bd9Sstevel@tonic-gate 			    whoami, sysevent_get_seq(ev), vendor,
21477c478bd9Sstevel@tonic-gate 			    publisher, class, subclass, errno, ev_nretries);
21487c478bd9Sstevel@tonic-gate 		}
21497c478bd9Sstevel@tonic-gate 		ret = EAGAIN;
21507c478bd9Sstevel@tonic-gate 		ev_nretries++;
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	free(publisher);
21547c478bd9Sstevel@tonic-gate 	free(vendor);
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	return (ret);
21577c478bd9Sstevel@tonic-gate }
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate /*
21607c478bd9Sstevel@tonic-gate  * syseventd daemon module initialization
21617c478bd9Sstevel@tonic-gate  */
21627c478bd9Sstevel@tonic-gate struct slm_mod_ops *
21637c478bd9Sstevel@tonic-gate slm_init()
21647c478bd9Sstevel@tonic-gate {
21657c478bd9Sstevel@tonic-gate 	char	lock_file[PATH_MAX+1];
21667c478bd9Sstevel@tonic-gate 	int	lock_fd;
21677c478bd9Sstevel@tonic-gate 	int	err;
21687c478bd9Sstevel@tonic-gate 
21697c478bd9Sstevel@tonic-gate 	/*
21707c478bd9Sstevel@tonic-gate 	 * This functionality is not supported in the mini-root
21717c478bd9Sstevel@tonic-gate 	 * environment, ie install.  If root_dir is set, implying
21727c478bd9Sstevel@tonic-gate 	 * install, we quietly fail.  Return dummy ops rather
21737c478bd9Sstevel@tonic-gate 	 * than NULL to avoid error msgs out of syseventd.
21747c478bd9Sstevel@tonic-gate 	 */
21757c478bd9Sstevel@tonic-gate 	if (strcmp(root_dir, "") != 0) {
21767c478bd9Sstevel@tonic-gate 		return (&sysevent_conf_dummy_mod_ops);
21777c478bd9Sstevel@tonic-gate 	}
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	ev_nretries = 0;
21807c478bd9Sstevel@tonic-gate 	first_event = 1;
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 	/*
21837c478bd9Sstevel@tonic-gate 	 * Initialize the channel to syseventconfd
21847c478bd9Sstevel@tonic-gate 	 */
21857c478bd9Sstevel@tonic-gate 	confd_handle = sysevent_open_channel_alt(SYSEVENTCONFD_SERVICE_DOOR);
21867c478bd9Sstevel@tonic-gate 	if (confd_handle == NULL) {
21877c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, CHANNEL_OPEN_ERR);
21887c478bd9Sstevel@tonic-gate 		return (NULL);
21897c478bd9Sstevel@tonic-gate 	}
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	if (sysevent_bind_publisher(confd_handle) != 0) {
21927c478bd9Sstevel@tonic-gate 		if (errno == EBUSY) {
21937c478bd9Sstevel@tonic-gate 			sysevent_cleanup_publishers(confd_handle);
21947c478bd9Sstevel@tonic-gate 			if (sysevent_bind_publisher(confd_handle) != 0) {
21957c478bd9Sstevel@tonic-gate 				sysevent_close_channel(confd_handle);
21967c478bd9Sstevel@tonic-gate 				return (NULL);
21977c478bd9Sstevel@tonic-gate 			}
21987c478bd9Sstevel@tonic-gate 		}
21997c478bd9Sstevel@tonic-gate 	}
22007c478bd9Sstevel@tonic-gate 
22017c478bd9Sstevel@tonic-gate 	sysevent_cleanup_subscribers(confd_handle);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	cmdq = NULL;
22047c478bd9Sstevel@tonic-gate 	cmdq_tail = NULL;
22057c478bd9Sstevel@tonic-gate 	cmdq_cnt = 0;
22067c478bd9Sstevel@tonic-gate 	want_fini = 0;
22077c478bd9Sstevel@tonic-gate 	confd_err_msg_emitted = 0;
22087c478bd9Sstevel@tonic-gate 	if (confd_state != CONFD_STATE_OK) {
22097c478bd9Sstevel@tonic-gate 		confd_state = CONFD_STATE_NOT_RUNNING;
22107c478bd9Sstevel@tonic-gate 	}
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate 	confd_retries = 0;
22137c478bd9Sstevel@tonic-gate 	transport_retries = 0;
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	(void) mutex_init(&cmdq_lock, USYNC_THREAD, NULL);
22167c478bd9Sstevel@tonic-gate 	(void) cond_init(&cmdq_cv, USYNC_THREAD, NULL);
22177c478bd9Sstevel@tonic-gate 	(void) cond_init(&cmdq_thr_cv, USYNC_THREAD, NULL);
22187c478bd9Sstevel@tonic-gate 
22197c478bd9Sstevel@tonic-gate 	/*
22207c478bd9Sstevel@tonic-gate 	 * Create thread to flush cmd queue
22217c478bd9Sstevel@tonic-gate 	 */
22227c478bd9Sstevel@tonic-gate 	if ((err = thr_create(NULL, NULL, (void *(*)(void*))queue_flush_thr,
22237c478bd9Sstevel@tonic-gate 	    (void *)NULL, 0, &cmdq_thr_id)) != 0) {
22247c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, THR_CREATE_ERR, strerror(err));
22257c478bd9Sstevel@tonic-gate 		sysevent_close_channel(confd_handle);
22267c478bd9Sstevel@tonic-gate 		confd_handle = NULL;
22277c478bd9Sstevel@tonic-gate 		(void) mutex_destroy(&cmdq_lock);
22287c478bd9Sstevel@tonic-gate 		(void) cond_destroy(&cmdq_cv);
22297c478bd9Sstevel@tonic-gate 		(void) cond_destroy(&cmdq_thr_cv);
22307c478bd9Sstevel@tonic-gate 		return (NULL);
22317c478bd9Sstevel@tonic-gate 	}
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 	if ((lock_fd = enter_lock(lock_file)) == -1) {
22347c478bd9Sstevel@tonic-gate 		(void) thr_join(cmdq_thr_id, NULL, NULL);
22357c478bd9Sstevel@tonic-gate 		sysevent_close_channel(confd_handle);
22367c478bd9Sstevel@tonic-gate 		confd_handle = NULL;
22377c478bd9Sstevel@tonic-gate 		(void) mutex_destroy(&cmdq_lock);
22387c478bd9Sstevel@tonic-gate 		(void) cond_destroy(&cmdq_cv);
22397c478bd9Sstevel@tonic-gate 		(void) cond_destroy(&cmdq_thr_cv);
22407c478bd9Sstevel@tonic-gate 		return (NULL);
22417c478bd9Sstevel@tonic-gate 	}
22427c478bd9Sstevel@tonic-gate 
22437c478bd9Sstevel@tonic-gate 	build_event_table();
22447c478bd9Sstevel@tonic-gate 	exit_lock(lock_fd, lock_file);
22457c478bd9Sstevel@tonic-gate 	return (&sysevent_conf_mod_ops);
22467c478bd9Sstevel@tonic-gate }
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate /*
22497c478bd9Sstevel@tonic-gate  * syseventd daemon module tear-down
22507c478bd9Sstevel@tonic-gate  */
22517c478bd9Sstevel@tonic-gate void
22527c478bd9Sstevel@tonic-gate slm_fini()
22537c478bd9Sstevel@tonic-gate {
22547c478bd9Sstevel@tonic-gate 	int	err;
22557c478bd9Sstevel@tonic-gate 
22567c478bd9Sstevel@tonic-gate 	/*
22577c478bd9Sstevel@tonic-gate 	 * Nothing to clean up if we're in the install environment
22587c478bd9Sstevel@tonic-gate 	 */
22597c478bd9Sstevel@tonic-gate 	if (strcmp(root_dir, "") != 0) {
22607c478bd9Sstevel@tonic-gate 		return;
22617c478bd9Sstevel@tonic-gate 	}
22627c478bd9Sstevel@tonic-gate 
22637c478bd9Sstevel@tonic-gate 	/*
22647c478bd9Sstevel@tonic-gate 	 * Wait for the queue to drain
22657c478bd9Sstevel@tonic-gate 	 */
22667c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&cmdq_lock);
22677c478bd9Sstevel@tonic-gate 	want_fini = 1;
22687c478bd9Sstevel@tonic-gate 	(void) cond_signal(&cmdq_cv);
22697c478bd9Sstevel@tonic-gate 	(void) cond_wait(&cmdq_thr_cv, &cmdq_lock);
22707c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&cmdq_lock);
22717c478bd9Sstevel@tonic-gate 
22727c478bd9Sstevel@tonic-gate 	/*
22737c478bd9Sstevel@tonic-gate 	 * Shut down the the queue flush thread
22747c478bd9Sstevel@tonic-gate 	 */
22757c478bd9Sstevel@tonic-gate 	if ((err = thr_join(cmdq_thr_id, NULL, NULL)) != 0) {
22767c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR, THR_JOIN_ERR, strerror(err));
22777c478bd9Sstevel@tonic-gate 	}
22787c478bd9Sstevel@tonic-gate 
22797c478bd9Sstevel@tonic-gate 	sysevent_close_channel(confd_handle);
22807c478bd9Sstevel@tonic-gate 	confd_handle = NULL;
22817c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&cmdq_lock);
22827c478bd9Sstevel@tonic-gate 	(void) cond_destroy(&cmdq_cv);
22837c478bd9Sstevel@tonic-gate 	(void) cond_destroy(&cmdq_thr_cv);
22847c478bd9Sstevel@tonic-gate 	free_event_table();
22857c478bd9Sstevel@tonic-gate }
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
22887c478bd9Sstevel@tonic-gate static int
22897c478bd9Sstevel@tonic-gate sysevent_conf_dummy_event(sysevent_t *ev, int flag)
22907c478bd9Sstevel@tonic-gate {
22917c478bd9Sstevel@tonic-gate 	return (0);
22927c478bd9Sstevel@tonic-gate }
2293