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