17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
580ab886dSwesolows  * Common Development and Distribution License (the "License").
680ab886dSwesolows  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
2180ab886dSwesolows 
227c478bd9Sstevel@tonic-gate /*
23f6e214c7SGavin Maltby  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <stdio.h>
277c478bd9Sstevel@tonic-gate #include <fcntl.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <door.h>
307c478bd9Sstevel@tonic-gate #include <unistd.h>
317c478bd9Sstevel@tonic-gate #include <stddef.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <string.h>
347c478bd9Sstevel@tonic-gate #include <strings.h>
357c478bd9Sstevel@tonic-gate #include <synch.h>
367c478bd9Sstevel@tonic-gate #include <pthread.h>
37f6e214c7SGavin Maltby #include <signal.h>
387c478bd9Sstevel@tonic-gate #include <thread.h>
397c478bd9Sstevel@tonic-gate #include <libnvpair.h>
407c478bd9Sstevel@tonic-gate #include <assert.h>
417c478bd9Sstevel@tonic-gate #include <sys/stat.h>
427c478bd9Sstevel@tonic-gate #include <sys/types.h>
437c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
447c478bd9Sstevel@tonic-gate #include <sys/mnttab.h>
457c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
467c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate #include "libsysevent.h"
497c478bd9Sstevel@tonic-gate #include "libsysevent_impl.h"
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * libsysevent - The system event framework library
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  *		This library provides routines to help with marshalling
557c478bd9Sstevel@tonic-gate  *		and unmarshalling of data contained in a sysevent event
567c478bd9Sstevel@tonic-gate  *		buffer.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	SE_ENCODE_METHOD	NV_ENCODE_NATIVE
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #define	dprint	if (libsysevent_debug) (void) printf
627c478bd9Sstevel@tonic-gate static int libsysevent_debug = 0;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate static sysevent_t *se_unpack(sysevent_t *);
657c478bd9Sstevel@tonic-gate static int cleanup_id(sysevent_handle_t *shp, uint32_t id, int type);
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate /*
687c478bd9Sstevel@tonic-gate  * The following routines allow system event publication to the sysevent
697c478bd9Sstevel@tonic-gate  * framework.
707c478bd9Sstevel@tonic-gate  */
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate /*
737c478bd9Sstevel@tonic-gate  * sysevent_alloc - allocate a sysevent buffer
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate static sysevent_t *
sysevent_alloc(char * class,int class_sz,char * subclass,int subclass_sz,char * pub,int pub_sz,nvlist_t * attr_list)767c478bd9Sstevel@tonic-gate sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz,
770762f44eSToomas Soome     char *pub, int pub_sz, nvlist_t *attr_list)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 	int payload_sz;
807c478bd9Sstevel@tonic-gate 	int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
817c478bd9Sstevel@tonic-gate 	size_t nvlist_sz = 0;
827c478bd9Sstevel@tonic-gate 	char *attr;
837c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
847c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 	if (attr_list != NULL) {
877c478bd9Sstevel@tonic-gate 		if (nvlist_size(attr_list, &nvlist_sz, SE_ENCODE_METHOD)
887c478bd9Sstevel@tonic-gate 		    != 0) {
897c478bd9Sstevel@tonic-gate 			return (NULL);
907c478bd9Sstevel@tonic-gate 		}
917c478bd9Sstevel@tonic-gate 	}
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	/*
947c478bd9Sstevel@tonic-gate 	 * Calculate and reserve space for the class, subclass and
957c478bd9Sstevel@tonic-gate 	 * publisher strings in the event buffer
967c478bd9Sstevel@tonic-gate 	 */
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate 	/* String sizes must be 64-bit aligned in the event buffer */
997c478bd9Sstevel@tonic-gate 	aligned_class_sz = SE_ALIGN(class_sz);
1007c478bd9Sstevel@tonic-gate 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
1017c478bd9Sstevel@tonic-gate 	aligned_pub_sz = SE_ALIGN(pub_sz);
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
10449b225e1SGavin Maltby 	    (aligned_subclass_sz - sizeof (uint64_t)) +
10549b225e1SGavin Maltby 	    (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) +
10649b225e1SGavin Maltby 	    nvlist_sz;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	/*
1097c478bd9Sstevel@tonic-gate 	 * Allocate event buffer plus additional payload overhead.
1107c478bd9Sstevel@tonic-gate 	 */
1117c478bd9Sstevel@tonic-gate 	ev = calloc(1, sizeof (sysevent_impl_t) + payload_sz);
1127c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
1137c478bd9Sstevel@tonic-gate 		return (NULL);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	/* Initialize the event buffer data */
1177c478bd9Sstevel@tonic-gate 	SE_VERSION(ev) = SYS_EVENT_VERSION;
1187c478bd9Sstevel@tonic-gate 	(void) bcopy(class, SE_CLASS_NAME(ev), class_sz);
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
1217c478bd9Sstevel@tonic-gate 		+ aligned_class_sz;
1227c478bd9Sstevel@tonic-gate 	(void) bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
1257c478bd9Sstevel@tonic-gate 	(void) bcopy(pub, SE_PUB_NAME(ev), pub_sz);
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) = payload_sz;
1287c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = (uint64_t)0;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate 	/* Check for attribute list */
1317c478bd9Sstevel@tonic-gate 	if (attr_list == NULL) {
1327c478bd9Sstevel@tonic-gate 		return (ev);
1337c478bd9Sstevel@tonic-gate 	}
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	/* Copy attribute data to contiguous memory */
1367c478bd9Sstevel@tonic-gate 	SE_FLAG(ev) = SE_PACKED_BUF;
1377c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
1387c478bd9Sstevel@tonic-gate 	attr = (char *)((caddr_t)ev + attr_offset);
1397c478bd9Sstevel@tonic-gate 	if (nvlist_pack(attr_list, &attr, &nvlist_sz, SE_ENCODE_METHOD,
1407c478bd9Sstevel@tonic-gate 	    0) != 0) {
1417c478bd9Sstevel@tonic-gate 		free(ev);
1427c478bd9Sstevel@tonic-gate 		return (NULL);
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	return (ev);
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate /*
1497c478bd9Sstevel@tonic-gate  * sysevent_post_event - generate a system event via the sysevent framework
1507c478bd9Sstevel@tonic-gate  */
1517c478bd9Sstevel@tonic-gate int
sysevent_post_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list,sysevent_id_t * eid)1527c478bd9Sstevel@tonic-gate sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name,
1530762f44eSToomas Soome     nvlist_t *attr_list, sysevent_id_t *eid)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	int error;
1567c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 	ev = sysevent_alloc_event(class, subclass, vendor, pub_name, attr_list);
1597c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
1607c478bd9Sstevel@tonic-gate 		return (-1);
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT,
16449b225e1SGavin Maltby 	    (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), (uintptr_t)eid, 0);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	sysevent_free(ev);
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate 	if (error) {
1697c478bd9Sstevel@tonic-gate 		errno = EIO;
1707c478bd9Sstevel@tonic-gate 		return (-1);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	return (0);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate /*
1777c478bd9Sstevel@tonic-gate  * The following routines are used to free or duplicate a
1787c478bd9Sstevel@tonic-gate  * sysevent event buffer.
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate  * sysevent_dup - Allocate and copy an event buffer
1837c478bd9Sstevel@tonic-gate  *	Copies both packed and unpacked to unpacked sysevent.
1847c478bd9Sstevel@tonic-gate  */
1857c478bd9Sstevel@tonic-gate sysevent_t *
sysevent_dup(sysevent_t * ev)1867c478bd9Sstevel@tonic-gate sysevent_dup(sysevent_t *ev)
1877c478bd9Sstevel@tonic-gate {
1887c478bd9Sstevel@tonic-gate 	nvlist_t *nvl, *cnvl = NULL;
1897c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
1907c478bd9Sstevel@tonic-gate 	sysevent_t *copy;
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate 	if (SE_FLAG(ev) == SE_PACKED_BUF)
1937c478bd9Sstevel@tonic-gate 		return (se_unpack(ev));
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate 	/* Copy event header information */
1967c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
1977c478bd9Sstevel@tonic-gate 	copy = calloc(1, attr_offset);
1987c478bd9Sstevel@tonic-gate 	if (copy == NULL)
1997c478bd9Sstevel@tonic-gate 		return (NULL);
2007c478bd9Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
2017c478bd9Sstevel@tonic-gate 
20280ab886dSwesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2037c478bd9Sstevel@tonic-gate 	if (nvl && nvlist_dup(nvl, &cnvl, 0) != 0) {
2047c478bd9Sstevel@tonic-gate 		free(copy);
2057c478bd9Sstevel@tonic-gate 		return (NULL);
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = (uintptr_t)cnvl;
2097c478bd9Sstevel@tonic-gate 	SE_FLAG(copy) = 0;	/* unpacked */
2107c478bd9Sstevel@tonic-gate 	return (copy);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate /*
2147c478bd9Sstevel@tonic-gate  * sysevent_free - Free memory allocated for an event buffer
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate void
sysevent_free(sysevent_t * ev)2177c478bd9Sstevel@tonic-gate sysevent_free(sysevent_t *ev)
2187c478bd9Sstevel@tonic-gate {
21980ab886dSwesolows 	nvlist_t *attr_list = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2207c478bd9Sstevel@tonic-gate 
221aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(attr_list);
2227c478bd9Sstevel@tonic-gate 	free(ev);
2237c478bd9Sstevel@tonic-gate }
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate /*
2267c478bd9Sstevel@tonic-gate  * The following routines are used to extract attribute data from a sysevent
2277c478bd9Sstevel@tonic-gate  * handle.
2287c478bd9Sstevel@tonic-gate  */
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate /*
2317c478bd9Sstevel@tonic-gate  * sysevent_get_attr_list - allocate and return an attribute associated with
2327c478bd9Sstevel@tonic-gate  *			the given sysevent buffer.
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate int
sysevent_get_attr_list(sysevent_t * ev,nvlist_t ** nvlist)2357c478bd9Sstevel@tonic-gate sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	int error;
2387c478bd9Sstevel@tonic-gate 	caddr_t attr;
2397c478bd9Sstevel@tonic-gate 	size_t attr_len;
2407c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
2417c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	*nvlist = NULL;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/* Duplicate attribute for an unpacked sysevent buffer */
2467c478bd9Sstevel@tonic-gate 	if (SE_FLAG(ev) != SE_PACKED_BUF) {
24780ab886dSwesolows 		nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2487c478bd9Sstevel@tonic-gate 		if (nvl == NULL) {
2497c478bd9Sstevel@tonic-gate 			return (0);
2507c478bd9Sstevel@tonic-gate 		}
2517c478bd9Sstevel@tonic-gate 		if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) {
2527c478bd9Sstevel@tonic-gate 			if (error == ENOMEM) {
2537c478bd9Sstevel@tonic-gate 				errno = error;
2547c478bd9Sstevel@tonic-gate 			} else {
2557c478bd9Sstevel@tonic-gate 				errno = EINVAL;
2567c478bd9Sstevel@tonic-gate 			}
2577c478bd9Sstevel@tonic-gate 			return (-1);
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 		return (0);
2607c478bd9Sstevel@tonic-gate 	}
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
2637c478bd9Sstevel@tonic-gate 	if (SE_SIZE(ev) == attr_offset) {
2647c478bd9Sstevel@tonic-gate 		return (0);
2657c478bd9Sstevel@tonic-gate 	}
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* unpack nvlist */
2687c478bd9Sstevel@tonic-gate 	attr = (caddr_t)ev + attr_offset;
2697c478bd9Sstevel@tonic-gate 	attr_len = SE_SIZE(ev) - attr_offset;
2707c478bd9Sstevel@tonic-gate 	if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
2717c478bd9Sstevel@tonic-gate 		if (error == ENOMEM) {
2727c478bd9Sstevel@tonic-gate 			errno = error;
2730762f44eSToomas Soome 		} else {
2747c478bd9Sstevel@tonic-gate 			errno = EINVAL;
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 		return (-1);
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	return (0);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * sysevent_attr_name - Get name of attribute
2847c478bd9Sstevel@tonic-gate  */
2857c478bd9Sstevel@tonic-gate char *
sysevent_attr_name(sysevent_attr_t * attr)2867c478bd9Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr)
2877c478bd9Sstevel@tonic-gate {
2887c478bd9Sstevel@tonic-gate 	if (attr == NULL) {
2897c478bd9Sstevel@tonic-gate 		errno = EINVAL;
2907c478bd9Sstevel@tonic-gate 		return (NULL);
2917c478bd9Sstevel@tonic-gate 	}
2927c478bd9Sstevel@tonic-gate 	return (nvpair_name((nvpair_t *)attr));
2937c478bd9Sstevel@tonic-gate }
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate /*
2967c478bd9Sstevel@tonic-gate  * sysevent_attr_value - Get attribute value data and type
2977c478bd9Sstevel@tonic-gate  */
2987c478bd9Sstevel@tonic-gate int
sysevent_attr_value(sysevent_attr_t * attr,sysevent_value_t * se_value)2997c478bd9Sstevel@tonic-gate sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value)
3007c478bd9Sstevel@tonic-gate {
3017c478bd9Sstevel@tonic-gate 	nvpair_t *nvp = attr;
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate 	if (nvp == NULL)
3047c478bd9Sstevel@tonic-gate 		return (EINVAL);
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	/* Convert DATA_TYPE_* to SE_DATA_TYPE_* */
3077c478bd9Sstevel@tonic-gate 	switch (nvpair_type(nvp)) {
3087c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
3097c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_BYTE;
3107c478bd9Sstevel@tonic-gate 		(void) nvpair_value_byte(nvp, &se_value->value.sv_byte);
3117c478bd9Sstevel@tonic-gate 		break;
3127c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT16:
3137c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT16;
3147c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int16(nvp, &se_value->value.sv_int16);
3157c478bd9Sstevel@tonic-gate 		break;
3167c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
3177c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT16;
3187c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16);
3197c478bd9Sstevel@tonic-gate 		break;
3207c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT32:
3217c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT32;
3227c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int32(nvp, &se_value->value.sv_int32);
3237c478bd9Sstevel@tonic-gate 		break;
3247c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
3257c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT32;
3267c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32);
3277c478bd9Sstevel@tonic-gate 		break;
3287c478bd9Sstevel@tonic-gate 	case DATA_TYPE_INT64:
3297c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT64;
3307c478bd9Sstevel@tonic-gate 		(void) nvpair_value_int64(nvp, &se_value->value.sv_int64);
3317c478bd9Sstevel@tonic-gate 		break;
3327c478bd9Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
3337c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT64;
3347c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64);
3357c478bd9Sstevel@tonic-gate 		break;
3367c478bd9Sstevel@tonic-gate 	case DATA_TYPE_STRING:
3377c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_STRING;
3387c478bd9Sstevel@tonic-gate 		(void) nvpair_value_string(nvp, &se_value->value.sv_string);
3397c478bd9Sstevel@tonic-gate 		break;
3407c478bd9Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
3417c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_BYTES;
3427c478bd9Sstevel@tonic-gate 		(void) nvpair_value_byte_array(nvp,
3437c478bd9Sstevel@tonic-gate 		    &se_value->value.sv_bytes.data,
3447c478bd9Sstevel@tonic-gate 		    (uint_t *)&se_value->value.sv_bytes.size);
3457c478bd9Sstevel@tonic-gate 		break;
3467c478bd9Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
3477c478bd9Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_TIME;
3487c478bd9Sstevel@tonic-gate 		(void) nvpair_value_hrtime(nvp, &se_value->value.sv_time);
3497c478bd9Sstevel@tonic-gate 		break;
3507c478bd9Sstevel@tonic-gate 	default:
3517c478bd9Sstevel@tonic-gate 		return (ENOTSUP);
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	return (0);
3547c478bd9Sstevel@tonic-gate }
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate /*
3577c478bd9Sstevel@tonic-gate  * sysevent_attr_next - Get next attribute in event attribute list
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate sysevent_attr_t *
sysevent_attr_next(sysevent_t * ev,sysevent_attr_t * attr)3607c478bd9Sstevel@tonic-gate sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr)
3617c478bd9Sstevel@tonic-gate {
3627c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
3637c478bd9Sstevel@tonic-gate 	nvpair_t *nvp = attr;
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	/* all user visible sysevent_t's are unpacked */
3667c478bd9Sstevel@tonic-gate 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
3697c478bd9Sstevel@tonic-gate 		return (NULL);
3707c478bd9Sstevel@tonic-gate 	}
3717c478bd9Sstevel@tonic-gate 
37280ab886dSwesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
3737c478bd9Sstevel@tonic-gate 	return (nvlist_next_nvpair(nvl, nvp));
3747c478bd9Sstevel@tonic-gate }
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * sysevent_lookup_attr - Lookup attribute by name and datatype.
3787c478bd9Sstevel@tonic-gate  */
3797c478bd9Sstevel@tonic-gate int
sysevent_lookup_attr(sysevent_t * ev,char * name,int datatype,sysevent_value_t * se_value)3807c478bd9Sstevel@tonic-gate sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype,
3810762f44eSToomas Soome     sysevent_value_t *se_value)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	nvpair_t *nvp;
3847c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
3897c478bd9Sstevel@tonic-gate 		return (ENOENT);
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate 	/*
3937c478bd9Sstevel@tonic-gate 	 * sysevent matches on both name and datatype
3947c478bd9Sstevel@tonic-gate 	 * nvlist_look mataches name only. So we walk
3957c478bd9Sstevel@tonic-gate 	 * nvlist manually here.
3967c478bd9Sstevel@tonic-gate 	 */
39780ab886dSwesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
3987c478bd9Sstevel@tonic-gate 	nvp = nvlist_next_nvpair(nvl, NULL);
3997c478bd9Sstevel@tonic-gate 	while (nvp) {
4007c478bd9Sstevel@tonic-gate 		if ((strcmp(name, nvpair_name(nvp)) == 0) &&
4017c478bd9Sstevel@tonic-gate 		    (sysevent_attr_value(nvp, se_value) == 0) &&
4027c478bd9Sstevel@tonic-gate 		    (se_value->value_type == datatype))
4037c478bd9Sstevel@tonic-gate 			return (0);
4047c478bd9Sstevel@tonic-gate 		nvp = nvlist_next_nvpair(nvl, nvp);
4057c478bd9Sstevel@tonic-gate 	}
4067c478bd9Sstevel@tonic-gate 	return (ENOENT);
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate /* Routines to extract event header information */
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate /*
4127c478bd9Sstevel@tonic-gate  * sysevent_get_class - Get class id
4137c478bd9Sstevel@tonic-gate  */
4147c478bd9Sstevel@tonic-gate int
sysevent_get_class(sysevent_t * ev)4157c478bd9Sstevel@tonic-gate sysevent_get_class(sysevent_t *ev)
4167c478bd9Sstevel@tonic-gate {
4177c478bd9Sstevel@tonic-gate 	return (SE_CLASS(ev));
4187c478bd9Sstevel@tonic-gate }
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate  * sysevent_get_subclass - Get subclass id
4227c478bd9Sstevel@tonic-gate  */
4237c478bd9Sstevel@tonic-gate int
sysevent_get_subclass(sysevent_t * ev)4247c478bd9Sstevel@tonic-gate sysevent_get_subclass(sysevent_t *ev)
4257c478bd9Sstevel@tonic-gate {
4267c478bd9Sstevel@tonic-gate 	return (SE_SUBCLASS(ev));
4277c478bd9Sstevel@tonic-gate }
4287c478bd9Sstevel@tonic-gate 
4297c478bd9Sstevel@tonic-gate /*
4307c478bd9Sstevel@tonic-gate  * sysevent_get_class_name - Get class name string
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate char *
sysevent_get_class_name(sysevent_t * ev)4337c478bd9Sstevel@tonic-gate sysevent_get_class_name(sysevent_t *ev)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	return (SE_CLASS_NAME(ev));
4367c478bd9Sstevel@tonic-gate }
4377c478bd9Sstevel@tonic-gate 
4387c478bd9Sstevel@tonic-gate typedef enum {
4397c478bd9Sstevel@tonic-gate 	PUB_VEND,
4407c478bd9Sstevel@tonic-gate 	PUB_KEYWD,
4417c478bd9Sstevel@tonic-gate 	PUB_NAME,
4427c478bd9Sstevel@tonic-gate 	PUB_PID
4437c478bd9Sstevel@tonic-gate } se_pub_id_t;
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate /*
4467c478bd9Sstevel@tonic-gate  * sysevent_get_pub - Get publisher name string
4477c478bd9Sstevel@tonic-gate  */
4487c478bd9Sstevel@tonic-gate char *
sysevent_get_pub(sysevent_t * ev)4497c478bd9Sstevel@tonic-gate sysevent_get_pub(sysevent_t *ev)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	return (SE_PUB_NAME(ev));
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /*
4557c478bd9Sstevel@tonic-gate  * Get the requested string pointed by the token.
4567c478bd9Sstevel@tonic-gate  *
4577c478bd9Sstevel@tonic-gate  * Return NULL if not found or for insufficient memory.
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate static char *
parse_pub_id(sysevent_t * ev,se_pub_id_t token)4607c478bd9Sstevel@tonic-gate parse_pub_id(sysevent_t *ev, se_pub_id_t token)
4617c478bd9Sstevel@tonic-gate {
4627c478bd9Sstevel@tonic-gate 	int i;
4637c478bd9Sstevel@tonic-gate 	char *pub_id, *pub_element, *str, *next;
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	next = pub_id = strdup(sysevent_get_pub(ev));
4667c478bd9Sstevel@tonic-gate 	for (i = 0; i <= token; ++i) {
4677c478bd9Sstevel@tonic-gate 		str = strtok_r(next, ":", &next);
4687c478bd9Sstevel@tonic-gate 		if (str == NULL) {
4697c478bd9Sstevel@tonic-gate 			free(pub_id);
4707c478bd9Sstevel@tonic-gate 			return (NULL);
4717c478bd9Sstevel@tonic-gate 		}
4727c478bd9Sstevel@tonic-gate 	}
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	pub_element = strdup(str);
4757c478bd9Sstevel@tonic-gate 	free(pub_id);
4767c478bd9Sstevel@tonic-gate 	return (pub_element);
4777c478bd9Sstevel@tonic-gate }
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate /*
4807c478bd9Sstevel@tonic-gate  * Return a pointer to the string following the token
4817c478bd9Sstevel@tonic-gate  *
4827c478bd9Sstevel@tonic-gate  * Note: This is a dedicated function for parsing
4837c478bd9Sstevel@tonic-gate  * publisher strings and not for general purpose.
4847c478bd9Sstevel@tonic-gate  */
4857c478bd9Sstevel@tonic-gate static const char *
pub_idx(const char * pstr,int token)4867c478bd9Sstevel@tonic-gate pub_idx(const char *pstr, int token)
4877c478bd9Sstevel@tonic-gate {
4887c478bd9Sstevel@tonic-gate 	int i;
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate 	for (i = 1; i <= token; i++) {
4917c478bd9Sstevel@tonic-gate 		if ((pstr = index(pstr, ':')) == NULL)
4927c478bd9Sstevel@tonic-gate 			return (NULL);
4937c478bd9Sstevel@tonic-gate 		pstr++;
4947c478bd9Sstevel@tonic-gate 	}
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate 	/* String might be empty */
4977c478bd9Sstevel@tonic-gate 	if (pstr) {
4987c478bd9Sstevel@tonic-gate 		if (*pstr == '\0' || *pstr == ':')
4997c478bd9Sstevel@tonic-gate 			return (NULL);
5007c478bd9Sstevel@tonic-gate 	}
5017c478bd9Sstevel@tonic-gate 	return (pstr);
5027c478bd9Sstevel@tonic-gate }
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate char *
sysevent_get_vendor_name(sysevent_t * ev)5057c478bd9Sstevel@tonic-gate sysevent_get_vendor_name(sysevent_t *ev)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	return (parse_pub_id(ev, PUB_VEND));
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate char *
sysevent_get_pub_name(sysevent_t * ev)5117c478bd9Sstevel@tonic-gate sysevent_get_pub_name(sysevent_t *ev)
5127c478bd9Sstevel@tonic-gate {
5137c478bd9Sstevel@tonic-gate 	return (parse_pub_id(ev, PUB_NAME));
5147c478bd9Sstevel@tonic-gate }
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate  * Provide the pid encoded in the publisher string
5187c478bd9Sstevel@tonic-gate  * w/o allocating any resouces.
5197c478bd9Sstevel@tonic-gate  */
5207c478bd9Sstevel@tonic-gate void
sysevent_get_pid(sysevent_t * ev,pid_t * pid)5217c478bd9Sstevel@tonic-gate sysevent_get_pid(sysevent_t *ev, pid_t *pid)
5227c478bd9Sstevel@tonic-gate {
5237c478bd9Sstevel@tonic-gate 	const char *part_str;
5247c478bd9Sstevel@tonic-gate 	const char *pub_str = sysevent_get_pub(ev);
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	*pid = (pid_t)SE_KERN_PID;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	part_str = pub_idx(pub_str, PUB_KEYWD);
5297c478bd9Sstevel@tonic-gate 	if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL)
5307c478bd9Sstevel@tonic-gate 		return;
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL)
5337c478bd9Sstevel@tonic-gate 		return;
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate 	*pid = (pid_t)atoi(part_str);
5367c478bd9Sstevel@tonic-gate }
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate /*
5397c478bd9Sstevel@tonic-gate  * sysevent_get_subclass_name - Get subclass name string
5407c478bd9Sstevel@tonic-gate  */
5417c478bd9Sstevel@tonic-gate char *
sysevent_get_subclass_name(sysevent_t * ev)5427c478bd9Sstevel@tonic-gate sysevent_get_subclass_name(sysevent_t *ev)
5437c478bd9Sstevel@tonic-gate {
5447c478bd9Sstevel@tonic-gate 	return (SE_SUBCLASS_NAME(ev));
5457c478bd9Sstevel@tonic-gate }
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate /*
5487c478bd9Sstevel@tonic-gate  * sysevent_get_seq - Get event sequence id
5497c478bd9Sstevel@tonic-gate  */
5507c478bd9Sstevel@tonic-gate uint64_t
sysevent_get_seq(sysevent_t * ev)5517c478bd9Sstevel@tonic-gate sysevent_get_seq(sysevent_t *ev)
5527c478bd9Sstevel@tonic-gate {
5537c478bd9Sstevel@tonic-gate 	return (SE_SEQ(ev));
5547c478bd9Sstevel@tonic-gate }
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate  * sysevent_get_time - Get event timestamp
5587c478bd9Sstevel@tonic-gate  */
5597c478bd9Sstevel@tonic-gate void
sysevent_get_time(sysevent_t * ev,hrtime_t * etime)5607c478bd9Sstevel@tonic-gate sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
5617c478bd9Sstevel@tonic-gate {
5627c478bd9Sstevel@tonic-gate 	*etime = SE_TIME(ev);
5637c478bd9Sstevel@tonic-gate }
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate /*
5667c478bd9Sstevel@tonic-gate  * sysevent_get_size - Get event buffer size
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate size_t
sysevent_get_size(sysevent_t * ev)5697c478bd9Sstevel@tonic-gate sysevent_get_size(sysevent_t *ev)
5707c478bd9Sstevel@tonic-gate {
5717c478bd9Sstevel@tonic-gate 	return ((size_t)SE_SIZE(ev));
5727c478bd9Sstevel@tonic-gate }
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate /*
5757c478bd9Sstevel@tonic-gate  * The following routines are used by devfsadm_mod.c to propagate event
5767c478bd9Sstevel@tonic-gate  * buffers to devfsadmd.  These routines will serve as the basis for
5777c478bd9Sstevel@tonic-gate  * event channel publication and subscription.
5787c478bd9Sstevel@tonic-gate  */
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate /*
5817c478bd9Sstevel@tonic-gate  * sysevent_alloc_event -
5827c478bd9Sstevel@tonic-gate  *	allocate a sysevent buffer for sending through an established event
5837c478bd9Sstevel@tonic-gate  *	channel.
5847c478bd9Sstevel@tonic-gate  */
5857c478bd9Sstevel@tonic-gate sysevent_t *
sysevent_alloc_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list)5867c478bd9Sstevel@tonic-gate sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name,
5870762f44eSToomas Soome     nvlist_t *attr_list)
5887c478bd9Sstevel@tonic-gate {
5897c478bd9Sstevel@tonic-gate 	int class_sz, subclass_sz, pub_sz;
5907c478bd9Sstevel@tonic-gate 	char *pub_id;
5917c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
5927c478bd9Sstevel@tonic-gate 
5937c478bd9Sstevel@tonic-gate 	if ((class == NULL) || (subclass == NULL) || (vendor == NULL) ||
5947c478bd9Sstevel@tonic-gate 	    (pub_name == NULL)) {
5957c478bd9Sstevel@tonic-gate 		errno = EINVAL;
5967c478bd9Sstevel@tonic-gate 		return (NULL);
5977c478bd9Sstevel@tonic-gate 	}
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
6007c478bd9Sstevel@tonic-gate 	subclass_sz = strlen(subclass) + 1;
6017c478bd9Sstevel@tonic-gate 	if ((class_sz > MAX_CLASS_LEN) ||
6027c478bd9Sstevel@tonic-gate 	    (subclass_sz > MAX_SUBCLASS_LEN)) {
6037c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6047c478bd9Sstevel@tonic-gate 		return (NULL);
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * Calculate the publisher size plus string seperators and maximum
6097c478bd9Sstevel@tonic-gate 	 * pid characters
6107c478bd9Sstevel@tonic-gate 	 */
6117c478bd9Sstevel@tonic-gate 	pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14;
6127c478bd9Sstevel@tonic-gate 	if (pub_sz > MAX_PUB_LEN) {
6137c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6147c478bd9Sstevel@tonic-gate 		return (NULL);
6157c478bd9Sstevel@tonic-gate 	}
6167c478bd9Sstevel@tonic-gate 	pub_id = malloc(pub_sz);
6177c478bd9Sstevel@tonic-gate 	if (pub_id == NULL) {
6187c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6197c478bd9Sstevel@tonic-gate 		return (NULL);
6207c478bd9Sstevel@tonic-gate 	}
6217c478bd9Sstevel@tonic-gate 	if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB,
6227c478bd9Sstevel@tonic-gate 	    pub_name, (int)getpid()) >= pub_sz) {
6237c478bd9Sstevel@tonic-gate 		free(pub_id);
6247c478bd9Sstevel@tonic-gate 		errno = EINVAL;
6257c478bd9Sstevel@tonic-gate 		return (NULL);
6267c478bd9Sstevel@tonic-gate 	}
6277c478bd9Sstevel@tonic-gate 	pub_sz = strlen(pub_id) + 1;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	ev = sysevent_alloc(class, class_sz, subclass, subclass_sz,
6307c478bd9Sstevel@tonic-gate 	    pub_id, pub_sz, attr_list);
6317c478bd9Sstevel@tonic-gate 	free(pub_id);
6327c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
6337c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
6347c478bd9Sstevel@tonic-gate 		return (NULL);
6357c478bd9Sstevel@tonic-gate 	}
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 	return (ev);
6387c478bd9Sstevel@tonic-gate }
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate /*
6417c478bd9Sstevel@tonic-gate  * se_unpack - unpack nvlist to a searchable list.
6427c478bd9Sstevel@tonic-gate  *	If already unpacked, will do a dup.
6437c478bd9Sstevel@tonic-gate  */
6447c478bd9Sstevel@tonic-gate static sysevent_t *
se_unpack(sysevent_t * ev)6457c478bd9Sstevel@tonic-gate se_unpack(sysevent_t *ev)
6467c478bd9Sstevel@tonic-gate {
6477c478bd9Sstevel@tonic-gate 	caddr_t attr;
6487c478bd9Sstevel@tonic-gate 	size_t attr_len;
6497c478bd9Sstevel@tonic-gate 	nvlist_t *attrp = NULL;
6507c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
6517c478bd9Sstevel@tonic-gate 	sysevent_t *copy;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	assert(SE_FLAG(ev) == SE_PACKED_BUF);
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	/* Copy event header information */
6567c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
6577c478bd9Sstevel@tonic-gate 	copy = calloc(1, attr_offset);
6587c478bd9Sstevel@tonic-gate 	if (copy == NULL)
6597c478bd9Sstevel@tonic-gate 		return (NULL);
6607c478bd9Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
6617c478bd9Sstevel@tonic-gate 	SE_FLAG(copy) = 0;	/* unpacked */
6627c478bd9Sstevel@tonic-gate 
6637c478bd9Sstevel@tonic-gate 	/* unpack nvlist */
6647c478bd9Sstevel@tonic-gate 	attr = (caddr_t)ev + attr_offset;
6657c478bd9Sstevel@tonic-gate 	attr_len = SE_SIZE(ev) - attr_offset;
6667c478bd9Sstevel@tonic-gate 	if (attr_len == 0) {
6677c478bd9Sstevel@tonic-gate 		return (copy);
6687c478bd9Sstevel@tonic-gate 	}
6697c478bd9Sstevel@tonic-gate 	if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) {
6707c478bd9Sstevel@tonic-gate 		free(copy);
6717c478bd9Sstevel@tonic-gate 		return (NULL);
6727c478bd9Sstevel@tonic-gate 	}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = (uintptr_t)attrp;
6757c478bd9Sstevel@tonic-gate 	return (copy);
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate /*
6797c478bd9Sstevel@tonic-gate  * se_print - Prints elements in an event buffer
6807c478bd9Sstevel@tonic-gate  */
6817c478bd9Sstevel@tonic-gate void
se_print(FILE * fp,sysevent_t * ev)6827c478bd9Sstevel@tonic-gate se_print(FILE *fp, sysevent_t *ev)
6837c478bd9Sstevel@tonic-gate {
6847c478bd9Sstevel@tonic-gate 	char *vendor, *pub;
6857c478bd9Sstevel@tonic-gate 	pid_t pid;
6867c478bd9Sstevel@tonic-gate 	hrtime_t hrt;
6877c478bd9Sstevel@tonic-gate 	nvlist_t *attr_list = NULL;
6887c478bd9Sstevel@tonic-gate 
6897c478bd9Sstevel@tonic-gate 	(void) sysevent_get_time(ev, &hrt);
6907c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n",
69149b225e1SGavin Maltby 	    hrt, (longlong_t)sysevent_get_seq(ev));
6927c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev));
6937c478bd9Sstevel@tonic-gate 	(void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev));
6947c478bd9Sstevel@tonic-gate 	if ((vendor =  sysevent_get_vendor_name(ev)) != NULL) {
6957c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\tvendor = %s\n", vendor);
6967c478bd9Sstevel@tonic-gate 		free(vendor);
6977c478bd9Sstevel@tonic-gate 	}
6987c478bd9Sstevel@tonic-gate 	if ((pub = sysevent_get_pub_name(ev)) != NULL) {
6997c478bd9Sstevel@tonic-gate 		sysevent_get_pid(ev, &pid);
7007c478bd9Sstevel@tonic-gate 		(void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid);
7017c478bd9Sstevel@tonic-gate 		free(pub);
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) {
7057c478bd9Sstevel@tonic-gate 		nvlist_print(fp, attr_list);
7067c478bd9Sstevel@tonic-gate 		nvlist_free(attr_list);
7077c478bd9Sstevel@tonic-gate 	}
7087c478bd9Sstevel@tonic-gate }
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate /*
7117c478bd9Sstevel@tonic-gate  * The following routines are provided to support establishment and use
7127c478bd9Sstevel@tonic-gate  * of sysevent channels.  A sysevent channel is established between
7137c478bd9Sstevel@tonic-gate  * publishers and subscribers of sysevents for an agreed upon channel name.
7147c478bd9Sstevel@tonic-gate  * These routines currently support sysevent channels between user-level
7157c478bd9Sstevel@tonic-gate  * applications running on the same system.
7167c478bd9Sstevel@tonic-gate  *
7177c478bd9Sstevel@tonic-gate  * Sysevent channels may be created by a single publisher or subscriber process.
7187c478bd9Sstevel@tonic-gate  * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in
7197c478bd9Sstevel@tonic-gate  * receiving sysevent notifications on the named channel.  At present, only
7207c478bd9Sstevel@tonic-gate  * one publisher is allowed per sysevent channel.
7217c478bd9Sstevel@tonic-gate  *
7227c478bd9Sstevel@tonic-gate  * The registration information for each channel is kept in the kernel.  A
7237c478bd9Sstevel@tonic-gate  * kernel-based registration was chosen for persistence and reliability reasons.
7247c478bd9Sstevel@tonic-gate  * If either a publisher or a subscriber exits for any reason, the channel
7257c478bd9Sstevel@tonic-gate  * properties are maintained until all publishers and subscribers have exited.
7267c478bd9Sstevel@tonic-gate  * Additionally, an in-kernel registration allows the API to be extended to
7277c478bd9Sstevel@tonic-gate  * include kernel subscribers as well as userland subscribers in the future.
7287c478bd9Sstevel@tonic-gate  *
7297c478bd9Sstevel@tonic-gate  * To insure fast lookup of subscriptions, a cached copy of the registration
7307c478bd9Sstevel@tonic-gate  * is kept and maintained for the publisher process.  Updates are made
7317c478bd9Sstevel@tonic-gate  * everytime a change is made in the kernel.  Changes to the registration are
7327c478bd9Sstevel@tonic-gate  * expected to be infrequent.
7337c478bd9Sstevel@tonic-gate  *
7347c478bd9Sstevel@tonic-gate  * Channel communication between publisher and subscriber processes is
7357c478bd9Sstevel@tonic-gate  * implemented primarily via doors.  Each publisher creates a door for
7367c478bd9Sstevel@tonic-gate  * registration notifications and each subscriber creates a door for event
7377c478bd9Sstevel@tonic-gate  * delivery.
7387c478bd9Sstevel@tonic-gate  *
739*bbf21555SRichard Lowe  * Most of these routines are used by syseventd(8), the sysevent publisher
7407c478bd9Sstevel@tonic-gate  * for the syseventd channel.  Processes wishing to receive sysevent
7417c478bd9Sstevel@tonic-gate  * notifications from syseventd may use a set of public
7427c478bd9Sstevel@tonic-gate  * APIs designed to subscribe to syseventd sysevents.  The subscription
7437c478bd9Sstevel@tonic-gate  * APIs are implemented in accordance with PSARC/2001/076.
7447c478bd9Sstevel@tonic-gate  *
7457c478bd9Sstevel@tonic-gate  */
7467c478bd9Sstevel@tonic-gate 
7477c478bd9Sstevel@tonic-gate /*
7487c478bd9Sstevel@tonic-gate  * Door handlers for the channel subscribers
7497c478bd9Sstevel@tonic-gate  */
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate /*
7527c478bd9Sstevel@tonic-gate  * subscriber_event_handler - generic event handling wrapper for subscribers
7537c478bd9Sstevel@tonic-gate  *			This handler is used to process incoming sysevent
7547c478bd9Sstevel@tonic-gate  *			notifications from channel publishers.
7557c478bd9Sstevel@tonic-gate  *			It is created as a seperate thread in each subscriber
7567c478bd9Sstevel@tonic-gate  *			process per subscription.
7577c478bd9Sstevel@tonic-gate  */
75855622cebSToomas Soome static void *
subscriber_event_handler(void * arg)75955622cebSToomas Soome subscriber_event_handler(void *arg)
7607c478bd9Sstevel@tonic-gate {
76155622cebSToomas Soome 	sysevent_handle_t *shp = arg;
7627c478bd9Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
7637c478bd9Sstevel@tonic-gate 	sysevent_queue_t *evqp;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
7667c478bd9Sstevel@tonic-gate 
767f6e214c7SGavin Maltby 	/* See hack alert in sysevent_bind_subscriber_cmn */
7680762f44eSToomas Soome 	if (sub_info->sp_handler_tid == 0)
769f6e214c7SGavin Maltby 		sub_info->sp_handler_tid = thr_self();
770f6e214c7SGavin Maltby 
7717c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
7727c478bd9Sstevel@tonic-gate 	for (;;) {
7737c478bd9Sstevel@tonic-gate 		while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) {
7747c478bd9Sstevel@tonic-gate 			(void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock);
7757c478bd9Sstevel@tonic-gate 		}
7767c478bd9Sstevel@tonic-gate 		evqp = sub_info->sp_evq_head;
7777c478bd9Sstevel@tonic-gate 		while (evqp) {
7787c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&sub_info->sp_qlock);
7797c478bd9Sstevel@tonic-gate 			(void) sub_info->sp_func(evqp->sq_ev);
7807c478bd9Sstevel@tonic-gate 			(void) mutex_lock(&sub_info->sp_qlock);
7817c478bd9Sstevel@tonic-gate 			sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next;
7827c478bd9Sstevel@tonic-gate 			free(evqp->sq_ev);
7837c478bd9Sstevel@tonic-gate 			free(evqp);
7847c478bd9Sstevel@tonic-gate 			evqp = sub_info->sp_evq_head;
7857c478bd9Sstevel@tonic-gate 		}
7867c478bd9Sstevel@tonic-gate 		if (!SH_BOUND(shp)) {
7877c478bd9Sstevel@tonic-gate 			(void) mutex_unlock(&sub_info->sp_qlock);
78855622cebSToomas Soome 			return (NULL);
7897c478bd9Sstevel@tonic-gate 		}
7907c478bd9Sstevel@tonic-gate 	}
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
7937c478bd9Sstevel@tonic-gate }
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate /*
7967c478bd9Sstevel@tonic-gate  * Data structure used to communicate event subscription cache updates
7977c478bd9Sstevel@tonic-gate  * to publishers via a registration door
7987c478bd9Sstevel@tonic-gate  */
7997c478bd9Sstevel@tonic-gate struct reg_args {
8007c478bd9Sstevel@tonic-gate 	uint32_t ra_sub_id;
8017c478bd9Sstevel@tonic-gate 	uint32_t ra_op;
8027c478bd9Sstevel@tonic-gate 	uint64_t ra_buf_ptr;
8037c478bd9Sstevel@tonic-gate };
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate /*
8077c478bd9Sstevel@tonic-gate  * event_deliver_service - generic event delivery service routine.  This routine
8087c478bd9Sstevel@tonic-gate  *		is called in response to a door call to post an event.
8097c478bd9Sstevel@tonic-gate  *
8107c478bd9Sstevel@tonic-gate  */
81149b225e1SGavin Maltby /*ARGSUSED*/
8127c478bd9Sstevel@tonic-gate static void
event_deliver_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)8137c478bd9Sstevel@tonic-gate event_deliver_service(void *cookie, char *args, size_t alen,
8147c478bd9Sstevel@tonic-gate     door_desc_t *ddp, uint_t ndid)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	int	ret = 0;
8177c478bd9Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
8187c478bd9Sstevel@tonic-gate 	sysevent_handle_t *shp;
8197c478bd9Sstevel@tonic-gate 	sysevent_queue_t *new_eq;
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if (args == NULL || alen < sizeof (uint32_t)) {
8227c478bd9Sstevel@tonic-gate 		ret = EINVAL;
8237c478bd9Sstevel@tonic-gate 		goto return_from_door;
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	/* Publisher checking on subscriber */
8277c478bd9Sstevel@tonic-gate 	if (alen == sizeof (uint32_t)) {
8287c478bd9Sstevel@tonic-gate 		ret = 0;
8297c478bd9Sstevel@tonic-gate 		goto return_from_door;
8307c478bd9Sstevel@tonic-gate 	}
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	shp = (sysevent_handle_t *)cookie;
8337c478bd9Sstevel@tonic-gate 	if (shp == NULL) {
8347c478bd9Sstevel@tonic-gate 		ret = EBADF;
8357c478bd9Sstevel@tonic-gate 		goto return_from_door;
8367c478bd9Sstevel@tonic-gate 	}
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/*
8397c478bd9Sstevel@tonic-gate 	 * Mustn't block if we are trying to update the registration with
8407c478bd9Sstevel@tonic-gate 	 * the publisher
8417c478bd9Sstevel@tonic-gate 	 */
8427c478bd9Sstevel@tonic-gate 	if (mutex_trylock(SH_LOCK(shp)) != 0) {
8437c478bd9Sstevel@tonic-gate 		ret = EAGAIN;
8447c478bd9Sstevel@tonic-gate 		goto return_from_door;
8457c478bd9Sstevel@tonic-gate 	}
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
8487c478bd9Sstevel@tonic-gate 		ret = EBADF;
8497c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8507c478bd9Sstevel@tonic-gate 		goto return_from_door;
8517c478bd9Sstevel@tonic-gate 	}
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
8547c478bd9Sstevel@tonic-gate 	if (sub_info == NULL) {
8557c478bd9Sstevel@tonic-gate 		ret = EBADF;
8567c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8577c478bd9Sstevel@tonic-gate 		goto return_from_door;
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	new_eq = (sysevent_queue_t *)calloc(1,
8617c478bd9Sstevel@tonic-gate 	    sizeof (sysevent_queue_t));
8627c478bd9Sstevel@tonic-gate 	if (new_eq == NULL) {
8637c478bd9Sstevel@tonic-gate 		ret = EAGAIN;
8647c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8657c478bd9Sstevel@tonic-gate 		goto return_from_door;
8667c478bd9Sstevel@tonic-gate 	}
8677c478bd9Sstevel@tonic-gate 
8687c478bd9Sstevel@tonic-gate 	/*
8697c478bd9Sstevel@tonic-gate 	 * Allocate and copy the event buffer into the subscriber's
8707c478bd9Sstevel@tonic-gate 	 * address space
8717c478bd9Sstevel@tonic-gate 	 */
8727c478bd9Sstevel@tonic-gate 	new_eq->sq_ev = calloc(1, alen);
8737c478bd9Sstevel@tonic-gate 	if (new_eq->sq_ev == NULL) {
8747c478bd9Sstevel@tonic-gate 		free(new_eq);
8757c478bd9Sstevel@tonic-gate 		ret = EAGAIN;
8767c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8777c478bd9Sstevel@tonic-gate 		goto return_from_door;
8787c478bd9Sstevel@tonic-gate 	}
8797c478bd9Sstevel@tonic-gate 	(void) bcopy(args, new_eq->sq_ev, alen);
8807c478bd9Sstevel@tonic-gate 
8817c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
8827c478bd9Sstevel@tonic-gate 	if (sub_info->sp_evq_head == NULL) {
8837c478bd9Sstevel@tonic-gate 		sub_info->sp_evq_head = new_eq;
8847c478bd9Sstevel@tonic-gate 	} else {
8857c478bd9Sstevel@tonic-gate 		sub_info->sp_evq_tail->sq_next = new_eq;
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate 	sub_info->sp_evq_tail = new_eq;
8887c478bd9Sstevel@tonic-gate 
8897c478bd9Sstevel@tonic-gate 	(void) cond_signal(&sub_info->sp_cv);
8907c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&sub_info->sp_qlock);
8917c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate return_from_door:
8947c478bd9Sstevel@tonic-gate 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
8957c478bd9Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
8967c478bd9Sstevel@tonic-gate }
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate /*
8997c478bd9Sstevel@tonic-gate  * Sysevent subscription information is maintained in the kernel.  Updates
9007c478bd9Sstevel@tonic-gate  * to the in-kernel registration database is expected to be infrequent and
9017c478bd9Sstevel@tonic-gate  * offers consistency for publishers and subscribers that may come and go
9027c478bd9Sstevel@tonic-gate  * for a given channel.
9037c478bd9Sstevel@tonic-gate  *
9047c478bd9Sstevel@tonic-gate  * To expedite registration lookups by publishers, a cached copy of the
9057c478bd9Sstevel@tonic-gate  * kernel registration database is kept per-channel.  Caches are invalidated
9067c478bd9Sstevel@tonic-gate  * and refreshed upon state changes to the in-kernel registration database.
9077c478bd9Sstevel@tonic-gate  *
9087c478bd9Sstevel@tonic-gate  * To prevent stale subscriber data, publishers may remove subsriber
9097c478bd9Sstevel@tonic-gate  * registrations from the in-kernel registration database in the event
9107c478bd9Sstevel@tonic-gate  * that a particular subscribing process is unresponsive.
9117c478bd9Sstevel@tonic-gate  *
9127c478bd9Sstevel@tonic-gate  * The following routines provide a mechanism to update publisher and subscriber
9137c478bd9Sstevel@tonic-gate  * information for a specified channel.
9147c478bd9Sstevel@tonic-gate  */
9157c478bd9Sstevel@tonic-gate 
9167c478bd9Sstevel@tonic-gate /*
9177c478bd9Sstevel@tonic-gate  * clnt_deliver_event - Deliver an event through the consumer's event
9187c478bd9Sstevel@tonic-gate  *			delivery door
9197c478bd9Sstevel@tonic-gate  *
9207c478bd9Sstevel@tonic-gate  * Returns -1 if message not delivered. With errno set to cause of error.
9217c478bd9Sstevel@tonic-gate  * Returns 0 for success with the results returned in posting buffer.
9227c478bd9Sstevel@tonic-gate  */
9237c478bd9Sstevel@tonic-gate static int
clnt_deliver_event(int service_door,void * data,size_t datalen,void * result,size_t rlen)9247c478bd9Sstevel@tonic-gate clnt_deliver_event(int service_door, void *data, size_t datalen,
9250762f44eSToomas Soome     void *result, size_t rlen)
9267c478bd9Sstevel@tonic-gate {
9277c478bd9Sstevel@tonic-gate 	int error = 0;
9287c478bd9Sstevel@tonic-gate 	door_arg_t door_arg;
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	door_arg.rbuf = result;
9317c478bd9Sstevel@tonic-gate 	door_arg.rsize = rlen;
9327c478bd9Sstevel@tonic-gate 	door_arg.data_ptr = data;
9337c478bd9Sstevel@tonic-gate 	door_arg.data_size = datalen;
9347c478bd9Sstevel@tonic-gate 	door_arg.desc_ptr = NULL;
9357c478bd9Sstevel@tonic-gate 	door_arg.desc_num = 0;
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/*
9387c478bd9Sstevel@tonic-gate 	 * Make door call
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 	while ((error = door_call(service_door, &door_arg)) != 0) {
9417c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR) {
9427c478bd9Sstevel@tonic-gate 			continue;
9437c478bd9Sstevel@tonic-gate 		} else {
9447c478bd9Sstevel@tonic-gate 			error = errno;
9457c478bd9Sstevel@tonic-gate 			break;
9467c478bd9Sstevel@tonic-gate 		}
9477c478bd9Sstevel@tonic-gate 	}
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	return (error);
9507c478bd9Sstevel@tonic-gate }
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate static int
update_publisher_cache(subscriber_priv_t * sub_info,int update_op,uint32_t sub_id,size_t datasz,uchar_t * data)9537c478bd9Sstevel@tonic-gate update_publisher_cache(subscriber_priv_t *sub_info, int update_op,
9540762f44eSToomas Soome     uint32_t sub_id, size_t datasz, uchar_t *data)
9557c478bd9Sstevel@tonic-gate {
9567c478bd9Sstevel@tonic-gate 	int pub_fd;
9577c478bd9Sstevel@tonic-gate 	uint32_t result = 0;
9587c478bd9Sstevel@tonic-gate 	struct reg_args *rargs;
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate 	rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) +
9617c478bd9Sstevel@tonic-gate 	    datasz);
9627c478bd9Sstevel@tonic-gate 	if (rargs == NULL) {
9637c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
9647c478bd9Sstevel@tonic-gate 		return (-1);
9657c478bd9Sstevel@tonic-gate 	}
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	rargs->ra_sub_id = sub_id;
9687c478bd9Sstevel@tonic-gate 	rargs->ra_op = update_op;
9697c478bd9Sstevel@tonic-gate 	bcopy(data, (char *)&rargs->ra_buf_ptr, datasz);
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	pub_fd = open(sub_info->sp_door_name, O_RDONLY);
9727c478bd9Sstevel@tonic-gate 	(void) clnt_deliver_event(pub_fd, (void *)rargs,
9737c478bd9Sstevel@tonic-gate 	    sizeof (struct reg_args) + datasz, &result, sizeof (result));
9747c478bd9Sstevel@tonic-gate 	(void) close(pub_fd);
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	free(rargs);
9777c478bd9Sstevel@tonic-gate 	if (result != 0) {
9787c478bd9Sstevel@tonic-gate 		errno = result;
9797c478bd9Sstevel@tonic-gate 		return (-1);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate 	return (0);
9837c478bd9Sstevel@tonic-gate }
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate /*
9877c478bd9Sstevel@tonic-gate  * update_kernel_registration - update the in-kernel registration for the
9887c478bd9Sstevel@tonic-gate  * given channel.
9897c478bd9Sstevel@tonic-gate  */
9907c478bd9Sstevel@tonic-gate static int
update_kernel_registration(sysevent_handle_t * shp,int update_type,int update_op,uint32_t * sub_id,size_t datasz,uchar_t * data)9917c478bd9Sstevel@tonic-gate update_kernel_registration(sysevent_handle_t *shp, int update_type,
9920762f44eSToomas Soome     int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data)
9937c478bd9Sstevel@tonic-gate {
9947c478bd9Sstevel@tonic-gate 	int error;
9957c478bd9Sstevel@tonic-gate 	char *channel_name = SH_CHANNEL_NAME(shp);
9967c478bd9Sstevel@tonic-gate 	se_pubsub_t udata;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	udata.ps_channel_name_len = strlen(channel_name) + 1;
9997c478bd9Sstevel@tonic-gate 	udata.ps_op = update_op;
10007c478bd9Sstevel@tonic-gate 	udata.ps_type = update_type;
10017c478bd9Sstevel@tonic-gate 	udata.ps_buflen = datasz;
10027c478bd9Sstevel@tonic-gate 	udata.ps_id = *sub_id;
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
10057c478bd9Sstevel@tonic-gate 	    (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0))
10067c478bd9Sstevel@tonic-gate 	    != 0) {
10077c478bd9Sstevel@tonic-gate 		return (error);
10087c478bd9Sstevel@tonic-gate 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	*sub_id = udata.ps_id;
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate 	return (error);
10137c478bd9Sstevel@tonic-gate }
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate /*
10167c478bd9Sstevel@tonic-gate  * get_kernel_registration - get the current subscriber registration for
10177c478bd9Sstevel@tonic-gate  * the given channel
10187c478bd9Sstevel@tonic-gate  */
10197c478bd9Sstevel@tonic-gate static nvlist_t *
get_kernel_registration(char * channel_name,uint32_t class_id)10207c478bd9Sstevel@tonic-gate get_kernel_registration(char *channel_name, uint32_t class_id)
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate 	char *nvlbuf;
10237c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
10247c478bd9Sstevel@tonic-gate 	se_pubsub_t udata;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ);
10277c478bd9Sstevel@tonic-gate 	if (nvlbuf == NULL) {
10287c478bd9Sstevel@tonic-gate 		return (NULL);
10297c478bd9Sstevel@tonic-gate 	}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	udata.ps_buflen = MAX_SUBSCRIPTION_SZ;
10327c478bd9Sstevel@tonic-gate 	udata.ps_channel_name_len = strlen(channel_name) + 1;
10337c478bd9Sstevel@tonic-gate 	udata.ps_id = class_id;
10347c478bd9Sstevel@tonic-gate 	udata.ps_op = SE_GET_REGISTRATION;
10357c478bd9Sstevel@tonic-gate 	udata.ps_type = PUBLISHER;
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
10387c478bd9Sstevel@tonic-gate 	    (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0)
10397c478bd9Sstevel@tonic-gate 	    != 0) {
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 		/* Need a bigger buffer to hold channel registration */
10427c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN) {
10437c478bd9Sstevel@tonic-gate 			free(nvlbuf);
10447c478bd9Sstevel@tonic-gate 			nvlbuf = calloc(1, udata.ps_buflen);
10457c478bd9Sstevel@tonic-gate 			if (nvlbuf == NULL)
10467c478bd9Sstevel@tonic-gate 				return (NULL);
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 			/* Try again */
10497c478bd9Sstevel@tonic-gate 			if (modctl(MODEVENTS,
10507c478bd9Sstevel@tonic-gate 			    (uintptr_t)MODEVENTS_REGISTER_EVENT,
10517c478bd9Sstevel@tonic-gate 			    (uintptr_t)channel_name, (uintptr_t)nvlbuf,
10527c478bd9Sstevel@tonic-gate 			    (uintptr_t)&udata, 0) != 0) {
10537c478bd9Sstevel@tonic-gate 				free(nvlbuf);
10547c478bd9Sstevel@tonic-gate 				return (NULL);
10557c478bd9Sstevel@tonic-gate 			}
10567c478bd9Sstevel@tonic-gate 		} else {
10577c478bd9Sstevel@tonic-gate 			free(nvlbuf);
10587c478bd9Sstevel@tonic-gate 			return (NULL);
10597c478bd9Sstevel@tonic-gate 		}
10607c478bd9Sstevel@tonic-gate 	}
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) {
10637c478bd9Sstevel@tonic-gate 		free(nvlbuf);
10647c478bd9Sstevel@tonic-gate 		return (NULL);
10657c478bd9Sstevel@tonic-gate 	}
10667c478bd9Sstevel@tonic-gate 	free(nvlbuf);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 	return (nvl);
10697c478bd9Sstevel@tonic-gate }
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate /*
10727c478bd9Sstevel@tonic-gate  * The following routines provide a mechanism for publishers to maintain
10737c478bd9Sstevel@tonic-gate  * subscriber information.
10747c478bd9Sstevel@tonic-gate  */
10757c478bd9Sstevel@tonic-gate 
10767c478bd9Sstevel@tonic-gate static void
dealloc_subscribers(sysevent_handle_t * shp)10777c478bd9Sstevel@tonic-gate dealloc_subscribers(sysevent_handle_t *shp)
10787c478bd9Sstevel@tonic-gate {
10797c478bd9Sstevel@tonic-gate 	int i;
10807c478bd9Sstevel@tonic-gate 	subscriber_data_t *sub;
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
10837c478bd9Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
10847c478bd9Sstevel@tonic-gate 		if (sub != NULL) {
10857c478bd9Sstevel@tonic-gate 			free(sub->sd_door_name);
10867c478bd9Sstevel@tonic-gate 			free(sub);
10877c478bd9Sstevel@tonic-gate 		}
10887c478bd9Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, i) = NULL;
10897c478bd9Sstevel@tonic-gate 	}
10907c478bd9Sstevel@tonic-gate }
10917c478bd9Sstevel@tonic-gate 
109249b225e1SGavin Maltby /*ARGSUSED*/
10937c478bd9Sstevel@tonic-gate static int
alloc_subscriber(sysevent_handle_t * shp,uint32_t sub_id,int oflag)10947c478bd9Sstevel@tonic-gate alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate 	subscriber_data_t *sub;
10977c478bd9Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	if (SH_SUBSCRIBER(shp, sub_id) != NULL) {
11007c478bd9Sstevel@tonic-gate 		return (0);
11017c478bd9Sstevel@tonic-gate 	}
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 	/* Allocate and initialize the subscriber data */
11047c478bd9Sstevel@tonic-gate 	sub = (subscriber_data_t *)calloc(1,
11057c478bd9Sstevel@tonic-gate 	    sizeof (subscriber_data_t));
11067c478bd9Sstevel@tonic-gate 	if (sub == NULL) {
11077c478bd9Sstevel@tonic-gate 		return (-1);
11087c478bd9Sstevel@tonic-gate 	}
11097c478bd9Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
11107c478bd9Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
11117c478bd9Sstevel@tonic-gate 		free(sub);
11127c478bd9Sstevel@tonic-gate 		return (-1);
11137c478bd9Sstevel@tonic-gate 	}
11147c478bd9Sstevel@tonic-gate 
11157c478bd9Sstevel@tonic-gate 	sub->sd_flag = ACTIVE;
11167c478bd9Sstevel@tonic-gate 	sub->sd_door_name = strdup(door_name);
11177c478bd9Sstevel@tonic-gate 	if (sub->sd_door_name == NULL) {
11187c478bd9Sstevel@tonic-gate 		free(sub);
11197c478bd9Sstevel@tonic-gate 		return (-1);
11207c478bd9Sstevel@tonic-gate 	}
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	SH_SUBSCRIBER(shp, sub_id) = sub;
11237c478bd9Sstevel@tonic-gate 	return (0);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate }
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate /*
11287c478bd9Sstevel@tonic-gate  * The following routines are used to update and maintain the registration cache
11297c478bd9Sstevel@tonic-gate  * for a particular sysevent channel.
11307c478bd9Sstevel@tonic-gate  */
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate static uint32_t
hash_func(const char * s)11337c478bd9Sstevel@tonic-gate hash_func(const char *s)
11347c478bd9Sstevel@tonic-gate {
11357c478bd9Sstevel@tonic-gate 	uint32_t result = 0;
11367c478bd9Sstevel@tonic-gate 	uint_t g;
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate 	while (*s != '\0') {
11397c478bd9Sstevel@tonic-gate 		result <<= 4;
11407c478bd9Sstevel@tonic-gate 		result += (uint32_t)*s++;
11417c478bd9Sstevel@tonic-gate 		g = result & 0xf0000000;
11427c478bd9Sstevel@tonic-gate 		if (g != 0) {
11437c478bd9Sstevel@tonic-gate 			result ^= g >> 24;
11447c478bd9Sstevel@tonic-gate 			result ^= g;
11457c478bd9Sstevel@tonic-gate 		}
11467c478bd9Sstevel@tonic-gate 	}
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 	return (result);
11497c478bd9Sstevel@tonic-gate }
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate subclass_lst_t *
cache_find_subclass(class_lst_t * c_list,char * subclass)11527c478bd9Sstevel@tonic-gate cache_find_subclass(class_lst_t *c_list, char *subclass)
11537c478bd9Sstevel@tonic-gate {
11547c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	if (c_list == NULL)
11577c478bd9Sstevel@tonic-gate 		return (NULL);
11587c478bd9Sstevel@tonic-gate 
11597c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
11607c478bd9Sstevel@tonic-gate 
11617c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
11627c478bd9Sstevel@tonic-gate 		if (strcmp(sc_list->sl_name, subclass) == 0) {
11637c478bd9Sstevel@tonic-gate 			return (sc_list);
11647c478bd9Sstevel@tonic-gate 		}
11657c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	return (NULL);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 
11727c478bd9Sstevel@tonic-gate static class_lst_t *
cache_find_class(sysevent_handle_t * shp,char * class)11737c478bd9Sstevel@tonic-gate cache_find_class(sysevent_handle_t *shp, char *class)
11747c478bd9Sstevel@tonic-gate {
11757c478bd9Sstevel@tonic-gate 	int index;
11767c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
11777c478bd9Sstevel@tonic-gate 	class_lst_t **class_hash = SH_CLASS_HASH(shp);
11787c478bd9Sstevel@tonic-gate 
11797c478bd9Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
11807c478bd9Sstevel@tonic-gate 		return (class_hash[0]);
11817c478bd9Sstevel@tonic-gate 	}
11827c478bd9Sstevel@tonic-gate 
11837c478bd9Sstevel@tonic-gate 	index = CLASS_HASH(class);
11847c478bd9Sstevel@tonic-gate 	c_list = class_hash[index];
11857c478bd9Sstevel@tonic-gate 	while (c_list != NULL) {
11867c478bd9Sstevel@tonic-gate 		if (strcmp(class, c_list->cl_name) == 0) {
11877c478bd9Sstevel@tonic-gate 			break;
11887c478bd9Sstevel@tonic-gate 		}
11897c478bd9Sstevel@tonic-gate 		c_list = c_list->cl_next;
11907c478bd9Sstevel@tonic-gate 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	return (c_list);
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate static int
cache_insert_subclass(class_lst_t * c_list,char ** subclass_names,int subclass_num,uint32_t sub_id)11967c478bd9Sstevel@tonic-gate cache_insert_subclass(class_lst_t *c_list, char **subclass_names,
11970762f44eSToomas Soome     int subclass_num, uint32_t sub_id)
11987c478bd9Sstevel@tonic-gate {
11997c478bd9Sstevel@tonic-gate 	int i;
12007c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
12017c478bd9Sstevel@tonic-gate 
12027c478bd9Sstevel@tonic-gate 	for (i = 0; i < subclass_num; ++i) {
12037c478bd9Sstevel@tonic-gate 		if ((sc_list = cache_find_subclass(c_list, subclass_names[i]))
12047c478bd9Sstevel@tonic-gate 		    != NULL) {
12057c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
12067c478bd9Sstevel@tonic-gate 		} else {
12077c478bd9Sstevel@tonic-gate 			sc_list = (subclass_lst_t *)calloc(1,
12087c478bd9Sstevel@tonic-gate 			    sizeof (subclass_lst_t));
12097c478bd9Sstevel@tonic-gate 			if (sc_list == NULL)
12107c478bd9Sstevel@tonic-gate 				return (-1);
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 			sc_list->sl_name = strdup(subclass_names[i]);
12137c478bd9Sstevel@tonic-gate 			if (sc_list->sl_name == NULL) {
12147c478bd9Sstevel@tonic-gate 				free(sc_list);
12157c478bd9Sstevel@tonic-gate 				return (-1);
12167c478bd9Sstevel@tonic-gate 			}
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
12197c478bd9Sstevel@tonic-gate 			sc_list->sl_next = c_list->cl_subclass_list;
12207c478bd9Sstevel@tonic-gate 			c_list->cl_subclass_list = sc_list;
12217c478bd9Sstevel@tonic-gate 		}
12227c478bd9Sstevel@tonic-gate 	}
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	return (0);
12257c478bd9Sstevel@tonic-gate }
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate static int
cache_insert_class(sysevent_handle_t * shp,char * class,char ** subclass_names,int subclass_num,uint32_t sub_id)12287c478bd9Sstevel@tonic-gate cache_insert_class(sysevent_handle_t *shp, char *class,
12290762f44eSToomas Soome     char **subclass_names, int subclass_num, uint32_t sub_id)
12307c478bd9Sstevel@tonic-gate {
12317c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
12347c478bd9Sstevel@tonic-gate 		char *subclass_all = EC_SUB_ALL;
12357c478bd9Sstevel@tonic-gate 
12367c478bd9Sstevel@tonic-gate 		(void) cache_insert_subclass(SH_CLASS_HASH(shp)[0],
12377c478bd9Sstevel@tonic-gate 		    (char **)&subclass_all, 1, sub_id);
12387c478bd9Sstevel@tonic-gate 		return (0);
12397c478bd9Sstevel@tonic-gate 	}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	/* New class, add to the registration cache */
12427c478bd9Sstevel@tonic-gate 	if ((c_list = cache_find_class(shp, class)) == NULL) {
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 		c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t));
12457c478bd9Sstevel@tonic-gate 		if (c_list == NULL) {
12467c478bd9Sstevel@tonic-gate 			return (1);
12477c478bd9Sstevel@tonic-gate 		}
12487c478bd9Sstevel@tonic-gate 		c_list->cl_name = strdup(class);
12497c478bd9Sstevel@tonic-gate 		if (c_list->cl_name == NULL) {
12507c478bd9Sstevel@tonic-gate 			free(c_list);
12517c478bd9Sstevel@tonic-gate 			return (1);
12527c478bd9Sstevel@tonic-gate 		}
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 		c_list->cl_subclass_list = (subclass_lst_t *)
12557c478bd9Sstevel@tonic-gate 		    calloc(1, sizeof (subclass_lst_t));
12567c478bd9Sstevel@tonic-gate 		if (c_list->cl_subclass_list == NULL) {
12577c478bd9Sstevel@tonic-gate 			free(c_list->cl_name);
12587c478bd9Sstevel@tonic-gate 			free(c_list);
12597c478bd9Sstevel@tonic-gate 			return (1);
12607c478bd9Sstevel@tonic-gate 		}
12617c478bd9Sstevel@tonic-gate 		c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL);
12627c478bd9Sstevel@tonic-gate 		if (c_list->cl_subclass_list->sl_name == NULL) {
12637c478bd9Sstevel@tonic-gate 			free(c_list->cl_subclass_list);
12647c478bd9Sstevel@tonic-gate 			free(c_list->cl_name);
12657c478bd9Sstevel@tonic-gate 			free(c_list);
12667c478bd9Sstevel@tonic-gate 			return (1);
12677c478bd9Sstevel@tonic-gate 		}
12687c478bd9Sstevel@tonic-gate 		c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)];
12697c478bd9Sstevel@tonic-gate 		SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list;
12707c478bd9Sstevel@tonic-gate 
12717c478bd9Sstevel@tonic-gate 	}
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate 	/* Update the subclass list */
12747c478bd9Sstevel@tonic-gate 	if (cache_insert_subclass(c_list, subclass_names, subclass_num,
12757c478bd9Sstevel@tonic-gate 	    sub_id) != 0)
12767c478bd9Sstevel@tonic-gate 		return (1);
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate 	return (0);
12797c478bd9Sstevel@tonic-gate }
12807c478bd9Sstevel@tonic-gate 
12817c478bd9Sstevel@tonic-gate static void
cache_remove_all_class(sysevent_handle_t * shp,uint32_t sub_id)12827c478bd9Sstevel@tonic-gate cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id)
12837c478bd9Sstevel@tonic-gate {
12847c478bd9Sstevel@tonic-gate 	int i;
12857c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
12867c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
12897c478bd9Sstevel@tonic-gate 		c_list = SH_CLASS_HASH(shp)[i];
12907c478bd9Sstevel@tonic-gate 		while (c_list != NULL) {
12917c478bd9Sstevel@tonic-gate 			sc_list = c_list->cl_subclass_list;
12927c478bd9Sstevel@tonic-gate 			while (sc_list != NULL) {
12937c478bd9Sstevel@tonic-gate 				sc_list->sl_num[sub_id] = 0;
12947c478bd9Sstevel@tonic-gate 				sc_list = sc_list->sl_next;
12957c478bd9Sstevel@tonic-gate 			}
12967c478bd9Sstevel@tonic-gate 			c_list = c_list->cl_next;
12977c478bd9Sstevel@tonic-gate 		}
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate static void
cache_remove_class(sysevent_handle_t * shp,char * class,uint32_t sub_id)13027c478bd9Sstevel@tonic-gate cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id)
13037c478bd9Sstevel@tonic-gate {
13047c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
13057c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
13067c478bd9Sstevel@tonic-gate 
13077c478bd9Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
13087c478bd9Sstevel@tonic-gate 		cache_remove_all_class(shp, sub_id);
13097c478bd9Sstevel@tonic-gate 		return;
13107c478bd9Sstevel@tonic-gate 	}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 	if ((c_list = cache_find_class(shp, class)) == NULL) {
13137c478bd9Sstevel@tonic-gate 		return;
13147c478bd9Sstevel@tonic-gate 	}
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
13177c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
13187c478bd9Sstevel@tonic-gate 		sc_list->sl_num[sub_id] = 0;
13197c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
13207c478bd9Sstevel@tonic-gate 	}
13217c478bd9Sstevel@tonic-gate }
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate static void
free_cached_registration(sysevent_handle_t * shp)13247c478bd9Sstevel@tonic-gate free_cached_registration(sysevent_handle_t *shp)
13257c478bd9Sstevel@tonic-gate {
13267c478bd9Sstevel@tonic-gate 	int i;
13277c478bd9Sstevel@tonic-gate 	class_lst_t *clist, *next_clist;
13287c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list, *next_sc;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; i++) {
13317c478bd9Sstevel@tonic-gate 		clist = SH_CLASS_HASH(shp)[i];
13327c478bd9Sstevel@tonic-gate 		while (clist != NULL) {
13337c478bd9Sstevel@tonic-gate 			sc_list = clist->cl_subclass_list;
13347c478bd9Sstevel@tonic-gate 			while (sc_list != NULL) {
13357c478bd9Sstevel@tonic-gate 				free(sc_list->sl_name);
13367c478bd9Sstevel@tonic-gate 				next_sc = sc_list->sl_next;
13377c478bd9Sstevel@tonic-gate 				free(sc_list);
13387c478bd9Sstevel@tonic-gate 				sc_list = next_sc;
13397c478bd9Sstevel@tonic-gate 			}
13407c478bd9Sstevel@tonic-gate 			free(clist->cl_name);
13417c478bd9Sstevel@tonic-gate 			next_clist = clist->cl_next;
13427c478bd9Sstevel@tonic-gate 			free(clist);
13437c478bd9Sstevel@tonic-gate 			clist = next_clist;
13447c478bd9Sstevel@tonic-gate 		}
13457c478bd9Sstevel@tonic-gate 		SH_CLASS_HASH(shp)[i] = NULL;
13467c478bd9Sstevel@tonic-gate 	}
13477c478bd9Sstevel@tonic-gate }
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate static int
create_cached_registration(sysevent_handle_t * shp,class_lst_t ** class_hash)13507c478bd9Sstevel@tonic-gate create_cached_registration(sysevent_handle_t *shp,
13510762f44eSToomas Soome     class_lst_t **class_hash)
13527c478bd9Sstevel@tonic-gate {
13537c478bd9Sstevel@tonic-gate 	int i, j, new_class;
13547c478bd9Sstevel@tonic-gate 	char *class_name;
13557c478bd9Sstevel@tonic-gate 	uint_t num_elem;
13567c478bd9Sstevel@tonic-gate 	uchar_t *subscribers;
13577c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
13587c478bd9Sstevel@tonic-gate 	nvpair_t *nvpair;
13597c478bd9Sstevel@tonic-gate 	class_lst_t *clist;
13607c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
13617c478bd9Sstevel@tonic-gate 
13627c478bd9Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 		if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i))
13657c478bd9Sstevel@tonic-gate 		    == NULL) {
13667c478bd9Sstevel@tonic-gate 			if (errno == ENOENT) {
13677c478bd9Sstevel@tonic-gate 				class_hash[i] = NULL;
13687c478bd9Sstevel@tonic-gate 				continue;
13697c478bd9Sstevel@tonic-gate 			} else {
13707c478bd9Sstevel@tonic-gate 				goto create_failed;
13717c478bd9Sstevel@tonic-gate 			}
13727c478bd9Sstevel@tonic-gate 		}
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 
13757c478bd9Sstevel@tonic-gate 		nvpair = NULL;
13767c478bd9Sstevel@tonic-gate 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
13777c478bd9Sstevel@tonic-gate 			goto create_failed;
13787c478bd9Sstevel@tonic-gate 		}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 		new_class = 1;
13817c478bd9Sstevel@tonic-gate 		while (new_class) {
13827c478bd9Sstevel@tonic-gate 			/* Extract the class name from the nvpair */
13837c478bd9Sstevel@tonic-gate 			if (nvpair_value_string(nvpair, &class_name) != 0) {
13847c478bd9Sstevel@tonic-gate 				goto create_failed;
13857c478bd9Sstevel@tonic-gate 			}
13867c478bd9Sstevel@tonic-gate 			clist = (class_lst_t *)
13877c478bd9Sstevel@tonic-gate 			    calloc(1, sizeof (class_lst_t));
13887c478bd9Sstevel@tonic-gate 			if (clist == NULL) {
13897c478bd9Sstevel@tonic-gate 				goto create_failed;
13907c478bd9Sstevel@tonic-gate 			}
13917c478bd9Sstevel@tonic-gate 
13927c478bd9Sstevel@tonic-gate 			clist->cl_name = strdup(class_name);
13937c478bd9Sstevel@tonic-gate 			if (clist->cl_name == NULL) {
13947c478bd9Sstevel@tonic-gate 				free(clist);
13957c478bd9Sstevel@tonic-gate 				goto create_failed;
13967c478bd9Sstevel@tonic-gate 			}
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 			/*
13997c478bd9Sstevel@tonic-gate 			 * Extract the subclass name and registration
14007c478bd9Sstevel@tonic-gate 			 * from the nvpair
14017c478bd9Sstevel@tonic-gate 			 */
14027c478bd9Sstevel@tonic-gate 			if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
14037c478bd9Sstevel@tonic-gate 			    == NULL) {
14047c478bd9Sstevel@tonic-gate 				free(clist->cl_name);
14057c478bd9Sstevel@tonic-gate 				free(clist);
14067c478bd9Sstevel@tonic-gate 				goto create_failed;
14077c478bd9Sstevel@tonic-gate 			}
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 			clist->cl_next = class_hash[i];
14107c478bd9Sstevel@tonic-gate 			class_hash[i] = clist;
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 			for (;;) {
14137c478bd9Sstevel@tonic-gate 
14147c478bd9Sstevel@tonic-gate 				sc_list = (subclass_lst_t *)calloc(1,
14157c478bd9Sstevel@tonic-gate 				    sizeof (subclass_lst_t));
14167c478bd9Sstevel@tonic-gate 				if (sc_list == NULL) {
14177c478bd9Sstevel@tonic-gate 					goto create_failed;
14187c478bd9Sstevel@tonic-gate 				}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 				sc_list->sl_next = clist->cl_subclass_list;
14217c478bd9Sstevel@tonic-gate 				clist->cl_subclass_list = sc_list;
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 				sc_list->sl_name = strdup(nvpair_name(nvpair));
14247c478bd9Sstevel@tonic-gate 				if (sc_list->sl_name == NULL) {
14257c478bd9Sstevel@tonic-gate 					goto create_failed;
14267c478bd9Sstevel@tonic-gate 				}
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 				if (nvpair_value_byte_array(nvpair,
14297c478bd9Sstevel@tonic-gate 				    &subscribers, &num_elem) != 0) {
14307c478bd9Sstevel@tonic-gate 					goto create_failed;
14317c478bd9Sstevel@tonic-gate 				}
14327c478bd9Sstevel@tonic-gate 				bcopy(subscribers, (uchar_t *)sc_list->sl_num,
14337c478bd9Sstevel@tonic-gate 				    MAX_SUBSCRIBERS + 1);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 				for (j = 1; j <= MAX_SUBSCRIBERS; ++j) {
14367c478bd9Sstevel@tonic-gate 					if (sc_list->sl_num[j] == 0)
14377c478bd9Sstevel@tonic-gate 						continue;
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 					if (alloc_subscriber(shp, j, 1) != 0) {
14407c478bd9Sstevel@tonic-gate 						goto create_failed;
14417c478bd9Sstevel@tonic-gate 					}
14427c478bd9Sstevel@tonic-gate 				}
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 				/*
14457c478bd9Sstevel@tonic-gate 				 * Check next nvpair - either subclass or
14467c478bd9Sstevel@tonic-gate 				 * class
14477c478bd9Sstevel@tonic-gate 				 */
14487c478bd9Sstevel@tonic-gate 				if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
14497c478bd9Sstevel@tonic-gate 				    == NULL) {
14507c478bd9Sstevel@tonic-gate 					new_class = 0;
14517c478bd9Sstevel@tonic-gate 					break;
14527c478bd9Sstevel@tonic-gate 				} else if (strcmp(nvpair_name(nvpair),
14537c478bd9Sstevel@tonic-gate 				    CLASS_NAME) == 0) {
14547c478bd9Sstevel@tonic-gate 					break;
14557c478bd9Sstevel@tonic-gate 				}
14567c478bd9Sstevel@tonic-gate 			}
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 	return (0);
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate create_failed:
14637c478bd9Sstevel@tonic-gate 	dealloc_subscribers(shp);
14647c478bd9Sstevel@tonic-gate 	free_cached_registration(shp);
1465aab83bb8SJosef 'Jeff' Sipek 	nvlist_free(nvl);
14667c478bd9Sstevel@tonic-gate 	return (-1);
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate }
14697c478bd9Sstevel@tonic-gate 
14707c478bd9Sstevel@tonic-gate /*
14717c478bd9Sstevel@tonic-gate  * cache_update_service - generic event publisher service routine.  This routine
14727c478bd9Sstevel@tonic-gate  *		is called in response to a registration cache update.
14737c478bd9Sstevel@tonic-gate  *
14747c478bd9Sstevel@tonic-gate  */
147549b225e1SGavin Maltby /*ARGSUSED*/
14767c478bd9Sstevel@tonic-gate static void
cache_update_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)14777c478bd9Sstevel@tonic-gate cache_update_service(void *cookie, char *args, size_t alen,
14787c478bd9Sstevel@tonic-gate     door_desc_t *ddp, uint_t ndid)
14797c478bd9Sstevel@tonic-gate {
14807c478bd9Sstevel@tonic-gate 	int ret = 0;
14817c478bd9Sstevel@tonic-gate 	uint_t num_elem;
14827c478bd9Sstevel@tonic-gate 	char *class, **event_list;
14837c478bd9Sstevel@tonic-gate 	size_t datalen;
14847c478bd9Sstevel@tonic-gate 	uint32_t sub_id;
14857c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
14867c478bd9Sstevel@tonic-gate 	nvpair_t *nvpair = NULL;
14877c478bd9Sstevel@tonic-gate 	struct reg_args *rargs;
14887c478bd9Sstevel@tonic-gate 	sysevent_handle_t *shp;
14897c478bd9Sstevel@tonic-gate 	subscriber_data_t *sub;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	if (alen < sizeof (struct reg_args) || cookie == NULL) {
14927c478bd9Sstevel@tonic-gate 		ret = EINVAL;
14937c478bd9Sstevel@tonic-gate 		goto return_from_door;
14947c478bd9Sstevel@tonic-gate 	}
14957c478bd9Sstevel@tonic-gate 
149649b225e1SGavin Maltby 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
14977c478bd9Sstevel@tonic-gate 	rargs = (struct reg_args *)args;
14987c478bd9Sstevel@tonic-gate 	shp = (sysevent_handle_t *)cookie;
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	datalen = alen - sizeof (struct reg_args);
15017c478bd9Sstevel@tonic-gate 	sub_id = rargs->ra_sub_id;
15027c478bd9Sstevel@tonic-gate 
15037c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	switch (rargs->ra_op) {
15067c478bd9Sstevel@tonic-gate 	case SE_UNREGISTER:
15077c478bd9Sstevel@tonic-gate 		class = (char *)&rargs->ra_buf_ptr;
15087c478bd9Sstevel@tonic-gate 		cache_remove_class(shp, (char *)class,
15097c478bd9Sstevel@tonic-gate 		    sub_id);
15107c478bd9Sstevel@tonic-gate 		break;
15117c478bd9Sstevel@tonic-gate 	case SE_UNBIND_REGISTRATION:
15127c478bd9Sstevel@tonic-gate 
15137c478bd9Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, sub_id);
15147c478bd9Sstevel@tonic-gate 		if (sub == NULL)
15157c478bd9Sstevel@tonic-gate 			break;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		free(sub->sd_door_name);
15187c478bd9Sstevel@tonic-gate 		free(sub);
15197c478bd9Sstevel@tonic-gate 		cache_remove_class(shp, EC_ALL, sub_id);
15207c478bd9Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, sub_id) = NULL;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 		break;
15237c478bd9Sstevel@tonic-gate 	case SE_BIND_REGISTRATION:
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 		/* New subscriber */
15267c478bd9Sstevel@tonic-gate 		if (alloc_subscriber(shp, sub_id, 0) != 0) {
15277c478bd9Sstevel@tonic-gate 			ret = ENOMEM;
15287c478bd9Sstevel@tonic-gate 			break;
15297c478bd9Sstevel@tonic-gate 		}
15307c478bd9Sstevel@tonic-gate 		break;
15317c478bd9Sstevel@tonic-gate 	case SE_REGISTER:
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 		if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
15347c478bd9Sstevel@tonic-gate 			ret = EINVAL;
15357c478bd9Sstevel@tonic-gate 			break;
15367c478bd9Sstevel@tonic-gate 		}
15377c478bd9Sstevel@tonic-gate 		/* Get new registration data */
15387c478bd9Sstevel@tonic-gate 		if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
15397c478bd9Sstevel@tonic-gate 		    &nvl, 0) != 0) {
15407c478bd9Sstevel@tonic-gate 			ret =  EFAULT;
15417c478bd9Sstevel@tonic-gate 			break;
15427c478bd9Sstevel@tonic-gate 		}
15437c478bd9Sstevel@tonic-gate 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
15447c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
15457c478bd9Sstevel@tonic-gate 			ret = EFAULT;
15467c478bd9Sstevel@tonic-gate 			break;
15477c478bd9Sstevel@tonic-gate 		}
15487c478bd9Sstevel@tonic-gate 		if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
15497c478bd9Sstevel@tonic-gate 		    != 0) {
15507c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
15517c478bd9Sstevel@tonic-gate 			ret =  EFAULT;
15527c478bd9Sstevel@tonic-gate 			break;
15537c478bd9Sstevel@tonic-gate 		}
15547c478bd9Sstevel@tonic-gate 		class = nvpair_name(nvpair);
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 		ret = cache_insert_class(shp, class,
15577c478bd9Sstevel@tonic-gate 		    event_list, num_elem, sub_id);
15587c478bd9Sstevel@tonic-gate 		if (ret != 0) {
15597c478bd9Sstevel@tonic-gate 			cache_remove_class(shp, class, sub_id);
15607c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
15617c478bd9Sstevel@tonic-gate 			ret =  EFAULT;
15627c478bd9Sstevel@tonic-gate 			break;
15637c478bd9Sstevel@tonic-gate 		}
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate 		break;
15687c478bd9Sstevel@tonic-gate 	case SE_CLEANUP:
15697c478bd9Sstevel@tonic-gate 		/* Cleanup stale subscribers */
15707c478bd9Sstevel@tonic-gate 		sysevent_cleanup_subscribers(shp);
15717c478bd9Sstevel@tonic-gate 		break;
15727c478bd9Sstevel@tonic-gate 	default:
15737c478bd9Sstevel@tonic-gate 		ret =  EINVAL;
15747c478bd9Sstevel@tonic-gate 	}
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
15777c478bd9Sstevel@tonic-gate 
15787c478bd9Sstevel@tonic-gate return_from_door:
15797c478bd9Sstevel@tonic-gate 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
15807c478bd9Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
15817c478bd9Sstevel@tonic-gate }
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate /*
15847c478bd9Sstevel@tonic-gate  * sysevent_send_event -
15857c478bd9Sstevel@tonic-gate  * Send an event via the communication channel associated with the sysevent
15867c478bd9Sstevel@tonic-gate  * handle.  Event notifications are broadcast to all subscribers based upon
15877c478bd9Sstevel@tonic-gate  * the event class and subclass.  The handle must have been previously
15887c478bd9Sstevel@tonic-gate  * allocated and bound by
15897c478bd9Sstevel@tonic-gate  * sysevent_open_channel() and sysevent_bind_publisher()
15907c478bd9Sstevel@tonic-gate  */
15917c478bd9Sstevel@tonic-gate int
sysevent_send_event(sysevent_handle_t * shp,sysevent_t * ev)15927c478bd9Sstevel@tonic-gate sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
15937c478bd9Sstevel@tonic-gate {
15947c478bd9Sstevel@tonic-gate 	int i, error, sub_fd, result = 0;
15957c478bd9Sstevel@tonic-gate 	int deliver_error = 0;
15967c478bd9Sstevel@tonic-gate 	int subscribers_sent = 0;
15977c478bd9Sstevel@tonic-gate 	int want_resend, resend_cnt = 0;
15987c478bd9Sstevel@tonic-gate 	char *event_class, *event_subclass;
15997c478bd9Sstevel@tonic-gate 	uchar_t *all_class_subscribers, *all_subclass_subscribers;
16007c478bd9Sstevel@tonic-gate 	uchar_t *subclass_subscribers;
16017c478bd9Sstevel@tonic-gate 	subscriber_data_t *sub;
16027c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_lst;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	/* Check for proper registration */
16057c478bd9Sstevel@tonic-gate 	event_class = sysevent_get_class_name(ev);
16067c478bd9Sstevel@tonic-gate 	event_subclass = sysevent_get_subclass_name(ev);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate send_event:
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	want_resend = 0;
16137c478bd9Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
16147c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
16157c478bd9Sstevel@tonic-gate 		errno = EINVAL;
16167c478bd9Sstevel@tonic-gate 		return (-1);
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	/* Find all subscribers for this event class/subclass */
16207c478bd9Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16217c478bd9Sstevel@tonic-gate 	    cache_find_class(shp, EC_ALL), EC_SUB_ALL);
16227c478bd9Sstevel@tonic-gate 	all_class_subscribers = sc_lst->sl_num;
16237c478bd9Sstevel@tonic-gate 
16247c478bd9Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16257c478bd9Sstevel@tonic-gate 	    cache_find_class(shp, event_class), EC_SUB_ALL);
16267c478bd9Sstevel@tonic-gate 	if (sc_lst)
16277c478bd9Sstevel@tonic-gate 		all_subclass_subscribers = sc_lst->sl_num;
16287c478bd9Sstevel@tonic-gate 	else
16297c478bd9Sstevel@tonic-gate 		all_subclass_subscribers = NULL;
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16327c478bd9Sstevel@tonic-gate 	    cache_find_class(shp, event_class), event_subclass);
16337c478bd9Sstevel@tonic-gate 	if (sc_lst)
16347c478bd9Sstevel@tonic-gate 		subclass_subscribers = sc_lst->sl_num;
16357c478bd9Sstevel@tonic-gate 	else
16367c478bd9Sstevel@tonic-gate 		subclass_subscribers = NULL;
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	/* Send event buffer to all valid subscribers */
16397c478bd9Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
16407c478bd9Sstevel@tonic-gate 		if ((all_class_subscribers[i] |
16417c478bd9Sstevel@tonic-gate 		    (all_subclass_subscribers && all_subclass_subscribers[i]) |
16427c478bd9Sstevel@tonic-gate 		    (subclass_subscribers && subclass_subscribers[i])) == 0)
16437c478bd9Sstevel@tonic-gate 			continue;
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
16467c478bd9Sstevel@tonic-gate 		assert(sub != NULL);
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 		/* Check for active subscriber */
16497c478bd9Sstevel@tonic-gate 		if (!(sub->sd_flag & ACTIVE)) {
16507c478bd9Sstevel@tonic-gate 			dprint("sysevent_send_event: subscriber %d inactive\n",
16517c478bd9Sstevel@tonic-gate 			    i);
16527c478bd9Sstevel@tonic-gate 			continue;
16537c478bd9Sstevel@tonic-gate 		}
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 		/* Process only resend requests */
16567c478bd9Sstevel@tonic-gate 		if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
16577c478bd9Sstevel@tonic-gate 			continue;
16587c478bd9Sstevel@tonic-gate 		}
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
16617c478bd9Sstevel@tonic-gate 			dprint("sysevent_send_event: Failed to open "
16627c478bd9Sstevel@tonic-gate 			    "%s: %s\n", sub->sd_door_name, strerror(errno));
16637c478bd9Sstevel@tonic-gate 			continue;
16647c478bd9Sstevel@tonic-gate 		}
16657c478bd9Sstevel@tonic-gate 		result = 0;
16667c478bd9Sstevel@tonic-gate 		error = clnt_deliver_event(sub_fd, ev,
16677c478bd9Sstevel@tonic-gate 		    sysevent_get_size(ev), &result, sizeof (result));
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 		(void) close(sub_fd);
16707c478bd9Sstevel@tonic-gate 
16717c478bd9Sstevel@tonic-gate 		/* Successful door call */
16727c478bd9Sstevel@tonic-gate 		if (error == 0) {
16737c478bd9Sstevel@tonic-gate 			switch (result) {
16747c478bd9Sstevel@tonic-gate 			/* Subscriber requested EAGAIN */
16757c478bd9Sstevel@tonic-gate 			case EAGAIN:
16767c478bd9Sstevel@tonic-gate 				if (resend_cnt > SE_MAX_RETRY_LIMIT) {
16777c478bd9Sstevel@tonic-gate 					deliver_error = 1;
16787c478bd9Sstevel@tonic-gate 				} else {
16797c478bd9Sstevel@tonic-gate 					want_resend = 1;
16807c478bd9Sstevel@tonic-gate 					dprint("sysevent_send_event: resend "
16817c478bd9Sstevel@tonic-gate 					    "requested for %d\n", i);
16827c478bd9Sstevel@tonic-gate 					sub->sd_flag |= SEND_AGAIN;
16837c478bd9Sstevel@tonic-gate 				}
16847c478bd9Sstevel@tonic-gate 				break;
16857c478bd9Sstevel@tonic-gate 			/* Bad sysevent handle for subscriber */
16867c478bd9Sstevel@tonic-gate 			case EBADF:
16877c478bd9Sstevel@tonic-gate 			case EINVAL:
16887c478bd9Sstevel@tonic-gate 				dprint("sysevent_send_event: Bad sysevent "
16897c478bd9Sstevel@tonic-gate 				    "handle for %s", sub->sd_door_name);
16907c478bd9Sstevel@tonic-gate 				sub->sd_flag = 0;
16917c478bd9Sstevel@tonic-gate 				deliver_error = 1;
16927c478bd9Sstevel@tonic-gate 				break;
16937c478bd9Sstevel@tonic-gate 			/* Successful delivery */
16947c478bd9Sstevel@tonic-gate 			default:
16957c478bd9Sstevel@tonic-gate 				sub->sd_flag &= ~SEND_AGAIN;
16967c478bd9Sstevel@tonic-gate 				++subscribers_sent;
16977c478bd9Sstevel@tonic-gate 			}
16987c478bd9Sstevel@tonic-gate 		} else {
16997c478bd9Sstevel@tonic-gate 			dprint("sysevent_send_event: Failed door call "
17007c478bd9Sstevel@tonic-gate 			    "to %s: %s: %d\n", sub->sd_door_name,
17017c478bd9Sstevel@tonic-gate 			    strerror(errno), result);
17027c478bd9Sstevel@tonic-gate 			sub->sd_flag = 0;
17037c478bd9Sstevel@tonic-gate 			deliver_error = 1;
17047c478bd9Sstevel@tonic-gate 		}
17057c478bd9Sstevel@tonic-gate 	}
17067c478bd9Sstevel@tonic-gate 
17077c478bd9Sstevel@tonic-gate 	if (want_resend) {
17087c478bd9Sstevel@tonic-gate 		resend_cnt++;
17097c478bd9Sstevel@tonic-gate 		goto send_event;
17107c478bd9Sstevel@tonic-gate 	}
17117c478bd9Sstevel@tonic-gate 
17127c478bd9Sstevel@tonic-gate 	if (deliver_error) {
17137c478bd9Sstevel@tonic-gate 		sysevent_cleanup_subscribers(shp);
17147c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
17157c478bd9Sstevel@tonic-gate 		errno = EFAULT;
17167c478bd9Sstevel@tonic-gate 		return (-1);
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	if (subscribers_sent == 0) {
17227c478bd9Sstevel@tonic-gate 		dprint("sysevent_send_event: No subscribers for %s:%s\n",
17237c478bd9Sstevel@tonic-gate 		    event_class, event_subclass);
17247c478bd9Sstevel@tonic-gate 		errno = ENOENT;
17257c478bd9Sstevel@tonic-gate 		return (-1);
17267c478bd9Sstevel@tonic-gate 	}
17277c478bd9Sstevel@tonic-gate 
17287c478bd9Sstevel@tonic-gate 	return (0);
17297c478bd9Sstevel@tonic-gate }
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate /*
17327c478bd9Sstevel@tonic-gate  * Common routine to establish an event channel through which an event
17337c478bd9Sstevel@tonic-gate  * publisher or subscriber may post or receive events.
17347c478bd9Sstevel@tonic-gate  */
17357c478bd9Sstevel@tonic-gate static sysevent_handle_t *
sysevent_open_channel_common(const char * channel_path)17367c478bd9Sstevel@tonic-gate sysevent_open_channel_common(const char *channel_path)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate 	uint32_t sub_id = 0;
17397c478bd9Sstevel@tonic-gate 	char *begin_path;
17407c478bd9Sstevel@tonic-gate 	struct stat chan_stat;
17417c478bd9Sstevel@tonic-gate 	sysevent_handle_t *shp;
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
17457c478bd9Sstevel@tonic-gate 		errno = EINVAL;
17467c478bd9Sstevel@tonic-gate 		return (NULL);
17477c478bd9Sstevel@tonic-gate 	}
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
17507c478bd9Sstevel@tonic-gate 		if (errno != EEXIST) {
17517c478bd9Sstevel@tonic-gate 			errno = EACCES;
17527c478bd9Sstevel@tonic-gate 			return (NULL);
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 	}
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	/* Check channel file permissions */
17577c478bd9Sstevel@tonic-gate 	if (stat(channel_path, &chan_stat) != 0) {
17587c478bd9Sstevel@tonic-gate 		dprint("sysevent_open_channel: Invalid permissions for channel "
17597c478bd9Sstevel@tonic-gate 		    "%s\n", channel_path);
17607c478bd9Sstevel@tonic-gate 		errno = EACCES;
17617c478bd9Sstevel@tonic-gate 		return (NULL);
17627c478bd9Sstevel@tonic-gate 	} else if (chan_stat.st_uid != getuid() ||
17634bc0a2efScasper 	    !S_ISDIR(chan_stat.st_mode)) {
17647c478bd9Sstevel@tonic-gate 		dprint("sysevent_open_channel: Invalid "
17657c478bd9Sstevel@tonic-gate 		    "permissions for channel %s\n: %d:%d:%d", channel_path,
17667c478bd9Sstevel@tonic-gate 		    (int)chan_stat.st_uid, (int)chan_stat.st_gid,
17677c478bd9Sstevel@tonic-gate 		    (int)chan_stat.st_mode);
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 		errno = EACCES;
17707c478bd9Sstevel@tonic-gate 		return (NULL);
17717c478bd9Sstevel@tonic-gate 	}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	shp = calloc(1, sizeof (sysevent_impl_hdl_t));
17747c478bd9Sstevel@tonic-gate 	if (shp == NULL) {
17757c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
17767c478bd9Sstevel@tonic-gate 		return (NULL);
17777c478bd9Sstevel@tonic-gate 	}
17787c478bd9Sstevel@tonic-gate 
17797c478bd9Sstevel@tonic-gate 	SH_CHANNEL_NAME(shp) = NULL;
17807c478bd9Sstevel@tonic-gate 	SH_CHANNEL_PATH(shp) = strdup(channel_path);
17817c478bd9Sstevel@tonic-gate 	if (SH_CHANNEL_PATH(shp) == NULL) {
17827c478bd9Sstevel@tonic-gate 		free(shp);
17837c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
17847c478bd9Sstevel@tonic-gate 		return (NULL);
17857c478bd9Sstevel@tonic-gate 	}
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	/* Extract the channel name */
17887c478bd9Sstevel@tonic-gate 	begin_path = SH_CHANNEL_PATH(shp);
17897c478bd9Sstevel@tonic-gate 	while (*begin_path != '\0' &&
17907c478bd9Sstevel@tonic-gate 	    (begin_path = strpbrk(begin_path, "/")) != NULL) {
17917c478bd9Sstevel@tonic-gate 		++begin_path;
17927c478bd9Sstevel@tonic-gate 		SH_CHANNEL_NAME(shp) = begin_path;
17937c478bd9Sstevel@tonic-gate 	}
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 	if (update_kernel_registration(shp, 0,
17967c478bd9Sstevel@tonic-gate 	    SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
17977c478bd9Sstevel@tonic-gate 		dprint("sysevent_open_channel: Failed for channel %s\n",
17987c478bd9Sstevel@tonic-gate 		    SH_CHANNEL_NAME(shp));
17997c478bd9Sstevel@tonic-gate 		free(SH_CHANNEL_PATH(shp));
18007c478bd9Sstevel@tonic-gate 		free(shp);
18017c478bd9Sstevel@tonic-gate 		errno = EFAULT;
18027c478bd9Sstevel@tonic-gate 		return (NULL);
18037c478bd9Sstevel@tonic-gate 	}
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	(void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 	return (shp);
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate /*
18117c478bd9Sstevel@tonic-gate  * Establish a sysevent channel for publication and subscription
18127c478bd9Sstevel@tonic-gate  */
18137c478bd9Sstevel@tonic-gate sysevent_handle_t *
sysevent_open_channel(const char * channel)18147c478bd9Sstevel@tonic-gate sysevent_open_channel(const char *channel)
18157c478bd9Sstevel@tonic-gate {
18167c478bd9Sstevel@tonic-gate 	int var_run_mounted = 0;
18177c478bd9Sstevel@tonic-gate 	char full_channel[MAXPATHLEN + 1];
18187c478bd9Sstevel@tonic-gate 	FILE *fp;
18197c478bd9Sstevel@tonic-gate 	struct stat chan_stat;
18207c478bd9Sstevel@tonic-gate 	struct extmnttab m;
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	if (channel == NULL) {
18237c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18247c478bd9Sstevel@tonic-gate 		return (NULL);
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate 	/*
18287c478bd9Sstevel@tonic-gate 	 * Check that /var/run is mounted as tmpfs before allowing a channel
18297c478bd9Sstevel@tonic-gate 	 * to be opened.
18307c478bd9Sstevel@tonic-gate 	 */
1831004388ebScasper 	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
18327c478bd9Sstevel@tonic-gate 		errno = EACCES;
18337c478bd9Sstevel@tonic-gate 		return (NULL);
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	resetmnttab(fp);
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
18397c478bd9Sstevel@tonic-gate 		if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
184049b225e1SGavin Maltby 		    strcmp(m.mnt_fstype, "tmpfs") == 0) {
18417c478bd9Sstevel@tonic-gate 			var_run_mounted = 1;
18427c478bd9Sstevel@tonic-gate 			break;
18437c478bd9Sstevel@tonic-gate 		}
18447c478bd9Sstevel@tonic-gate 	}
18457c478bd9Sstevel@tonic-gate 	(void) fclose(fp);
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	if (!var_run_mounted) {
18487c478bd9Sstevel@tonic-gate 		errno = EACCES;
18497c478bd9Sstevel@tonic-gate 		return (NULL);
18507c478bd9Sstevel@tonic-gate 	}
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	if (stat(CHAN_PATH, &chan_stat) < 0) {
18537c478bd9Sstevel@tonic-gate 		if (mkdir(CHAN_PATH,
18547c478bd9Sstevel@tonic-gate 		    S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
18557c478bd9Sstevel@tonic-gate 			dprint("sysevent_open_channel: Unable "
18567c478bd9Sstevel@tonic-gate 			    "to create channel directory %s:%s\n", CHAN_PATH,
18577c478bd9Sstevel@tonic-gate 			    strerror(errno));
18587c478bd9Sstevel@tonic-gate 			if (errno != EEXIST) {
18597c478bd9Sstevel@tonic-gate 				errno = EACCES;
18607c478bd9Sstevel@tonic-gate 				return (NULL);
18617c478bd9Sstevel@tonic-gate 			}
18627c478bd9Sstevel@tonic-gate 		}
18637c478bd9Sstevel@tonic-gate 	}
18647c478bd9Sstevel@tonic-gate 
18657c478bd9Sstevel@tonic-gate 	if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
18667c478bd9Sstevel@tonic-gate 	    MAXPATHLEN) {
18677c478bd9Sstevel@tonic-gate 		errno = EINVAL;
18687c478bd9Sstevel@tonic-gate 		return (NULL);
18697c478bd9Sstevel@tonic-gate 	}
18707c478bd9Sstevel@tonic-gate 
18717c478bd9Sstevel@tonic-gate 	return (sysevent_open_channel_common(full_channel));
18727c478bd9Sstevel@tonic-gate }
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate /*
18757c478bd9Sstevel@tonic-gate  * Establish a sysevent channel for publication and subscription
18767c478bd9Sstevel@tonic-gate  * Full path to the channel determined by the caller
18777c478bd9Sstevel@tonic-gate  */
18787c478bd9Sstevel@tonic-gate sysevent_handle_t *
sysevent_open_channel_alt(const char * channel_path)18797c478bd9Sstevel@tonic-gate sysevent_open_channel_alt(const char *channel_path)
18807c478bd9Sstevel@tonic-gate {
18817c478bd9Sstevel@tonic-gate 	return (sysevent_open_channel_common(channel_path));
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate /*
18857c478bd9Sstevel@tonic-gate  * sysevent_close_channel - Clean up resources associated with a previously
18867c478bd9Sstevel@tonic-gate  *				opened sysevent channel
18877c478bd9Sstevel@tonic-gate  */
18887c478bd9Sstevel@tonic-gate void
sysevent_close_channel(sysevent_handle_t * shp)18897c478bd9Sstevel@tonic-gate sysevent_close_channel(sysevent_handle_t *shp)
18907c478bd9Sstevel@tonic-gate {
18917c478bd9Sstevel@tonic-gate 	int error = errno;
18927c478bd9Sstevel@tonic-gate 	uint32_t sub_id = 0;
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	if (shp == NULL) {
18957c478bd9Sstevel@tonic-gate 		return;
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
18997c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
19007c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19017c478bd9Sstevel@tonic-gate 		if (SH_TYPE(shp) == PUBLISHER)
19027c478bd9Sstevel@tonic-gate 			sysevent_unbind_publisher(shp);
19037c478bd9Sstevel@tonic-gate 		else if (SH_TYPE(shp) == SUBSCRIBER)
19047c478bd9Sstevel@tonic-gate 			sysevent_unbind_subscriber(shp);
19057c478bd9Sstevel@tonic-gate 		(void) mutex_lock(SH_LOCK(shp));
19067c478bd9Sstevel@tonic-gate 	}
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	(void) update_kernel_registration(shp, 0,
19097c478bd9Sstevel@tonic-gate 	    SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
19107c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	free(SH_CHANNEL_PATH(shp));
19137c478bd9Sstevel@tonic-gate 	free(shp);
19147c478bd9Sstevel@tonic-gate 	errno = error;
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate /*
19187c478bd9Sstevel@tonic-gate  * sysevent_bind_publisher - Bind an event publisher to an event channel
19197c478bd9Sstevel@tonic-gate  */
19207c478bd9Sstevel@tonic-gate int
sysevent_bind_publisher(sysevent_handle_t * shp)19217c478bd9Sstevel@tonic-gate sysevent_bind_publisher(sysevent_handle_t *shp)
19227c478bd9Sstevel@tonic-gate {
19237c478bd9Sstevel@tonic-gate 	int error = 0;
19247c478bd9Sstevel@tonic-gate 	int fd = -1;
19257c478bd9Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
19267c478bd9Sstevel@tonic-gate 	uint32_t pub_id;
19277c478bd9Sstevel@tonic-gate 	struct stat reg_stat;
19287c478bd9Sstevel@tonic-gate 	publisher_priv_t *pub;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	if (shp == NULL) {
19317c478bd9Sstevel@tonic-gate 		errno = EINVAL;
19327c478bd9Sstevel@tonic-gate 		return (-1);
19337c478bd9Sstevel@tonic-gate 	}
19347c478bd9Sstevel@tonic-gate 
19357c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
19367c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
19377c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19387c478bd9Sstevel@tonic-gate 		errno = EINVAL;
19397c478bd9Sstevel@tonic-gate 		return (-1);
19407c478bd9Sstevel@tonic-gate 	}
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
19437c478bd9Sstevel@tonic-gate 	    NULL) {
19447c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19457c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
19467c478bd9Sstevel@tonic-gate 		return (-1);
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 	SH_PRIV_DATA(shp) = (void *)pub;
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
19517c478bd9Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
19527c478bd9Sstevel@tonic-gate 		free(pub);
19537c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19547c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
19557c478bd9Sstevel@tonic-gate 		return (-1);
19567c478bd9Sstevel@tonic-gate 	}
19577c478bd9Sstevel@tonic-gate 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
19587c478bd9Sstevel@tonic-gate 		free(pub);
19597c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19607c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
19617c478bd9Sstevel@tonic-gate 		return (-1);
19627c478bd9Sstevel@tonic-gate 	}
19637c478bd9Sstevel@tonic-gate 
19647c478bd9Sstevel@tonic-gate 	/* Only one publisher allowed per channel */
19657c478bd9Sstevel@tonic-gate 	if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
19667c478bd9Sstevel@tonic-gate 		if (errno != ENOENT) {
19677c478bd9Sstevel@tonic-gate 			error = EINVAL;
19687c478bd9Sstevel@tonic-gate 			goto fail;
19697c478bd9Sstevel@tonic-gate 		}
19707c478bd9Sstevel@tonic-gate 	}
19717c478bd9Sstevel@tonic-gate 
19727c478bd9Sstevel@tonic-gate 	/*
19737c478bd9Sstevel@tonic-gate 	 * Remove door file for robustness.
19747c478bd9Sstevel@tonic-gate 	 */
19757c478bd9Sstevel@tonic-gate 	if (unlink(SH_DOOR_NAME(shp)) != 0)
19767c478bd9Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
19777c478bd9Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate 	/* Open channel registration door */
19807c478bd9Sstevel@tonic-gate 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
19817c478bd9Sstevel@tonic-gate 	    S_IREAD|S_IWRITE);
19827c478bd9Sstevel@tonic-gate 	if (fd == -1) {
19837c478bd9Sstevel@tonic-gate 		error = EINVAL;
19847c478bd9Sstevel@tonic-gate 		goto fail;
19857c478bd9Sstevel@tonic-gate 	}
19867c478bd9Sstevel@tonic-gate 
19877c478bd9Sstevel@tonic-gate 	/*
19887c478bd9Sstevel@tonic-gate 	 * Create the registration service for this publisher.
19897c478bd9Sstevel@tonic-gate 	 */
19907c478bd9Sstevel@tonic-gate 	if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
19917c478bd9Sstevel@tonic-gate 	    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
19927c478bd9Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: door create failed: "
19937c478bd9Sstevel@tonic-gate 		    "%s\n", strerror(errno));
19947c478bd9Sstevel@tonic-gate 		error = EFAULT;
19957c478bd9Sstevel@tonic-gate 		goto fail;
19967c478bd9Sstevel@tonic-gate 	}
19977c478bd9Sstevel@tonic-gate 
19987c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
19997c478bd9Sstevel@tonic-gate 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
20007c478bd9Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: unable to "
20017c478bd9Sstevel@tonic-gate 		    "bind event channel: fattach: %s\n",
20027c478bd9Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
20037c478bd9Sstevel@tonic-gate 		error = EACCES;
20047c478bd9Sstevel@tonic-gate 		goto fail;
20057c478bd9Sstevel@tonic-gate 	}
20067c478bd9Sstevel@tonic-gate 
20077c478bd9Sstevel@tonic-gate 	/* Bind this publisher in the kernel registration database */
20087c478bd9Sstevel@tonic-gate 	if (update_kernel_registration(shp, PUBLISHER,
20097c478bd9Sstevel@tonic-gate 	    SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
20107c478bd9Sstevel@tonic-gate 		error = errno;
20117c478bd9Sstevel@tonic-gate 		goto fail;
20127c478bd9Sstevel@tonic-gate 	}
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate 	SH_ID(shp) = pub_id;
20157c478bd9Sstevel@tonic-gate 	SH_BOUND(shp) = 1;
20167c478bd9Sstevel@tonic-gate 	SH_TYPE(shp) = PUBLISHER;
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	/* Create the subscription registration cache */
20207c478bd9Sstevel@tonic-gate 	if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
20217c478bd9Sstevel@tonic-gate 		(void) update_kernel_registration(shp,
20227c478bd9Sstevel@tonic-gate 		    PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
20237c478bd9Sstevel@tonic-gate 		error = EFAULT;
20247c478bd9Sstevel@tonic-gate 		goto fail;
20257c478bd9Sstevel@tonic-gate 	}
20267c478bd9Sstevel@tonic-gate 	(void) close(fd);
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
20297c478bd9Sstevel@tonic-gate 
20307c478bd9Sstevel@tonic-gate 	return (0);
20317c478bd9Sstevel@tonic-gate 
20327c478bd9Sstevel@tonic-gate fail:
20337c478bd9Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
20347c478bd9Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
20357c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
20367c478bd9Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
20377c478bd9Sstevel@tonic-gate 	free(pub);
20387c478bd9Sstevel@tonic-gate 	(void) close(fd);
20397c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
20407c478bd9Sstevel@tonic-gate 	errno = error;
20417c478bd9Sstevel@tonic-gate 	return (-1);
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate 
2044f6e214c7SGavin Maltby static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2045f6e214c7SGavin Maltby static pthread_attr_t xdoor_thrattr;
2046f6e214c7SGavin Maltby 
2047f6e214c7SGavin Maltby static void
xdoor_thrattr_init(void)2048f6e214c7SGavin Maltby xdoor_thrattr_init(void)
2049f6e214c7SGavin Maltby {
2050f6e214c7SGavin Maltby 	(void) pthread_attr_init(&xdoor_thrattr);
2051f6e214c7SGavin Maltby 	(void) pthread_attr_setdetachstate(&xdoor_thrattr,
2052f6e214c7SGavin Maltby 	    PTHREAD_CREATE_DETACHED);
2053f6e214c7SGavin Maltby 	(void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2054f6e214c7SGavin Maltby }
2055f6e214c7SGavin Maltby 
2056f6e214c7SGavin Maltby static int
xdoor_server_create(door_info_t * dip,void * (* startf)(void *),void * startfarg,void * cookie)2057f6e214c7SGavin Maltby xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2058f6e214c7SGavin Maltby     void *startfarg, void *cookie)
2059f6e214c7SGavin Maltby {
2060f6e214c7SGavin Maltby 	struct sysevent_subattr_impl *xsa = cookie;
2061f6e214c7SGavin Maltby 	pthread_attr_t *thrattr;
2062f6e214c7SGavin Maltby 	sigset_t oset;
2063f6e214c7SGavin Maltby 	int err;
2064f6e214c7SGavin Maltby 
2065f6e214c7SGavin Maltby 	if (xsa->xs_thrcreate) {
2066f6e214c7SGavin Maltby 		return (xsa->xs_thrcreate(dip, startf, startfarg,
2067f6e214c7SGavin Maltby 		    xsa->xs_thrcreate_cookie));
2068f6e214c7SGavin Maltby 	}
2069f6e214c7SGavin Maltby 
2070f6e214c7SGavin Maltby 	if (xsa->xs_thrattr == NULL) {
2071f6e214c7SGavin Maltby 		(void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2072f6e214c7SGavin Maltby 		thrattr = &xdoor_thrattr;
2073f6e214c7SGavin Maltby 	} else {
2074f6e214c7SGavin Maltby 		thrattr = xsa->xs_thrattr;
2075f6e214c7SGavin Maltby 	}
2076f6e214c7SGavin Maltby 
2077f6e214c7SGavin Maltby 	(void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2078f6e214c7SGavin Maltby 	err = pthread_create(NULL, thrattr, startf, startfarg);
2079f6e214c7SGavin Maltby 	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2080f6e214c7SGavin Maltby 
2081f6e214c7SGavin Maltby 	return (err == 0 ? 1 : -1);
2082f6e214c7SGavin Maltby }
2083f6e214c7SGavin Maltby 
2084f6e214c7SGavin Maltby static void
xdoor_server_setup(void * cookie)2085f6e214c7SGavin Maltby xdoor_server_setup(void *cookie)
2086f6e214c7SGavin Maltby {
2087f6e214c7SGavin Maltby 	struct sysevent_subattr_impl *xsa = cookie;
2088f6e214c7SGavin Maltby 
2089f6e214c7SGavin Maltby 	if (xsa->xs_thrsetup) {
2090f6e214c7SGavin Maltby 		xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2091f6e214c7SGavin Maltby 	} else {
2092f6e214c7SGavin Maltby 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2093f6e214c7SGavin Maltby 		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2094f6e214c7SGavin Maltby 	}
2095f6e214c7SGavin Maltby }
2096f6e214c7SGavin Maltby 
2097f6e214c7SGavin Maltby static int
sysevent_bind_subscriber_cmn(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2098f6e214c7SGavin Maltby sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
20990762f44eSToomas Soome     void (*event_handler)(sysevent_t *ev),
21000762f44eSToomas Soome     sysevent_subattr_t *subattr)
21017c478bd9Sstevel@tonic-gate {
21027c478bd9Sstevel@tonic-gate 	int fd = -1;
21037c478bd9Sstevel@tonic-gate 	int error = 0;
21047c478bd9Sstevel@tonic-gate 	uint32_t sub_id = 0;
21057c478bd9Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
21067c478bd9Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
2107f6e214c7SGavin Maltby 	int created;
2108f6e214c7SGavin Maltby 	struct sysevent_subattr_impl *xsa =
2109f6e214c7SGavin Maltby 	    (struct sysevent_subattr_impl *)subattr;
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	if (shp == NULL || event_handler == NULL) {
21127c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21137c478bd9Sstevel@tonic-gate 		return (-1);
21147c478bd9Sstevel@tonic-gate 	}
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
21177c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
21187c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21197c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21207c478bd9Sstevel@tonic-gate 		return (-1);
21217c478bd9Sstevel@tonic-gate 	}
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	if ((sub_info = (subscriber_priv_t *)calloc(1,
21247c478bd9Sstevel@tonic-gate 	    sizeof (subscriber_priv_t))) == NULL) {
21257c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
21267c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21277c478bd9Sstevel@tonic-gate 		return (-1);
21287c478bd9Sstevel@tonic-gate 	}
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
21317c478bd9Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
21327c478bd9Sstevel@tonic-gate 		free(sub_info);
21337c478bd9Sstevel@tonic-gate 		errno = EINVAL;
21347c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21357c478bd9Sstevel@tonic-gate 		return (-1);
21367c478bd9Sstevel@tonic-gate 	}
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
21397c478bd9Sstevel@tonic-gate 		free(sub_info);
21407c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
21417c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21427c478bd9Sstevel@tonic-gate 		return (-1);
21437c478bd9Sstevel@tonic-gate 	}
21447c478bd9Sstevel@tonic-gate 	(void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
21457c478bd9Sstevel@tonic-gate 	(void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
21467c478bd9Sstevel@tonic-gate 	sub_info->sp_func = event_handler;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	/* Update the in-kernel registration */
21497c478bd9Sstevel@tonic-gate 	if (update_kernel_registration(shp, SUBSCRIBER,
21507c478bd9Sstevel@tonic-gate 	    SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
21517c478bd9Sstevel@tonic-gate 		error = errno;
21527c478bd9Sstevel@tonic-gate 		goto fail;
21537c478bd9Sstevel@tonic-gate 	}
21547c478bd9Sstevel@tonic-gate 	SH_ID(shp) = sub_id;
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
21577c478bd9Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
21587c478bd9Sstevel@tonic-gate 		error = EINVAL;
21597c478bd9Sstevel@tonic-gate 		goto fail;
21607c478bd9Sstevel@tonic-gate 	}
21617c478bd9Sstevel@tonic-gate 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
21627c478bd9Sstevel@tonic-gate 		error = ENOMEM;
21637c478bd9Sstevel@tonic-gate 		goto fail;
21647c478bd9Sstevel@tonic-gate 	}
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	/*
21677c478bd9Sstevel@tonic-gate 	 * Remove door file for robustness.
21687c478bd9Sstevel@tonic-gate 	 */
21697c478bd9Sstevel@tonic-gate 	if (unlink(SH_DOOR_NAME(shp)) != 0)
21707c478bd9Sstevel@tonic-gate 		dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
21717c478bd9Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
21747c478bd9Sstevel@tonic-gate 	if (fd == -1) {
21757c478bd9Sstevel@tonic-gate 		error = EFAULT;
21767c478bd9Sstevel@tonic-gate 		goto fail;
21777c478bd9Sstevel@tonic-gate 	}
21787c478bd9Sstevel@tonic-gate 
21797c478bd9Sstevel@tonic-gate 	/*
21807c478bd9Sstevel@tonic-gate 	 * Create the sysevent door service for this client.
21817c478bd9Sstevel@tonic-gate 	 * syseventd will use this door service to propagate
21827c478bd9Sstevel@tonic-gate 	 * events to the client.
21837c478bd9Sstevel@tonic-gate 	 */
2184f6e214c7SGavin Maltby 	if (subattr == NULL) {
2185f6e214c7SGavin Maltby 		SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2186f6e214c7SGavin Maltby 		    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2187f6e214c7SGavin Maltby 	} else {
2188f6e214c7SGavin Maltby 		SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2189f6e214c7SGavin Maltby 		    (void *)shp,
2190f6e214c7SGavin Maltby 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2191f6e214c7SGavin Maltby 		    xdoor_server_create, xdoor_server_setup,
2192f6e214c7SGavin Maltby 		    (void *)subattr, 1);
2193f6e214c7SGavin Maltby 	}
2194f6e214c7SGavin Maltby 
2195f6e214c7SGavin Maltby 	if (SH_DOOR_DESC(shp) == -1) {
21967c478bd9Sstevel@tonic-gate 		dprint("sysevent_bind_subscriber: door create failed: "
219749b225e1SGavin Maltby 		    "%s\n", strerror(errno));
21987c478bd9Sstevel@tonic-gate 		error = EFAULT;
21997c478bd9Sstevel@tonic-gate 		goto fail;
22007c478bd9Sstevel@tonic-gate 	}
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
22037c478bd9Sstevel@tonic-gate 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
22047c478bd9Sstevel@tonic-gate 		error = EFAULT;
22057c478bd9Sstevel@tonic-gate 		goto fail;
22067c478bd9Sstevel@tonic-gate 	}
22077c478bd9Sstevel@tonic-gate 	(void) close(fd);
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
22107c478bd9Sstevel@tonic-gate 	    sub_id, 0, NULL) != 0) {
22117c478bd9Sstevel@tonic-gate 		error = errno;
22127c478bd9Sstevel@tonic-gate 		(void) update_kernel_registration(shp, SUBSCRIBER,
22137c478bd9Sstevel@tonic-gate 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
22147c478bd9Sstevel@tonic-gate 		goto fail;
22157c478bd9Sstevel@tonic-gate 	}
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	SH_BOUND(shp) = 1;
22187c478bd9Sstevel@tonic-gate 	SH_TYPE(shp) = SUBSCRIBER;
22197c478bd9Sstevel@tonic-gate 	SH_PRIV_DATA(shp) = (void *)sub_info;
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	/* Create an event handler thread */
2222f6e214c7SGavin Maltby 	if (xsa == NULL || xsa->xs_thrcreate == NULL) {
222355622cebSToomas Soome 		created = thr_create(NULL, 0, subscriber_event_handler,
2224f6e214c7SGavin Maltby 		    shp, THR_BOUND, &sub_info->sp_handler_tid) == 0;
2225f6e214c7SGavin Maltby 	} else {
2226f6e214c7SGavin Maltby 		/*
2227f6e214c7SGavin Maltby 		 * A terrible hack.  We will use the extended private
2228f6e214c7SGavin Maltby 		 * door thread creation function the caller passed in to
2229f6e214c7SGavin Maltby 		 * create the event handler thread.  That function will
2230f6e214c7SGavin Maltby 		 * be called with our chosen thread start function and arg
2231f6e214c7SGavin Maltby 		 * instead of the usual libc-provided ones, but that's ok
2232f6e214c7SGavin Maltby 		 * as it is required to use them verbatim anyway.  We will
2233f6e214c7SGavin Maltby 		 * pass a NULL door_info_t pointer to the function - so
2234f6e214c7SGavin Maltby 		 * callers depending on this hack had better be prepared
2235f6e214c7SGavin Maltby 		 * for that.  All this allow the caller to rubberstamp
2236f6e214c7SGavin Maltby 		 * the created thread as it wishes.  But we don't get
2237f6e214c7SGavin Maltby 		 * the created threadid with this, so we modify the
2238f6e214c7SGavin Maltby 		 * thread start function to stash it.
2239f6e214c7SGavin Maltby 		 */
2240f6e214c7SGavin Maltby 
224155622cebSToomas Soome 		created = xsa->xs_thrcreate(NULL, subscriber_event_handler,
2242f6e214c7SGavin Maltby 		    shp, xsa->xs_thrcreate_cookie) == 1;
2243f6e214c7SGavin Maltby 	}
2244f6e214c7SGavin Maltby 
2245f6e214c7SGavin Maltby 	if (!created) {
22467c478bd9Sstevel@tonic-gate 		error = EFAULT;
22477c478bd9Sstevel@tonic-gate 		goto fail;
22487c478bd9Sstevel@tonic-gate 	}
22497c478bd9Sstevel@tonic-gate 
22507c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
22517c478bd9Sstevel@tonic-gate 
22527c478bd9Sstevel@tonic-gate 	return (0);
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate fail:
22557c478bd9Sstevel@tonic-gate 	(void) close(fd);
22567c478bd9Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
22577c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
22587c478bd9Sstevel@tonic-gate 	(void) cond_destroy(&sub_info->sp_cv);
22597c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&sub_info->sp_qlock);
22607c478bd9Sstevel@tonic-gate 	free(sub_info->sp_door_name);
22617c478bd9Sstevel@tonic-gate 	free(sub_info);
22627c478bd9Sstevel@tonic-gate 	if (SH_ID(shp)) {
22637c478bd9Sstevel@tonic-gate 		(void) update_kernel_registration(shp, SUBSCRIBER,
22647c478bd9Sstevel@tonic-gate 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
22657c478bd9Sstevel@tonic-gate 		SH_ID(shp) = 0;
22667c478bd9Sstevel@tonic-gate 	}
22677c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
22687c478bd9Sstevel@tonic-gate 		(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
22697c478bd9Sstevel@tonic-gate 		    sub_id, 0, NULL);
22707c478bd9Sstevel@tonic-gate 		free(SH_DOOR_NAME(shp));
22717c478bd9Sstevel@tonic-gate 		SH_BOUND(shp) = 0;
22727c478bd9Sstevel@tonic-gate 	}
22737c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
22747c478bd9Sstevel@tonic-gate 
22757c478bd9Sstevel@tonic-gate 	errno = error;
22767c478bd9Sstevel@tonic-gate 
22777c478bd9Sstevel@tonic-gate 	return (-1);
22787c478bd9Sstevel@tonic-gate }
22797c478bd9Sstevel@tonic-gate 
2280f6e214c7SGavin Maltby /*
2281f6e214c7SGavin Maltby  * sysevent_bind_subscriber - Bind an event receiver to an event channel
2282f6e214c7SGavin Maltby  */
2283f6e214c7SGavin Maltby int
sysevent_bind_subscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev))2284f6e214c7SGavin Maltby sysevent_bind_subscriber(sysevent_handle_t *shp,
22850762f44eSToomas Soome     void (*event_handler)(sysevent_t *ev))
2286f6e214c7SGavin Maltby {
2287f6e214c7SGavin Maltby 	return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2288f6e214c7SGavin Maltby }
2289f6e214c7SGavin Maltby 
2290f6e214c7SGavin Maltby /*
2291f6e214c7SGavin Maltby  * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2292f6e214c7SGavin Maltby  * attributes specified.
2293f6e214c7SGavin Maltby  */
2294f6e214c7SGavin Maltby int
sysevent_bind_xsubscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2295f6e214c7SGavin Maltby sysevent_bind_xsubscriber(sysevent_handle_t *shp,
22960762f44eSToomas Soome     void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2297f6e214c7SGavin Maltby {
2298f6e214c7SGavin Maltby 	return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2299f6e214c7SGavin Maltby }
2300f6e214c7SGavin Maltby 
23017c478bd9Sstevel@tonic-gate /*
23027c478bd9Sstevel@tonic-gate  * sysevent_register_event - register an event class and associated subclasses
23037c478bd9Sstevel@tonic-gate  *		for an event subscriber
23047c478bd9Sstevel@tonic-gate  */
23057c478bd9Sstevel@tonic-gate int
sysevent_register_event(sysevent_handle_t * shp,const char * ev_class,const char ** ev_subclass,int subclass_num)23067c478bd9Sstevel@tonic-gate sysevent_register_event(sysevent_handle_t *shp,
23070762f44eSToomas Soome     const char *ev_class, const char **ev_subclass,
23080762f44eSToomas Soome     int subclass_num)
23097c478bd9Sstevel@tonic-gate {
23107c478bd9Sstevel@tonic-gate 	int error;
23117c478bd9Sstevel@tonic-gate 	char *event_class = (char *)ev_class;
23127c478bd9Sstevel@tonic-gate 	char **event_subclass_list = (char **)ev_subclass;
23137c478bd9Sstevel@tonic-gate 	char *nvlbuf = NULL;
23147c478bd9Sstevel@tonic-gate 	size_t datalen;
23157c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
23187c478bd9Sstevel@tonic-gate 	if (event_class == NULL || event_subclass_list == NULL ||
23197c478bd9Sstevel@tonic-gate 	    event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
23207c478bd9Sstevel@tonic-gate 	    subclass_num <= 0) {
23217c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23227c478bd9Sstevel@tonic-gate 		errno = EINVAL;
23237c478bd9Sstevel@tonic-gate 		return (-1);
23247c478bd9Sstevel@tonic-gate 	}
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
23277c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23287c478bd9Sstevel@tonic-gate 		return (-1);
23297c478bd9Sstevel@tonic-gate 	}
23307c478bd9Sstevel@tonic-gate 	if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
23317c478bd9Sstevel@tonic-gate 	    subclass_num) != 0) {
23327c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
23337c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23347c478bd9Sstevel@tonic-gate 		return (-1);
23357c478bd9Sstevel@tonic-gate 	}
23367c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
23377c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
23387c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23397c478bd9Sstevel@tonic-gate 		return (-1);
23407c478bd9Sstevel@tonic-gate 	}
23417c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
23427c478bd9Sstevel@tonic-gate 
23437c478bd9Sstevel@tonic-gate 	/* Store new subscriber in in-kernel registration */
23447c478bd9Sstevel@tonic-gate 	if (update_kernel_registration(shp, SUBSCRIBER,
23457c478bd9Sstevel@tonic-gate 	    SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
23467c478bd9Sstevel@tonic-gate 	    != 0) {
23477c478bd9Sstevel@tonic-gate 		error = errno;
23487c478bd9Sstevel@tonic-gate 		free(nvlbuf);
23497c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23507c478bd9Sstevel@tonic-gate 		errno = error;
23517c478bd9Sstevel@tonic-gate 		return (-1);
23527c478bd9Sstevel@tonic-gate 	}
23537c478bd9Sstevel@tonic-gate 	/* Update the publisher's cached registration */
23547c478bd9Sstevel@tonic-gate 	if (update_publisher_cache(
23557c478bd9Sstevel@tonic-gate 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
23567c478bd9Sstevel@tonic-gate 	    SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
23577c478bd9Sstevel@tonic-gate 		error = errno;
23587c478bd9Sstevel@tonic-gate 		free(nvlbuf);
23597c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23607c478bd9Sstevel@tonic-gate 		errno = error;
23617c478bd9Sstevel@tonic-gate 		return (-1);
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 	free(nvlbuf);
23657c478bd9Sstevel@tonic-gate 
23667c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate 	return (0);
23697c478bd9Sstevel@tonic-gate }
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate /*
23727c478bd9Sstevel@tonic-gate  * sysevent_unregister_event - Unregister an event class and associated
23737c478bd9Sstevel@tonic-gate  *				subclasses for an event subscriber
23747c478bd9Sstevel@tonic-gate  */
23757c478bd9Sstevel@tonic-gate void
sysevent_unregister_event(sysevent_handle_t * shp,const char * class)23767c478bd9Sstevel@tonic-gate sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
23777c478bd9Sstevel@tonic-gate {
23787c478bd9Sstevel@tonic-gate 	size_t class_sz;
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
23837c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23847c478bd9Sstevel@tonic-gate 		return;
23857c478bd9Sstevel@tonic-gate 	}
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	/* Remove subscriber from in-kernel registration */
23887c478bd9Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
23897c478bd9Sstevel@tonic-gate 	(void) update_kernel_registration(shp, SUBSCRIBER,
23907c478bd9Sstevel@tonic-gate 	    SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
23917c478bd9Sstevel@tonic-gate 	/* Update the publisher's cached registration */
23927c478bd9Sstevel@tonic-gate 	(void) update_publisher_cache(
23937c478bd9Sstevel@tonic-gate 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
23947c478bd9Sstevel@tonic-gate 	    SH_ID(shp), class_sz, (uchar_t *)class);
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
23977c478bd9Sstevel@tonic-gate }
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate static int
cleanup_id(sysevent_handle_t * shp,uint32_t id,int type)24007c478bd9Sstevel@tonic-gate cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
24017c478bd9Sstevel@tonic-gate {
24027c478bd9Sstevel@tonic-gate 	dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	/* Remove registration from the kernel */
24057c478bd9Sstevel@tonic-gate 	if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
24067c478bd9Sstevel@tonic-gate 	    0, NULL) != 0) {
24077c478bd9Sstevel@tonic-gate 		dprint("cleanup_id: Unable to clean "
24087c478bd9Sstevel@tonic-gate 		    "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
24097c478bd9Sstevel@tonic-gate 		return (-1);
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 
24127c478bd9Sstevel@tonic-gate 	return (0);
24137c478bd9Sstevel@tonic-gate }
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
24177c478bd9Sstevel@tonic-gate  *		allocated to unresponsive subscribers.
24187c478bd9Sstevel@tonic-gate  */
24197c478bd9Sstevel@tonic-gate void
sysevent_cleanup_subscribers(sysevent_handle_t * shp)24207c478bd9Sstevel@tonic-gate sysevent_cleanup_subscribers(sysevent_handle_t *shp)
24217c478bd9Sstevel@tonic-gate {
24227c478bd9Sstevel@tonic-gate 	uint32_t ping, result;
24237c478bd9Sstevel@tonic-gate 	int i, error, sub_fd;
24247c478bd9Sstevel@tonic-gate 	subscriber_data_t *sub;
24257c478bd9Sstevel@tonic-gate 
24267c478bd9Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
24277c478bd9Sstevel@tonic-gate 		return;
24287c478bd9Sstevel@tonic-gate 	}
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
24337c478bd9Sstevel@tonic-gate 		if (sub == NULL) {
24347c478bd9Sstevel@tonic-gate 			continue;
24357c478bd9Sstevel@tonic-gate 		}
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
24387c478bd9Sstevel@tonic-gate 			continue;
24397c478bd9Sstevel@tonic-gate 		}
24407c478bd9Sstevel@tonic-gate 		/* Check for valid and responsive subscriber */
24417c478bd9Sstevel@tonic-gate 		error = clnt_deliver_event(sub_fd, &ping,
24427c478bd9Sstevel@tonic-gate 		    sizeof (uint32_t), &result, sizeof (result));
24437c478bd9Sstevel@tonic-gate 		(void) close(sub_fd);
24447c478bd9Sstevel@tonic-gate 
24457c478bd9Sstevel@tonic-gate 		/* Only cleanup on EBADF (Invalid door descriptor) */
24467c478bd9Sstevel@tonic-gate 		if (error != EBADF)
24477c478bd9Sstevel@tonic-gate 			continue;
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 		if (cleanup_id(shp, i, SUBSCRIBER) != 0)
24507c478bd9Sstevel@tonic-gate 			continue;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 		cache_remove_class(shp, EC_ALL, i);
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 		free(sub->sd_door_name);
24557c478bd9Sstevel@tonic-gate 		free(sub);
24567c478bd9Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, i) = NULL;
24577c478bd9Sstevel@tonic-gate 	}
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate }
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate /*
24627c478bd9Sstevel@tonic-gate  * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
24637c478bd9Sstevel@tonic-gate  *		as needed.
24647c478bd9Sstevel@tonic-gate  */
24657c478bd9Sstevel@tonic-gate void
sysevent_cleanup_publishers(sysevent_handle_t * shp)24667c478bd9Sstevel@tonic-gate sysevent_cleanup_publishers(sysevent_handle_t *shp)
24677c478bd9Sstevel@tonic-gate {
24687c478bd9Sstevel@tonic-gate 	(void) cleanup_id(shp, 1, PUBLISHER);
24697c478bd9Sstevel@tonic-gate }
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate /*
24727c478bd9Sstevel@tonic-gate  * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
24737c478bd9Sstevel@tonic-gate  */
24747c478bd9Sstevel@tonic-gate void
sysevent_unbind_subscriber(sysevent_handle_t * shp)24757c478bd9Sstevel@tonic-gate sysevent_unbind_subscriber(sysevent_handle_t *shp)
24767c478bd9Sstevel@tonic-gate {
24777c478bd9Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	if (shp == NULL)
24807c478bd9Sstevel@tonic-gate 		return;
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
24837c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp) == 0) {
24847c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
24857c478bd9Sstevel@tonic-gate 		return;
24867c478bd9Sstevel@tonic-gate 	}
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 	/* Update the in-kernel registration */
24897c478bd9Sstevel@tonic-gate 	(void) update_kernel_registration(shp, SUBSCRIBER,
24907c478bd9Sstevel@tonic-gate 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
24917c478bd9Sstevel@tonic-gate 
24927c478bd9Sstevel@tonic-gate 	/* Update the sysevent channel publisher */
24937c478bd9Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
24947c478bd9Sstevel@tonic-gate 	(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
24957c478bd9Sstevel@tonic-gate 	    SH_ID(shp), 0, NULL);
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 	/* Close down event delivery facilities */
24987c478bd9Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
24997c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate 	/*
25027c478bd9Sstevel@tonic-gate 	 * Release resources and wait for pending event delivery to
25037c478bd9Sstevel@tonic-gate 	 * complete.
25047c478bd9Sstevel@tonic-gate 	 */
25057c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
25067c478bd9Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
25077c478bd9Sstevel@tonic-gate 	/* Signal event handler and drain the subscriber's event queue */
25087c478bd9Sstevel@tonic-gate 	(void) cond_signal(&sub_info->sp_cv);
25097c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&sub_info->sp_qlock);
25100762f44eSToomas Soome 	if (sub_info->sp_handler_tid != 0)
2511f6e214c7SGavin Maltby 		(void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
25127c478bd9Sstevel@tonic-gate 
25137c478bd9Sstevel@tonic-gate 	(void) cond_destroy(&sub_info->sp_cv);
25147c478bd9Sstevel@tonic-gate 	(void) mutex_destroy(&sub_info->sp_qlock);
25157c478bd9Sstevel@tonic-gate 	free(sub_info->sp_door_name);
25167c478bd9Sstevel@tonic-gate 	free(sub_info);
25177c478bd9Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
25187c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
25197c478bd9Sstevel@tonic-gate }
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate /*
25227c478bd9Sstevel@tonic-gate  * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
25237c478bd9Sstevel@tonic-gate  */
25247c478bd9Sstevel@tonic-gate void
sysevent_unbind_publisher(sysevent_handle_t * shp)25257c478bd9Sstevel@tonic-gate sysevent_unbind_publisher(sysevent_handle_t *shp)
25267c478bd9Sstevel@tonic-gate {
25277c478bd9Sstevel@tonic-gate 	if (shp == NULL)
25287c478bd9Sstevel@tonic-gate 		return;
25297c478bd9Sstevel@tonic-gate 
25307c478bd9Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
25317c478bd9Sstevel@tonic-gate 	if (SH_BOUND(shp) == 0) {
25327c478bd9Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
25337c478bd9Sstevel@tonic-gate 		return;
25347c478bd9Sstevel@tonic-gate 	}
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 	/* Close down the registration facilities */
25377c478bd9Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
25387c478bd9Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	/* Update the in-kernel registration */
25417c478bd9Sstevel@tonic-gate 	(void) update_kernel_registration(shp, PUBLISHER,
25427c478bd9Sstevel@tonic-gate 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
25437c478bd9Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
25447c478bd9Sstevel@tonic-gate 
25457c478bd9Sstevel@tonic-gate 	/* Free resources associated with bind */
25467c478bd9Sstevel@tonic-gate 	free_cached_registration(shp);
25477c478bd9Sstevel@tonic-gate 	dealloc_subscribers(shp);
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 	free(SH_PRIV_DATA(shp));
25507c478bd9Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
25517c478bd9Sstevel@tonic-gate 	SH_ID(shp) = 0;
25527c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
25537c478bd9Sstevel@tonic-gate }
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate /*
2556*bbf21555SRichard Lowe  * Evolving APIs to subscribe to syseventd(8) system events.
25577c478bd9Sstevel@tonic-gate  */
25587c478bd9Sstevel@tonic-gate 
2559f6e214c7SGavin Maltby static sysevent_handle_t *
sysevent_bind_handle_cmn(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2560f6e214c7SGavin Maltby sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2561f6e214c7SGavin Maltby     sysevent_subattr_t *subattr)
25627c478bd9Sstevel@tonic-gate {
25637c478bd9Sstevel@tonic-gate 	sysevent_handle_t *shp;
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 	if (getuid() != 0) {
25667c478bd9Sstevel@tonic-gate 		errno = EACCES;
25677c478bd9Sstevel@tonic-gate 		return (NULL);
25687c478bd9Sstevel@tonic-gate 	}
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	if (event_handler == NULL) {
25717c478bd9Sstevel@tonic-gate 		errno = EINVAL;
25727c478bd9Sstevel@tonic-gate 		return (NULL);
25737c478bd9Sstevel@tonic-gate 	}
25747c478bd9Sstevel@tonic-gate 
25757c478bd9Sstevel@tonic-gate 	if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
25767c478bd9Sstevel@tonic-gate 		return (NULL);
25777c478bd9Sstevel@tonic-gate 	}
25787c478bd9Sstevel@tonic-gate 
2579f6e214c7SGavin Maltby 	if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
25807c478bd9Sstevel@tonic-gate 		/*
25817c478bd9Sstevel@tonic-gate 		 * Ask syseventd to clean-up any stale subcribers and try to
25827c478bd9Sstevel@tonic-gate 		 * to bind again
25837c478bd9Sstevel@tonic-gate 		 */
25847c478bd9Sstevel@tonic-gate 		if (errno == EBUSY) {
25857c478bd9Sstevel@tonic-gate 			int pub_fd;
25867c478bd9Sstevel@tonic-gate 			char door_name[MAXPATHLEN];
25877c478bd9Sstevel@tonic-gate 			uint32_t result;
25887c478bd9Sstevel@tonic-gate 			struct reg_args rargs;
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 			if (snprintf(door_name, MAXPATHLEN, "%s/%s",
25917c478bd9Sstevel@tonic-gate 			    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
25927c478bd9Sstevel@tonic-gate 				sysevent_close_channel(shp);
25937c478bd9Sstevel@tonic-gate 				errno = EINVAL;
25947c478bd9Sstevel@tonic-gate 				return (NULL);
25957c478bd9Sstevel@tonic-gate 			}
25967c478bd9Sstevel@tonic-gate 
25977c478bd9Sstevel@tonic-gate 			rargs.ra_op = SE_CLEANUP;
25987c478bd9Sstevel@tonic-gate 			pub_fd = open(door_name, O_RDONLY);
25997c478bd9Sstevel@tonic-gate 			(void) clnt_deliver_event(pub_fd, (void *)&rargs,
26007c478bd9Sstevel@tonic-gate 			    sizeof (struct reg_args), &result, sizeof (result));
26017c478bd9Sstevel@tonic-gate 			(void) close(pub_fd);
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 			/* Try to bind again */
2604f6e214c7SGavin Maltby 			if (sysevent_bind_xsubscriber(shp, event_handler,
2605f6e214c7SGavin Maltby 			    subattr) != 0) {
26067c478bd9Sstevel@tonic-gate 				sysevent_close_channel(shp);
26077c478bd9Sstevel@tonic-gate 				return (NULL);
26087c478bd9Sstevel@tonic-gate 			}
26097c478bd9Sstevel@tonic-gate 		} else {
26107c478bd9Sstevel@tonic-gate 			sysevent_close_channel(shp);
26117c478bd9Sstevel@tonic-gate 			return (NULL);
26127c478bd9Sstevel@tonic-gate 		}
26137c478bd9Sstevel@tonic-gate 	}
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 	return (shp);
26167c478bd9Sstevel@tonic-gate }
26177c478bd9Sstevel@tonic-gate 
2618f6e214c7SGavin Maltby /*
2619f6e214c7SGavin Maltby  * sysevent_bind_handle - Bind application event handler for syseventd
2620f6e214c7SGavin Maltby  *		subscription.
2621f6e214c7SGavin Maltby  */
2622f6e214c7SGavin Maltby sysevent_handle_t *
sysevent_bind_handle(void (* event_handler)(sysevent_t * ev))2623f6e214c7SGavin Maltby sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2624f6e214c7SGavin Maltby {
2625f6e214c7SGavin Maltby 	return (sysevent_bind_handle_cmn(event_handler, NULL));
2626f6e214c7SGavin Maltby }
2627f6e214c7SGavin Maltby 
2628f6e214c7SGavin Maltby /*
2629f6e214c7SGavin Maltby  * sysevent_bind_xhandle - Bind application event handler for syseventd
2630f6e214c7SGavin Maltby  *		subscription, using door_xcreate and attributes as specified.
2631f6e214c7SGavin Maltby  */
2632f6e214c7SGavin Maltby sysevent_handle_t *
sysevent_bind_xhandle(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2633f6e214c7SGavin Maltby sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2634f6e214c7SGavin Maltby     sysevent_subattr_t *subattr)
2635f6e214c7SGavin Maltby {
2636f6e214c7SGavin Maltby 	return (sysevent_bind_handle_cmn(event_handler, subattr));
2637f6e214c7SGavin Maltby }
2638f6e214c7SGavin Maltby 
26397c478bd9Sstevel@tonic-gate /*
26407c478bd9Sstevel@tonic-gate  * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
26417c478bd9Sstevel@tonic-gate  */
26427c478bd9Sstevel@tonic-gate void
sysevent_unbind_handle(sysevent_handle_t * shp)26437c478bd9Sstevel@tonic-gate sysevent_unbind_handle(sysevent_handle_t *shp)
26447c478bd9Sstevel@tonic-gate {
26457c478bd9Sstevel@tonic-gate 	sysevent_unbind_subscriber(shp);
26467c478bd9Sstevel@tonic-gate 	sysevent_close_channel(shp);
26477c478bd9Sstevel@tonic-gate }
26487c478bd9Sstevel@tonic-gate 
26497c478bd9Sstevel@tonic-gate /*
26507c478bd9Sstevel@tonic-gate  * sysevent_subscribe_event - Subscribe to system event notification from
2651*bbf21555SRichard Lowe  *			syseventd(8) for the class and subclasses specified.
26527c478bd9Sstevel@tonic-gate  */
26537c478bd9Sstevel@tonic-gate int
sysevent_subscribe_event(sysevent_handle_t * shp,const char * event_class,const char ** event_subclass_list,int num_subclasses)26547c478bd9Sstevel@tonic-gate sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
26550762f44eSToomas Soome     const char **event_subclass_list, int num_subclasses)
26567c478bd9Sstevel@tonic-gate {
26577c478bd9Sstevel@tonic-gate 	return (sysevent_register_event(shp, event_class,
26587c478bd9Sstevel@tonic-gate 	    event_subclass_list, num_subclasses));
26597c478bd9Sstevel@tonic-gate }
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate void
sysevent_unsubscribe_event(sysevent_handle_t * shp,const char * event_class)26627c478bd9Sstevel@tonic-gate sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
26637c478bd9Sstevel@tonic-gate {
26647c478bd9Sstevel@tonic-gate 	sysevent_unregister_event(shp, event_class);
26657c478bd9Sstevel@tonic-gate }
2666