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), ®_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