xref: /onnv-gate/usr/src/lib/libsysevent/libsysevent.c (revision 12967:ab9ae749152f)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51717Swesolows  * Common Development and Distribution License (the "License").
61717Swesolows  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211717Swesolows 
220Sstevel@tonic-gate /*
23*12967Sgavin.maltby@oracle.com  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <stdio.h>
270Sstevel@tonic-gate #include <fcntl.h>
280Sstevel@tonic-gate #include <errno.h>
290Sstevel@tonic-gate #include <door.h>
300Sstevel@tonic-gate #include <unistd.h>
310Sstevel@tonic-gate #include <stddef.h>
320Sstevel@tonic-gate #include <stdlib.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <strings.h>
350Sstevel@tonic-gate #include <synch.h>
360Sstevel@tonic-gate #include <pthread.h>
37*12967Sgavin.maltby@oracle.com #include <signal.h>
380Sstevel@tonic-gate #include <thread.h>
390Sstevel@tonic-gate #include <libnvpair.h>
400Sstevel@tonic-gate #include <assert.h>
410Sstevel@tonic-gate #include <sys/stat.h>
420Sstevel@tonic-gate #include <sys/types.h>
430Sstevel@tonic-gate #include <sys/modctl.h>
440Sstevel@tonic-gate #include <sys/mnttab.h>
450Sstevel@tonic-gate #include <sys/sysevent.h>
460Sstevel@tonic-gate #include <sys/sysevent_impl.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include "libsysevent.h"
490Sstevel@tonic-gate #include "libsysevent_impl.h"
500Sstevel@tonic-gate 
510Sstevel@tonic-gate /*
520Sstevel@tonic-gate  * libsysevent - The system event framework library
530Sstevel@tonic-gate  *
540Sstevel@tonic-gate  *		This library provides routines to help with marshalling
550Sstevel@tonic-gate  *		and unmarshalling of data contained in a sysevent event
560Sstevel@tonic-gate  *		buffer.
570Sstevel@tonic-gate  */
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	SE_ENCODE_METHOD	NV_ENCODE_NATIVE
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #define	dprint	if (libsysevent_debug) (void) printf
620Sstevel@tonic-gate static int libsysevent_debug = 0;
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static sysevent_t *se_unpack(sysevent_t *);
650Sstevel@tonic-gate static int cleanup_id(sysevent_handle_t *shp, uint32_t id, int type);
660Sstevel@tonic-gate 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * The following routines allow system event publication to the sysevent
690Sstevel@tonic-gate  * framework.
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate 
720Sstevel@tonic-gate /*
730Sstevel@tonic-gate  * sysevent_alloc - allocate a sysevent buffer
740Sstevel@tonic-gate  */
750Sstevel@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)760Sstevel@tonic-gate sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz,
770Sstevel@tonic-gate 	char *pub, int pub_sz, nvlist_t *attr_list)
780Sstevel@tonic-gate {
790Sstevel@tonic-gate 	int payload_sz;
800Sstevel@tonic-gate 	int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
810Sstevel@tonic-gate 	size_t nvlist_sz = 0;
820Sstevel@tonic-gate 	char *attr;
830Sstevel@tonic-gate 	uint64_t attr_offset;
840Sstevel@tonic-gate 	sysevent_t *ev;
850Sstevel@tonic-gate 
860Sstevel@tonic-gate 	if (attr_list != NULL) {
870Sstevel@tonic-gate 		if (nvlist_size(attr_list, &nvlist_sz, SE_ENCODE_METHOD)
880Sstevel@tonic-gate 		    != 0) {
890Sstevel@tonic-gate 			return (NULL);
900Sstevel@tonic-gate 		}
910Sstevel@tonic-gate 	}
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	/*
940Sstevel@tonic-gate 	 * Calculate and reserve space for the class, subclass and
950Sstevel@tonic-gate 	 * publisher strings in the event buffer
960Sstevel@tonic-gate 	 */
970Sstevel@tonic-gate 
980Sstevel@tonic-gate 	/* String sizes must be 64-bit aligned in the event buffer */
990Sstevel@tonic-gate 	aligned_class_sz = SE_ALIGN(class_sz);
1000Sstevel@tonic-gate 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
1010Sstevel@tonic-gate 	aligned_pub_sz = SE_ALIGN(pub_sz);
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
10411102SGavin.Maltby@Sun.COM 	    (aligned_subclass_sz - sizeof (uint64_t)) +
10511102SGavin.Maltby@Sun.COM 	    (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) +
10611102SGavin.Maltby@Sun.COM 	    nvlist_sz;
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate 	/*
1090Sstevel@tonic-gate 	 * Allocate event buffer plus additional payload overhead.
1100Sstevel@tonic-gate 	 */
1110Sstevel@tonic-gate 	ev = calloc(1, sizeof (sysevent_impl_t) + payload_sz);
1120Sstevel@tonic-gate 	if (ev == NULL) {
1130Sstevel@tonic-gate 		return (NULL);
1140Sstevel@tonic-gate 	}
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/* Initialize the event buffer data */
1170Sstevel@tonic-gate 	SE_VERSION(ev) = SYS_EVENT_VERSION;
1180Sstevel@tonic-gate 	(void) bcopy(class, SE_CLASS_NAME(ev), class_sz);
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
1210Sstevel@tonic-gate 		+ aligned_class_sz;
1220Sstevel@tonic-gate 	(void) bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
1250Sstevel@tonic-gate 	(void) bcopy(pub, SE_PUB_NAME(ev), pub_sz);
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) = payload_sz;
1280Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = (uint64_t)0;
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/* Check for attribute list */
1310Sstevel@tonic-gate 	if (attr_list == NULL) {
1320Sstevel@tonic-gate 		return (ev);
1330Sstevel@tonic-gate 	}
1340Sstevel@tonic-gate 
1350Sstevel@tonic-gate 	/* Copy attribute data to contiguous memory */
1360Sstevel@tonic-gate 	SE_FLAG(ev) = SE_PACKED_BUF;
1370Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
1380Sstevel@tonic-gate 	attr = (char *)((caddr_t)ev + attr_offset);
1390Sstevel@tonic-gate 	if (nvlist_pack(attr_list, &attr, &nvlist_sz, SE_ENCODE_METHOD,
1400Sstevel@tonic-gate 	    0) != 0) {
1410Sstevel@tonic-gate 		free(ev);
1420Sstevel@tonic-gate 		return (NULL);
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	return (ev);
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate /*
1490Sstevel@tonic-gate  * sysevent_post_event - generate a system event via the sysevent framework
1500Sstevel@tonic-gate  */
1510Sstevel@tonic-gate int
sysevent_post_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list,sysevent_id_t * eid)1520Sstevel@tonic-gate sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name,
1530Sstevel@tonic-gate 	nvlist_t *attr_list, sysevent_id_t *eid)
1540Sstevel@tonic-gate {
1550Sstevel@tonic-gate 	int error;
1560Sstevel@tonic-gate 	sysevent_t *ev;
1570Sstevel@tonic-gate 
1580Sstevel@tonic-gate 	ev = sysevent_alloc_event(class, subclass, vendor, pub_name, attr_list);
1590Sstevel@tonic-gate 	if (ev == NULL) {
1600Sstevel@tonic-gate 		return (-1);
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT,
16411102SGavin.Maltby@Sun.COM 	    (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), (uintptr_t)eid, 0);
1650Sstevel@tonic-gate 
1660Sstevel@tonic-gate 	sysevent_free(ev);
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	if (error) {
1690Sstevel@tonic-gate 		errno = EIO;
1700Sstevel@tonic-gate 		return (-1);
1710Sstevel@tonic-gate 	}
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate 	return (0);
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate  * The following routines are used to free or duplicate a
1780Sstevel@tonic-gate  * sysevent event buffer.
1790Sstevel@tonic-gate  */
1800Sstevel@tonic-gate 
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate  * sysevent_dup - Allocate and copy an event buffer
1830Sstevel@tonic-gate  *	Copies both packed and unpacked to unpacked sysevent.
1840Sstevel@tonic-gate  */
1850Sstevel@tonic-gate sysevent_t *
sysevent_dup(sysevent_t * ev)1860Sstevel@tonic-gate sysevent_dup(sysevent_t *ev)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	nvlist_t *nvl, *cnvl = NULL;
1890Sstevel@tonic-gate 	uint64_t attr_offset;
1900Sstevel@tonic-gate 	sysevent_t *copy;
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (SE_FLAG(ev) == SE_PACKED_BUF)
1930Sstevel@tonic-gate 		return (se_unpack(ev));
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	/* Copy event header information */
1960Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
1970Sstevel@tonic-gate 	copy = calloc(1, attr_offset);
1980Sstevel@tonic-gate 	if (copy == NULL)
1990Sstevel@tonic-gate 		return (NULL);
2000Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
2010Sstevel@tonic-gate 
2021717Swesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2030Sstevel@tonic-gate 	if (nvl && nvlist_dup(nvl, &cnvl, 0) != 0) {
2040Sstevel@tonic-gate 		free(copy);
2050Sstevel@tonic-gate 		return (NULL);
2060Sstevel@tonic-gate 	}
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = (uintptr_t)cnvl;
2090Sstevel@tonic-gate 	SE_FLAG(copy) = 0;	/* unpacked */
2100Sstevel@tonic-gate 	return (copy);
2110Sstevel@tonic-gate }
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate  * sysevent_free - Free memory allocated for an event buffer
2150Sstevel@tonic-gate  */
2160Sstevel@tonic-gate void
sysevent_free(sysevent_t * ev)2170Sstevel@tonic-gate sysevent_free(sysevent_t *ev)
2180Sstevel@tonic-gate {
2191717Swesolows 	nvlist_t *attr_list = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2200Sstevel@tonic-gate 
2210Sstevel@tonic-gate 	if (attr_list)
2220Sstevel@tonic-gate 		nvlist_free(attr_list);
2230Sstevel@tonic-gate 	free(ev);
2240Sstevel@tonic-gate }
2250Sstevel@tonic-gate 
2260Sstevel@tonic-gate /*
2270Sstevel@tonic-gate  * The following routines are used to extract attribute data from a sysevent
2280Sstevel@tonic-gate  * handle.
2290Sstevel@tonic-gate  */
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate /*
2320Sstevel@tonic-gate  * sysevent_get_attr_list - allocate and return an attribute associated with
2330Sstevel@tonic-gate  *			the given sysevent buffer.
2340Sstevel@tonic-gate  */
2350Sstevel@tonic-gate int
sysevent_get_attr_list(sysevent_t * ev,nvlist_t ** nvlist)2360Sstevel@tonic-gate sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
2370Sstevel@tonic-gate {
2380Sstevel@tonic-gate 	int error;
2390Sstevel@tonic-gate 	caddr_t attr;
2400Sstevel@tonic-gate 	size_t attr_len;
2410Sstevel@tonic-gate 	uint64_t attr_offset;
2420Sstevel@tonic-gate 	nvlist_t *nvl;
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate 	*nvlist = NULL;
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	/* Duplicate attribute for an unpacked sysevent buffer */
2470Sstevel@tonic-gate 	if (SE_FLAG(ev) != SE_PACKED_BUF) {
2481717Swesolows 		nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
2490Sstevel@tonic-gate 		if (nvl == NULL) {
2500Sstevel@tonic-gate 			return (0);
2510Sstevel@tonic-gate 		}
2520Sstevel@tonic-gate 		if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) {
2530Sstevel@tonic-gate 			if (error == ENOMEM) {
2540Sstevel@tonic-gate 				errno = error;
2550Sstevel@tonic-gate 			} else {
2560Sstevel@tonic-gate 				errno = EINVAL;
2570Sstevel@tonic-gate 			}
2580Sstevel@tonic-gate 			return (-1);
2590Sstevel@tonic-gate 		}
2600Sstevel@tonic-gate 		return (0);
2610Sstevel@tonic-gate 	}
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
2640Sstevel@tonic-gate 	if (SE_SIZE(ev) == attr_offset) {
2650Sstevel@tonic-gate 		return (0);
2660Sstevel@tonic-gate 	}
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate 	/* unpack nvlist */
2690Sstevel@tonic-gate 	attr = (caddr_t)ev + attr_offset;
2700Sstevel@tonic-gate 	attr_len = SE_SIZE(ev) - attr_offset;
2710Sstevel@tonic-gate 	if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
2720Sstevel@tonic-gate 		if (error == ENOMEM) {
2730Sstevel@tonic-gate 			errno = error;
2740Sstevel@tonic-gate 		} else 	{
2750Sstevel@tonic-gate 			errno = EINVAL;
2760Sstevel@tonic-gate 		}
2770Sstevel@tonic-gate 		return (-1);
2780Sstevel@tonic-gate 	}
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (0);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * sysevent_attr_name - Get name of attribute
2850Sstevel@tonic-gate  */
2860Sstevel@tonic-gate char *
sysevent_attr_name(sysevent_attr_t * attr)2870Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr)
2880Sstevel@tonic-gate {
2890Sstevel@tonic-gate 	if (attr == NULL) {
2900Sstevel@tonic-gate 		errno = EINVAL;
2910Sstevel@tonic-gate 		return (NULL);
2920Sstevel@tonic-gate 	}
2930Sstevel@tonic-gate 	return (nvpair_name((nvpair_t *)attr));
2940Sstevel@tonic-gate }
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate /*
2970Sstevel@tonic-gate  * sysevent_attr_value - Get attribute value data and type
2980Sstevel@tonic-gate  */
2990Sstevel@tonic-gate int
sysevent_attr_value(sysevent_attr_t * attr,sysevent_value_t * se_value)3000Sstevel@tonic-gate sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	nvpair_t *nvp = attr;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	if (nvp == NULL)
3050Sstevel@tonic-gate 		return (EINVAL);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 	/* Convert DATA_TYPE_* to SE_DATA_TYPE_* */
3080Sstevel@tonic-gate 	switch (nvpair_type(nvp)) {
3090Sstevel@tonic-gate 	case DATA_TYPE_BYTE:
3100Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_BYTE;
3110Sstevel@tonic-gate 		(void) nvpair_value_byte(nvp, &se_value->value.sv_byte);
3120Sstevel@tonic-gate 		break;
3130Sstevel@tonic-gate 	case DATA_TYPE_INT16:
3140Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT16;
3150Sstevel@tonic-gate 		(void) nvpair_value_int16(nvp, &se_value->value.sv_int16);
3160Sstevel@tonic-gate 		break;
3170Sstevel@tonic-gate 	case DATA_TYPE_UINT16:
3180Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT16;
3190Sstevel@tonic-gate 		(void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16);
3200Sstevel@tonic-gate 		break;
3210Sstevel@tonic-gate 	case DATA_TYPE_INT32:
3220Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT32;
3230Sstevel@tonic-gate 		(void) nvpair_value_int32(nvp, &se_value->value.sv_int32);
3240Sstevel@tonic-gate 		break;
3250Sstevel@tonic-gate 	case DATA_TYPE_UINT32:
3260Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT32;
3270Sstevel@tonic-gate 		(void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32);
3280Sstevel@tonic-gate 		break;
3290Sstevel@tonic-gate 	case DATA_TYPE_INT64:
3300Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_INT64;
3310Sstevel@tonic-gate 		(void) nvpair_value_int64(nvp, &se_value->value.sv_int64);
3320Sstevel@tonic-gate 		break;
3330Sstevel@tonic-gate 	case DATA_TYPE_UINT64:
3340Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_UINT64;
3350Sstevel@tonic-gate 		(void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64);
3360Sstevel@tonic-gate 		break;
3370Sstevel@tonic-gate 	case DATA_TYPE_STRING:
3380Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_STRING;
3390Sstevel@tonic-gate 		(void) nvpair_value_string(nvp, &se_value->value.sv_string);
3400Sstevel@tonic-gate 		break;
3410Sstevel@tonic-gate 	case DATA_TYPE_BYTE_ARRAY:
3420Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_BYTES;
3430Sstevel@tonic-gate 		(void) nvpair_value_byte_array(nvp,
3440Sstevel@tonic-gate 		    &se_value->value.sv_bytes.data,
3450Sstevel@tonic-gate 		    (uint_t *)&se_value->value.sv_bytes.size);
3460Sstevel@tonic-gate 		break;
3470Sstevel@tonic-gate 	case DATA_TYPE_HRTIME:
3480Sstevel@tonic-gate 		se_value->value_type = SE_DATA_TYPE_TIME;
3490Sstevel@tonic-gate 		(void) nvpair_value_hrtime(nvp, &se_value->value.sv_time);
3500Sstevel@tonic-gate 		break;
3510Sstevel@tonic-gate 	default:
3520Sstevel@tonic-gate 		return (ENOTSUP);
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 	return (0);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate /*
3580Sstevel@tonic-gate  * sysevent_attr_next - Get next attribute in event attribute list
3590Sstevel@tonic-gate  */
3600Sstevel@tonic-gate sysevent_attr_t *
sysevent_attr_next(sysevent_t * ev,sysevent_attr_t * attr)3610Sstevel@tonic-gate sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr)
3620Sstevel@tonic-gate {
3630Sstevel@tonic-gate 	nvlist_t *nvl;
3640Sstevel@tonic-gate 	nvpair_t *nvp = attr;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	/* all user visible sysevent_t's are unpacked */
3670Sstevel@tonic-gate 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
3700Sstevel@tonic-gate 		return (NULL);
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3731717Swesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
3740Sstevel@tonic-gate 	return (nvlist_next_nvpair(nvl, nvp));
3750Sstevel@tonic-gate }
3760Sstevel@tonic-gate 
3770Sstevel@tonic-gate /*
3780Sstevel@tonic-gate  * sysevent_lookup_attr - Lookup attribute by name and datatype.
3790Sstevel@tonic-gate  */
3800Sstevel@tonic-gate int
sysevent_lookup_attr(sysevent_t * ev,char * name,int datatype,sysevent_value_t * se_value)3810Sstevel@tonic-gate sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype,
3820Sstevel@tonic-gate 	sysevent_value_t *se_value)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	nvpair_t *nvp;
3850Sstevel@tonic-gate 	nvlist_t *nvl;
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
3900Sstevel@tonic-gate 		return (ENOENT);
3910Sstevel@tonic-gate 	}
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	/*
3940Sstevel@tonic-gate 	 * sysevent matches on both name and datatype
3950Sstevel@tonic-gate 	 * nvlist_look mataches name only. So we walk
3960Sstevel@tonic-gate 	 * nvlist manually here.
3970Sstevel@tonic-gate 	 */
3981717Swesolows 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
3990Sstevel@tonic-gate 	nvp = nvlist_next_nvpair(nvl, NULL);
4000Sstevel@tonic-gate 	while (nvp) {
4010Sstevel@tonic-gate 		if ((strcmp(name, nvpair_name(nvp)) == 0) &&
4020Sstevel@tonic-gate 		    (sysevent_attr_value(nvp, se_value) == 0) &&
4030Sstevel@tonic-gate 		    (se_value->value_type == datatype))
4040Sstevel@tonic-gate 			return (0);
4050Sstevel@tonic-gate 		nvp = nvlist_next_nvpair(nvl, nvp);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 	return (ENOENT);
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate /* Routines to extract event header information */
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate /*
4130Sstevel@tonic-gate  * sysevent_get_class - Get class id
4140Sstevel@tonic-gate  */
4150Sstevel@tonic-gate int
sysevent_get_class(sysevent_t * ev)4160Sstevel@tonic-gate sysevent_get_class(sysevent_t *ev)
4170Sstevel@tonic-gate {
4180Sstevel@tonic-gate 	return (SE_CLASS(ev));
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate /*
4220Sstevel@tonic-gate  * sysevent_get_subclass - Get subclass id
4230Sstevel@tonic-gate  */
4240Sstevel@tonic-gate int
sysevent_get_subclass(sysevent_t * ev)4250Sstevel@tonic-gate sysevent_get_subclass(sysevent_t *ev)
4260Sstevel@tonic-gate {
4270Sstevel@tonic-gate 	return (SE_SUBCLASS(ev));
4280Sstevel@tonic-gate }
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate /*
4310Sstevel@tonic-gate  * sysevent_get_class_name - Get class name string
4320Sstevel@tonic-gate  */
4330Sstevel@tonic-gate char *
sysevent_get_class_name(sysevent_t * ev)4340Sstevel@tonic-gate sysevent_get_class_name(sysevent_t *ev)
4350Sstevel@tonic-gate {
4360Sstevel@tonic-gate 	return (SE_CLASS_NAME(ev));
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate typedef enum {
4400Sstevel@tonic-gate 	PUB_VEND,
4410Sstevel@tonic-gate 	PUB_KEYWD,
4420Sstevel@tonic-gate 	PUB_NAME,
4430Sstevel@tonic-gate 	PUB_PID
4440Sstevel@tonic-gate } se_pub_id_t;
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate /*
4470Sstevel@tonic-gate  * sysevent_get_pub - Get publisher name string
4480Sstevel@tonic-gate  */
4490Sstevel@tonic-gate char *
sysevent_get_pub(sysevent_t * ev)4500Sstevel@tonic-gate sysevent_get_pub(sysevent_t *ev)
4510Sstevel@tonic-gate {
4520Sstevel@tonic-gate 	return (SE_PUB_NAME(ev));
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate  * Get the requested string pointed by the token.
4570Sstevel@tonic-gate  *
4580Sstevel@tonic-gate  * Return NULL if not found or for insufficient memory.
4590Sstevel@tonic-gate  */
4600Sstevel@tonic-gate static char *
parse_pub_id(sysevent_t * ev,se_pub_id_t token)4610Sstevel@tonic-gate parse_pub_id(sysevent_t *ev, se_pub_id_t token)
4620Sstevel@tonic-gate {
4630Sstevel@tonic-gate 	int i;
4640Sstevel@tonic-gate 	char *pub_id, *pub_element, *str, *next;
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	next = pub_id = strdup(sysevent_get_pub(ev));
4670Sstevel@tonic-gate 	for (i = 0; i <= token; ++i) {
4680Sstevel@tonic-gate 		str = strtok_r(next, ":", &next);
4690Sstevel@tonic-gate 		if (str == NULL) {
4700Sstevel@tonic-gate 			free(pub_id);
4710Sstevel@tonic-gate 			return (NULL);
4720Sstevel@tonic-gate 		}
4730Sstevel@tonic-gate 	}
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	pub_element = strdup(str);
4760Sstevel@tonic-gate 	free(pub_id);
4770Sstevel@tonic-gate 	return (pub_element);
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate /*
4810Sstevel@tonic-gate  * Return a pointer to the string following the token
4820Sstevel@tonic-gate  *
4830Sstevel@tonic-gate  * Note: This is a dedicated function for parsing
4840Sstevel@tonic-gate  * publisher strings and not for general purpose.
4850Sstevel@tonic-gate  */
4860Sstevel@tonic-gate static const char *
pub_idx(const char * pstr,int token)4870Sstevel@tonic-gate pub_idx(const char *pstr, int token)
4880Sstevel@tonic-gate {
4890Sstevel@tonic-gate 	int i;
4900Sstevel@tonic-gate 
4910Sstevel@tonic-gate 	for (i = 1; i <= token; i++) {
4920Sstevel@tonic-gate 		if ((pstr = index(pstr, ':')) == NULL)
4930Sstevel@tonic-gate 			return (NULL);
4940Sstevel@tonic-gate 		pstr++;
4950Sstevel@tonic-gate 	}
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	/* String might be empty */
4980Sstevel@tonic-gate 	if (pstr) {
4990Sstevel@tonic-gate 		if (*pstr == '\0' || *pstr == ':')
5000Sstevel@tonic-gate 			return (NULL);
5010Sstevel@tonic-gate 	}
5020Sstevel@tonic-gate 	return (pstr);
5030Sstevel@tonic-gate }
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate char *
sysevent_get_vendor_name(sysevent_t * ev)5060Sstevel@tonic-gate sysevent_get_vendor_name(sysevent_t *ev)
5070Sstevel@tonic-gate {
5080Sstevel@tonic-gate 	return (parse_pub_id(ev, PUB_VEND));
5090Sstevel@tonic-gate }
5100Sstevel@tonic-gate 
5110Sstevel@tonic-gate char *
sysevent_get_pub_name(sysevent_t * ev)5120Sstevel@tonic-gate sysevent_get_pub_name(sysevent_t *ev)
5130Sstevel@tonic-gate {
5140Sstevel@tonic-gate 	return (parse_pub_id(ev, PUB_NAME));
5150Sstevel@tonic-gate }
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate /*
5180Sstevel@tonic-gate  * Provide the pid encoded in the publisher string
5190Sstevel@tonic-gate  * w/o allocating any resouces.
5200Sstevel@tonic-gate  */
5210Sstevel@tonic-gate void
sysevent_get_pid(sysevent_t * ev,pid_t * pid)5220Sstevel@tonic-gate sysevent_get_pid(sysevent_t *ev, pid_t *pid)
5230Sstevel@tonic-gate {
5240Sstevel@tonic-gate 	const char *part_str;
5250Sstevel@tonic-gate 	const char *pub_str = sysevent_get_pub(ev);
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	*pid = (pid_t)SE_KERN_PID;
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	part_str = pub_idx(pub_str, PUB_KEYWD);
5300Sstevel@tonic-gate 	if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL)
5310Sstevel@tonic-gate 		return;
5320Sstevel@tonic-gate 
5330Sstevel@tonic-gate 	if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL)
5340Sstevel@tonic-gate 		return;
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	*pid = (pid_t)atoi(part_str);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate /*
5400Sstevel@tonic-gate  * sysevent_get_subclass_name - Get subclass name string
5410Sstevel@tonic-gate  */
5420Sstevel@tonic-gate char *
sysevent_get_subclass_name(sysevent_t * ev)5430Sstevel@tonic-gate sysevent_get_subclass_name(sysevent_t *ev)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate 	return (SE_SUBCLASS_NAME(ev));
5460Sstevel@tonic-gate }
5470Sstevel@tonic-gate 
5480Sstevel@tonic-gate /*
5490Sstevel@tonic-gate  * sysevent_get_seq - Get event sequence id
5500Sstevel@tonic-gate  */
5510Sstevel@tonic-gate uint64_t
sysevent_get_seq(sysevent_t * ev)5520Sstevel@tonic-gate sysevent_get_seq(sysevent_t *ev)
5530Sstevel@tonic-gate {
5540Sstevel@tonic-gate 	return (SE_SEQ(ev));
5550Sstevel@tonic-gate }
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate  * sysevent_get_time - Get event timestamp
5590Sstevel@tonic-gate  */
5600Sstevel@tonic-gate void
sysevent_get_time(sysevent_t * ev,hrtime_t * etime)5610Sstevel@tonic-gate sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
5620Sstevel@tonic-gate {
5630Sstevel@tonic-gate 	*etime = SE_TIME(ev);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * sysevent_get_size - Get event buffer size
5680Sstevel@tonic-gate  */
5690Sstevel@tonic-gate size_t
sysevent_get_size(sysevent_t * ev)5700Sstevel@tonic-gate sysevent_get_size(sysevent_t *ev)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	return ((size_t)SE_SIZE(ev));
5730Sstevel@tonic-gate }
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate /*
5760Sstevel@tonic-gate  * The following routines are used by devfsadm_mod.c to propagate event
5770Sstevel@tonic-gate  * buffers to devfsadmd.  These routines will serve as the basis for
5780Sstevel@tonic-gate  * event channel publication and subscription.
5790Sstevel@tonic-gate  */
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate /*
5820Sstevel@tonic-gate  * sysevent_alloc_event -
5830Sstevel@tonic-gate  *	allocate a sysevent buffer for sending through an established event
5840Sstevel@tonic-gate  *	channel.
5850Sstevel@tonic-gate  */
5860Sstevel@tonic-gate sysevent_t *
sysevent_alloc_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list)5870Sstevel@tonic-gate sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name,
5880Sstevel@tonic-gate 	nvlist_t *attr_list)
5890Sstevel@tonic-gate {
5900Sstevel@tonic-gate 	int class_sz, subclass_sz, pub_sz;
5910Sstevel@tonic-gate 	char *pub_id;
5920Sstevel@tonic-gate 	sysevent_t *ev;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	if ((class == NULL) || (subclass == NULL) || (vendor == NULL) ||
5950Sstevel@tonic-gate 	    (pub_name == NULL)) {
5960Sstevel@tonic-gate 		errno = EINVAL;
5970Sstevel@tonic-gate 		return (NULL);
5980Sstevel@tonic-gate 	}
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
6010Sstevel@tonic-gate 	subclass_sz = strlen(subclass) + 1;
6020Sstevel@tonic-gate 	if ((class_sz > MAX_CLASS_LEN) ||
6030Sstevel@tonic-gate 	    (subclass_sz > MAX_SUBCLASS_LEN)) {
6040Sstevel@tonic-gate 		errno = EINVAL;
6050Sstevel@tonic-gate 		return (NULL);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/*
6090Sstevel@tonic-gate 	 * Calculate the publisher size plus string seperators and maximum
6100Sstevel@tonic-gate 	 * pid characters
6110Sstevel@tonic-gate 	 */
6120Sstevel@tonic-gate 	pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14;
6130Sstevel@tonic-gate 	if (pub_sz > MAX_PUB_LEN) {
6140Sstevel@tonic-gate 		errno = EINVAL;
6150Sstevel@tonic-gate 		return (NULL);
6160Sstevel@tonic-gate 	}
6170Sstevel@tonic-gate 	pub_id = malloc(pub_sz);
6180Sstevel@tonic-gate 	if (pub_id == NULL) {
6190Sstevel@tonic-gate 		errno = ENOMEM;
6200Sstevel@tonic-gate 		return (NULL);
6210Sstevel@tonic-gate 	}
6220Sstevel@tonic-gate 	if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB,
6230Sstevel@tonic-gate 	    pub_name, (int)getpid()) >= pub_sz) {
6240Sstevel@tonic-gate 		free(pub_id);
6250Sstevel@tonic-gate 		errno = EINVAL;
6260Sstevel@tonic-gate 		return (NULL);
6270Sstevel@tonic-gate 	}
6280Sstevel@tonic-gate 	pub_sz = strlen(pub_id) + 1;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	ev = sysevent_alloc(class, class_sz, subclass, subclass_sz,
6310Sstevel@tonic-gate 	    pub_id, pub_sz, attr_list);
6320Sstevel@tonic-gate 	free(pub_id);
6330Sstevel@tonic-gate 	if (ev == NULL) {
6340Sstevel@tonic-gate 		errno = ENOMEM;
6350Sstevel@tonic-gate 		return (NULL);
6360Sstevel@tonic-gate 	}
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	return (ev);
6390Sstevel@tonic-gate }
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate /*
6420Sstevel@tonic-gate  * se_unpack - unpack nvlist to a searchable list.
6430Sstevel@tonic-gate  *	If already unpacked, will do a dup.
6440Sstevel@tonic-gate  */
6450Sstevel@tonic-gate static sysevent_t *
se_unpack(sysevent_t * ev)6460Sstevel@tonic-gate se_unpack(sysevent_t *ev)
6470Sstevel@tonic-gate {
6480Sstevel@tonic-gate 	caddr_t attr;
6490Sstevel@tonic-gate 	size_t attr_len;
6500Sstevel@tonic-gate 	nvlist_t *attrp = NULL;
6510Sstevel@tonic-gate 	uint64_t attr_offset;
6520Sstevel@tonic-gate 	sysevent_t *copy;
6530Sstevel@tonic-gate 
6540Sstevel@tonic-gate 	assert(SE_FLAG(ev) == SE_PACKED_BUF);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	/* Copy event header information */
6570Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
6580Sstevel@tonic-gate 	copy = calloc(1, attr_offset);
6590Sstevel@tonic-gate 	if (copy == NULL)
6600Sstevel@tonic-gate 		return (NULL);
6610Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
6620Sstevel@tonic-gate 	SE_FLAG(copy) = 0;	/* unpacked */
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* unpack nvlist */
6650Sstevel@tonic-gate 	attr = (caddr_t)ev + attr_offset;
6660Sstevel@tonic-gate 	attr_len = SE_SIZE(ev) - attr_offset;
6670Sstevel@tonic-gate 	if (attr_len == 0) {
6680Sstevel@tonic-gate 		return (copy);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 	if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) {
6710Sstevel@tonic-gate 		free(copy);
6720Sstevel@tonic-gate 		return (NULL);
6730Sstevel@tonic-gate 	}
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = (uintptr_t)attrp;
6760Sstevel@tonic-gate 	return (copy);
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate /*
6800Sstevel@tonic-gate  * se_print - Prints elements in an event buffer
6810Sstevel@tonic-gate  */
6820Sstevel@tonic-gate void
se_print(FILE * fp,sysevent_t * ev)6830Sstevel@tonic-gate se_print(FILE *fp, sysevent_t *ev)
6840Sstevel@tonic-gate {
6850Sstevel@tonic-gate 	char *vendor, *pub;
6860Sstevel@tonic-gate 	pid_t pid;
6870Sstevel@tonic-gate 	hrtime_t hrt;
6880Sstevel@tonic-gate 	nvlist_t *attr_list = NULL;
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 	(void) sysevent_get_time(ev, &hrt);
6910Sstevel@tonic-gate 	(void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n",
69211102SGavin.Maltby@Sun.COM 	    hrt, (longlong_t)sysevent_get_seq(ev));
6930Sstevel@tonic-gate 	(void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev));
6940Sstevel@tonic-gate 	(void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev));
6950Sstevel@tonic-gate 	if ((vendor =  sysevent_get_vendor_name(ev)) != NULL) {
6960Sstevel@tonic-gate 		(void) fprintf(fp, "\tvendor = %s\n", vendor);
6970Sstevel@tonic-gate 		free(vendor);
6980Sstevel@tonic-gate 	}
6990Sstevel@tonic-gate 	if ((pub = sysevent_get_pub_name(ev)) != NULL) {
7000Sstevel@tonic-gate 		sysevent_get_pid(ev, &pid);
7010Sstevel@tonic-gate 		(void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid);
7020Sstevel@tonic-gate 		free(pub);
7030Sstevel@tonic-gate 	}
7040Sstevel@tonic-gate 
7050Sstevel@tonic-gate 	if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) {
7060Sstevel@tonic-gate 		nvlist_print(fp, attr_list);
7070Sstevel@tonic-gate 		nvlist_free(attr_list);
7080Sstevel@tonic-gate 	}
7090Sstevel@tonic-gate }
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate  * The following routines are provided to support establishment and use
7130Sstevel@tonic-gate  * of sysevent channels.  A sysevent channel is established between
7140Sstevel@tonic-gate  * publishers and subscribers of sysevents for an agreed upon channel name.
7150Sstevel@tonic-gate  * These routines currently support sysevent channels between user-level
7160Sstevel@tonic-gate  * applications running on the same system.
7170Sstevel@tonic-gate  *
7180Sstevel@tonic-gate  * Sysevent channels may be created by a single publisher or subscriber process.
7190Sstevel@tonic-gate  * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in
7200Sstevel@tonic-gate  * receiving sysevent notifications on the named channel.  At present, only
7210Sstevel@tonic-gate  * one publisher is allowed per sysevent channel.
7220Sstevel@tonic-gate  *
7230Sstevel@tonic-gate  * The registration information for each channel is kept in the kernel.  A
7240Sstevel@tonic-gate  * kernel-based registration was chosen for persistence and reliability reasons.
7250Sstevel@tonic-gate  * If either a publisher or a subscriber exits for any reason, the channel
7260Sstevel@tonic-gate  * properties are maintained until all publishers and subscribers have exited.
7270Sstevel@tonic-gate  * Additionally, an in-kernel registration allows the API to be extended to
7280Sstevel@tonic-gate  * include kernel subscribers as well as userland subscribers in the future.
7290Sstevel@tonic-gate  *
7300Sstevel@tonic-gate  * To insure fast lookup of subscriptions, a cached copy of the registration
7310Sstevel@tonic-gate  * is kept and maintained for the publisher process.  Updates are made
7320Sstevel@tonic-gate  * everytime a change is made in the kernel.  Changes to the registration are
7330Sstevel@tonic-gate  * expected to be infrequent.
7340Sstevel@tonic-gate  *
7350Sstevel@tonic-gate  * Channel communication between publisher and subscriber processes is
7360Sstevel@tonic-gate  * implemented primarily via doors.  Each publisher creates a door for
7370Sstevel@tonic-gate  * registration notifications and each subscriber creates a door for event
7380Sstevel@tonic-gate  * delivery.
7390Sstevel@tonic-gate  *
7400Sstevel@tonic-gate  * Most of these routines are used by syseventd(1M), the sysevent publisher
7410Sstevel@tonic-gate  * for the syseventd channel.  Processes wishing to receive sysevent
7420Sstevel@tonic-gate  * notifications from syseventd may use a set of public
7430Sstevel@tonic-gate  * APIs designed to subscribe to syseventd sysevents.  The subscription
7440Sstevel@tonic-gate  * APIs are implemented in accordance with PSARC/2001/076.
7450Sstevel@tonic-gate  *
7460Sstevel@tonic-gate  */
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate /*
7490Sstevel@tonic-gate  * Door handlers for the channel subscribers
7500Sstevel@tonic-gate  */
7510Sstevel@tonic-gate 
7520Sstevel@tonic-gate /*
7530Sstevel@tonic-gate  * subscriber_event_handler - generic event handling wrapper for subscribers
7540Sstevel@tonic-gate  *			This handler is used to process incoming sysevent
7550Sstevel@tonic-gate  *			notifications from channel publishers.
7560Sstevel@tonic-gate  *			It is created as a seperate thread in each subscriber
7570Sstevel@tonic-gate  *			process per subscription.
7580Sstevel@tonic-gate  */
7590Sstevel@tonic-gate static void
subscriber_event_handler(sysevent_handle_t * shp)7600Sstevel@tonic-gate subscriber_event_handler(sysevent_handle_t *shp)
7610Sstevel@tonic-gate {
7620Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
7630Sstevel@tonic-gate 	sysevent_queue_t *evqp;
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
7660Sstevel@tonic-gate 
767*12967Sgavin.maltby@oracle.com 	/* See hack alert in sysevent_bind_subscriber_cmn */
768*12967Sgavin.maltby@oracle.com 	if (sub_info->sp_handler_tid == NULL)
769*12967Sgavin.maltby@oracle.com 		sub_info->sp_handler_tid = thr_self();
770*12967Sgavin.maltby@oracle.com 
7710Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
7720Sstevel@tonic-gate 	for (;;) {
7730Sstevel@tonic-gate 		while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) {
7740Sstevel@tonic-gate 			(void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock);
7750Sstevel@tonic-gate 		}
7760Sstevel@tonic-gate 		evqp = sub_info->sp_evq_head;
7770Sstevel@tonic-gate 		while (evqp) {
7780Sstevel@tonic-gate 			(void) mutex_unlock(&sub_info->sp_qlock);
7790Sstevel@tonic-gate 			(void) sub_info->sp_func(evqp->sq_ev);
7800Sstevel@tonic-gate 			(void) mutex_lock(&sub_info->sp_qlock);
7810Sstevel@tonic-gate 			sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next;
7820Sstevel@tonic-gate 			free(evqp->sq_ev);
7830Sstevel@tonic-gate 			free(evqp);
7840Sstevel@tonic-gate 			evqp = sub_info->sp_evq_head;
7850Sstevel@tonic-gate 		}
7860Sstevel@tonic-gate 		if (!SH_BOUND(shp)) {
7870Sstevel@tonic-gate 			(void) mutex_unlock(&sub_info->sp_qlock);
7880Sstevel@tonic-gate 			return;
7890Sstevel@tonic-gate 		}
7900Sstevel@tonic-gate 	}
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	/* NOTREACHED */
7930Sstevel@tonic-gate }
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate /*
7960Sstevel@tonic-gate  * Data structure used to communicate event subscription cache updates
7970Sstevel@tonic-gate  * to publishers via a registration door
7980Sstevel@tonic-gate  */
7990Sstevel@tonic-gate struct reg_args {
8000Sstevel@tonic-gate 	uint32_t ra_sub_id;
8010Sstevel@tonic-gate 	uint32_t ra_op;
8020Sstevel@tonic-gate 	uint64_t ra_buf_ptr;
8030Sstevel@tonic-gate };
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate /*
8070Sstevel@tonic-gate  * event_deliver_service - generic event delivery service routine.  This routine
8080Sstevel@tonic-gate  *		is called in response to a door call to post an event.
8090Sstevel@tonic-gate  *
8100Sstevel@tonic-gate  */
81111102SGavin.Maltby@Sun.COM /*ARGSUSED*/
8120Sstevel@tonic-gate static void
event_deliver_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)8130Sstevel@tonic-gate event_deliver_service(void *cookie, char *args, size_t alen,
8140Sstevel@tonic-gate     door_desc_t *ddp, uint_t ndid)
8150Sstevel@tonic-gate {
8160Sstevel@tonic-gate 	int	ret = 0;
8170Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
8180Sstevel@tonic-gate 	sysevent_handle_t *shp;
8190Sstevel@tonic-gate 	sysevent_queue_t *new_eq;
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate 	if (args == NULL || alen < sizeof (uint32_t)) {
8220Sstevel@tonic-gate 		ret = EINVAL;
8230Sstevel@tonic-gate 		goto return_from_door;
8240Sstevel@tonic-gate 	}
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	/* Publisher checking on subscriber */
8270Sstevel@tonic-gate 	if (alen == sizeof (uint32_t)) {
8280Sstevel@tonic-gate 		ret = 0;
8290Sstevel@tonic-gate 		goto return_from_door;
8300Sstevel@tonic-gate 	}
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	shp = (sysevent_handle_t *)cookie;
8330Sstevel@tonic-gate 	if (shp == NULL) {
8340Sstevel@tonic-gate 		ret = EBADF;
8350Sstevel@tonic-gate 		goto return_from_door;
8360Sstevel@tonic-gate 	}
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	/*
8390Sstevel@tonic-gate 	 * Mustn't block if we are trying to update the registration with
8400Sstevel@tonic-gate 	 * the publisher
8410Sstevel@tonic-gate 	 */
8420Sstevel@tonic-gate 	if (mutex_trylock(SH_LOCK(shp)) != 0) {
8430Sstevel@tonic-gate 		ret = EAGAIN;
8440Sstevel@tonic-gate 		goto return_from_door;
8450Sstevel@tonic-gate 	}
8460Sstevel@tonic-gate 
8470Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
8480Sstevel@tonic-gate 		ret = EBADF;
8490Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8500Sstevel@tonic-gate 		goto return_from_door;
8510Sstevel@tonic-gate 	}
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
8540Sstevel@tonic-gate 	if (sub_info == NULL) {
8550Sstevel@tonic-gate 		ret = EBADF;
8560Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8570Sstevel@tonic-gate 		goto return_from_door;
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	new_eq = (sysevent_queue_t *)calloc(1,
8610Sstevel@tonic-gate 	    sizeof (sysevent_queue_t));
8620Sstevel@tonic-gate 	if (new_eq == NULL) {
8630Sstevel@tonic-gate 		ret = EAGAIN;
8640Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8650Sstevel@tonic-gate 		goto return_from_door;
8660Sstevel@tonic-gate 	}
8670Sstevel@tonic-gate 
8680Sstevel@tonic-gate 	/*
8690Sstevel@tonic-gate 	 * Allocate and copy the event buffer into the subscriber's
8700Sstevel@tonic-gate 	 * address space
8710Sstevel@tonic-gate 	 */
8720Sstevel@tonic-gate 	new_eq->sq_ev = calloc(1, alen);
8730Sstevel@tonic-gate 	if (new_eq->sq_ev == NULL) {
8740Sstevel@tonic-gate 		free(new_eq);
8750Sstevel@tonic-gate 		ret = EAGAIN;
8760Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
8770Sstevel@tonic-gate 		goto return_from_door;
8780Sstevel@tonic-gate 	}
8790Sstevel@tonic-gate 	(void) bcopy(args, new_eq->sq_ev, alen);
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
8820Sstevel@tonic-gate 	if (sub_info->sp_evq_head == NULL) {
8830Sstevel@tonic-gate 		sub_info->sp_evq_head = new_eq;
8840Sstevel@tonic-gate 	} else {
8850Sstevel@tonic-gate 		sub_info->sp_evq_tail->sq_next = new_eq;
8860Sstevel@tonic-gate 	}
8870Sstevel@tonic-gate 	sub_info->sp_evq_tail = new_eq;
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	(void) cond_signal(&sub_info->sp_cv);
8900Sstevel@tonic-gate 	(void) mutex_unlock(&sub_info->sp_qlock);
8910Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
8920Sstevel@tonic-gate 
8930Sstevel@tonic-gate return_from_door:
8940Sstevel@tonic-gate 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
8950Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate  * Sysevent subscription information is maintained in the kernel.  Updates
9000Sstevel@tonic-gate  * to the in-kernel registration database is expected to be infrequent and
9010Sstevel@tonic-gate  * offers consistency for publishers and subscribers that may come and go
9020Sstevel@tonic-gate  * for a given channel.
9030Sstevel@tonic-gate  *
9040Sstevel@tonic-gate  * To expedite registration lookups by publishers, a cached copy of the
9050Sstevel@tonic-gate  * kernel registration database is kept per-channel.  Caches are invalidated
9060Sstevel@tonic-gate  * and refreshed upon state changes to the in-kernel registration database.
9070Sstevel@tonic-gate  *
9080Sstevel@tonic-gate  * To prevent stale subscriber data, publishers may remove subsriber
9090Sstevel@tonic-gate  * registrations from the in-kernel registration database in the event
9100Sstevel@tonic-gate  * that a particular subscribing process is unresponsive.
9110Sstevel@tonic-gate  *
9120Sstevel@tonic-gate  * The following routines provide a mechanism to update publisher and subscriber
9130Sstevel@tonic-gate  * information for a specified channel.
9140Sstevel@tonic-gate  */
9150Sstevel@tonic-gate 
9160Sstevel@tonic-gate /*
9170Sstevel@tonic-gate  * clnt_deliver_event - Deliver an event through the consumer's event
9180Sstevel@tonic-gate  *			delivery door
9190Sstevel@tonic-gate  *
9200Sstevel@tonic-gate  * Returns -1 if message not delivered. With errno set to cause of error.
9210Sstevel@tonic-gate  * Returns 0 for success with the results returned in posting buffer.
9220Sstevel@tonic-gate  */
9230Sstevel@tonic-gate static int
clnt_deliver_event(int service_door,void * data,size_t datalen,void * result,size_t rlen)9240Sstevel@tonic-gate clnt_deliver_event(int service_door, void *data, size_t datalen,
9250Sstevel@tonic-gate 	void *result, size_t rlen)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate 	int error = 0;
9280Sstevel@tonic-gate 	door_arg_t door_arg;
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 	door_arg.rbuf = result;
9310Sstevel@tonic-gate 	door_arg.rsize = rlen;
9320Sstevel@tonic-gate 	door_arg.data_ptr = data;
9330Sstevel@tonic-gate 	door_arg.data_size = datalen;
9340Sstevel@tonic-gate 	door_arg.desc_ptr = NULL;
9350Sstevel@tonic-gate 	door_arg.desc_num = 0;
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate 	/*
9380Sstevel@tonic-gate 	 * Make door call
9390Sstevel@tonic-gate 	 */
9400Sstevel@tonic-gate 	while ((error = door_call(service_door, &door_arg)) != 0) {
9410Sstevel@tonic-gate 		if (errno == EAGAIN || errno == EINTR) {
9420Sstevel@tonic-gate 			continue;
9430Sstevel@tonic-gate 		} else {
9440Sstevel@tonic-gate 			error = errno;
9450Sstevel@tonic-gate 			break;
9460Sstevel@tonic-gate 		}
9470Sstevel@tonic-gate 	}
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate 	return (error);
9500Sstevel@tonic-gate }
9510Sstevel@tonic-gate 
9520Sstevel@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)9530Sstevel@tonic-gate update_publisher_cache(subscriber_priv_t *sub_info, int update_op,
9540Sstevel@tonic-gate 	uint32_t sub_id, size_t datasz, uchar_t *data)
9550Sstevel@tonic-gate {
9560Sstevel@tonic-gate 	int pub_fd;
9570Sstevel@tonic-gate 	uint32_t result = 0;
9580Sstevel@tonic-gate 	struct reg_args *rargs;
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate 	rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) +
9610Sstevel@tonic-gate 	    datasz);
9620Sstevel@tonic-gate 	if (rargs == NULL) {
9630Sstevel@tonic-gate 		errno = ENOMEM;
9640Sstevel@tonic-gate 		return (-1);
9650Sstevel@tonic-gate 	}
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	rargs->ra_sub_id = sub_id;
9680Sstevel@tonic-gate 	rargs->ra_op = update_op;
9690Sstevel@tonic-gate 	bcopy(data, (char *)&rargs->ra_buf_ptr, datasz);
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 	pub_fd = open(sub_info->sp_door_name, O_RDONLY);
9720Sstevel@tonic-gate 	(void) clnt_deliver_event(pub_fd, (void *)rargs,
9730Sstevel@tonic-gate 	    sizeof (struct reg_args) + datasz, &result, sizeof (result));
9740Sstevel@tonic-gate 	(void) close(pub_fd);
9750Sstevel@tonic-gate 
9760Sstevel@tonic-gate 	free(rargs);
9770Sstevel@tonic-gate 	if (result != 0) {
9780Sstevel@tonic-gate 		errno = result;
9790Sstevel@tonic-gate 		return (-1);
9800Sstevel@tonic-gate 	}
9810Sstevel@tonic-gate 
9820Sstevel@tonic-gate 	return (0);
9830Sstevel@tonic-gate }
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate 
9860Sstevel@tonic-gate /*
9870Sstevel@tonic-gate  * update_kernel_registration - update the in-kernel registration for the
9880Sstevel@tonic-gate  * given channel.
9890Sstevel@tonic-gate  */
9900Sstevel@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)9910Sstevel@tonic-gate update_kernel_registration(sysevent_handle_t *shp, int update_type,
9920Sstevel@tonic-gate 	int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data)
9930Sstevel@tonic-gate {
9940Sstevel@tonic-gate 	int error;
9950Sstevel@tonic-gate 	char *channel_name = SH_CHANNEL_NAME(shp);
9960Sstevel@tonic-gate 	se_pubsub_t udata;
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	udata.ps_channel_name_len = strlen(channel_name) + 1;
9990Sstevel@tonic-gate 	udata.ps_op = update_op;
10000Sstevel@tonic-gate 	udata.ps_type = update_type;
10010Sstevel@tonic-gate 	udata.ps_buflen = datasz;
10020Sstevel@tonic-gate 	udata.ps_id = *sub_id;
10030Sstevel@tonic-gate 
10040Sstevel@tonic-gate 	if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
10050Sstevel@tonic-gate 	    (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0))
10060Sstevel@tonic-gate 	    != 0) {
10070Sstevel@tonic-gate 		return (error);
10080Sstevel@tonic-gate 	}
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate 	*sub_id = udata.ps_id;
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate 	return (error);
10130Sstevel@tonic-gate }
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate /*
10160Sstevel@tonic-gate  * get_kernel_registration - get the current subscriber registration for
10170Sstevel@tonic-gate  * the given channel
10180Sstevel@tonic-gate  */
10190Sstevel@tonic-gate static nvlist_t *
get_kernel_registration(char * channel_name,uint32_t class_id)10200Sstevel@tonic-gate get_kernel_registration(char *channel_name, uint32_t class_id)
10210Sstevel@tonic-gate {
10220Sstevel@tonic-gate 	char *nvlbuf;
10230Sstevel@tonic-gate 	nvlist_t *nvl;
10240Sstevel@tonic-gate 	se_pubsub_t udata;
10250Sstevel@tonic-gate 
10260Sstevel@tonic-gate 	nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ);
10270Sstevel@tonic-gate 	if (nvlbuf == NULL) {
10280Sstevel@tonic-gate 		return (NULL);
10290Sstevel@tonic-gate 	}
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	udata.ps_buflen = MAX_SUBSCRIPTION_SZ;
10320Sstevel@tonic-gate 	udata.ps_channel_name_len = strlen(channel_name) + 1;
10330Sstevel@tonic-gate 	udata.ps_id = class_id;
10340Sstevel@tonic-gate 	udata.ps_op = SE_GET_REGISTRATION;
10350Sstevel@tonic-gate 	udata.ps_type = PUBLISHER;
10360Sstevel@tonic-gate 
10370Sstevel@tonic-gate 	if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
10380Sstevel@tonic-gate 	    (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0)
10390Sstevel@tonic-gate 	    != 0) {
10400Sstevel@tonic-gate 
10410Sstevel@tonic-gate 		/* Need a bigger buffer to hold channel registration */
10420Sstevel@tonic-gate 		if (errno == EAGAIN) {
10430Sstevel@tonic-gate 			free(nvlbuf);
10440Sstevel@tonic-gate 			nvlbuf = calloc(1, udata.ps_buflen);
10450Sstevel@tonic-gate 			if (nvlbuf == NULL)
10460Sstevel@tonic-gate 				return (NULL);
10470Sstevel@tonic-gate 
10480Sstevel@tonic-gate 			/* Try again */
10490Sstevel@tonic-gate 			if (modctl(MODEVENTS,
10500Sstevel@tonic-gate 			    (uintptr_t)MODEVENTS_REGISTER_EVENT,
10510Sstevel@tonic-gate 			    (uintptr_t)channel_name, (uintptr_t)nvlbuf,
10520Sstevel@tonic-gate 			    (uintptr_t)&udata, 0) != 0) {
10530Sstevel@tonic-gate 				free(nvlbuf);
10540Sstevel@tonic-gate 				return (NULL);
10550Sstevel@tonic-gate 			}
10560Sstevel@tonic-gate 		} else {
10570Sstevel@tonic-gate 			free(nvlbuf);
10580Sstevel@tonic-gate 			return (NULL);
10590Sstevel@tonic-gate 		}
10600Sstevel@tonic-gate 	}
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) {
10630Sstevel@tonic-gate 		free(nvlbuf);
10640Sstevel@tonic-gate 		return (NULL);
10650Sstevel@tonic-gate 	}
10660Sstevel@tonic-gate 	free(nvlbuf);
10670Sstevel@tonic-gate 
10680Sstevel@tonic-gate 	return (nvl);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate 
10710Sstevel@tonic-gate /*
10720Sstevel@tonic-gate  * The following routines provide a mechanism for publishers to maintain
10730Sstevel@tonic-gate  * subscriber information.
10740Sstevel@tonic-gate  */
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate static void
dealloc_subscribers(sysevent_handle_t * shp)10770Sstevel@tonic-gate dealloc_subscribers(sysevent_handle_t *shp)
10780Sstevel@tonic-gate {
10790Sstevel@tonic-gate 	int i;
10800Sstevel@tonic-gate 	subscriber_data_t *sub;
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
10830Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
10840Sstevel@tonic-gate 		if (sub != NULL) {
10850Sstevel@tonic-gate 			free(sub->sd_door_name);
10860Sstevel@tonic-gate 			free(sub);
10870Sstevel@tonic-gate 		}
10880Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, i) = NULL;
10890Sstevel@tonic-gate 	}
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
109211102SGavin.Maltby@Sun.COM /*ARGSUSED*/
10930Sstevel@tonic-gate static int
alloc_subscriber(sysevent_handle_t * shp,uint32_t sub_id,int oflag)10940Sstevel@tonic-gate alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag)
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate 	subscriber_data_t *sub;
10970Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 	if (SH_SUBSCRIBER(shp, sub_id) != NULL) {
11000Sstevel@tonic-gate 		return (0);
11010Sstevel@tonic-gate 	}
11020Sstevel@tonic-gate 
11030Sstevel@tonic-gate 	/* Allocate and initialize the subscriber data */
11040Sstevel@tonic-gate 	sub = (subscriber_data_t *)calloc(1,
11050Sstevel@tonic-gate 	    sizeof (subscriber_data_t));
11060Sstevel@tonic-gate 	if (sub == NULL) {
11070Sstevel@tonic-gate 		return (-1);
11080Sstevel@tonic-gate 	}
11090Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
11100Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
11110Sstevel@tonic-gate 		free(sub);
11120Sstevel@tonic-gate 		return (-1);
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	sub->sd_flag = ACTIVE;
11160Sstevel@tonic-gate 	sub->sd_door_name = strdup(door_name);
11170Sstevel@tonic-gate 	if (sub->sd_door_name == NULL) {
11180Sstevel@tonic-gate 		free(sub);
11190Sstevel@tonic-gate 		return (-1);
11200Sstevel@tonic-gate 	}
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	SH_SUBSCRIBER(shp, sub_id) = sub;
11230Sstevel@tonic-gate 	return (0);
11240Sstevel@tonic-gate 
11250Sstevel@tonic-gate }
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate /*
11280Sstevel@tonic-gate  * The following routines are used to update and maintain the registration cache
11290Sstevel@tonic-gate  * for a particular sysevent channel.
11300Sstevel@tonic-gate  */
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate static uint32_t
hash_func(const char * s)11330Sstevel@tonic-gate hash_func(const char *s)
11340Sstevel@tonic-gate {
11350Sstevel@tonic-gate 	uint32_t result = 0;
11360Sstevel@tonic-gate 	uint_t g;
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate 	while (*s != '\0') {
11390Sstevel@tonic-gate 		result <<= 4;
11400Sstevel@tonic-gate 		result += (uint32_t)*s++;
11410Sstevel@tonic-gate 		g = result & 0xf0000000;
11420Sstevel@tonic-gate 		if (g != 0) {
11430Sstevel@tonic-gate 			result ^= g >> 24;
11440Sstevel@tonic-gate 			result ^= g;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 	}
11470Sstevel@tonic-gate 
11480Sstevel@tonic-gate 	return (result);
11490Sstevel@tonic-gate }
11500Sstevel@tonic-gate 
11510Sstevel@tonic-gate subclass_lst_t *
cache_find_subclass(class_lst_t * c_list,char * subclass)11520Sstevel@tonic-gate cache_find_subclass(class_lst_t *c_list, char *subclass)
11530Sstevel@tonic-gate {
11540Sstevel@tonic-gate 	subclass_lst_t *sc_list;
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	if (c_list == NULL)
11570Sstevel@tonic-gate 		return (NULL);
11580Sstevel@tonic-gate 
11590Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	while (sc_list != NULL) {
11620Sstevel@tonic-gate 		if (strcmp(sc_list->sl_name, subclass) == 0) {
11630Sstevel@tonic-gate 			return (sc_list);
11640Sstevel@tonic-gate 		}
11650Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
11660Sstevel@tonic-gate 	}
11670Sstevel@tonic-gate 
11680Sstevel@tonic-gate 	return (NULL);
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate 
11720Sstevel@tonic-gate static class_lst_t *
cache_find_class(sysevent_handle_t * shp,char * class)11730Sstevel@tonic-gate cache_find_class(sysevent_handle_t *shp, char *class)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate 	int index;
11760Sstevel@tonic-gate 	class_lst_t *c_list;
11770Sstevel@tonic-gate 	class_lst_t **class_hash = SH_CLASS_HASH(shp);
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
11800Sstevel@tonic-gate 		return (class_hash[0]);
11810Sstevel@tonic-gate 	}
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	index = CLASS_HASH(class);
11840Sstevel@tonic-gate 	c_list = class_hash[index];
11850Sstevel@tonic-gate 	while (c_list != NULL) {
11860Sstevel@tonic-gate 		if (strcmp(class, c_list->cl_name) == 0) {
11870Sstevel@tonic-gate 			break;
11880Sstevel@tonic-gate 		}
11890Sstevel@tonic-gate 		c_list = c_list->cl_next;
11900Sstevel@tonic-gate 	}
11910Sstevel@tonic-gate 
11920Sstevel@tonic-gate 	return (c_list);
11930Sstevel@tonic-gate }
11940Sstevel@tonic-gate 
11950Sstevel@tonic-gate static int
cache_insert_subclass(class_lst_t * c_list,char ** subclass_names,int subclass_num,uint32_t sub_id)11960Sstevel@tonic-gate cache_insert_subclass(class_lst_t *c_list, char **subclass_names,
11970Sstevel@tonic-gate 	int subclass_num, uint32_t sub_id)
11980Sstevel@tonic-gate {
11990Sstevel@tonic-gate 	int i;
12000Sstevel@tonic-gate 	subclass_lst_t *sc_list;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	for (i = 0; i < subclass_num; ++i) {
12030Sstevel@tonic-gate 		if ((sc_list = cache_find_subclass(c_list, subclass_names[i]))
12040Sstevel@tonic-gate 		    != NULL) {
12050Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
12060Sstevel@tonic-gate 		} else {
12070Sstevel@tonic-gate 			sc_list = (subclass_lst_t *)calloc(1,
12080Sstevel@tonic-gate 			    sizeof (subclass_lst_t));
12090Sstevel@tonic-gate 			if (sc_list == NULL)
12100Sstevel@tonic-gate 				return (-1);
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 			sc_list->sl_name = strdup(subclass_names[i]);
12130Sstevel@tonic-gate 			if (sc_list->sl_name == NULL) {
12140Sstevel@tonic-gate 				free(sc_list);
12150Sstevel@tonic-gate 				return (-1);
12160Sstevel@tonic-gate 			}
12170Sstevel@tonic-gate 
12180Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
12190Sstevel@tonic-gate 			sc_list->sl_next = c_list->cl_subclass_list;
12200Sstevel@tonic-gate 			c_list->cl_subclass_list = sc_list;
12210Sstevel@tonic-gate 		}
12220Sstevel@tonic-gate 	}
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate 	return (0);
12250Sstevel@tonic-gate }
12260Sstevel@tonic-gate 
12270Sstevel@tonic-gate static int
cache_insert_class(sysevent_handle_t * shp,char * class,char ** subclass_names,int subclass_num,uint32_t sub_id)12280Sstevel@tonic-gate cache_insert_class(sysevent_handle_t *shp, char *class,
12290Sstevel@tonic-gate 	char **subclass_names, int subclass_num, uint32_t sub_id)
12300Sstevel@tonic-gate {
12310Sstevel@tonic-gate 	class_lst_t *c_list;
12320Sstevel@tonic-gate 
12330Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
12340Sstevel@tonic-gate 		char *subclass_all = EC_SUB_ALL;
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 		(void) cache_insert_subclass(SH_CLASS_HASH(shp)[0],
12370Sstevel@tonic-gate 		    (char **)&subclass_all, 1, sub_id);
12380Sstevel@tonic-gate 		return (0);
12390Sstevel@tonic-gate 	}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 	/* New class, add to the registration cache */
12420Sstevel@tonic-gate 	if ((c_list = cache_find_class(shp, class)) == NULL) {
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 		c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t));
12450Sstevel@tonic-gate 		if (c_list == NULL) {
12460Sstevel@tonic-gate 			return (1);
12470Sstevel@tonic-gate 		}
12480Sstevel@tonic-gate 		c_list->cl_name = strdup(class);
12490Sstevel@tonic-gate 		if (c_list->cl_name == NULL) {
12500Sstevel@tonic-gate 			free(c_list);
12510Sstevel@tonic-gate 			return (1);
12520Sstevel@tonic-gate 		}
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		c_list->cl_subclass_list = (subclass_lst_t *)
12550Sstevel@tonic-gate 		    calloc(1, sizeof (subclass_lst_t));
12560Sstevel@tonic-gate 		if (c_list->cl_subclass_list == NULL) {
12570Sstevel@tonic-gate 			free(c_list->cl_name);
12580Sstevel@tonic-gate 			free(c_list);
12590Sstevel@tonic-gate 			return (1);
12600Sstevel@tonic-gate 		}
12610Sstevel@tonic-gate 		c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL);
12620Sstevel@tonic-gate 		if (c_list->cl_subclass_list->sl_name == NULL) {
12630Sstevel@tonic-gate 			free(c_list->cl_subclass_list);
12640Sstevel@tonic-gate 			free(c_list->cl_name);
12650Sstevel@tonic-gate 			free(c_list);
12660Sstevel@tonic-gate 			return (1);
12670Sstevel@tonic-gate 		}
12680Sstevel@tonic-gate 		c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)];
12690Sstevel@tonic-gate 		SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list;
12700Sstevel@tonic-gate 
12710Sstevel@tonic-gate 	}
12720Sstevel@tonic-gate 
12730Sstevel@tonic-gate 	/* Update the subclass list */
12740Sstevel@tonic-gate 	if (cache_insert_subclass(c_list, subclass_names, subclass_num,
12750Sstevel@tonic-gate 	    sub_id) != 0)
12760Sstevel@tonic-gate 		return (1);
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate 	return (0);
12790Sstevel@tonic-gate }
12800Sstevel@tonic-gate 
12810Sstevel@tonic-gate static void
cache_remove_all_class(sysevent_handle_t * shp,uint32_t sub_id)12820Sstevel@tonic-gate cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id)
12830Sstevel@tonic-gate {
12840Sstevel@tonic-gate 	int i;
12850Sstevel@tonic-gate 	class_lst_t *c_list;
12860Sstevel@tonic-gate 	subclass_lst_t *sc_list;
12870Sstevel@tonic-gate 
12880Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
12890Sstevel@tonic-gate 		c_list = SH_CLASS_HASH(shp)[i];
12900Sstevel@tonic-gate 		while (c_list != NULL) {
12910Sstevel@tonic-gate 			sc_list = c_list->cl_subclass_list;
12920Sstevel@tonic-gate 			while (sc_list != NULL) {
12930Sstevel@tonic-gate 				sc_list->sl_num[sub_id] = 0;
12940Sstevel@tonic-gate 				sc_list = sc_list->sl_next;
12950Sstevel@tonic-gate 			}
12960Sstevel@tonic-gate 			c_list = c_list->cl_next;
12970Sstevel@tonic-gate 		}
12980Sstevel@tonic-gate 	}
12990Sstevel@tonic-gate }
13000Sstevel@tonic-gate 
13010Sstevel@tonic-gate static void
cache_remove_class(sysevent_handle_t * shp,char * class,uint32_t sub_id)13020Sstevel@tonic-gate cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id)
13030Sstevel@tonic-gate {
13040Sstevel@tonic-gate 	class_lst_t *c_list;
13050Sstevel@tonic-gate 	subclass_lst_t *sc_list;
13060Sstevel@tonic-gate 
13070Sstevel@tonic-gate 	if (strcmp(class, EC_ALL) == 0) {
13080Sstevel@tonic-gate 		cache_remove_all_class(shp, sub_id);
13090Sstevel@tonic-gate 		return;
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	if ((c_list = cache_find_class(shp, class)) == NULL) {
13130Sstevel@tonic-gate 		return;
13140Sstevel@tonic-gate 	}
13150Sstevel@tonic-gate 
13160Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
13170Sstevel@tonic-gate 	while (sc_list != NULL) {
13180Sstevel@tonic-gate 		sc_list->sl_num[sub_id] = 0;
13190Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
13200Sstevel@tonic-gate 	}
13210Sstevel@tonic-gate }
13220Sstevel@tonic-gate 
13230Sstevel@tonic-gate static void
free_cached_registration(sysevent_handle_t * shp)13240Sstevel@tonic-gate free_cached_registration(sysevent_handle_t *shp)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	int i;
13270Sstevel@tonic-gate 	class_lst_t *clist, *next_clist;
13280Sstevel@tonic-gate 	subclass_lst_t *sc_list, *next_sc;
13290Sstevel@tonic-gate 
13300Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; i++) {
13310Sstevel@tonic-gate 		clist = SH_CLASS_HASH(shp)[i];
13320Sstevel@tonic-gate 		while (clist != NULL) {
13330Sstevel@tonic-gate 			sc_list = clist->cl_subclass_list;
13340Sstevel@tonic-gate 			while (sc_list != NULL) {
13350Sstevel@tonic-gate 				free(sc_list->sl_name);
13360Sstevel@tonic-gate 				next_sc = sc_list->sl_next;
13370Sstevel@tonic-gate 				free(sc_list);
13380Sstevel@tonic-gate 				sc_list = next_sc;
13390Sstevel@tonic-gate 			}
13400Sstevel@tonic-gate 			free(clist->cl_name);
13410Sstevel@tonic-gate 			next_clist = clist->cl_next;
13420Sstevel@tonic-gate 			free(clist);
13430Sstevel@tonic-gate 			clist = next_clist;
13440Sstevel@tonic-gate 		}
13450Sstevel@tonic-gate 		SH_CLASS_HASH(shp)[i] = NULL;
13460Sstevel@tonic-gate 	}
13470Sstevel@tonic-gate }
13480Sstevel@tonic-gate 
13490Sstevel@tonic-gate static int
create_cached_registration(sysevent_handle_t * shp,class_lst_t ** class_hash)13500Sstevel@tonic-gate create_cached_registration(sysevent_handle_t *shp,
13510Sstevel@tonic-gate 	class_lst_t **class_hash)
13520Sstevel@tonic-gate {
13530Sstevel@tonic-gate 	int i, j, new_class;
13540Sstevel@tonic-gate 	char *class_name;
13550Sstevel@tonic-gate 	uint_t num_elem;
13560Sstevel@tonic-gate 	uchar_t *subscribers;
13570Sstevel@tonic-gate 	nvlist_t *nvl;
13580Sstevel@tonic-gate 	nvpair_t *nvpair;
13590Sstevel@tonic-gate 	class_lst_t *clist;
13600Sstevel@tonic-gate 	subclass_lst_t *sc_list;
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
13630Sstevel@tonic-gate 
13640Sstevel@tonic-gate 		if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i))
13650Sstevel@tonic-gate 		    == NULL) {
13660Sstevel@tonic-gate 			if (errno == ENOENT) {
13670Sstevel@tonic-gate 				class_hash[i] = NULL;
13680Sstevel@tonic-gate 				continue;
13690Sstevel@tonic-gate 			} else {
13700Sstevel@tonic-gate 				goto create_failed;
13710Sstevel@tonic-gate 			}
13720Sstevel@tonic-gate 		}
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate 
13750Sstevel@tonic-gate 		nvpair = NULL;
13760Sstevel@tonic-gate 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
13770Sstevel@tonic-gate 			goto create_failed;
13780Sstevel@tonic-gate 		}
13790Sstevel@tonic-gate 
13800Sstevel@tonic-gate 		new_class = 1;
13810Sstevel@tonic-gate 		while (new_class) {
13820Sstevel@tonic-gate 			/* Extract the class name from the nvpair */
13830Sstevel@tonic-gate 			if (nvpair_value_string(nvpair, &class_name) != 0) {
13840Sstevel@tonic-gate 				goto create_failed;
13850Sstevel@tonic-gate 			}
13860Sstevel@tonic-gate 			clist = (class_lst_t *)
13870Sstevel@tonic-gate 			    calloc(1, sizeof (class_lst_t));
13880Sstevel@tonic-gate 			if (clist == NULL) {
13890Sstevel@tonic-gate 				goto create_failed;
13900Sstevel@tonic-gate 			}
13910Sstevel@tonic-gate 
13920Sstevel@tonic-gate 			clist->cl_name = strdup(class_name);
13930Sstevel@tonic-gate 			if (clist->cl_name == NULL) {
13940Sstevel@tonic-gate 				free(clist);
13950Sstevel@tonic-gate 				goto create_failed;
13960Sstevel@tonic-gate 			}
13970Sstevel@tonic-gate 
13980Sstevel@tonic-gate 			/*
13990Sstevel@tonic-gate 			 * Extract the subclass name and registration
14000Sstevel@tonic-gate 			 * from the nvpair
14010Sstevel@tonic-gate 			 */
14020Sstevel@tonic-gate 			if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
14030Sstevel@tonic-gate 			    == NULL) {
14040Sstevel@tonic-gate 				free(clist->cl_name);
14050Sstevel@tonic-gate 				free(clist);
14060Sstevel@tonic-gate 				goto create_failed;
14070Sstevel@tonic-gate 			}
14080Sstevel@tonic-gate 
14090Sstevel@tonic-gate 			clist->cl_next = class_hash[i];
14100Sstevel@tonic-gate 			class_hash[i] = clist;
14110Sstevel@tonic-gate 
14120Sstevel@tonic-gate 			for (;;) {
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 				sc_list = (subclass_lst_t *)calloc(1,
14150Sstevel@tonic-gate 				    sizeof (subclass_lst_t));
14160Sstevel@tonic-gate 				if (sc_list == NULL) {
14170Sstevel@tonic-gate 					goto create_failed;
14180Sstevel@tonic-gate 				}
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 				sc_list->sl_next = clist->cl_subclass_list;
14210Sstevel@tonic-gate 				clist->cl_subclass_list = sc_list;
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate 				sc_list->sl_name = strdup(nvpair_name(nvpair));
14240Sstevel@tonic-gate 				if (sc_list->sl_name == NULL) {
14250Sstevel@tonic-gate 					goto create_failed;
14260Sstevel@tonic-gate 				}
14270Sstevel@tonic-gate 
14280Sstevel@tonic-gate 				if (nvpair_value_byte_array(nvpair,
14290Sstevel@tonic-gate 				    &subscribers, &num_elem) != 0) {
14300Sstevel@tonic-gate 					goto create_failed;
14310Sstevel@tonic-gate 				}
14320Sstevel@tonic-gate 				bcopy(subscribers, (uchar_t *)sc_list->sl_num,
14330Sstevel@tonic-gate 				    MAX_SUBSCRIBERS + 1);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 				for (j = 1; j <= MAX_SUBSCRIBERS; ++j) {
14360Sstevel@tonic-gate 					if (sc_list->sl_num[j] == 0)
14370Sstevel@tonic-gate 						continue;
14380Sstevel@tonic-gate 
14390Sstevel@tonic-gate 					if (alloc_subscriber(shp, j, 1) != 0) {
14400Sstevel@tonic-gate 						goto create_failed;
14410Sstevel@tonic-gate 					}
14420Sstevel@tonic-gate 				}
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 				/*
14450Sstevel@tonic-gate 				 * Check next nvpair - either subclass or
14460Sstevel@tonic-gate 				 * class
14470Sstevel@tonic-gate 				 */
14480Sstevel@tonic-gate 				if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
14490Sstevel@tonic-gate 				    == NULL) {
14500Sstevel@tonic-gate 					new_class = 0;
14510Sstevel@tonic-gate 					break;
14520Sstevel@tonic-gate 				} else if (strcmp(nvpair_name(nvpair),
14530Sstevel@tonic-gate 				    CLASS_NAME) == 0) {
14540Sstevel@tonic-gate 					break;
14550Sstevel@tonic-gate 				}
14560Sstevel@tonic-gate 			}
14570Sstevel@tonic-gate 		}
14580Sstevel@tonic-gate 		nvlist_free(nvl);
14590Sstevel@tonic-gate 	}
14600Sstevel@tonic-gate 	return (0);
14610Sstevel@tonic-gate 
14620Sstevel@tonic-gate create_failed:
14630Sstevel@tonic-gate 	dealloc_subscribers(shp);
14640Sstevel@tonic-gate 	free_cached_registration(shp);
14650Sstevel@tonic-gate 	if (nvl)
14660Sstevel@tonic-gate 		nvlist_free(nvl);
14670Sstevel@tonic-gate 	return (-1);
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate }
14700Sstevel@tonic-gate 
14710Sstevel@tonic-gate /*
14720Sstevel@tonic-gate  * cache_update_service - generic event publisher service routine.  This routine
14730Sstevel@tonic-gate  *		is called in response to a registration cache update.
14740Sstevel@tonic-gate  *
14750Sstevel@tonic-gate  */
147611102SGavin.Maltby@Sun.COM /*ARGSUSED*/
14770Sstevel@tonic-gate static void
cache_update_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)14780Sstevel@tonic-gate cache_update_service(void *cookie, char *args, size_t alen,
14790Sstevel@tonic-gate     door_desc_t *ddp, uint_t ndid)
14800Sstevel@tonic-gate {
14810Sstevel@tonic-gate 	int ret = 0;
14820Sstevel@tonic-gate 	uint_t num_elem;
14830Sstevel@tonic-gate 	char *class, **event_list;
14840Sstevel@tonic-gate 	size_t datalen;
14850Sstevel@tonic-gate 	uint32_t sub_id;
14860Sstevel@tonic-gate 	nvlist_t *nvl;
14870Sstevel@tonic-gate 	nvpair_t *nvpair = NULL;
14880Sstevel@tonic-gate 	struct reg_args *rargs;
14890Sstevel@tonic-gate 	sysevent_handle_t *shp;
14900Sstevel@tonic-gate 	subscriber_data_t *sub;
14910Sstevel@tonic-gate 
14920Sstevel@tonic-gate 	if (alen < sizeof (struct reg_args) || cookie == NULL) {
14930Sstevel@tonic-gate 		ret = EINVAL;
14940Sstevel@tonic-gate 		goto return_from_door;
14950Sstevel@tonic-gate 	}
14960Sstevel@tonic-gate 
149711102SGavin.Maltby@Sun.COM 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
14980Sstevel@tonic-gate 	rargs = (struct reg_args *)args;
14990Sstevel@tonic-gate 	shp = (sysevent_handle_t *)cookie;
15000Sstevel@tonic-gate 
15010Sstevel@tonic-gate 	datalen = alen - sizeof (struct reg_args);
15020Sstevel@tonic-gate 	sub_id = rargs->ra_sub_id;
15030Sstevel@tonic-gate 
15040Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
15050Sstevel@tonic-gate 
15060Sstevel@tonic-gate 	switch (rargs->ra_op) {
15070Sstevel@tonic-gate 	case SE_UNREGISTER:
15080Sstevel@tonic-gate 		class = (char *)&rargs->ra_buf_ptr;
15090Sstevel@tonic-gate 		cache_remove_class(shp, (char *)class,
15100Sstevel@tonic-gate 		    sub_id);
15110Sstevel@tonic-gate 		break;
15120Sstevel@tonic-gate 	case SE_UNBIND_REGISTRATION:
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, sub_id);
15150Sstevel@tonic-gate 		if (sub == NULL)
15160Sstevel@tonic-gate 			break;
15170Sstevel@tonic-gate 
15180Sstevel@tonic-gate 		free(sub->sd_door_name);
15190Sstevel@tonic-gate 		free(sub);
15200Sstevel@tonic-gate 		cache_remove_class(shp, EC_ALL, sub_id);
15210Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, sub_id) = NULL;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 		break;
15240Sstevel@tonic-gate 	case SE_BIND_REGISTRATION:
15250Sstevel@tonic-gate 
15260Sstevel@tonic-gate 		/* New subscriber */
15270Sstevel@tonic-gate 		if (alloc_subscriber(shp, sub_id, 0) != 0) {
15280Sstevel@tonic-gate 			ret = ENOMEM;
15290Sstevel@tonic-gate 			break;
15300Sstevel@tonic-gate 		}
15310Sstevel@tonic-gate 		break;
15320Sstevel@tonic-gate 	case SE_REGISTER:
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 		if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
15350Sstevel@tonic-gate 			ret = EINVAL;
15360Sstevel@tonic-gate 			break;
15370Sstevel@tonic-gate 		}
15380Sstevel@tonic-gate 		/* Get new registration data */
15390Sstevel@tonic-gate 		if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
15400Sstevel@tonic-gate 		    &nvl, 0) != 0) {
15410Sstevel@tonic-gate 			ret =  EFAULT;
15420Sstevel@tonic-gate 			break;
15430Sstevel@tonic-gate 		}
15440Sstevel@tonic-gate 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
15450Sstevel@tonic-gate 			nvlist_free(nvl);
15460Sstevel@tonic-gate 			ret = EFAULT;
15470Sstevel@tonic-gate 			break;
15480Sstevel@tonic-gate 		}
15490Sstevel@tonic-gate 		if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
15500Sstevel@tonic-gate 		    != 0) {
15510Sstevel@tonic-gate 			nvlist_free(nvl);
15520Sstevel@tonic-gate 			ret =  EFAULT;
15530Sstevel@tonic-gate 			break;
15540Sstevel@tonic-gate 		}
15550Sstevel@tonic-gate 		class = nvpair_name(nvpair);
15560Sstevel@tonic-gate 
15570Sstevel@tonic-gate 		ret = cache_insert_class(shp, class,
15580Sstevel@tonic-gate 		    event_list, num_elem, sub_id);
15590Sstevel@tonic-gate 		if (ret != 0) {
15600Sstevel@tonic-gate 			cache_remove_class(shp, class, sub_id);
15610Sstevel@tonic-gate 			nvlist_free(nvl);
15620Sstevel@tonic-gate 			ret =  EFAULT;
15630Sstevel@tonic-gate 			break;
15640Sstevel@tonic-gate 		}
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 		nvlist_free(nvl);
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 		break;
15690Sstevel@tonic-gate 	case SE_CLEANUP:
15700Sstevel@tonic-gate 		/* Cleanup stale subscribers */
15710Sstevel@tonic-gate 		sysevent_cleanup_subscribers(shp);
15720Sstevel@tonic-gate 		break;
15730Sstevel@tonic-gate 	default:
15740Sstevel@tonic-gate 		ret =  EINVAL;
15750Sstevel@tonic-gate 	}
15760Sstevel@tonic-gate 
15770Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate return_from_door:
15800Sstevel@tonic-gate 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
15810Sstevel@tonic-gate 	(void) door_return(NULL, 0, NULL, 0);
15820Sstevel@tonic-gate }
15830Sstevel@tonic-gate 
15840Sstevel@tonic-gate /*
15850Sstevel@tonic-gate  * sysevent_send_event -
15860Sstevel@tonic-gate  * Send an event via the communication channel associated with the sysevent
15870Sstevel@tonic-gate  * handle.  Event notifications are broadcast to all subscribers based upon
15880Sstevel@tonic-gate  * the event class and subclass.  The handle must have been previously
15890Sstevel@tonic-gate  * allocated and bound by
15900Sstevel@tonic-gate  * sysevent_open_channel() and sysevent_bind_publisher()
15910Sstevel@tonic-gate  */
15920Sstevel@tonic-gate int
sysevent_send_event(sysevent_handle_t * shp,sysevent_t * ev)15930Sstevel@tonic-gate sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
15940Sstevel@tonic-gate {
15950Sstevel@tonic-gate 	int i, error, sub_fd, result = 0;
15960Sstevel@tonic-gate 	int deliver_error = 0;
15970Sstevel@tonic-gate 	int subscribers_sent = 0;
15980Sstevel@tonic-gate 	int want_resend, resend_cnt = 0;
15990Sstevel@tonic-gate 	char *event_class, *event_subclass;
16000Sstevel@tonic-gate 	uchar_t *all_class_subscribers, *all_subclass_subscribers;
16010Sstevel@tonic-gate 	uchar_t *subclass_subscribers;
16020Sstevel@tonic-gate 	subscriber_data_t *sub;
16030Sstevel@tonic-gate 	subclass_lst_t *sc_lst;
16040Sstevel@tonic-gate 
16050Sstevel@tonic-gate 	/* Check for proper registration */
16060Sstevel@tonic-gate 	event_class = sysevent_get_class_name(ev);
16070Sstevel@tonic-gate 	event_subclass = sysevent_get_subclass_name(ev);
16080Sstevel@tonic-gate 
16090Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate send_event:
16120Sstevel@tonic-gate 
16130Sstevel@tonic-gate 	want_resend = 0;
16140Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
16150Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
16160Sstevel@tonic-gate 		errno = EINVAL;
16170Sstevel@tonic-gate 		return (-1);
16180Sstevel@tonic-gate 	}
16190Sstevel@tonic-gate 
16200Sstevel@tonic-gate 	/* Find all subscribers for this event class/subclass */
16210Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16220Sstevel@tonic-gate 	    cache_find_class(shp, EC_ALL), EC_SUB_ALL);
16230Sstevel@tonic-gate 	all_class_subscribers = sc_lst->sl_num;
16240Sstevel@tonic-gate 
16250Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16260Sstevel@tonic-gate 	    cache_find_class(shp, event_class), EC_SUB_ALL);
16270Sstevel@tonic-gate 	if (sc_lst)
16280Sstevel@tonic-gate 		all_subclass_subscribers = sc_lst->sl_num;
16290Sstevel@tonic-gate 	else
16300Sstevel@tonic-gate 		all_subclass_subscribers = NULL;
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	sc_lst = cache_find_subclass(
16330Sstevel@tonic-gate 	    cache_find_class(shp, event_class), event_subclass);
16340Sstevel@tonic-gate 	if (sc_lst)
16350Sstevel@tonic-gate 		subclass_subscribers = sc_lst->sl_num;
16360Sstevel@tonic-gate 	else
16370Sstevel@tonic-gate 		subclass_subscribers = NULL;
16380Sstevel@tonic-gate 
16390Sstevel@tonic-gate 	/* Send event buffer to all valid subscribers */
16400Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
16410Sstevel@tonic-gate 		if ((all_class_subscribers[i] |
16420Sstevel@tonic-gate 		    (all_subclass_subscribers && all_subclass_subscribers[i]) |
16430Sstevel@tonic-gate 		    (subclass_subscribers && subclass_subscribers[i])) == 0)
16440Sstevel@tonic-gate 			continue;
16450Sstevel@tonic-gate 
16460Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
16470Sstevel@tonic-gate 		assert(sub != NULL);
16480Sstevel@tonic-gate 
16490Sstevel@tonic-gate 		/* Check for active subscriber */
16500Sstevel@tonic-gate 		if (!(sub->sd_flag & ACTIVE)) {
16510Sstevel@tonic-gate 			dprint("sysevent_send_event: subscriber %d inactive\n",
16520Sstevel@tonic-gate 			    i);
16530Sstevel@tonic-gate 			continue;
16540Sstevel@tonic-gate 		}
16550Sstevel@tonic-gate 
16560Sstevel@tonic-gate 		/* Process only resend requests */
16570Sstevel@tonic-gate 		if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
16580Sstevel@tonic-gate 			continue;
16590Sstevel@tonic-gate 		}
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
16620Sstevel@tonic-gate 			dprint("sysevent_send_event: Failed to open "
16630Sstevel@tonic-gate 			    "%s: %s\n", sub->sd_door_name, strerror(errno));
16640Sstevel@tonic-gate 			continue;
16650Sstevel@tonic-gate 		}
16660Sstevel@tonic-gate 		result = 0;
16670Sstevel@tonic-gate 		error = clnt_deliver_event(sub_fd, ev,
16680Sstevel@tonic-gate 		    sysevent_get_size(ev), &result, sizeof (result));
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 		(void) close(sub_fd);
16710Sstevel@tonic-gate 
16720Sstevel@tonic-gate 		/* Successful door call */
16730Sstevel@tonic-gate 		if (error == 0) {
16740Sstevel@tonic-gate 			switch (result) {
16750Sstevel@tonic-gate 			/* Subscriber requested EAGAIN */
16760Sstevel@tonic-gate 			case EAGAIN:
16770Sstevel@tonic-gate 				if (resend_cnt > SE_MAX_RETRY_LIMIT) {
16780Sstevel@tonic-gate 					deliver_error = 1;
16790Sstevel@tonic-gate 				} else {
16800Sstevel@tonic-gate 					want_resend = 1;
16810Sstevel@tonic-gate 					dprint("sysevent_send_event: resend "
16820Sstevel@tonic-gate 					    "requested for %d\n", i);
16830Sstevel@tonic-gate 					sub->sd_flag |= SEND_AGAIN;
16840Sstevel@tonic-gate 				}
16850Sstevel@tonic-gate 				break;
16860Sstevel@tonic-gate 			/* Bad sysevent handle for subscriber */
16870Sstevel@tonic-gate 			case EBADF:
16880Sstevel@tonic-gate 			case EINVAL:
16890Sstevel@tonic-gate 				dprint("sysevent_send_event: Bad sysevent "
16900Sstevel@tonic-gate 				    "handle for %s", sub->sd_door_name);
16910Sstevel@tonic-gate 				sub->sd_flag = 0;
16920Sstevel@tonic-gate 				deliver_error = 1;
16930Sstevel@tonic-gate 				break;
16940Sstevel@tonic-gate 			/* Successful delivery */
16950Sstevel@tonic-gate 			default:
16960Sstevel@tonic-gate 				sub->sd_flag &= ~SEND_AGAIN;
16970Sstevel@tonic-gate 				++subscribers_sent;
16980Sstevel@tonic-gate 			}
16990Sstevel@tonic-gate 		} else {
17000Sstevel@tonic-gate 			dprint("sysevent_send_event: Failed door call "
17010Sstevel@tonic-gate 			    "to %s: %s: %d\n", sub->sd_door_name,
17020Sstevel@tonic-gate 			    strerror(errno), result);
17030Sstevel@tonic-gate 			sub->sd_flag = 0;
17040Sstevel@tonic-gate 			deliver_error = 1;
17050Sstevel@tonic-gate 		}
17060Sstevel@tonic-gate 	}
17070Sstevel@tonic-gate 
17080Sstevel@tonic-gate 	if (want_resend) {
17090Sstevel@tonic-gate 		resend_cnt++;
17100Sstevel@tonic-gate 		goto send_event;
17110Sstevel@tonic-gate 	}
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	if (deliver_error) {
17140Sstevel@tonic-gate 		sysevent_cleanup_subscribers(shp);
17150Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
17160Sstevel@tonic-gate 		errno = EFAULT;
17170Sstevel@tonic-gate 		return (-1);
17180Sstevel@tonic-gate 	}
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
17210Sstevel@tonic-gate 
17220Sstevel@tonic-gate 	if (subscribers_sent == 0) {
17230Sstevel@tonic-gate 		dprint("sysevent_send_event: No subscribers for %s:%s\n",
17240Sstevel@tonic-gate 		    event_class, event_subclass);
17250Sstevel@tonic-gate 		errno = ENOENT;
17260Sstevel@tonic-gate 		return (-1);
17270Sstevel@tonic-gate 	}
17280Sstevel@tonic-gate 
17290Sstevel@tonic-gate 	return (0);
17300Sstevel@tonic-gate }
17310Sstevel@tonic-gate 
17320Sstevel@tonic-gate /*
17330Sstevel@tonic-gate  * Common routine to establish an event channel through which an event
17340Sstevel@tonic-gate  * publisher or subscriber may post or receive events.
17350Sstevel@tonic-gate  */
17360Sstevel@tonic-gate static sysevent_handle_t *
sysevent_open_channel_common(const char * channel_path)17370Sstevel@tonic-gate sysevent_open_channel_common(const char *channel_path)
17380Sstevel@tonic-gate {
17390Sstevel@tonic-gate 	uint32_t sub_id = 0;
17400Sstevel@tonic-gate 	char *begin_path;
17410Sstevel@tonic-gate 	struct stat chan_stat;
17420Sstevel@tonic-gate 	sysevent_handle_t *shp;
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 
17450Sstevel@tonic-gate 	if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
17460Sstevel@tonic-gate 		errno = EINVAL;
17470Sstevel@tonic-gate 		return (NULL);
17480Sstevel@tonic-gate 	}
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
17510Sstevel@tonic-gate 		if (errno != EEXIST) {
17520Sstevel@tonic-gate 			errno = EACCES;
17530Sstevel@tonic-gate 			return (NULL);
17540Sstevel@tonic-gate 		}
17550Sstevel@tonic-gate 	}
17560Sstevel@tonic-gate 
17570Sstevel@tonic-gate 	/* Check channel file permissions */
17580Sstevel@tonic-gate 	if (stat(channel_path, &chan_stat) != 0) {
17590Sstevel@tonic-gate 		dprint("sysevent_open_channel: Invalid permissions for channel "
17600Sstevel@tonic-gate 		    "%s\n", channel_path);
17610Sstevel@tonic-gate 		errno = EACCES;
17620Sstevel@tonic-gate 		return (NULL);
17630Sstevel@tonic-gate 	} else if (chan_stat.st_uid != getuid() ||
1764871Scasper 	    !S_ISDIR(chan_stat.st_mode)) {
17650Sstevel@tonic-gate 		dprint("sysevent_open_channel: Invalid "
17660Sstevel@tonic-gate 		    "permissions for channel %s\n: %d:%d:%d", channel_path,
17670Sstevel@tonic-gate 		    (int)chan_stat.st_uid, (int)chan_stat.st_gid,
17680Sstevel@tonic-gate 		    (int)chan_stat.st_mode);
17690Sstevel@tonic-gate 
17700Sstevel@tonic-gate 		errno = EACCES;
17710Sstevel@tonic-gate 		return (NULL);
17720Sstevel@tonic-gate 	}
17730Sstevel@tonic-gate 
17740Sstevel@tonic-gate 	shp = calloc(1, sizeof (sysevent_impl_hdl_t));
17750Sstevel@tonic-gate 	if (shp == NULL) {
17760Sstevel@tonic-gate 		errno = ENOMEM;
17770Sstevel@tonic-gate 		return (NULL);
17780Sstevel@tonic-gate 	}
17790Sstevel@tonic-gate 
17800Sstevel@tonic-gate 	SH_CHANNEL_NAME(shp) = NULL;
17810Sstevel@tonic-gate 	SH_CHANNEL_PATH(shp) = strdup(channel_path);
17820Sstevel@tonic-gate 	if (SH_CHANNEL_PATH(shp) == NULL) {
17830Sstevel@tonic-gate 		free(shp);
17840Sstevel@tonic-gate 		errno = ENOMEM;
17850Sstevel@tonic-gate 		return (NULL);
17860Sstevel@tonic-gate 	}
17870Sstevel@tonic-gate 
17880Sstevel@tonic-gate 	/* Extract the channel name */
17890Sstevel@tonic-gate 	begin_path = SH_CHANNEL_PATH(shp);
17900Sstevel@tonic-gate 	while (*begin_path != '\0' &&
17910Sstevel@tonic-gate 	    (begin_path = strpbrk(begin_path, "/")) != NULL) {
17920Sstevel@tonic-gate 		++begin_path;
17930Sstevel@tonic-gate 		SH_CHANNEL_NAME(shp) = begin_path;
17940Sstevel@tonic-gate 	}
17950Sstevel@tonic-gate 
17960Sstevel@tonic-gate 	if (update_kernel_registration(shp, 0,
17970Sstevel@tonic-gate 	    SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
17980Sstevel@tonic-gate 		dprint("sysevent_open_channel: Failed for channel %s\n",
17990Sstevel@tonic-gate 		    SH_CHANNEL_NAME(shp));
18000Sstevel@tonic-gate 		free(SH_CHANNEL_PATH(shp));
18010Sstevel@tonic-gate 		free(shp);
18020Sstevel@tonic-gate 		errno = EFAULT;
18030Sstevel@tonic-gate 		return (NULL);
18040Sstevel@tonic-gate 	}
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	(void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	return (shp);
18090Sstevel@tonic-gate }
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate /*
18120Sstevel@tonic-gate  * Establish a sysevent channel for publication and subscription
18130Sstevel@tonic-gate  */
18140Sstevel@tonic-gate sysevent_handle_t *
sysevent_open_channel(const char * channel)18150Sstevel@tonic-gate sysevent_open_channel(const char *channel)
18160Sstevel@tonic-gate {
18170Sstevel@tonic-gate 	int var_run_mounted = 0;
18180Sstevel@tonic-gate 	char full_channel[MAXPATHLEN + 1];
18190Sstevel@tonic-gate 	FILE *fp;
18200Sstevel@tonic-gate 	struct stat chan_stat;
18210Sstevel@tonic-gate 	struct extmnttab m;
18220Sstevel@tonic-gate 
18230Sstevel@tonic-gate 	if (channel == NULL) {
18240Sstevel@tonic-gate 		errno = EINVAL;
18250Sstevel@tonic-gate 		return (NULL);
18260Sstevel@tonic-gate 	}
18270Sstevel@tonic-gate 
18280Sstevel@tonic-gate 	/*
18290Sstevel@tonic-gate 	 * Check that /var/run is mounted as tmpfs before allowing a channel
18300Sstevel@tonic-gate 	 * to be opened.
18310Sstevel@tonic-gate 	 */
18321914Scasper 	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
18330Sstevel@tonic-gate 		errno = EACCES;
18340Sstevel@tonic-gate 		return (NULL);
18350Sstevel@tonic-gate 	}
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	resetmnttab(fp);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
18400Sstevel@tonic-gate 		if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
184111102SGavin.Maltby@Sun.COM 		    strcmp(m.mnt_fstype, "tmpfs") == 0) {
18420Sstevel@tonic-gate 			var_run_mounted = 1;
18430Sstevel@tonic-gate 			break;
18440Sstevel@tonic-gate 		}
18450Sstevel@tonic-gate 	}
18460Sstevel@tonic-gate 	(void) fclose(fp);
18470Sstevel@tonic-gate 
18480Sstevel@tonic-gate 	if (!var_run_mounted) {
18490Sstevel@tonic-gate 		errno = EACCES;
18500Sstevel@tonic-gate 		return (NULL);
18510Sstevel@tonic-gate 	}
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	if (stat(CHAN_PATH, &chan_stat) < 0) {
18540Sstevel@tonic-gate 		if (mkdir(CHAN_PATH,
18550Sstevel@tonic-gate 		    S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
18560Sstevel@tonic-gate 			dprint("sysevent_open_channel: Unable "
18570Sstevel@tonic-gate 			    "to create channel directory %s:%s\n", CHAN_PATH,
18580Sstevel@tonic-gate 			    strerror(errno));
18590Sstevel@tonic-gate 			if (errno != EEXIST) {
18600Sstevel@tonic-gate 				errno = EACCES;
18610Sstevel@tonic-gate 				return (NULL);
18620Sstevel@tonic-gate 			}
18630Sstevel@tonic-gate 		}
18640Sstevel@tonic-gate 	}
18650Sstevel@tonic-gate 
18660Sstevel@tonic-gate 	if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
18670Sstevel@tonic-gate 	    MAXPATHLEN) {
18680Sstevel@tonic-gate 		errno = EINVAL;
18690Sstevel@tonic-gate 		return (NULL);
18700Sstevel@tonic-gate 	}
18710Sstevel@tonic-gate 
18720Sstevel@tonic-gate 	return (sysevent_open_channel_common(full_channel));
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate 
18750Sstevel@tonic-gate /*
18760Sstevel@tonic-gate  * Establish a sysevent channel for publication and subscription
18770Sstevel@tonic-gate  * Full path to the channel determined by the caller
18780Sstevel@tonic-gate  */
18790Sstevel@tonic-gate sysevent_handle_t *
sysevent_open_channel_alt(const char * channel_path)18800Sstevel@tonic-gate sysevent_open_channel_alt(const char *channel_path)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	return (sysevent_open_channel_common(channel_path));
18830Sstevel@tonic-gate }
18840Sstevel@tonic-gate 
18850Sstevel@tonic-gate /*
18860Sstevel@tonic-gate  * sysevent_close_channel - Clean up resources associated with a previously
18870Sstevel@tonic-gate  *				opened sysevent channel
18880Sstevel@tonic-gate  */
18890Sstevel@tonic-gate void
sysevent_close_channel(sysevent_handle_t * shp)18900Sstevel@tonic-gate sysevent_close_channel(sysevent_handle_t *shp)
18910Sstevel@tonic-gate {
18920Sstevel@tonic-gate 	int error = errno;
18930Sstevel@tonic-gate 	uint32_t sub_id = 0;
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 	if (shp == NULL) {
18960Sstevel@tonic-gate 		return;
18970Sstevel@tonic-gate 	}
18980Sstevel@tonic-gate 
18990Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
19000Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
19010Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19020Sstevel@tonic-gate 		if (SH_TYPE(shp) == PUBLISHER)
19030Sstevel@tonic-gate 			sysevent_unbind_publisher(shp);
19040Sstevel@tonic-gate 		else if (SH_TYPE(shp) == SUBSCRIBER)
19050Sstevel@tonic-gate 			sysevent_unbind_subscriber(shp);
19060Sstevel@tonic-gate 		(void) mutex_lock(SH_LOCK(shp));
19070Sstevel@tonic-gate 	}
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	(void) update_kernel_registration(shp, 0,
19100Sstevel@tonic-gate 	    SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
19110Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	free(SH_CHANNEL_PATH(shp));
19140Sstevel@tonic-gate 	free(shp);
19150Sstevel@tonic-gate 	errno = error;
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate 
19180Sstevel@tonic-gate /*
19190Sstevel@tonic-gate  * sysevent_bind_publisher - Bind an event publisher to an event channel
19200Sstevel@tonic-gate  */
19210Sstevel@tonic-gate int
sysevent_bind_publisher(sysevent_handle_t * shp)19220Sstevel@tonic-gate sysevent_bind_publisher(sysevent_handle_t *shp)
19230Sstevel@tonic-gate {
19240Sstevel@tonic-gate 	int error = 0;
19250Sstevel@tonic-gate 	int fd = -1;
19260Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
19270Sstevel@tonic-gate 	uint32_t pub_id;
19280Sstevel@tonic-gate 	struct stat reg_stat;
19290Sstevel@tonic-gate 	publisher_priv_t *pub;
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate 	if (shp == NULL) {
19320Sstevel@tonic-gate 		errno = EINVAL;
19330Sstevel@tonic-gate 		return (-1);
19340Sstevel@tonic-gate 	}
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
19370Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
19380Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19390Sstevel@tonic-gate 		errno = EINVAL;
19400Sstevel@tonic-gate 		return (-1);
19410Sstevel@tonic-gate 	}
19420Sstevel@tonic-gate 
19430Sstevel@tonic-gate 	if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
19440Sstevel@tonic-gate 	    NULL) {
19450Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19460Sstevel@tonic-gate 		errno = ENOMEM;
19470Sstevel@tonic-gate 		return (-1);
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate 	SH_PRIV_DATA(shp) = (void *)pub;
19500Sstevel@tonic-gate 
19510Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
19520Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
19530Sstevel@tonic-gate 		free(pub);
19540Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19550Sstevel@tonic-gate 		errno = ENOMEM;
19560Sstevel@tonic-gate 		return (-1);
19570Sstevel@tonic-gate 	}
19580Sstevel@tonic-gate 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
19590Sstevel@tonic-gate 		free(pub);
19600Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
19610Sstevel@tonic-gate 		errno = ENOMEM;
19620Sstevel@tonic-gate 		return (-1);
19630Sstevel@tonic-gate 	}
19640Sstevel@tonic-gate 
19650Sstevel@tonic-gate 	/* Only one publisher allowed per channel */
19660Sstevel@tonic-gate 	if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
19670Sstevel@tonic-gate 		if (errno != ENOENT) {
19680Sstevel@tonic-gate 			error = EINVAL;
19690Sstevel@tonic-gate 			goto fail;
19700Sstevel@tonic-gate 		}
19710Sstevel@tonic-gate 	}
19720Sstevel@tonic-gate 
19730Sstevel@tonic-gate 	/*
19740Sstevel@tonic-gate 	 * Remove door file for robustness.
19750Sstevel@tonic-gate 	 */
19760Sstevel@tonic-gate 	if (unlink(SH_DOOR_NAME(shp)) != 0)
19770Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
19780Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
19790Sstevel@tonic-gate 
19800Sstevel@tonic-gate 	/* Open channel registration door */
19810Sstevel@tonic-gate 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
19820Sstevel@tonic-gate 	    S_IREAD|S_IWRITE);
19830Sstevel@tonic-gate 	if (fd == -1) {
19840Sstevel@tonic-gate 		error = EINVAL;
19850Sstevel@tonic-gate 		goto fail;
19860Sstevel@tonic-gate 	}
19870Sstevel@tonic-gate 
19880Sstevel@tonic-gate 	/*
19890Sstevel@tonic-gate 	 * Create the registration service for this publisher.
19900Sstevel@tonic-gate 	 */
19910Sstevel@tonic-gate 	if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
19920Sstevel@tonic-gate 	    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
19930Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: door create failed: "
19940Sstevel@tonic-gate 		    "%s\n", strerror(errno));
19950Sstevel@tonic-gate 		error = EFAULT;
19960Sstevel@tonic-gate 		goto fail;
19970Sstevel@tonic-gate 	}
19980Sstevel@tonic-gate 
19990Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
20000Sstevel@tonic-gate 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
20010Sstevel@tonic-gate 		dprint("sysevent_bind_publisher: unable to "
20020Sstevel@tonic-gate 		    "bind event channel: fattach: %s\n",
20030Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
20040Sstevel@tonic-gate 		error = EACCES;
20050Sstevel@tonic-gate 		goto fail;
20060Sstevel@tonic-gate 	}
20070Sstevel@tonic-gate 
20080Sstevel@tonic-gate 	/* Bind this publisher in the kernel registration database */
20090Sstevel@tonic-gate 	if (update_kernel_registration(shp, PUBLISHER,
20100Sstevel@tonic-gate 	    SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
20110Sstevel@tonic-gate 		error = errno;
20120Sstevel@tonic-gate 		goto fail;
20130Sstevel@tonic-gate 	}
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	SH_ID(shp) = pub_id;
20160Sstevel@tonic-gate 	SH_BOUND(shp) = 1;
20170Sstevel@tonic-gate 	SH_TYPE(shp) = PUBLISHER;
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	/* Create the subscription registration cache */
20210Sstevel@tonic-gate 	if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
20220Sstevel@tonic-gate 		(void) update_kernel_registration(shp,
20230Sstevel@tonic-gate 		    PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
20240Sstevel@tonic-gate 		error = EFAULT;
20250Sstevel@tonic-gate 		goto fail;
20260Sstevel@tonic-gate 	}
20270Sstevel@tonic-gate 	(void) close(fd);
20280Sstevel@tonic-gate 
20290Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
20300Sstevel@tonic-gate 
20310Sstevel@tonic-gate 	return (0);
20320Sstevel@tonic-gate 
20330Sstevel@tonic-gate fail:
20340Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
20350Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
20360Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
20370Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
20380Sstevel@tonic-gate 	free(pub);
20390Sstevel@tonic-gate 	(void) close(fd);
20400Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
20410Sstevel@tonic-gate 	errno = error;
20420Sstevel@tonic-gate 	return (-1);
20430Sstevel@tonic-gate }
20440Sstevel@tonic-gate 
2045*12967Sgavin.maltby@oracle.com static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2046*12967Sgavin.maltby@oracle.com static pthread_attr_t xdoor_thrattr;
2047*12967Sgavin.maltby@oracle.com 
2048*12967Sgavin.maltby@oracle.com static void
xdoor_thrattr_init(void)2049*12967Sgavin.maltby@oracle.com xdoor_thrattr_init(void)
2050*12967Sgavin.maltby@oracle.com {
2051*12967Sgavin.maltby@oracle.com 	(void) pthread_attr_init(&xdoor_thrattr);
2052*12967Sgavin.maltby@oracle.com 	(void) pthread_attr_setdetachstate(&xdoor_thrattr,
2053*12967Sgavin.maltby@oracle.com 	    PTHREAD_CREATE_DETACHED);
2054*12967Sgavin.maltby@oracle.com 	(void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2055*12967Sgavin.maltby@oracle.com }
2056*12967Sgavin.maltby@oracle.com 
2057*12967Sgavin.maltby@oracle.com static int
xdoor_server_create(door_info_t * dip,void * (* startf)(void *),void * startfarg,void * cookie)2058*12967Sgavin.maltby@oracle.com xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2059*12967Sgavin.maltby@oracle.com     void *startfarg, void *cookie)
2060*12967Sgavin.maltby@oracle.com {
2061*12967Sgavin.maltby@oracle.com 	struct sysevent_subattr_impl *xsa = cookie;
2062*12967Sgavin.maltby@oracle.com 	pthread_attr_t *thrattr;
2063*12967Sgavin.maltby@oracle.com 	sigset_t oset;
2064*12967Sgavin.maltby@oracle.com 	int err;
2065*12967Sgavin.maltby@oracle.com 
2066*12967Sgavin.maltby@oracle.com 	if (xsa->xs_thrcreate) {
2067*12967Sgavin.maltby@oracle.com 		return (xsa->xs_thrcreate(dip, startf, startfarg,
2068*12967Sgavin.maltby@oracle.com 		    xsa->xs_thrcreate_cookie));
2069*12967Sgavin.maltby@oracle.com 	}
2070*12967Sgavin.maltby@oracle.com 
2071*12967Sgavin.maltby@oracle.com 	if (xsa->xs_thrattr == NULL) {
2072*12967Sgavin.maltby@oracle.com 		(void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2073*12967Sgavin.maltby@oracle.com 		thrattr = &xdoor_thrattr;
2074*12967Sgavin.maltby@oracle.com 	} else {
2075*12967Sgavin.maltby@oracle.com 		thrattr = xsa->xs_thrattr;
2076*12967Sgavin.maltby@oracle.com 	}
2077*12967Sgavin.maltby@oracle.com 
2078*12967Sgavin.maltby@oracle.com 	(void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2079*12967Sgavin.maltby@oracle.com 	err = pthread_create(NULL, thrattr, startf, startfarg);
2080*12967Sgavin.maltby@oracle.com 	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2081*12967Sgavin.maltby@oracle.com 
2082*12967Sgavin.maltby@oracle.com 	return (err == 0 ? 1 : -1);
2083*12967Sgavin.maltby@oracle.com }
2084*12967Sgavin.maltby@oracle.com 
2085*12967Sgavin.maltby@oracle.com static void
xdoor_server_setup(void * cookie)2086*12967Sgavin.maltby@oracle.com xdoor_server_setup(void *cookie)
2087*12967Sgavin.maltby@oracle.com {
2088*12967Sgavin.maltby@oracle.com 	struct sysevent_subattr_impl *xsa = cookie;
2089*12967Sgavin.maltby@oracle.com 
2090*12967Sgavin.maltby@oracle.com 	if (xsa->xs_thrsetup) {
2091*12967Sgavin.maltby@oracle.com 		xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2092*12967Sgavin.maltby@oracle.com 	} else {
2093*12967Sgavin.maltby@oracle.com 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2094*12967Sgavin.maltby@oracle.com 		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2095*12967Sgavin.maltby@oracle.com 	}
2096*12967Sgavin.maltby@oracle.com }
2097*12967Sgavin.maltby@oracle.com 
2098*12967Sgavin.maltby@oracle.com static int
sysevent_bind_subscriber_cmn(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2099*12967Sgavin.maltby@oracle.com sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
2100*12967Sgavin.maltby@oracle.com 	void (*event_handler)(sysevent_t *ev),
2101*12967Sgavin.maltby@oracle.com 	sysevent_subattr_t *subattr)
21020Sstevel@tonic-gate {
21030Sstevel@tonic-gate 	int fd = -1;
21040Sstevel@tonic-gate 	int error = 0;
21050Sstevel@tonic-gate 	uint32_t sub_id = 0;
21060Sstevel@tonic-gate 	char door_name[MAXPATHLEN];
21070Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
2108*12967Sgavin.maltby@oracle.com 	int created;
2109*12967Sgavin.maltby@oracle.com 	struct sysevent_subattr_impl *xsa =
2110*12967Sgavin.maltby@oracle.com 	    (struct sysevent_subattr_impl *)subattr;
21110Sstevel@tonic-gate 
21120Sstevel@tonic-gate 	if (shp == NULL || event_handler == NULL) {
21130Sstevel@tonic-gate 		errno = EINVAL;
21140Sstevel@tonic-gate 		return (-1);
21150Sstevel@tonic-gate 	}
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
21180Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
21190Sstevel@tonic-gate 		errno = EINVAL;
21200Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21210Sstevel@tonic-gate 		return (-1);
21220Sstevel@tonic-gate 	}
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	if ((sub_info = (subscriber_priv_t *)calloc(1,
21250Sstevel@tonic-gate 	    sizeof (subscriber_priv_t))) == NULL) {
21260Sstevel@tonic-gate 		errno = ENOMEM;
21270Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21280Sstevel@tonic-gate 		return (-1);
21290Sstevel@tonic-gate 	}
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
21320Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
21330Sstevel@tonic-gate 		free(sub_info);
21340Sstevel@tonic-gate 		errno = EINVAL;
21350Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21360Sstevel@tonic-gate 		return (-1);
21370Sstevel@tonic-gate 	}
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
21400Sstevel@tonic-gate 		free(sub_info);
21410Sstevel@tonic-gate 		errno = ENOMEM;
21420Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
21430Sstevel@tonic-gate 		return (-1);
21440Sstevel@tonic-gate 	}
21450Sstevel@tonic-gate 	(void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
21460Sstevel@tonic-gate 	(void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
21470Sstevel@tonic-gate 	sub_info->sp_func = event_handler;
21480Sstevel@tonic-gate 
21490Sstevel@tonic-gate 	/* Update the in-kernel registration */
21500Sstevel@tonic-gate 	if (update_kernel_registration(shp, SUBSCRIBER,
21510Sstevel@tonic-gate 	    SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
21520Sstevel@tonic-gate 		error = errno;
21530Sstevel@tonic-gate 		goto fail;
21540Sstevel@tonic-gate 	}
21550Sstevel@tonic-gate 	SH_ID(shp) = sub_id;
21560Sstevel@tonic-gate 
21570Sstevel@tonic-gate 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
21580Sstevel@tonic-gate 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
21590Sstevel@tonic-gate 		error = EINVAL;
21600Sstevel@tonic-gate 		goto fail;
21610Sstevel@tonic-gate 	}
21620Sstevel@tonic-gate 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
21630Sstevel@tonic-gate 		error = ENOMEM;
21640Sstevel@tonic-gate 		goto fail;
21650Sstevel@tonic-gate 	}
21660Sstevel@tonic-gate 
21670Sstevel@tonic-gate 	/*
21680Sstevel@tonic-gate 	 * Remove door file for robustness.
21690Sstevel@tonic-gate 	 */
21700Sstevel@tonic-gate 	if (unlink(SH_DOOR_NAME(shp)) != 0)
21710Sstevel@tonic-gate 		dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
21720Sstevel@tonic-gate 		    SH_DOOR_NAME(shp));
21730Sstevel@tonic-gate 
21740Sstevel@tonic-gate 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
21750Sstevel@tonic-gate 	if (fd == -1) {
21760Sstevel@tonic-gate 		error = EFAULT;
21770Sstevel@tonic-gate 		goto fail;
21780Sstevel@tonic-gate 	}
21790Sstevel@tonic-gate 
21800Sstevel@tonic-gate 	/*
21810Sstevel@tonic-gate 	 * Create the sysevent door service for this client.
21820Sstevel@tonic-gate 	 * syseventd will use this door service to propagate
21830Sstevel@tonic-gate 	 * events to the client.
21840Sstevel@tonic-gate 	 */
2185*12967Sgavin.maltby@oracle.com 	if (subattr == NULL) {
2186*12967Sgavin.maltby@oracle.com 		SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2187*12967Sgavin.maltby@oracle.com 		    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2188*12967Sgavin.maltby@oracle.com 	} else {
2189*12967Sgavin.maltby@oracle.com 		SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2190*12967Sgavin.maltby@oracle.com 		    (void *)shp,
2191*12967Sgavin.maltby@oracle.com 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2192*12967Sgavin.maltby@oracle.com 		    xdoor_server_create, xdoor_server_setup,
2193*12967Sgavin.maltby@oracle.com 		    (void *)subattr, 1);
2194*12967Sgavin.maltby@oracle.com 	}
2195*12967Sgavin.maltby@oracle.com 
2196*12967Sgavin.maltby@oracle.com 	if (SH_DOOR_DESC(shp) == -1) {
21970Sstevel@tonic-gate 		dprint("sysevent_bind_subscriber: door create failed: "
219811102SGavin.Maltby@Sun.COM 		    "%s\n", strerror(errno));
21990Sstevel@tonic-gate 		error = EFAULT;
22000Sstevel@tonic-gate 		goto fail;
22010Sstevel@tonic-gate 	}
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
22040Sstevel@tonic-gate 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
22050Sstevel@tonic-gate 		error = EFAULT;
22060Sstevel@tonic-gate 		goto fail;
22070Sstevel@tonic-gate 	}
22080Sstevel@tonic-gate 	(void) close(fd);
22090Sstevel@tonic-gate 
22100Sstevel@tonic-gate 	if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
22110Sstevel@tonic-gate 	    sub_id, 0, NULL) != 0) {
22120Sstevel@tonic-gate 		error = errno;
22130Sstevel@tonic-gate 		(void) update_kernel_registration(shp, SUBSCRIBER,
22140Sstevel@tonic-gate 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
22150Sstevel@tonic-gate 		goto fail;
22160Sstevel@tonic-gate 	}
22170Sstevel@tonic-gate 
22180Sstevel@tonic-gate 	SH_BOUND(shp) = 1;
22190Sstevel@tonic-gate 	SH_TYPE(shp) = SUBSCRIBER;
22200Sstevel@tonic-gate 	SH_PRIV_DATA(shp) = (void *)sub_info;
22210Sstevel@tonic-gate 
2222*12967Sgavin.maltby@oracle.com 	/* Create an event handler thread */
2223*12967Sgavin.maltby@oracle.com 	if (xsa == NULL || xsa->xs_thrcreate == NULL) {
2224*12967Sgavin.maltby@oracle.com 		created = thr_create(NULL, NULL,
2225*12967Sgavin.maltby@oracle.com 		    (void *(*)(void *))subscriber_event_handler,
2226*12967Sgavin.maltby@oracle.com 		    shp, THR_BOUND, &sub_info->sp_handler_tid) == 0;
2227*12967Sgavin.maltby@oracle.com 	} else {
2228*12967Sgavin.maltby@oracle.com 		/*
2229*12967Sgavin.maltby@oracle.com 		 * A terrible hack.  We will use the extended private
2230*12967Sgavin.maltby@oracle.com 		 * door thread creation function the caller passed in to
2231*12967Sgavin.maltby@oracle.com 		 * create the event handler thread.  That function will
2232*12967Sgavin.maltby@oracle.com 		 * be called with our chosen thread start function and arg
2233*12967Sgavin.maltby@oracle.com 		 * instead of the usual libc-provided ones, but that's ok
2234*12967Sgavin.maltby@oracle.com 		 * as it is required to use them verbatim anyway.  We will
2235*12967Sgavin.maltby@oracle.com 		 * pass a NULL door_info_t pointer to the function - so
2236*12967Sgavin.maltby@oracle.com 		 * callers depending on this hack had better be prepared
2237*12967Sgavin.maltby@oracle.com 		 * for that.  All this allow the caller to rubberstamp
2238*12967Sgavin.maltby@oracle.com 		 * the created thread as it wishes.  But we don't get
2239*12967Sgavin.maltby@oracle.com 		 * the created threadid with this, so we modify the
2240*12967Sgavin.maltby@oracle.com 		 * thread start function to stash it.
2241*12967Sgavin.maltby@oracle.com 		 */
22420Sstevel@tonic-gate 
2243*12967Sgavin.maltby@oracle.com 		created = xsa->xs_thrcreate(NULL,
2244*12967Sgavin.maltby@oracle.com 		    (void *(*)(void *))subscriber_event_handler,
2245*12967Sgavin.maltby@oracle.com 		    shp, xsa->xs_thrcreate_cookie) == 1;
2246*12967Sgavin.maltby@oracle.com 	}
2247*12967Sgavin.maltby@oracle.com 
2248*12967Sgavin.maltby@oracle.com 	if (!created) {
22490Sstevel@tonic-gate 		error = EFAULT;
22500Sstevel@tonic-gate 		goto fail;
22510Sstevel@tonic-gate 	}
22520Sstevel@tonic-gate 
22530Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate 	return (0);
22560Sstevel@tonic-gate 
22570Sstevel@tonic-gate fail:
22580Sstevel@tonic-gate 	(void) close(fd);
22590Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
22600Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
22610Sstevel@tonic-gate 	(void) cond_destroy(&sub_info->sp_cv);
22620Sstevel@tonic-gate 	(void) mutex_destroy(&sub_info->sp_qlock);
22630Sstevel@tonic-gate 	free(sub_info->sp_door_name);
22640Sstevel@tonic-gate 	free(sub_info);
22650Sstevel@tonic-gate 	if (SH_ID(shp)) {
22660Sstevel@tonic-gate 		(void) update_kernel_registration(shp, SUBSCRIBER,
22670Sstevel@tonic-gate 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
22680Sstevel@tonic-gate 		SH_ID(shp) = 0;
22690Sstevel@tonic-gate 	}
22700Sstevel@tonic-gate 	if (SH_BOUND(shp)) {
22710Sstevel@tonic-gate 		(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
22720Sstevel@tonic-gate 		    sub_id, 0, NULL);
22730Sstevel@tonic-gate 		free(SH_DOOR_NAME(shp));
22740Sstevel@tonic-gate 		SH_BOUND(shp) = 0;
22750Sstevel@tonic-gate 	}
22760Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
22770Sstevel@tonic-gate 
22780Sstevel@tonic-gate 	errno = error;
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 	return (-1);
22810Sstevel@tonic-gate }
22820Sstevel@tonic-gate 
22830Sstevel@tonic-gate /*
2284*12967Sgavin.maltby@oracle.com  * sysevent_bind_subscriber - Bind an event receiver to an event channel
2285*12967Sgavin.maltby@oracle.com  */
2286*12967Sgavin.maltby@oracle.com int
sysevent_bind_subscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev))2287*12967Sgavin.maltby@oracle.com sysevent_bind_subscriber(sysevent_handle_t *shp,
2288*12967Sgavin.maltby@oracle.com 	void (*event_handler)(sysevent_t *ev))
2289*12967Sgavin.maltby@oracle.com {
2290*12967Sgavin.maltby@oracle.com 	return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2291*12967Sgavin.maltby@oracle.com }
2292*12967Sgavin.maltby@oracle.com 
2293*12967Sgavin.maltby@oracle.com /*
2294*12967Sgavin.maltby@oracle.com  * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2295*12967Sgavin.maltby@oracle.com  * attributes specified.
2296*12967Sgavin.maltby@oracle.com  */
2297*12967Sgavin.maltby@oracle.com int
sysevent_bind_xsubscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2298*12967Sgavin.maltby@oracle.com sysevent_bind_xsubscriber(sysevent_handle_t *shp,
2299*12967Sgavin.maltby@oracle.com 	void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2300*12967Sgavin.maltby@oracle.com {
2301*12967Sgavin.maltby@oracle.com 	return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2302*12967Sgavin.maltby@oracle.com }
2303*12967Sgavin.maltby@oracle.com 
2304*12967Sgavin.maltby@oracle.com /*
23050Sstevel@tonic-gate  * sysevent_register_event - register an event class and associated subclasses
23060Sstevel@tonic-gate  *		for an event subscriber
23070Sstevel@tonic-gate  */
23080Sstevel@tonic-gate int
sysevent_register_event(sysevent_handle_t * shp,const char * ev_class,const char ** ev_subclass,int subclass_num)23090Sstevel@tonic-gate sysevent_register_event(sysevent_handle_t *shp,
23100Sstevel@tonic-gate 	const char *ev_class, const char **ev_subclass,
23110Sstevel@tonic-gate 	int subclass_num)
23120Sstevel@tonic-gate {
23130Sstevel@tonic-gate 	int error;
23140Sstevel@tonic-gate 	char *event_class = (char *)ev_class;
23150Sstevel@tonic-gate 	char **event_subclass_list = (char **)ev_subclass;
23160Sstevel@tonic-gate 	char *nvlbuf = NULL;
23170Sstevel@tonic-gate 	size_t datalen;
23180Sstevel@tonic-gate 	nvlist_t *nvl;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
23210Sstevel@tonic-gate 	if (event_class == NULL || event_subclass_list == NULL ||
23220Sstevel@tonic-gate 	    event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
23230Sstevel@tonic-gate 	    subclass_num <= 0) {
23240Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23250Sstevel@tonic-gate 		errno = EINVAL;
23260Sstevel@tonic-gate 		return (-1);
23270Sstevel@tonic-gate 	}
23280Sstevel@tonic-gate 
23290Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
23300Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23310Sstevel@tonic-gate 		return (-1);
23320Sstevel@tonic-gate 	}
23330Sstevel@tonic-gate 	if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
23340Sstevel@tonic-gate 	    subclass_num) != 0) {
23350Sstevel@tonic-gate 		nvlist_free(nvl);
23360Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23370Sstevel@tonic-gate 		return (-1);
23380Sstevel@tonic-gate 	}
23390Sstevel@tonic-gate 	if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
23400Sstevel@tonic-gate 		nvlist_free(nvl);
23410Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23420Sstevel@tonic-gate 		return (-1);
23430Sstevel@tonic-gate 	}
23440Sstevel@tonic-gate 	nvlist_free(nvl);
23450Sstevel@tonic-gate 
23460Sstevel@tonic-gate 	/* Store new subscriber in in-kernel registration */
23470Sstevel@tonic-gate 	if (update_kernel_registration(shp, SUBSCRIBER,
23480Sstevel@tonic-gate 	    SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
23490Sstevel@tonic-gate 	    != 0) {
23500Sstevel@tonic-gate 		error = errno;
23510Sstevel@tonic-gate 		free(nvlbuf);
23520Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23530Sstevel@tonic-gate 		errno = error;
23540Sstevel@tonic-gate 		return (-1);
23550Sstevel@tonic-gate 	}
23560Sstevel@tonic-gate 	/* Update the publisher's cached registration */
23570Sstevel@tonic-gate 	if (update_publisher_cache(
23580Sstevel@tonic-gate 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
23590Sstevel@tonic-gate 	    SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
23600Sstevel@tonic-gate 		error = errno;
23610Sstevel@tonic-gate 		free(nvlbuf);
23620Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23630Sstevel@tonic-gate 		errno = error;
23640Sstevel@tonic-gate 		return (-1);
23650Sstevel@tonic-gate 	}
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 	free(nvlbuf);
23680Sstevel@tonic-gate 
23690Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	return (0);
23720Sstevel@tonic-gate }
23730Sstevel@tonic-gate 
23740Sstevel@tonic-gate /*
23750Sstevel@tonic-gate  * sysevent_unregister_event - Unregister an event class and associated
23760Sstevel@tonic-gate  *				subclasses for an event subscriber
23770Sstevel@tonic-gate  */
23780Sstevel@tonic-gate void
sysevent_unregister_event(sysevent_handle_t * shp,const char * class)23790Sstevel@tonic-gate sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
23800Sstevel@tonic-gate {
23810Sstevel@tonic-gate 	size_t class_sz;
23820Sstevel@tonic-gate 
23830Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
23840Sstevel@tonic-gate 
23850Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
23860Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
23870Sstevel@tonic-gate 		return;
23880Sstevel@tonic-gate 	}
23890Sstevel@tonic-gate 
23900Sstevel@tonic-gate 	/* Remove subscriber from in-kernel registration */
23910Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
23920Sstevel@tonic-gate 	(void) update_kernel_registration(shp, SUBSCRIBER,
23930Sstevel@tonic-gate 	    SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
23940Sstevel@tonic-gate 	/* Update the publisher's cached registration */
23950Sstevel@tonic-gate 	(void) update_publisher_cache(
23960Sstevel@tonic-gate 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
23970Sstevel@tonic-gate 	    SH_ID(shp), class_sz, (uchar_t *)class);
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
24000Sstevel@tonic-gate }
24010Sstevel@tonic-gate 
24020Sstevel@tonic-gate static int
cleanup_id(sysevent_handle_t * shp,uint32_t id,int type)24030Sstevel@tonic-gate cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
24040Sstevel@tonic-gate {
24050Sstevel@tonic-gate 	dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
24060Sstevel@tonic-gate 
24070Sstevel@tonic-gate 	/* Remove registration from the kernel */
24080Sstevel@tonic-gate 	if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
24090Sstevel@tonic-gate 	    0, NULL) != 0) {
24100Sstevel@tonic-gate 		dprint("cleanup_id: Unable to clean "
24110Sstevel@tonic-gate 		    "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
24120Sstevel@tonic-gate 		return (-1);
24130Sstevel@tonic-gate 	}
24140Sstevel@tonic-gate 
24150Sstevel@tonic-gate 	return (0);
24160Sstevel@tonic-gate }
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate /*
24190Sstevel@tonic-gate  * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
24200Sstevel@tonic-gate  *		allocated to unresponsive subscribers.
24210Sstevel@tonic-gate  */
24220Sstevel@tonic-gate void
sysevent_cleanup_subscribers(sysevent_handle_t * shp)24230Sstevel@tonic-gate sysevent_cleanup_subscribers(sysevent_handle_t *shp)
24240Sstevel@tonic-gate {
24250Sstevel@tonic-gate 	uint32_t ping, result;
24260Sstevel@tonic-gate 	int i, error, sub_fd;
24270Sstevel@tonic-gate 	subscriber_data_t *sub;
24280Sstevel@tonic-gate 
24290Sstevel@tonic-gate 	if (!SH_BOUND(shp)) {
24300Sstevel@tonic-gate 		return;
24310Sstevel@tonic-gate 	}
24320Sstevel@tonic-gate 
24330Sstevel@tonic-gate 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
24340Sstevel@tonic-gate 
24350Sstevel@tonic-gate 		sub = SH_SUBSCRIBER(shp, i);
24360Sstevel@tonic-gate 		if (sub == NULL) {
24370Sstevel@tonic-gate 			continue;
24380Sstevel@tonic-gate 		}
24390Sstevel@tonic-gate 
24400Sstevel@tonic-gate 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
24410Sstevel@tonic-gate 			continue;
24420Sstevel@tonic-gate 		}
24430Sstevel@tonic-gate 		/* Check for valid and responsive subscriber */
24440Sstevel@tonic-gate 		error = clnt_deliver_event(sub_fd, &ping,
24450Sstevel@tonic-gate 		    sizeof (uint32_t), &result, sizeof (result));
24460Sstevel@tonic-gate 		(void) close(sub_fd);
24470Sstevel@tonic-gate 
24480Sstevel@tonic-gate 		/* Only cleanup on EBADF (Invalid door descriptor) */
24490Sstevel@tonic-gate 		if (error != EBADF)
24500Sstevel@tonic-gate 			continue;
24510Sstevel@tonic-gate 
24520Sstevel@tonic-gate 		if (cleanup_id(shp, i, SUBSCRIBER) != 0)
24530Sstevel@tonic-gate 			continue;
24540Sstevel@tonic-gate 
24550Sstevel@tonic-gate 		cache_remove_class(shp, EC_ALL, i);
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 		free(sub->sd_door_name);
24580Sstevel@tonic-gate 		free(sub);
24590Sstevel@tonic-gate 		SH_SUBSCRIBER(shp, i) = NULL;
24600Sstevel@tonic-gate 	}
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate }
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate /*
24650Sstevel@tonic-gate  * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
24660Sstevel@tonic-gate  *		as needed.
24670Sstevel@tonic-gate  */
24680Sstevel@tonic-gate void
sysevent_cleanup_publishers(sysevent_handle_t * shp)24690Sstevel@tonic-gate sysevent_cleanup_publishers(sysevent_handle_t *shp)
24700Sstevel@tonic-gate {
24710Sstevel@tonic-gate 	(void) cleanup_id(shp, 1, PUBLISHER);
24720Sstevel@tonic-gate }
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate /*
24750Sstevel@tonic-gate  * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
24760Sstevel@tonic-gate  */
24770Sstevel@tonic-gate void
sysevent_unbind_subscriber(sysevent_handle_t * shp)24780Sstevel@tonic-gate sysevent_unbind_subscriber(sysevent_handle_t *shp)
24790Sstevel@tonic-gate {
24800Sstevel@tonic-gate 	subscriber_priv_t *sub_info;
24810Sstevel@tonic-gate 
24820Sstevel@tonic-gate 	if (shp == NULL)
24830Sstevel@tonic-gate 		return;
24840Sstevel@tonic-gate 
24850Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
24860Sstevel@tonic-gate 	if (SH_BOUND(shp) == 0) {
24870Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
24880Sstevel@tonic-gate 		return;
24890Sstevel@tonic-gate 	}
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate 	/* Update the in-kernel registration */
24920Sstevel@tonic-gate 	(void) update_kernel_registration(shp, SUBSCRIBER,
24930Sstevel@tonic-gate 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 	/* Update the sysevent channel publisher */
24960Sstevel@tonic-gate 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
24970Sstevel@tonic-gate 	(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
24980Sstevel@tonic-gate 	    SH_ID(shp), 0, NULL);
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 	/* Close down event delivery facilities */
25010Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
25020Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
25030Sstevel@tonic-gate 
25040Sstevel@tonic-gate 	/*
25050Sstevel@tonic-gate 	 * Release resources and wait for pending event delivery to
25060Sstevel@tonic-gate 	 * complete.
25070Sstevel@tonic-gate 	 */
25080Sstevel@tonic-gate 	(void) mutex_lock(&sub_info->sp_qlock);
25090Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
25100Sstevel@tonic-gate 	/* Signal event handler and drain the subscriber's event queue */
25110Sstevel@tonic-gate 	(void) cond_signal(&sub_info->sp_cv);
25120Sstevel@tonic-gate 	(void) mutex_unlock(&sub_info->sp_qlock);
2513*12967Sgavin.maltby@oracle.com 	if (sub_info->sp_handler_tid != NULL)
2514*12967Sgavin.maltby@oracle.com 		(void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
25150Sstevel@tonic-gate 
25160Sstevel@tonic-gate 	(void) cond_destroy(&sub_info->sp_cv);
25170Sstevel@tonic-gate 	(void) mutex_destroy(&sub_info->sp_qlock);
25180Sstevel@tonic-gate 	free(sub_info->sp_door_name);
25190Sstevel@tonic-gate 	free(sub_info);
25200Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
25210Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
25220Sstevel@tonic-gate }
25230Sstevel@tonic-gate 
25240Sstevel@tonic-gate /*
25250Sstevel@tonic-gate  * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
25260Sstevel@tonic-gate  */
25270Sstevel@tonic-gate void
sysevent_unbind_publisher(sysevent_handle_t * shp)25280Sstevel@tonic-gate sysevent_unbind_publisher(sysevent_handle_t *shp)
25290Sstevel@tonic-gate {
25300Sstevel@tonic-gate 	if (shp == NULL)
25310Sstevel@tonic-gate 		return;
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate 	(void) mutex_lock(SH_LOCK(shp));
25340Sstevel@tonic-gate 	if (SH_BOUND(shp) == 0) {
25350Sstevel@tonic-gate 		(void) mutex_unlock(SH_LOCK(shp));
25360Sstevel@tonic-gate 		return;
25370Sstevel@tonic-gate 	}
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate 	/* Close down the registration facilities */
25400Sstevel@tonic-gate 	(void) door_revoke(SH_DOOR_DESC(shp));
25410Sstevel@tonic-gate 	(void) fdetach(SH_DOOR_NAME(shp));
25420Sstevel@tonic-gate 
25430Sstevel@tonic-gate 	/* Update the in-kernel registration */
25440Sstevel@tonic-gate 	(void) update_kernel_registration(shp, PUBLISHER,
25450Sstevel@tonic-gate 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
25460Sstevel@tonic-gate 	SH_BOUND(shp) = 0;
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	/* Free resources associated with bind */
25490Sstevel@tonic-gate 	free_cached_registration(shp);
25500Sstevel@tonic-gate 	dealloc_subscribers(shp);
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate 	free(SH_PRIV_DATA(shp));
25530Sstevel@tonic-gate 	free(SH_DOOR_NAME(shp));
25540Sstevel@tonic-gate 	SH_ID(shp) = 0;
25550Sstevel@tonic-gate 	(void) mutex_unlock(SH_LOCK(shp));
25560Sstevel@tonic-gate }
25570Sstevel@tonic-gate 
25580Sstevel@tonic-gate /*
25590Sstevel@tonic-gate  * Evolving APIs to subscribe to syseventd(1M) system events.
25600Sstevel@tonic-gate  */
25610Sstevel@tonic-gate 
2562*12967Sgavin.maltby@oracle.com static sysevent_handle_t *
sysevent_bind_handle_cmn(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2563*12967Sgavin.maltby@oracle.com sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2564*12967Sgavin.maltby@oracle.com     sysevent_subattr_t *subattr)
25650Sstevel@tonic-gate {
25660Sstevel@tonic-gate 	sysevent_handle_t *shp;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	if (getuid() != 0) {
25690Sstevel@tonic-gate 		errno = EACCES;
25700Sstevel@tonic-gate 		return (NULL);
25710Sstevel@tonic-gate 	}
25720Sstevel@tonic-gate 
25730Sstevel@tonic-gate 	if (event_handler == NULL) {
25740Sstevel@tonic-gate 		errno = EINVAL;
25750Sstevel@tonic-gate 		return (NULL);
25760Sstevel@tonic-gate 	}
25770Sstevel@tonic-gate 
25780Sstevel@tonic-gate 	if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
25790Sstevel@tonic-gate 		return (NULL);
25800Sstevel@tonic-gate 	}
25810Sstevel@tonic-gate 
2582*12967Sgavin.maltby@oracle.com 	if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
25830Sstevel@tonic-gate 		/*
25840Sstevel@tonic-gate 		 * Ask syseventd to clean-up any stale subcribers and try to
25850Sstevel@tonic-gate 		 * to bind again
25860Sstevel@tonic-gate 		 */
25870Sstevel@tonic-gate 		if (errno == EBUSY) {
25880Sstevel@tonic-gate 			int pub_fd;
25890Sstevel@tonic-gate 			char door_name[MAXPATHLEN];
25900Sstevel@tonic-gate 			uint32_t result;
25910Sstevel@tonic-gate 			struct reg_args rargs;
25920Sstevel@tonic-gate 
25930Sstevel@tonic-gate 			if (snprintf(door_name, MAXPATHLEN, "%s/%s",
25940Sstevel@tonic-gate 			    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
25950Sstevel@tonic-gate 				sysevent_close_channel(shp);
25960Sstevel@tonic-gate 				errno = EINVAL;
25970Sstevel@tonic-gate 				return (NULL);
25980Sstevel@tonic-gate 			}
25990Sstevel@tonic-gate 
26000Sstevel@tonic-gate 			rargs.ra_op = SE_CLEANUP;
26010Sstevel@tonic-gate 			pub_fd = open(door_name, O_RDONLY);
26020Sstevel@tonic-gate 			(void) clnt_deliver_event(pub_fd, (void *)&rargs,
26030Sstevel@tonic-gate 			    sizeof (struct reg_args), &result, sizeof (result));
26040Sstevel@tonic-gate 			(void) close(pub_fd);
26050Sstevel@tonic-gate 
26060Sstevel@tonic-gate 			/* Try to bind again */
2607*12967Sgavin.maltby@oracle.com 			if (sysevent_bind_xsubscriber(shp, event_handler,
2608*12967Sgavin.maltby@oracle.com 			    subattr) != 0) {
26090Sstevel@tonic-gate 				sysevent_close_channel(shp);
26100Sstevel@tonic-gate 				return (NULL);
26110Sstevel@tonic-gate 			}
26120Sstevel@tonic-gate 		} else {
26130Sstevel@tonic-gate 			sysevent_close_channel(shp);
26140Sstevel@tonic-gate 			return (NULL);
26150Sstevel@tonic-gate 		}
26160Sstevel@tonic-gate 	}
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate 	return (shp);
26190Sstevel@tonic-gate }
26200Sstevel@tonic-gate 
26210Sstevel@tonic-gate /*
2622*12967Sgavin.maltby@oracle.com  * sysevent_bind_handle - Bind application event handler for syseventd
2623*12967Sgavin.maltby@oracle.com  *		subscription.
2624*12967Sgavin.maltby@oracle.com  */
2625*12967Sgavin.maltby@oracle.com sysevent_handle_t *
sysevent_bind_handle(void (* event_handler)(sysevent_t * ev))2626*12967Sgavin.maltby@oracle.com sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2627*12967Sgavin.maltby@oracle.com {
2628*12967Sgavin.maltby@oracle.com 	return (sysevent_bind_handle_cmn(event_handler, NULL));
2629*12967Sgavin.maltby@oracle.com }
2630*12967Sgavin.maltby@oracle.com 
2631*12967Sgavin.maltby@oracle.com /*
2632*12967Sgavin.maltby@oracle.com  * sysevent_bind_xhandle - Bind application event handler for syseventd
2633*12967Sgavin.maltby@oracle.com  *		subscription, using door_xcreate and attributes as specified.
2634*12967Sgavin.maltby@oracle.com  */
2635*12967Sgavin.maltby@oracle.com sysevent_handle_t *
sysevent_bind_xhandle(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2636*12967Sgavin.maltby@oracle.com sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2637*12967Sgavin.maltby@oracle.com     sysevent_subattr_t *subattr)
2638*12967Sgavin.maltby@oracle.com {
2639*12967Sgavin.maltby@oracle.com 	return (sysevent_bind_handle_cmn(event_handler, subattr));
2640*12967Sgavin.maltby@oracle.com }
2641*12967Sgavin.maltby@oracle.com 
2642*12967Sgavin.maltby@oracle.com /*
26430Sstevel@tonic-gate  * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
26440Sstevel@tonic-gate  */
26450Sstevel@tonic-gate void
sysevent_unbind_handle(sysevent_handle_t * shp)26460Sstevel@tonic-gate sysevent_unbind_handle(sysevent_handle_t *shp)
26470Sstevel@tonic-gate {
26480Sstevel@tonic-gate 	sysevent_unbind_subscriber(shp);
26490Sstevel@tonic-gate 	sysevent_close_channel(shp);
26500Sstevel@tonic-gate }
26510Sstevel@tonic-gate 
26520Sstevel@tonic-gate /*
26530Sstevel@tonic-gate  * sysevent_subscribe_event - Subscribe to system event notification from
26540Sstevel@tonic-gate  *			syseventd(1M) for the class and subclasses specified.
26550Sstevel@tonic-gate  */
26560Sstevel@tonic-gate int
sysevent_subscribe_event(sysevent_handle_t * shp,const char * event_class,const char ** event_subclass_list,int num_subclasses)26570Sstevel@tonic-gate sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
26580Sstevel@tonic-gate 	const char **event_subclass_list, int num_subclasses)
26590Sstevel@tonic-gate {
26600Sstevel@tonic-gate 	return (sysevent_register_event(shp, event_class,
26610Sstevel@tonic-gate 	    event_subclass_list, num_subclasses));
26620Sstevel@tonic-gate }
26630Sstevel@tonic-gate 
26640Sstevel@tonic-gate void
sysevent_unsubscribe_event(sysevent_handle_t * shp,const char * event_class)26650Sstevel@tonic-gate sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
26660Sstevel@tonic-gate {
26670Sstevel@tonic-gate 	sysevent_unregister_event(shp, event_class);
26680Sstevel@tonic-gate }
2669