1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 31*7c478bd9Sstevel@tonic-gate #include <errno.h> 32*7c478bd9Sstevel@tonic-gate #include <door.h> 33*7c478bd9Sstevel@tonic-gate #include <unistd.h> 34*7c478bd9Sstevel@tonic-gate #include <stddef.h> 35*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 36*7c478bd9Sstevel@tonic-gate #include <string.h> 37*7c478bd9Sstevel@tonic-gate #include <strings.h> 38*7c478bd9Sstevel@tonic-gate #include <synch.h> 39*7c478bd9Sstevel@tonic-gate #include <pthread.h> 40*7c478bd9Sstevel@tonic-gate #include <thread.h> 41*7c478bd9Sstevel@tonic-gate #include <libnvpair.h> 42*7c478bd9Sstevel@tonic-gate #include <assert.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 45*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 46*7c478bd9Sstevel@tonic-gate #include <sys/mnttab.h> 47*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 48*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 49*7c478bd9Sstevel@tonic-gate 50*7c478bd9Sstevel@tonic-gate #include "libsysevent.h" 51*7c478bd9Sstevel@tonic-gate #include "libsysevent_impl.h" 52*7c478bd9Sstevel@tonic-gate 53*7c478bd9Sstevel@tonic-gate /* 54*7c478bd9Sstevel@tonic-gate * libsysevent - The system event framework library 55*7c478bd9Sstevel@tonic-gate * 56*7c478bd9Sstevel@tonic-gate * This library provides routines to help with marshalling 57*7c478bd9Sstevel@tonic-gate * and unmarshalling of data contained in a sysevent event 58*7c478bd9Sstevel@tonic-gate * buffer. 59*7c478bd9Sstevel@tonic-gate */ 60*7c478bd9Sstevel@tonic-gate 61*7c478bd9Sstevel@tonic-gate #define SE_ENCODE_METHOD NV_ENCODE_NATIVE 62*7c478bd9Sstevel@tonic-gate 63*7c478bd9Sstevel@tonic-gate #define dprint if (libsysevent_debug) (void) printf 64*7c478bd9Sstevel@tonic-gate static int libsysevent_debug = 0; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate static sysevent_t *se_unpack(sysevent_t *); 67*7c478bd9Sstevel@tonic-gate static int cleanup_id(sysevent_handle_t *shp, uint32_t id, int type); 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate * The following routines allow system event publication to the sysevent 71*7c478bd9Sstevel@tonic-gate * framework. 72*7c478bd9Sstevel@tonic-gate */ 73*7c478bd9Sstevel@tonic-gate 74*7c478bd9Sstevel@tonic-gate /* 75*7c478bd9Sstevel@tonic-gate * sysevent_alloc - allocate a sysevent buffer 76*7c478bd9Sstevel@tonic-gate */ 77*7c478bd9Sstevel@tonic-gate static sysevent_t * 78*7c478bd9Sstevel@tonic-gate sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz, 79*7c478bd9Sstevel@tonic-gate char *pub, int pub_sz, nvlist_t *attr_list) 80*7c478bd9Sstevel@tonic-gate { 81*7c478bd9Sstevel@tonic-gate int payload_sz; 82*7c478bd9Sstevel@tonic-gate int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz; 83*7c478bd9Sstevel@tonic-gate size_t nvlist_sz = 0; 84*7c478bd9Sstevel@tonic-gate char *attr; 85*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 86*7c478bd9Sstevel@tonic-gate sysevent_t *ev; 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate if (attr_list != NULL) { 89*7c478bd9Sstevel@tonic-gate if (nvlist_size(attr_list, &nvlist_sz, SE_ENCODE_METHOD) 90*7c478bd9Sstevel@tonic-gate != 0) { 91*7c478bd9Sstevel@tonic-gate return (NULL); 92*7c478bd9Sstevel@tonic-gate } 93*7c478bd9Sstevel@tonic-gate } 94*7c478bd9Sstevel@tonic-gate 95*7c478bd9Sstevel@tonic-gate /* 96*7c478bd9Sstevel@tonic-gate * Calculate and reserve space for the class, subclass and 97*7c478bd9Sstevel@tonic-gate * publisher strings in the event buffer 98*7c478bd9Sstevel@tonic-gate */ 99*7c478bd9Sstevel@tonic-gate 100*7c478bd9Sstevel@tonic-gate /* String sizes must be 64-bit aligned in the event buffer */ 101*7c478bd9Sstevel@tonic-gate aligned_class_sz = SE_ALIGN(class_sz); 102*7c478bd9Sstevel@tonic-gate aligned_subclass_sz = SE_ALIGN(subclass_sz); 103*7c478bd9Sstevel@tonic-gate aligned_pub_sz = SE_ALIGN(pub_sz); 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate payload_sz = (aligned_class_sz - sizeof (uint64_t)) + 106*7c478bd9Sstevel@tonic-gate (aligned_subclass_sz - sizeof (uint64_t)) + 107*7c478bd9Sstevel@tonic-gate (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) + 108*7c478bd9Sstevel@tonic-gate nvlist_sz; 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* 111*7c478bd9Sstevel@tonic-gate * Allocate event buffer plus additional payload overhead. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate ev = calloc(1, sizeof (sysevent_impl_t) + payload_sz); 114*7c478bd9Sstevel@tonic-gate if (ev == NULL) { 115*7c478bd9Sstevel@tonic-gate return (NULL); 116*7c478bd9Sstevel@tonic-gate } 117*7c478bd9Sstevel@tonic-gate 118*7c478bd9Sstevel@tonic-gate /* Initialize the event buffer data */ 119*7c478bd9Sstevel@tonic-gate SE_VERSION(ev) = SYS_EVENT_VERSION; 120*7c478bd9Sstevel@tonic-gate (void) bcopy(class, SE_CLASS_NAME(ev), class_sz); 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name)) 123*7c478bd9Sstevel@tonic-gate + aligned_class_sz; 124*7c478bd9Sstevel@tonic-gate (void) bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz); 125*7c478bd9Sstevel@tonic-gate 126*7c478bd9Sstevel@tonic-gate SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz; 127*7c478bd9Sstevel@tonic-gate (void) bcopy(pub, SE_PUB_NAME(ev), pub_sz); 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate SE_PAYLOAD_SZ(ev) = payload_sz; 130*7c478bd9Sstevel@tonic-gate SE_ATTR_PTR(ev) = (uint64_t)0; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* Check for attribute list */ 133*7c478bd9Sstevel@tonic-gate if (attr_list == NULL) { 134*7c478bd9Sstevel@tonic-gate return (ev); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate /* Copy attribute data to contiguous memory */ 138*7c478bd9Sstevel@tonic-gate SE_FLAG(ev) = SE_PACKED_BUF; 139*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 140*7c478bd9Sstevel@tonic-gate attr = (char *)((caddr_t)ev + attr_offset); 141*7c478bd9Sstevel@tonic-gate if (nvlist_pack(attr_list, &attr, &nvlist_sz, SE_ENCODE_METHOD, 142*7c478bd9Sstevel@tonic-gate 0) != 0) { 143*7c478bd9Sstevel@tonic-gate free(ev); 144*7c478bd9Sstevel@tonic-gate return (NULL); 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate return (ev); 148*7c478bd9Sstevel@tonic-gate } 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate /* 151*7c478bd9Sstevel@tonic-gate * sysevent_post_event - generate a system event via the sysevent framework 152*7c478bd9Sstevel@tonic-gate */ 153*7c478bd9Sstevel@tonic-gate int 154*7c478bd9Sstevel@tonic-gate sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name, 155*7c478bd9Sstevel@tonic-gate nvlist_t *attr_list, sysevent_id_t *eid) 156*7c478bd9Sstevel@tonic-gate { 157*7c478bd9Sstevel@tonic-gate int error; 158*7c478bd9Sstevel@tonic-gate sysevent_t *ev; 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate ev = sysevent_alloc_event(class, subclass, vendor, pub_name, attr_list); 161*7c478bd9Sstevel@tonic-gate if (ev == NULL) { 162*7c478bd9Sstevel@tonic-gate return (-1); 163*7c478bd9Sstevel@tonic-gate } 164*7c478bd9Sstevel@tonic-gate 165*7c478bd9Sstevel@tonic-gate error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT, 166*7c478bd9Sstevel@tonic-gate (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), 167*7c478bd9Sstevel@tonic-gate (uintptr_t)eid, 0); 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate sysevent_free(ev); 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate if (error) { 172*7c478bd9Sstevel@tonic-gate errno = EIO; 173*7c478bd9Sstevel@tonic-gate return (-1); 174*7c478bd9Sstevel@tonic-gate } 175*7c478bd9Sstevel@tonic-gate 176*7c478bd9Sstevel@tonic-gate return (0); 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate /* 180*7c478bd9Sstevel@tonic-gate * The following routines are used to free or duplicate a 181*7c478bd9Sstevel@tonic-gate * sysevent event buffer. 182*7c478bd9Sstevel@tonic-gate */ 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate * sysevent_dup - Allocate and copy an event buffer 186*7c478bd9Sstevel@tonic-gate * Copies both packed and unpacked to unpacked sysevent. 187*7c478bd9Sstevel@tonic-gate */ 188*7c478bd9Sstevel@tonic-gate sysevent_t * 189*7c478bd9Sstevel@tonic-gate sysevent_dup(sysevent_t *ev) 190*7c478bd9Sstevel@tonic-gate { 191*7c478bd9Sstevel@tonic-gate nvlist_t *nvl, *cnvl = NULL; 192*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 193*7c478bd9Sstevel@tonic-gate sysevent_t *copy; 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate if (SE_FLAG(ev) == SE_PACKED_BUF) 196*7c478bd9Sstevel@tonic-gate return (se_unpack(ev)); 197*7c478bd9Sstevel@tonic-gate 198*7c478bd9Sstevel@tonic-gate /* Copy event header information */ 199*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 200*7c478bd9Sstevel@tonic-gate copy = calloc(1, attr_offset); 201*7c478bd9Sstevel@tonic-gate if (copy == NULL) 202*7c478bd9Sstevel@tonic-gate return (NULL); 203*7c478bd9Sstevel@tonic-gate bcopy(ev, copy, attr_offset); 204*7c478bd9Sstevel@tonic-gate 205*7c478bd9Sstevel@tonic-gate nvl = (nvlist_t *)SE_ATTR_PTR(ev); 206*7c478bd9Sstevel@tonic-gate if (nvl && nvlist_dup(nvl, &cnvl, 0) != 0) { 207*7c478bd9Sstevel@tonic-gate free(copy); 208*7c478bd9Sstevel@tonic-gate return (NULL); 209*7c478bd9Sstevel@tonic-gate } 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate SE_ATTR_PTR(copy) = (uintptr_t)cnvl; 212*7c478bd9Sstevel@tonic-gate SE_FLAG(copy) = 0; /* unpacked */ 213*7c478bd9Sstevel@tonic-gate return (copy); 214*7c478bd9Sstevel@tonic-gate } 215*7c478bd9Sstevel@tonic-gate 216*7c478bd9Sstevel@tonic-gate /* 217*7c478bd9Sstevel@tonic-gate * sysevent_free - Free memory allocated for an event buffer 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate void 220*7c478bd9Sstevel@tonic-gate sysevent_free(sysevent_t *ev) 221*7c478bd9Sstevel@tonic-gate { 222*7c478bd9Sstevel@tonic-gate nvlist_t *attr_list = (nvlist_t *)SE_ATTR_PTR(ev); 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate if (attr_list) 225*7c478bd9Sstevel@tonic-gate nvlist_free(attr_list); 226*7c478bd9Sstevel@tonic-gate free(ev); 227*7c478bd9Sstevel@tonic-gate } 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate /* 230*7c478bd9Sstevel@tonic-gate * The following routines are used to extract attribute data from a sysevent 231*7c478bd9Sstevel@tonic-gate * handle. 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * sysevent_get_attr_list - allocate and return an attribute associated with 236*7c478bd9Sstevel@tonic-gate * the given sysevent buffer. 237*7c478bd9Sstevel@tonic-gate */ 238*7c478bd9Sstevel@tonic-gate int 239*7c478bd9Sstevel@tonic-gate sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist) 240*7c478bd9Sstevel@tonic-gate { 241*7c478bd9Sstevel@tonic-gate int error; 242*7c478bd9Sstevel@tonic-gate caddr_t attr; 243*7c478bd9Sstevel@tonic-gate size_t attr_len; 244*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 245*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate *nvlist = NULL; 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* Duplicate attribute for an unpacked sysevent buffer */ 250*7c478bd9Sstevel@tonic-gate if (SE_FLAG(ev) != SE_PACKED_BUF) { 251*7c478bd9Sstevel@tonic-gate nvl = (nvlist_t *)SE_ATTR_PTR(ev); 252*7c478bd9Sstevel@tonic-gate if (nvl == NULL) { 253*7c478bd9Sstevel@tonic-gate return (0); 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) { 256*7c478bd9Sstevel@tonic-gate if (error == ENOMEM) { 257*7c478bd9Sstevel@tonic-gate errno = error; 258*7c478bd9Sstevel@tonic-gate } else { 259*7c478bd9Sstevel@tonic-gate errno = EINVAL; 260*7c478bd9Sstevel@tonic-gate } 261*7c478bd9Sstevel@tonic-gate return (-1); 262*7c478bd9Sstevel@tonic-gate } 263*7c478bd9Sstevel@tonic-gate return (0); 264*7c478bd9Sstevel@tonic-gate } 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 267*7c478bd9Sstevel@tonic-gate if (SE_SIZE(ev) == attr_offset) { 268*7c478bd9Sstevel@tonic-gate return (0); 269*7c478bd9Sstevel@tonic-gate } 270*7c478bd9Sstevel@tonic-gate 271*7c478bd9Sstevel@tonic-gate /* unpack nvlist */ 272*7c478bd9Sstevel@tonic-gate attr = (caddr_t)ev + attr_offset; 273*7c478bd9Sstevel@tonic-gate attr_len = SE_SIZE(ev) - attr_offset; 274*7c478bd9Sstevel@tonic-gate if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) { 275*7c478bd9Sstevel@tonic-gate if (error == ENOMEM) { 276*7c478bd9Sstevel@tonic-gate errno = error; 277*7c478bd9Sstevel@tonic-gate } else { 278*7c478bd9Sstevel@tonic-gate errno = EINVAL; 279*7c478bd9Sstevel@tonic-gate } 280*7c478bd9Sstevel@tonic-gate return (-1); 281*7c478bd9Sstevel@tonic-gate } 282*7c478bd9Sstevel@tonic-gate 283*7c478bd9Sstevel@tonic-gate return (0); 284*7c478bd9Sstevel@tonic-gate } 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate /* 287*7c478bd9Sstevel@tonic-gate * sysevent_attr_name - Get name of attribute 288*7c478bd9Sstevel@tonic-gate */ 289*7c478bd9Sstevel@tonic-gate char * 290*7c478bd9Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr) 291*7c478bd9Sstevel@tonic-gate { 292*7c478bd9Sstevel@tonic-gate if (attr == NULL) { 293*7c478bd9Sstevel@tonic-gate errno = EINVAL; 294*7c478bd9Sstevel@tonic-gate return (NULL); 295*7c478bd9Sstevel@tonic-gate } 296*7c478bd9Sstevel@tonic-gate return (nvpair_name((nvpair_t *)attr)); 297*7c478bd9Sstevel@tonic-gate } 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate /* 300*7c478bd9Sstevel@tonic-gate * sysevent_attr_value - Get attribute value data and type 301*7c478bd9Sstevel@tonic-gate */ 302*7c478bd9Sstevel@tonic-gate int 303*7c478bd9Sstevel@tonic-gate sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value) 304*7c478bd9Sstevel@tonic-gate { 305*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = attr; 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate if (nvp == NULL) 308*7c478bd9Sstevel@tonic-gate return (EINVAL); 309*7c478bd9Sstevel@tonic-gate 310*7c478bd9Sstevel@tonic-gate /* Convert DATA_TYPE_* to SE_DATA_TYPE_* */ 311*7c478bd9Sstevel@tonic-gate switch (nvpair_type(nvp)) { 312*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE: 313*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_BYTE; 314*7c478bd9Sstevel@tonic-gate (void) nvpair_value_byte(nvp, &se_value->value.sv_byte); 315*7c478bd9Sstevel@tonic-gate break; 316*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT16: 317*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_INT16; 318*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int16(nvp, &se_value->value.sv_int16); 319*7c478bd9Sstevel@tonic-gate break; 320*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT16: 321*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_UINT16; 322*7c478bd9Sstevel@tonic-gate (void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16); 323*7c478bd9Sstevel@tonic-gate break; 324*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT32: 325*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_INT32; 326*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int32(nvp, &se_value->value.sv_int32); 327*7c478bd9Sstevel@tonic-gate break; 328*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT32: 329*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_UINT32; 330*7c478bd9Sstevel@tonic-gate (void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32); 331*7c478bd9Sstevel@tonic-gate break; 332*7c478bd9Sstevel@tonic-gate case DATA_TYPE_INT64: 333*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_INT64; 334*7c478bd9Sstevel@tonic-gate (void) nvpair_value_int64(nvp, &se_value->value.sv_int64); 335*7c478bd9Sstevel@tonic-gate break; 336*7c478bd9Sstevel@tonic-gate case DATA_TYPE_UINT64: 337*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_UINT64; 338*7c478bd9Sstevel@tonic-gate (void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64); 339*7c478bd9Sstevel@tonic-gate break; 340*7c478bd9Sstevel@tonic-gate case DATA_TYPE_STRING: 341*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_STRING; 342*7c478bd9Sstevel@tonic-gate (void) nvpair_value_string(nvp, &se_value->value.sv_string); 343*7c478bd9Sstevel@tonic-gate break; 344*7c478bd9Sstevel@tonic-gate case DATA_TYPE_BYTE_ARRAY: 345*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_BYTES; 346*7c478bd9Sstevel@tonic-gate (void) nvpair_value_byte_array(nvp, 347*7c478bd9Sstevel@tonic-gate &se_value->value.sv_bytes.data, 348*7c478bd9Sstevel@tonic-gate (uint_t *)&se_value->value.sv_bytes.size); 349*7c478bd9Sstevel@tonic-gate break; 350*7c478bd9Sstevel@tonic-gate case DATA_TYPE_HRTIME: 351*7c478bd9Sstevel@tonic-gate se_value->value_type = SE_DATA_TYPE_TIME; 352*7c478bd9Sstevel@tonic-gate (void) nvpair_value_hrtime(nvp, &se_value->value.sv_time); 353*7c478bd9Sstevel@tonic-gate break; 354*7c478bd9Sstevel@tonic-gate default: 355*7c478bd9Sstevel@tonic-gate return (ENOTSUP); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate return (0); 358*7c478bd9Sstevel@tonic-gate } 359*7c478bd9Sstevel@tonic-gate 360*7c478bd9Sstevel@tonic-gate /* 361*7c478bd9Sstevel@tonic-gate * sysevent_attr_next - Get next attribute in event attribute list 362*7c478bd9Sstevel@tonic-gate */ 363*7c478bd9Sstevel@tonic-gate sysevent_attr_t * 364*7c478bd9Sstevel@tonic-gate sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr) 365*7c478bd9Sstevel@tonic-gate { 366*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 367*7c478bd9Sstevel@tonic-gate nvpair_t *nvp = attr; 368*7c478bd9Sstevel@tonic-gate 369*7c478bd9Sstevel@tonic-gate /* all user visible sysevent_t's are unpacked */ 370*7c478bd9Sstevel@tonic-gate assert(SE_FLAG(ev) != SE_PACKED_BUF); 371*7c478bd9Sstevel@tonic-gate 372*7c478bd9Sstevel@tonic-gate if (SE_ATTR_PTR(ev) == (uint64_t)0) { 373*7c478bd9Sstevel@tonic-gate return (NULL); 374*7c478bd9Sstevel@tonic-gate } 375*7c478bd9Sstevel@tonic-gate 376*7c478bd9Sstevel@tonic-gate nvl = (nvlist_t *)SE_ATTR_PTR(ev); 377*7c478bd9Sstevel@tonic-gate return (nvlist_next_nvpair(nvl, nvp)); 378*7c478bd9Sstevel@tonic-gate } 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate /* 381*7c478bd9Sstevel@tonic-gate * sysevent_lookup_attr - Lookup attribute by name and datatype. 382*7c478bd9Sstevel@tonic-gate */ 383*7c478bd9Sstevel@tonic-gate int 384*7c478bd9Sstevel@tonic-gate sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype, 385*7c478bd9Sstevel@tonic-gate sysevent_value_t *se_value) 386*7c478bd9Sstevel@tonic-gate { 387*7c478bd9Sstevel@tonic-gate nvpair_t *nvp; 388*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 389*7c478bd9Sstevel@tonic-gate 390*7c478bd9Sstevel@tonic-gate assert(SE_FLAG(ev) != SE_PACKED_BUF); 391*7c478bd9Sstevel@tonic-gate 392*7c478bd9Sstevel@tonic-gate if (SE_ATTR_PTR(ev) == (uint64_t)0) { 393*7c478bd9Sstevel@tonic-gate return (ENOENT); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * sysevent matches on both name and datatype 398*7c478bd9Sstevel@tonic-gate * nvlist_look mataches name only. So we walk 399*7c478bd9Sstevel@tonic-gate * nvlist manually here. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate nvl = (nvlist_t *)SE_ATTR_PTR(ev); 402*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, NULL); 403*7c478bd9Sstevel@tonic-gate while (nvp) { 404*7c478bd9Sstevel@tonic-gate if ((strcmp(name, nvpair_name(nvp)) == 0) && 405*7c478bd9Sstevel@tonic-gate (sysevent_attr_value(nvp, se_value) == 0) && 406*7c478bd9Sstevel@tonic-gate (se_value->value_type == datatype)) 407*7c478bd9Sstevel@tonic-gate return (0); 408*7c478bd9Sstevel@tonic-gate nvp = nvlist_next_nvpair(nvl, nvp); 409*7c478bd9Sstevel@tonic-gate } 410*7c478bd9Sstevel@tonic-gate return (ENOENT); 411*7c478bd9Sstevel@tonic-gate } 412*7c478bd9Sstevel@tonic-gate 413*7c478bd9Sstevel@tonic-gate /* Routines to extract event header information */ 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate /* 416*7c478bd9Sstevel@tonic-gate * sysevent_get_class - Get class id 417*7c478bd9Sstevel@tonic-gate */ 418*7c478bd9Sstevel@tonic-gate int 419*7c478bd9Sstevel@tonic-gate sysevent_get_class(sysevent_t *ev) 420*7c478bd9Sstevel@tonic-gate { 421*7c478bd9Sstevel@tonic-gate return (SE_CLASS(ev)); 422*7c478bd9Sstevel@tonic-gate } 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* 425*7c478bd9Sstevel@tonic-gate * sysevent_get_subclass - Get subclass id 426*7c478bd9Sstevel@tonic-gate */ 427*7c478bd9Sstevel@tonic-gate int 428*7c478bd9Sstevel@tonic-gate sysevent_get_subclass(sysevent_t *ev) 429*7c478bd9Sstevel@tonic-gate { 430*7c478bd9Sstevel@tonic-gate return (SE_SUBCLASS(ev)); 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate /* 434*7c478bd9Sstevel@tonic-gate * sysevent_get_class_name - Get class name string 435*7c478bd9Sstevel@tonic-gate */ 436*7c478bd9Sstevel@tonic-gate char * 437*7c478bd9Sstevel@tonic-gate sysevent_get_class_name(sysevent_t *ev) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate return (SE_CLASS_NAME(ev)); 440*7c478bd9Sstevel@tonic-gate } 441*7c478bd9Sstevel@tonic-gate 442*7c478bd9Sstevel@tonic-gate typedef enum { 443*7c478bd9Sstevel@tonic-gate PUB_VEND, 444*7c478bd9Sstevel@tonic-gate PUB_KEYWD, 445*7c478bd9Sstevel@tonic-gate PUB_NAME, 446*7c478bd9Sstevel@tonic-gate PUB_PID 447*7c478bd9Sstevel@tonic-gate } se_pub_id_t; 448*7c478bd9Sstevel@tonic-gate 449*7c478bd9Sstevel@tonic-gate /* 450*7c478bd9Sstevel@tonic-gate * sysevent_get_pub - Get publisher name string 451*7c478bd9Sstevel@tonic-gate */ 452*7c478bd9Sstevel@tonic-gate char * 453*7c478bd9Sstevel@tonic-gate sysevent_get_pub(sysevent_t *ev) 454*7c478bd9Sstevel@tonic-gate { 455*7c478bd9Sstevel@tonic-gate return (SE_PUB_NAME(ev)); 456*7c478bd9Sstevel@tonic-gate } 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate /* 459*7c478bd9Sstevel@tonic-gate * Get the requested string pointed by the token. 460*7c478bd9Sstevel@tonic-gate * 461*7c478bd9Sstevel@tonic-gate * Return NULL if not found or for insufficient memory. 462*7c478bd9Sstevel@tonic-gate */ 463*7c478bd9Sstevel@tonic-gate static char * 464*7c478bd9Sstevel@tonic-gate parse_pub_id(sysevent_t *ev, se_pub_id_t token) 465*7c478bd9Sstevel@tonic-gate { 466*7c478bd9Sstevel@tonic-gate int i; 467*7c478bd9Sstevel@tonic-gate char *pub_id, *pub_element, *str, *next; 468*7c478bd9Sstevel@tonic-gate 469*7c478bd9Sstevel@tonic-gate next = pub_id = strdup(sysevent_get_pub(ev)); 470*7c478bd9Sstevel@tonic-gate for (i = 0; i <= token; ++i) { 471*7c478bd9Sstevel@tonic-gate str = strtok_r(next, ":", &next); 472*7c478bd9Sstevel@tonic-gate if (str == NULL) { 473*7c478bd9Sstevel@tonic-gate free(pub_id); 474*7c478bd9Sstevel@tonic-gate return (NULL); 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate } 477*7c478bd9Sstevel@tonic-gate 478*7c478bd9Sstevel@tonic-gate pub_element = strdup(str); 479*7c478bd9Sstevel@tonic-gate free(pub_id); 480*7c478bd9Sstevel@tonic-gate return (pub_element); 481*7c478bd9Sstevel@tonic-gate } 482*7c478bd9Sstevel@tonic-gate 483*7c478bd9Sstevel@tonic-gate /* 484*7c478bd9Sstevel@tonic-gate * Return a pointer to the string following the token 485*7c478bd9Sstevel@tonic-gate * 486*7c478bd9Sstevel@tonic-gate * Note: This is a dedicated function for parsing 487*7c478bd9Sstevel@tonic-gate * publisher strings and not for general purpose. 488*7c478bd9Sstevel@tonic-gate */ 489*7c478bd9Sstevel@tonic-gate static const char * 490*7c478bd9Sstevel@tonic-gate pub_idx(const char *pstr, int token) 491*7c478bd9Sstevel@tonic-gate { 492*7c478bd9Sstevel@tonic-gate int i; 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate for (i = 1; i <= token; i++) { 495*7c478bd9Sstevel@tonic-gate if ((pstr = index(pstr, ':')) == NULL) 496*7c478bd9Sstevel@tonic-gate return (NULL); 497*7c478bd9Sstevel@tonic-gate pstr++; 498*7c478bd9Sstevel@tonic-gate } 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate /* String might be empty */ 501*7c478bd9Sstevel@tonic-gate if (pstr) { 502*7c478bd9Sstevel@tonic-gate if (*pstr == '\0' || *pstr == ':') 503*7c478bd9Sstevel@tonic-gate return (NULL); 504*7c478bd9Sstevel@tonic-gate } 505*7c478bd9Sstevel@tonic-gate return (pstr); 506*7c478bd9Sstevel@tonic-gate } 507*7c478bd9Sstevel@tonic-gate 508*7c478bd9Sstevel@tonic-gate char * 509*7c478bd9Sstevel@tonic-gate sysevent_get_vendor_name(sysevent_t *ev) 510*7c478bd9Sstevel@tonic-gate { 511*7c478bd9Sstevel@tonic-gate return (parse_pub_id(ev, PUB_VEND)); 512*7c478bd9Sstevel@tonic-gate } 513*7c478bd9Sstevel@tonic-gate 514*7c478bd9Sstevel@tonic-gate char * 515*7c478bd9Sstevel@tonic-gate sysevent_get_pub_name(sysevent_t *ev) 516*7c478bd9Sstevel@tonic-gate { 517*7c478bd9Sstevel@tonic-gate return (parse_pub_id(ev, PUB_NAME)); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate /* 521*7c478bd9Sstevel@tonic-gate * Provide the pid encoded in the publisher string 522*7c478bd9Sstevel@tonic-gate * w/o allocating any resouces. 523*7c478bd9Sstevel@tonic-gate */ 524*7c478bd9Sstevel@tonic-gate void 525*7c478bd9Sstevel@tonic-gate sysevent_get_pid(sysevent_t *ev, pid_t *pid) 526*7c478bd9Sstevel@tonic-gate { 527*7c478bd9Sstevel@tonic-gate const char *part_str; 528*7c478bd9Sstevel@tonic-gate const char *pub_str = sysevent_get_pub(ev); 529*7c478bd9Sstevel@tonic-gate 530*7c478bd9Sstevel@tonic-gate *pid = (pid_t)SE_KERN_PID; 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate part_str = pub_idx(pub_str, PUB_KEYWD); 533*7c478bd9Sstevel@tonic-gate if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL) 534*7c478bd9Sstevel@tonic-gate return; 535*7c478bd9Sstevel@tonic-gate 536*7c478bd9Sstevel@tonic-gate if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL) 537*7c478bd9Sstevel@tonic-gate return; 538*7c478bd9Sstevel@tonic-gate 539*7c478bd9Sstevel@tonic-gate *pid = (pid_t)atoi(part_str); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate 542*7c478bd9Sstevel@tonic-gate /* 543*7c478bd9Sstevel@tonic-gate * sysevent_get_subclass_name - Get subclass name string 544*7c478bd9Sstevel@tonic-gate */ 545*7c478bd9Sstevel@tonic-gate char * 546*7c478bd9Sstevel@tonic-gate sysevent_get_subclass_name(sysevent_t *ev) 547*7c478bd9Sstevel@tonic-gate { 548*7c478bd9Sstevel@tonic-gate return (SE_SUBCLASS_NAME(ev)); 549*7c478bd9Sstevel@tonic-gate } 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* 552*7c478bd9Sstevel@tonic-gate * sysevent_get_seq - Get event sequence id 553*7c478bd9Sstevel@tonic-gate */ 554*7c478bd9Sstevel@tonic-gate uint64_t 555*7c478bd9Sstevel@tonic-gate sysevent_get_seq(sysevent_t *ev) 556*7c478bd9Sstevel@tonic-gate { 557*7c478bd9Sstevel@tonic-gate return (SE_SEQ(ev)); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* 561*7c478bd9Sstevel@tonic-gate * sysevent_get_time - Get event timestamp 562*7c478bd9Sstevel@tonic-gate */ 563*7c478bd9Sstevel@tonic-gate void 564*7c478bd9Sstevel@tonic-gate sysevent_get_time(sysevent_t *ev, hrtime_t *etime) 565*7c478bd9Sstevel@tonic-gate { 566*7c478bd9Sstevel@tonic-gate *etime = SE_TIME(ev); 567*7c478bd9Sstevel@tonic-gate } 568*7c478bd9Sstevel@tonic-gate 569*7c478bd9Sstevel@tonic-gate /* 570*7c478bd9Sstevel@tonic-gate * sysevent_get_size - Get event buffer size 571*7c478bd9Sstevel@tonic-gate */ 572*7c478bd9Sstevel@tonic-gate size_t 573*7c478bd9Sstevel@tonic-gate sysevent_get_size(sysevent_t *ev) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate return ((size_t)SE_SIZE(ev)); 576*7c478bd9Sstevel@tonic-gate } 577*7c478bd9Sstevel@tonic-gate 578*7c478bd9Sstevel@tonic-gate /* 579*7c478bd9Sstevel@tonic-gate * The following routines are used by devfsadm_mod.c to propagate event 580*7c478bd9Sstevel@tonic-gate * buffers to devfsadmd. These routines will serve as the basis for 581*7c478bd9Sstevel@tonic-gate * event channel publication and subscription. 582*7c478bd9Sstevel@tonic-gate */ 583*7c478bd9Sstevel@tonic-gate 584*7c478bd9Sstevel@tonic-gate /* 585*7c478bd9Sstevel@tonic-gate * sysevent_alloc_event - 586*7c478bd9Sstevel@tonic-gate * allocate a sysevent buffer for sending through an established event 587*7c478bd9Sstevel@tonic-gate * channel. 588*7c478bd9Sstevel@tonic-gate */ 589*7c478bd9Sstevel@tonic-gate sysevent_t * 590*7c478bd9Sstevel@tonic-gate sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name, 591*7c478bd9Sstevel@tonic-gate nvlist_t *attr_list) 592*7c478bd9Sstevel@tonic-gate { 593*7c478bd9Sstevel@tonic-gate int class_sz, subclass_sz, pub_sz; 594*7c478bd9Sstevel@tonic-gate char *pub_id; 595*7c478bd9Sstevel@tonic-gate sysevent_t *ev; 596*7c478bd9Sstevel@tonic-gate 597*7c478bd9Sstevel@tonic-gate if ((class == NULL) || (subclass == NULL) || (vendor == NULL) || 598*7c478bd9Sstevel@tonic-gate (pub_name == NULL)) { 599*7c478bd9Sstevel@tonic-gate errno = EINVAL; 600*7c478bd9Sstevel@tonic-gate return (NULL); 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate 603*7c478bd9Sstevel@tonic-gate class_sz = strlen(class) + 1; 604*7c478bd9Sstevel@tonic-gate subclass_sz = strlen(subclass) + 1; 605*7c478bd9Sstevel@tonic-gate if ((class_sz > MAX_CLASS_LEN) || 606*7c478bd9Sstevel@tonic-gate (subclass_sz > MAX_SUBCLASS_LEN)) { 607*7c478bd9Sstevel@tonic-gate errno = EINVAL; 608*7c478bd9Sstevel@tonic-gate return (NULL); 609*7c478bd9Sstevel@tonic-gate } 610*7c478bd9Sstevel@tonic-gate 611*7c478bd9Sstevel@tonic-gate /* 612*7c478bd9Sstevel@tonic-gate * Calculate the publisher size plus string seperators and maximum 613*7c478bd9Sstevel@tonic-gate * pid characters 614*7c478bd9Sstevel@tonic-gate */ 615*7c478bd9Sstevel@tonic-gate pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14; 616*7c478bd9Sstevel@tonic-gate if (pub_sz > MAX_PUB_LEN) { 617*7c478bd9Sstevel@tonic-gate errno = EINVAL; 618*7c478bd9Sstevel@tonic-gate return (NULL); 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate pub_id = malloc(pub_sz); 621*7c478bd9Sstevel@tonic-gate if (pub_id == NULL) { 622*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 623*7c478bd9Sstevel@tonic-gate return (NULL); 624*7c478bd9Sstevel@tonic-gate } 625*7c478bd9Sstevel@tonic-gate if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB, 626*7c478bd9Sstevel@tonic-gate pub_name, (int)getpid()) >= pub_sz) { 627*7c478bd9Sstevel@tonic-gate free(pub_id); 628*7c478bd9Sstevel@tonic-gate errno = EINVAL; 629*7c478bd9Sstevel@tonic-gate return (NULL); 630*7c478bd9Sstevel@tonic-gate } 631*7c478bd9Sstevel@tonic-gate pub_sz = strlen(pub_id) + 1; 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate ev = sysevent_alloc(class, class_sz, subclass, subclass_sz, 634*7c478bd9Sstevel@tonic-gate pub_id, pub_sz, attr_list); 635*7c478bd9Sstevel@tonic-gate free(pub_id); 636*7c478bd9Sstevel@tonic-gate if (ev == NULL) { 637*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 638*7c478bd9Sstevel@tonic-gate return (NULL); 639*7c478bd9Sstevel@tonic-gate } 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate return (ev); 642*7c478bd9Sstevel@tonic-gate } 643*7c478bd9Sstevel@tonic-gate 644*7c478bd9Sstevel@tonic-gate /* 645*7c478bd9Sstevel@tonic-gate * se_unpack - unpack nvlist to a searchable list. 646*7c478bd9Sstevel@tonic-gate * If already unpacked, will do a dup. 647*7c478bd9Sstevel@tonic-gate */ 648*7c478bd9Sstevel@tonic-gate static sysevent_t * 649*7c478bd9Sstevel@tonic-gate se_unpack(sysevent_t *ev) 650*7c478bd9Sstevel@tonic-gate { 651*7c478bd9Sstevel@tonic-gate caddr_t attr; 652*7c478bd9Sstevel@tonic-gate size_t attr_len; 653*7c478bd9Sstevel@tonic-gate nvlist_t *attrp = NULL; 654*7c478bd9Sstevel@tonic-gate uint64_t attr_offset; 655*7c478bd9Sstevel@tonic-gate sysevent_t *copy; 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate assert(SE_FLAG(ev) == SE_PACKED_BUF); 658*7c478bd9Sstevel@tonic-gate 659*7c478bd9Sstevel@tonic-gate /* Copy event header information */ 660*7c478bd9Sstevel@tonic-gate attr_offset = SE_ATTR_OFF(ev); 661*7c478bd9Sstevel@tonic-gate copy = calloc(1, attr_offset); 662*7c478bd9Sstevel@tonic-gate if (copy == NULL) 663*7c478bd9Sstevel@tonic-gate return (NULL); 664*7c478bd9Sstevel@tonic-gate bcopy(ev, copy, attr_offset); 665*7c478bd9Sstevel@tonic-gate SE_FLAG(copy) = 0; /* unpacked */ 666*7c478bd9Sstevel@tonic-gate 667*7c478bd9Sstevel@tonic-gate /* unpack nvlist */ 668*7c478bd9Sstevel@tonic-gate attr = (caddr_t)ev + attr_offset; 669*7c478bd9Sstevel@tonic-gate attr_len = SE_SIZE(ev) - attr_offset; 670*7c478bd9Sstevel@tonic-gate if (attr_len == 0) { 671*7c478bd9Sstevel@tonic-gate return (copy); 672*7c478bd9Sstevel@tonic-gate } 673*7c478bd9Sstevel@tonic-gate if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) { 674*7c478bd9Sstevel@tonic-gate free(copy); 675*7c478bd9Sstevel@tonic-gate return (NULL); 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate 678*7c478bd9Sstevel@tonic-gate SE_ATTR_PTR(copy) = (uintptr_t)attrp; 679*7c478bd9Sstevel@tonic-gate return (copy); 680*7c478bd9Sstevel@tonic-gate } 681*7c478bd9Sstevel@tonic-gate 682*7c478bd9Sstevel@tonic-gate /* 683*7c478bd9Sstevel@tonic-gate * se_print - Prints elements in an event buffer 684*7c478bd9Sstevel@tonic-gate */ 685*7c478bd9Sstevel@tonic-gate void 686*7c478bd9Sstevel@tonic-gate se_print(FILE *fp, sysevent_t *ev) 687*7c478bd9Sstevel@tonic-gate { 688*7c478bd9Sstevel@tonic-gate char *vendor, *pub; 689*7c478bd9Sstevel@tonic-gate pid_t pid; 690*7c478bd9Sstevel@tonic-gate hrtime_t hrt; 691*7c478bd9Sstevel@tonic-gate nvlist_t *attr_list = NULL; 692*7c478bd9Sstevel@tonic-gate 693*7c478bd9Sstevel@tonic-gate (void) sysevent_get_time(ev, &hrt); 694*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n", 695*7c478bd9Sstevel@tonic-gate hrt, (longlong_t)sysevent_get_seq(ev)); 696*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev)); 697*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev)); 698*7c478bd9Sstevel@tonic-gate if ((vendor = sysevent_get_vendor_name(ev)) != NULL) { 699*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\tvendor = %s\n", vendor); 700*7c478bd9Sstevel@tonic-gate free(vendor); 701*7c478bd9Sstevel@tonic-gate } 702*7c478bd9Sstevel@tonic-gate if ((pub = sysevent_get_pub_name(ev)) != NULL) { 703*7c478bd9Sstevel@tonic-gate sysevent_get_pid(ev, &pid); 704*7c478bd9Sstevel@tonic-gate (void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid); 705*7c478bd9Sstevel@tonic-gate free(pub); 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) { 709*7c478bd9Sstevel@tonic-gate nvlist_print(fp, attr_list); 710*7c478bd9Sstevel@tonic-gate nvlist_free(attr_list); 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate 714*7c478bd9Sstevel@tonic-gate /* 715*7c478bd9Sstevel@tonic-gate * The following routines are provided to support establishment and use 716*7c478bd9Sstevel@tonic-gate * of sysevent channels. A sysevent channel is established between 717*7c478bd9Sstevel@tonic-gate * publishers and subscribers of sysevents for an agreed upon channel name. 718*7c478bd9Sstevel@tonic-gate * These routines currently support sysevent channels between user-level 719*7c478bd9Sstevel@tonic-gate * applications running on the same system. 720*7c478bd9Sstevel@tonic-gate * 721*7c478bd9Sstevel@tonic-gate * Sysevent channels may be created by a single publisher or subscriber process. 722*7c478bd9Sstevel@tonic-gate * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in 723*7c478bd9Sstevel@tonic-gate * receiving sysevent notifications on the named channel. At present, only 724*7c478bd9Sstevel@tonic-gate * one publisher is allowed per sysevent channel. 725*7c478bd9Sstevel@tonic-gate * 726*7c478bd9Sstevel@tonic-gate * The registration information for each channel is kept in the kernel. A 727*7c478bd9Sstevel@tonic-gate * kernel-based registration was chosen for persistence and reliability reasons. 728*7c478bd9Sstevel@tonic-gate * If either a publisher or a subscriber exits for any reason, the channel 729*7c478bd9Sstevel@tonic-gate * properties are maintained until all publishers and subscribers have exited. 730*7c478bd9Sstevel@tonic-gate * Additionally, an in-kernel registration allows the API to be extended to 731*7c478bd9Sstevel@tonic-gate * include kernel subscribers as well as userland subscribers in the future. 732*7c478bd9Sstevel@tonic-gate * 733*7c478bd9Sstevel@tonic-gate * To insure fast lookup of subscriptions, a cached copy of the registration 734*7c478bd9Sstevel@tonic-gate * is kept and maintained for the publisher process. Updates are made 735*7c478bd9Sstevel@tonic-gate * everytime a change is made in the kernel. Changes to the registration are 736*7c478bd9Sstevel@tonic-gate * expected to be infrequent. 737*7c478bd9Sstevel@tonic-gate * 738*7c478bd9Sstevel@tonic-gate * Channel communication between publisher and subscriber processes is 739*7c478bd9Sstevel@tonic-gate * implemented primarily via doors. Each publisher creates a door for 740*7c478bd9Sstevel@tonic-gate * registration notifications and each subscriber creates a door for event 741*7c478bd9Sstevel@tonic-gate * delivery. 742*7c478bd9Sstevel@tonic-gate * 743*7c478bd9Sstevel@tonic-gate * Most of these routines are used by syseventd(1M), the sysevent publisher 744*7c478bd9Sstevel@tonic-gate * for the syseventd channel. Processes wishing to receive sysevent 745*7c478bd9Sstevel@tonic-gate * notifications from syseventd may use a set of public 746*7c478bd9Sstevel@tonic-gate * APIs designed to subscribe to syseventd sysevents. The subscription 747*7c478bd9Sstevel@tonic-gate * APIs are implemented in accordance with PSARC/2001/076. 748*7c478bd9Sstevel@tonic-gate * 749*7c478bd9Sstevel@tonic-gate */ 750*7c478bd9Sstevel@tonic-gate 751*7c478bd9Sstevel@tonic-gate /* 752*7c478bd9Sstevel@tonic-gate * Door handlers for the channel subscribers 753*7c478bd9Sstevel@tonic-gate */ 754*7c478bd9Sstevel@tonic-gate 755*7c478bd9Sstevel@tonic-gate /* 756*7c478bd9Sstevel@tonic-gate * subscriber_event_handler - generic event handling wrapper for subscribers 757*7c478bd9Sstevel@tonic-gate * This handler is used to process incoming sysevent 758*7c478bd9Sstevel@tonic-gate * notifications from channel publishers. 759*7c478bd9Sstevel@tonic-gate * It is created as a seperate thread in each subscriber 760*7c478bd9Sstevel@tonic-gate * process per subscription. 761*7c478bd9Sstevel@tonic-gate */ 762*7c478bd9Sstevel@tonic-gate static void 763*7c478bd9Sstevel@tonic-gate subscriber_event_handler(sysevent_handle_t *shp) 764*7c478bd9Sstevel@tonic-gate { 765*7c478bd9Sstevel@tonic-gate subscriber_priv_t *sub_info; 766*7c478bd9Sstevel@tonic-gate sysevent_queue_t *evqp; 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 769*7c478bd9Sstevel@tonic-gate 770*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&sub_info->sp_qlock); 771*7c478bd9Sstevel@tonic-gate for (;;) { 772*7c478bd9Sstevel@tonic-gate while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) { 773*7c478bd9Sstevel@tonic-gate (void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock); 774*7c478bd9Sstevel@tonic-gate } 775*7c478bd9Sstevel@tonic-gate evqp = sub_info->sp_evq_head; 776*7c478bd9Sstevel@tonic-gate while (evqp) { 777*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&sub_info->sp_qlock); 778*7c478bd9Sstevel@tonic-gate (void) sub_info->sp_func(evqp->sq_ev); 779*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&sub_info->sp_qlock); 780*7c478bd9Sstevel@tonic-gate sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next; 781*7c478bd9Sstevel@tonic-gate free(evqp->sq_ev); 782*7c478bd9Sstevel@tonic-gate free(evqp); 783*7c478bd9Sstevel@tonic-gate evqp = sub_info->sp_evq_head; 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate if (!SH_BOUND(shp)) { 786*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&sub_info->sp_qlock); 787*7c478bd9Sstevel@tonic-gate return; 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate } 790*7c478bd9Sstevel@tonic-gate 791*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 792*7c478bd9Sstevel@tonic-gate } 793*7c478bd9Sstevel@tonic-gate 794*7c478bd9Sstevel@tonic-gate /* 795*7c478bd9Sstevel@tonic-gate * Data structure used to communicate event subscription cache updates 796*7c478bd9Sstevel@tonic-gate * to publishers via a registration door 797*7c478bd9Sstevel@tonic-gate */ 798*7c478bd9Sstevel@tonic-gate struct reg_args { 799*7c478bd9Sstevel@tonic-gate uint32_t ra_sub_id; 800*7c478bd9Sstevel@tonic-gate uint32_t ra_op; 801*7c478bd9Sstevel@tonic-gate uint64_t ra_buf_ptr; 802*7c478bd9Sstevel@tonic-gate }; 803*7c478bd9Sstevel@tonic-gate 804*7c478bd9Sstevel@tonic-gate 805*7c478bd9Sstevel@tonic-gate /* 806*7c478bd9Sstevel@tonic-gate * event_deliver_service - generic event delivery service routine. This routine 807*7c478bd9Sstevel@tonic-gate * is called in response to a door call to post an event. 808*7c478bd9Sstevel@tonic-gate * 809*7c478bd9Sstevel@tonic-gate */ 810*7c478bd9Sstevel@tonic-gate static void 811*7c478bd9Sstevel@tonic-gate event_deliver_service(void *cookie, char *args, size_t alen, 812*7c478bd9Sstevel@tonic-gate door_desc_t *ddp, uint_t ndid) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate int ret = 0; 815*7c478bd9Sstevel@tonic-gate subscriber_priv_t *sub_info; 816*7c478bd9Sstevel@tonic-gate sysevent_handle_t *shp; 817*7c478bd9Sstevel@tonic-gate sysevent_queue_t *new_eq; 818*7c478bd9Sstevel@tonic-gate 819*7c478bd9Sstevel@tonic-gate if (args == NULL || alen < sizeof (uint32_t)) { 820*7c478bd9Sstevel@tonic-gate ret = EINVAL; 821*7c478bd9Sstevel@tonic-gate goto return_from_door; 822*7c478bd9Sstevel@tonic-gate } 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate /* Publisher checking on subscriber */ 825*7c478bd9Sstevel@tonic-gate if (alen == sizeof (uint32_t)) { 826*7c478bd9Sstevel@tonic-gate ret = 0; 827*7c478bd9Sstevel@tonic-gate goto return_from_door; 828*7c478bd9Sstevel@tonic-gate } 829*7c478bd9Sstevel@tonic-gate 830*7c478bd9Sstevel@tonic-gate shp = (sysevent_handle_t *)cookie; 831*7c478bd9Sstevel@tonic-gate if (shp == NULL) { 832*7c478bd9Sstevel@tonic-gate ret = EBADF; 833*7c478bd9Sstevel@tonic-gate goto return_from_door; 834*7c478bd9Sstevel@tonic-gate } 835*7c478bd9Sstevel@tonic-gate 836*7c478bd9Sstevel@tonic-gate /* 837*7c478bd9Sstevel@tonic-gate * Mustn't block if we are trying to update the registration with 838*7c478bd9Sstevel@tonic-gate * the publisher 839*7c478bd9Sstevel@tonic-gate */ 840*7c478bd9Sstevel@tonic-gate if (mutex_trylock(SH_LOCK(shp)) != 0) { 841*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 842*7c478bd9Sstevel@tonic-gate goto return_from_door; 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate 845*7c478bd9Sstevel@tonic-gate if (!SH_BOUND(shp)) { 846*7c478bd9Sstevel@tonic-gate ret = EBADF; 847*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 848*7c478bd9Sstevel@tonic-gate goto return_from_door; 849*7c478bd9Sstevel@tonic-gate } 850*7c478bd9Sstevel@tonic-gate 851*7c478bd9Sstevel@tonic-gate sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 852*7c478bd9Sstevel@tonic-gate if (sub_info == NULL) { 853*7c478bd9Sstevel@tonic-gate ret = EBADF; 854*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 855*7c478bd9Sstevel@tonic-gate goto return_from_door; 856*7c478bd9Sstevel@tonic-gate } 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate new_eq = (sysevent_queue_t *)calloc(1, 859*7c478bd9Sstevel@tonic-gate sizeof (sysevent_queue_t)); 860*7c478bd9Sstevel@tonic-gate if (new_eq == NULL) { 861*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 862*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 863*7c478bd9Sstevel@tonic-gate goto return_from_door; 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate 866*7c478bd9Sstevel@tonic-gate /* 867*7c478bd9Sstevel@tonic-gate * Allocate and copy the event buffer into the subscriber's 868*7c478bd9Sstevel@tonic-gate * address space 869*7c478bd9Sstevel@tonic-gate */ 870*7c478bd9Sstevel@tonic-gate new_eq->sq_ev = calloc(1, alen); 871*7c478bd9Sstevel@tonic-gate if (new_eq->sq_ev == NULL) { 872*7c478bd9Sstevel@tonic-gate free(new_eq); 873*7c478bd9Sstevel@tonic-gate ret = EAGAIN; 874*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 875*7c478bd9Sstevel@tonic-gate goto return_from_door; 876*7c478bd9Sstevel@tonic-gate } 877*7c478bd9Sstevel@tonic-gate (void) bcopy(args, new_eq->sq_ev, alen); 878*7c478bd9Sstevel@tonic-gate 879*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&sub_info->sp_qlock); 880*7c478bd9Sstevel@tonic-gate if (sub_info->sp_evq_head == NULL) { 881*7c478bd9Sstevel@tonic-gate sub_info->sp_evq_head = new_eq; 882*7c478bd9Sstevel@tonic-gate } else { 883*7c478bd9Sstevel@tonic-gate sub_info->sp_evq_tail->sq_next = new_eq; 884*7c478bd9Sstevel@tonic-gate } 885*7c478bd9Sstevel@tonic-gate sub_info->sp_evq_tail = new_eq; 886*7c478bd9Sstevel@tonic-gate 887*7c478bd9Sstevel@tonic-gate (void) cond_signal(&sub_info->sp_cv); 888*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&sub_info->sp_qlock); 889*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 890*7c478bd9Sstevel@tonic-gate 891*7c478bd9Sstevel@tonic-gate return_from_door: 892*7c478bd9Sstevel@tonic-gate (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 893*7c478bd9Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate /* 897*7c478bd9Sstevel@tonic-gate * Sysevent subscription information is maintained in the kernel. Updates 898*7c478bd9Sstevel@tonic-gate * to the in-kernel registration database is expected to be infrequent and 899*7c478bd9Sstevel@tonic-gate * offers consistency for publishers and subscribers that may come and go 900*7c478bd9Sstevel@tonic-gate * for a given channel. 901*7c478bd9Sstevel@tonic-gate * 902*7c478bd9Sstevel@tonic-gate * To expedite registration lookups by publishers, a cached copy of the 903*7c478bd9Sstevel@tonic-gate * kernel registration database is kept per-channel. Caches are invalidated 904*7c478bd9Sstevel@tonic-gate * and refreshed upon state changes to the in-kernel registration database. 905*7c478bd9Sstevel@tonic-gate * 906*7c478bd9Sstevel@tonic-gate * To prevent stale subscriber data, publishers may remove subsriber 907*7c478bd9Sstevel@tonic-gate * registrations from the in-kernel registration database in the event 908*7c478bd9Sstevel@tonic-gate * that a particular subscribing process is unresponsive. 909*7c478bd9Sstevel@tonic-gate * 910*7c478bd9Sstevel@tonic-gate * The following routines provide a mechanism to update publisher and subscriber 911*7c478bd9Sstevel@tonic-gate * information for a specified channel. 912*7c478bd9Sstevel@tonic-gate */ 913*7c478bd9Sstevel@tonic-gate 914*7c478bd9Sstevel@tonic-gate /* 915*7c478bd9Sstevel@tonic-gate * clnt_deliver_event - Deliver an event through the consumer's event 916*7c478bd9Sstevel@tonic-gate * delivery door 917*7c478bd9Sstevel@tonic-gate * 918*7c478bd9Sstevel@tonic-gate * Returns -1 if message not delivered. With errno set to cause of error. 919*7c478bd9Sstevel@tonic-gate * Returns 0 for success with the results returned in posting buffer. 920*7c478bd9Sstevel@tonic-gate */ 921*7c478bd9Sstevel@tonic-gate static int 922*7c478bd9Sstevel@tonic-gate clnt_deliver_event(int service_door, void *data, size_t datalen, 923*7c478bd9Sstevel@tonic-gate void *result, size_t rlen) 924*7c478bd9Sstevel@tonic-gate { 925*7c478bd9Sstevel@tonic-gate int error = 0; 926*7c478bd9Sstevel@tonic-gate door_arg_t door_arg; 927*7c478bd9Sstevel@tonic-gate 928*7c478bd9Sstevel@tonic-gate door_arg.rbuf = result; 929*7c478bd9Sstevel@tonic-gate door_arg.rsize = rlen; 930*7c478bd9Sstevel@tonic-gate door_arg.data_ptr = data; 931*7c478bd9Sstevel@tonic-gate door_arg.data_size = datalen; 932*7c478bd9Sstevel@tonic-gate door_arg.desc_ptr = NULL; 933*7c478bd9Sstevel@tonic-gate door_arg.desc_num = 0; 934*7c478bd9Sstevel@tonic-gate 935*7c478bd9Sstevel@tonic-gate /* 936*7c478bd9Sstevel@tonic-gate * Make door call 937*7c478bd9Sstevel@tonic-gate */ 938*7c478bd9Sstevel@tonic-gate while ((error = door_call(service_door, &door_arg)) != 0) { 939*7c478bd9Sstevel@tonic-gate if (errno == EAGAIN || errno == EINTR) { 940*7c478bd9Sstevel@tonic-gate continue; 941*7c478bd9Sstevel@tonic-gate } else { 942*7c478bd9Sstevel@tonic-gate error = errno; 943*7c478bd9Sstevel@tonic-gate break; 944*7c478bd9Sstevel@tonic-gate } 945*7c478bd9Sstevel@tonic-gate } 946*7c478bd9Sstevel@tonic-gate 947*7c478bd9Sstevel@tonic-gate return (error); 948*7c478bd9Sstevel@tonic-gate } 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate static int 951*7c478bd9Sstevel@tonic-gate update_publisher_cache(subscriber_priv_t *sub_info, int update_op, 952*7c478bd9Sstevel@tonic-gate uint32_t sub_id, size_t datasz, uchar_t *data) 953*7c478bd9Sstevel@tonic-gate { 954*7c478bd9Sstevel@tonic-gate int pub_fd; 955*7c478bd9Sstevel@tonic-gate uint32_t result = 0; 956*7c478bd9Sstevel@tonic-gate struct reg_args *rargs; 957*7c478bd9Sstevel@tonic-gate 958*7c478bd9Sstevel@tonic-gate rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) + 959*7c478bd9Sstevel@tonic-gate datasz); 960*7c478bd9Sstevel@tonic-gate if (rargs == NULL) { 961*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 962*7c478bd9Sstevel@tonic-gate return (-1); 963*7c478bd9Sstevel@tonic-gate } 964*7c478bd9Sstevel@tonic-gate 965*7c478bd9Sstevel@tonic-gate rargs->ra_sub_id = sub_id; 966*7c478bd9Sstevel@tonic-gate rargs->ra_op = update_op; 967*7c478bd9Sstevel@tonic-gate bcopy(data, (char *)&rargs->ra_buf_ptr, datasz); 968*7c478bd9Sstevel@tonic-gate 969*7c478bd9Sstevel@tonic-gate pub_fd = open(sub_info->sp_door_name, O_RDONLY); 970*7c478bd9Sstevel@tonic-gate (void) clnt_deliver_event(pub_fd, (void *)rargs, 971*7c478bd9Sstevel@tonic-gate sizeof (struct reg_args) + datasz, &result, sizeof (result)); 972*7c478bd9Sstevel@tonic-gate (void) close(pub_fd); 973*7c478bd9Sstevel@tonic-gate 974*7c478bd9Sstevel@tonic-gate free(rargs); 975*7c478bd9Sstevel@tonic-gate if (result != 0) { 976*7c478bd9Sstevel@tonic-gate errno = result; 977*7c478bd9Sstevel@tonic-gate return (-1); 978*7c478bd9Sstevel@tonic-gate } 979*7c478bd9Sstevel@tonic-gate 980*7c478bd9Sstevel@tonic-gate return (0); 981*7c478bd9Sstevel@tonic-gate } 982*7c478bd9Sstevel@tonic-gate 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate /* 985*7c478bd9Sstevel@tonic-gate * update_kernel_registration - update the in-kernel registration for the 986*7c478bd9Sstevel@tonic-gate * given channel. 987*7c478bd9Sstevel@tonic-gate */ 988*7c478bd9Sstevel@tonic-gate static int 989*7c478bd9Sstevel@tonic-gate update_kernel_registration(sysevent_handle_t *shp, int update_type, 990*7c478bd9Sstevel@tonic-gate int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data) 991*7c478bd9Sstevel@tonic-gate { 992*7c478bd9Sstevel@tonic-gate int error; 993*7c478bd9Sstevel@tonic-gate char *channel_name = SH_CHANNEL_NAME(shp); 994*7c478bd9Sstevel@tonic-gate se_pubsub_t udata; 995*7c478bd9Sstevel@tonic-gate 996*7c478bd9Sstevel@tonic-gate udata.ps_channel_name_len = strlen(channel_name) + 1; 997*7c478bd9Sstevel@tonic-gate udata.ps_op = update_op; 998*7c478bd9Sstevel@tonic-gate udata.ps_type = update_type; 999*7c478bd9Sstevel@tonic-gate udata.ps_buflen = datasz; 1000*7c478bd9Sstevel@tonic-gate udata.ps_id = *sub_id; 1001*7c478bd9Sstevel@tonic-gate 1002*7c478bd9Sstevel@tonic-gate if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1003*7c478bd9Sstevel@tonic-gate (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0)) 1004*7c478bd9Sstevel@tonic-gate != 0) { 1005*7c478bd9Sstevel@tonic-gate return (error); 1006*7c478bd9Sstevel@tonic-gate } 1007*7c478bd9Sstevel@tonic-gate 1008*7c478bd9Sstevel@tonic-gate *sub_id = udata.ps_id; 1009*7c478bd9Sstevel@tonic-gate 1010*7c478bd9Sstevel@tonic-gate return (error); 1011*7c478bd9Sstevel@tonic-gate } 1012*7c478bd9Sstevel@tonic-gate 1013*7c478bd9Sstevel@tonic-gate /* 1014*7c478bd9Sstevel@tonic-gate * get_kernel_registration - get the current subscriber registration for 1015*7c478bd9Sstevel@tonic-gate * the given channel 1016*7c478bd9Sstevel@tonic-gate */ 1017*7c478bd9Sstevel@tonic-gate static nvlist_t * 1018*7c478bd9Sstevel@tonic-gate get_kernel_registration(char *channel_name, uint32_t class_id) 1019*7c478bd9Sstevel@tonic-gate { 1020*7c478bd9Sstevel@tonic-gate char *nvlbuf; 1021*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 1022*7c478bd9Sstevel@tonic-gate se_pubsub_t udata; 1023*7c478bd9Sstevel@tonic-gate 1024*7c478bd9Sstevel@tonic-gate nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ); 1025*7c478bd9Sstevel@tonic-gate if (nvlbuf == NULL) { 1026*7c478bd9Sstevel@tonic-gate return (NULL); 1027*7c478bd9Sstevel@tonic-gate } 1028*7c478bd9Sstevel@tonic-gate 1029*7c478bd9Sstevel@tonic-gate udata.ps_buflen = MAX_SUBSCRIPTION_SZ; 1030*7c478bd9Sstevel@tonic-gate udata.ps_channel_name_len = strlen(channel_name) + 1; 1031*7c478bd9Sstevel@tonic-gate udata.ps_id = class_id; 1032*7c478bd9Sstevel@tonic-gate udata.ps_op = SE_GET_REGISTRATION; 1033*7c478bd9Sstevel@tonic-gate udata.ps_type = PUBLISHER; 1034*7c478bd9Sstevel@tonic-gate 1035*7c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1036*7c478bd9Sstevel@tonic-gate (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0) 1037*7c478bd9Sstevel@tonic-gate != 0) { 1038*7c478bd9Sstevel@tonic-gate 1039*7c478bd9Sstevel@tonic-gate /* Need a bigger buffer to hold channel registration */ 1040*7c478bd9Sstevel@tonic-gate if (errno == EAGAIN) { 1041*7c478bd9Sstevel@tonic-gate free(nvlbuf); 1042*7c478bd9Sstevel@tonic-gate nvlbuf = calloc(1, udata.ps_buflen); 1043*7c478bd9Sstevel@tonic-gate if (nvlbuf == NULL) 1044*7c478bd9Sstevel@tonic-gate return (NULL); 1045*7c478bd9Sstevel@tonic-gate 1046*7c478bd9Sstevel@tonic-gate /* Try again */ 1047*7c478bd9Sstevel@tonic-gate if (modctl(MODEVENTS, 1048*7c478bd9Sstevel@tonic-gate (uintptr_t)MODEVENTS_REGISTER_EVENT, 1049*7c478bd9Sstevel@tonic-gate (uintptr_t)channel_name, (uintptr_t)nvlbuf, 1050*7c478bd9Sstevel@tonic-gate (uintptr_t)&udata, 0) != 0) { 1051*7c478bd9Sstevel@tonic-gate free(nvlbuf); 1052*7c478bd9Sstevel@tonic-gate return (NULL); 1053*7c478bd9Sstevel@tonic-gate } 1054*7c478bd9Sstevel@tonic-gate } else { 1055*7c478bd9Sstevel@tonic-gate free(nvlbuf); 1056*7c478bd9Sstevel@tonic-gate return (NULL); 1057*7c478bd9Sstevel@tonic-gate } 1058*7c478bd9Sstevel@tonic-gate } 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) { 1061*7c478bd9Sstevel@tonic-gate free(nvlbuf); 1062*7c478bd9Sstevel@tonic-gate return (NULL); 1063*7c478bd9Sstevel@tonic-gate } 1064*7c478bd9Sstevel@tonic-gate free(nvlbuf); 1065*7c478bd9Sstevel@tonic-gate 1066*7c478bd9Sstevel@tonic-gate return (nvl); 1067*7c478bd9Sstevel@tonic-gate } 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate /* 1070*7c478bd9Sstevel@tonic-gate * The following routines provide a mechanism for publishers to maintain 1071*7c478bd9Sstevel@tonic-gate * subscriber information. 1072*7c478bd9Sstevel@tonic-gate */ 1073*7c478bd9Sstevel@tonic-gate 1074*7c478bd9Sstevel@tonic-gate static void 1075*7c478bd9Sstevel@tonic-gate dealloc_subscribers(sysevent_handle_t *shp) 1076*7c478bd9Sstevel@tonic-gate { 1077*7c478bd9Sstevel@tonic-gate int i; 1078*7c478bd9Sstevel@tonic-gate subscriber_data_t *sub; 1079*7c478bd9Sstevel@tonic-gate 1080*7c478bd9Sstevel@tonic-gate for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1081*7c478bd9Sstevel@tonic-gate sub = SH_SUBSCRIBER(shp, i); 1082*7c478bd9Sstevel@tonic-gate if (sub != NULL) { 1083*7c478bd9Sstevel@tonic-gate free(sub->sd_door_name); 1084*7c478bd9Sstevel@tonic-gate free(sub); 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate SH_SUBSCRIBER(shp, i) = NULL; 1087*7c478bd9Sstevel@tonic-gate } 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate 1090*7c478bd9Sstevel@tonic-gate static int 1091*7c478bd9Sstevel@tonic-gate alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag) 1092*7c478bd9Sstevel@tonic-gate { 1093*7c478bd9Sstevel@tonic-gate subscriber_data_t *sub; 1094*7c478bd9Sstevel@tonic-gate char door_name[MAXPATHLEN]; 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate if (SH_SUBSCRIBER(shp, sub_id) != NULL) { 1097*7c478bd9Sstevel@tonic-gate return (0); 1098*7c478bd9Sstevel@tonic-gate } 1099*7c478bd9Sstevel@tonic-gate 1100*7c478bd9Sstevel@tonic-gate /* Allocate and initialize the subscriber data */ 1101*7c478bd9Sstevel@tonic-gate sub = (subscriber_data_t *)calloc(1, 1102*7c478bd9Sstevel@tonic-gate sizeof (subscriber_data_t)); 1103*7c478bd9Sstevel@tonic-gate if (sub == NULL) { 1104*7c478bd9Sstevel@tonic-gate return (-1); 1105*7c478bd9Sstevel@tonic-gate } 1106*7c478bd9Sstevel@tonic-gate if (snprintf(door_name, MAXPATHLEN, "%s/%d", 1107*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) { 1108*7c478bd9Sstevel@tonic-gate free(sub); 1109*7c478bd9Sstevel@tonic-gate return (-1); 1110*7c478bd9Sstevel@tonic-gate } 1111*7c478bd9Sstevel@tonic-gate 1112*7c478bd9Sstevel@tonic-gate sub->sd_flag = ACTIVE; 1113*7c478bd9Sstevel@tonic-gate sub->sd_door_name = strdup(door_name); 1114*7c478bd9Sstevel@tonic-gate if (sub->sd_door_name == NULL) { 1115*7c478bd9Sstevel@tonic-gate free(sub); 1116*7c478bd9Sstevel@tonic-gate return (-1); 1117*7c478bd9Sstevel@tonic-gate } 1118*7c478bd9Sstevel@tonic-gate 1119*7c478bd9Sstevel@tonic-gate SH_SUBSCRIBER(shp, sub_id) = sub; 1120*7c478bd9Sstevel@tonic-gate return (0); 1121*7c478bd9Sstevel@tonic-gate 1122*7c478bd9Sstevel@tonic-gate } 1123*7c478bd9Sstevel@tonic-gate 1124*7c478bd9Sstevel@tonic-gate /* 1125*7c478bd9Sstevel@tonic-gate * The following routines are used to update and maintain the registration cache 1126*7c478bd9Sstevel@tonic-gate * for a particular sysevent channel. 1127*7c478bd9Sstevel@tonic-gate */ 1128*7c478bd9Sstevel@tonic-gate 1129*7c478bd9Sstevel@tonic-gate static uint32_t 1130*7c478bd9Sstevel@tonic-gate hash_func(const char *s) 1131*7c478bd9Sstevel@tonic-gate { 1132*7c478bd9Sstevel@tonic-gate uint32_t result = 0; 1133*7c478bd9Sstevel@tonic-gate uint_t g; 1134*7c478bd9Sstevel@tonic-gate 1135*7c478bd9Sstevel@tonic-gate while (*s != '\0') { 1136*7c478bd9Sstevel@tonic-gate result <<= 4; 1137*7c478bd9Sstevel@tonic-gate result += (uint32_t)*s++; 1138*7c478bd9Sstevel@tonic-gate g = result & 0xf0000000; 1139*7c478bd9Sstevel@tonic-gate if (g != 0) { 1140*7c478bd9Sstevel@tonic-gate result ^= g >> 24; 1141*7c478bd9Sstevel@tonic-gate result ^= g; 1142*7c478bd9Sstevel@tonic-gate } 1143*7c478bd9Sstevel@tonic-gate } 1144*7c478bd9Sstevel@tonic-gate 1145*7c478bd9Sstevel@tonic-gate return (result); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate 1148*7c478bd9Sstevel@tonic-gate subclass_lst_t * 1149*7c478bd9Sstevel@tonic-gate cache_find_subclass(class_lst_t *c_list, char *subclass) 1150*7c478bd9Sstevel@tonic-gate { 1151*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 1152*7c478bd9Sstevel@tonic-gate 1153*7c478bd9Sstevel@tonic-gate if (c_list == NULL) 1154*7c478bd9Sstevel@tonic-gate return (NULL); 1155*7c478bd9Sstevel@tonic-gate 1156*7c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 1157*7c478bd9Sstevel@tonic-gate 1158*7c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 1159*7c478bd9Sstevel@tonic-gate if (strcmp(sc_list->sl_name, subclass) == 0) { 1160*7c478bd9Sstevel@tonic-gate return (sc_list); 1161*7c478bd9Sstevel@tonic-gate } 1162*7c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 1163*7c478bd9Sstevel@tonic-gate } 1164*7c478bd9Sstevel@tonic-gate 1165*7c478bd9Sstevel@tonic-gate return (NULL); 1166*7c478bd9Sstevel@tonic-gate } 1167*7c478bd9Sstevel@tonic-gate 1168*7c478bd9Sstevel@tonic-gate 1169*7c478bd9Sstevel@tonic-gate static class_lst_t * 1170*7c478bd9Sstevel@tonic-gate cache_find_class(sysevent_handle_t *shp, char *class) 1171*7c478bd9Sstevel@tonic-gate { 1172*7c478bd9Sstevel@tonic-gate int index; 1173*7c478bd9Sstevel@tonic-gate class_lst_t *c_list; 1174*7c478bd9Sstevel@tonic-gate class_lst_t **class_hash = SH_CLASS_HASH(shp); 1175*7c478bd9Sstevel@tonic-gate 1176*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_ALL) == 0) { 1177*7c478bd9Sstevel@tonic-gate return (class_hash[0]); 1178*7c478bd9Sstevel@tonic-gate } 1179*7c478bd9Sstevel@tonic-gate 1180*7c478bd9Sstevel@tonic-gate index = CLASS_HASH(class); 1181*7c478bd9Sstevel@tonic-gate c_list = class_hash[index]; 1182*7c478bd9Sstevel@tonic-gate while (c_list != NULL) { 1183*7c478bd9Sstevel@tonic-gate if (strcmp(class, c_list->cl_name) == 0) { 1184*7c478bd9Sstevel@tonic-gate break; 1185*7c478bd9Sstevel@tonic-gate } 1186*7c478bd9Sstevel@tonic-gate c_list = c_list->cl_next; 1187*7c478bd9Sstevel@tonic-gate } 1188*7c478bd9Sstevel@tonic-gate 1189*7c478bd9Sstevel@tonic-gate return (c_list); 1190*7c478bd9Sstevel@tonic-gate } 1191*7c478bd9Sstevel@tonic-gate 1192*7c478bd9Sstevel@tonic-gate static int 1193*7c478bd9Sstevel@tonic-gate cache_insert_subclass(class_lst_t *c_list, char **subclass_names, 1194*7c478bd9Sstevel@tonic-gate int subclass_num, uint32_t sub_id) 1195*7c478bd9Sstevel@tonic-gate { 1196*7c478bd9Sstevel@tonic-gate int i; 1197*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 1198*7c478bd9Sstevel@tonic-gate 1199*7c478bd9Sstevel@tonic-gate for (i = 0; i < subclass_num; ++i) { 1200*7c478bd9Sstevel@tonic-gate if ((sc_list = cache_find_subclass(c_list, subclass_names[i])) 1201*7c478bd9Sstevel@tonic-gate != NULL) { 1202*7c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 1; 1203*7c478bd9Sstevel@tonic-gate } else { 1204*7c478bd9Sstevel@tonic-gate sc_list = (subclass_lst_t *)calloc(1, 1205*7c478bd9Sstevel@tonic-gate sizeof (subclass_lst_t)); 1206*7c478bd9Sstevel@tonic-gate if (sc_list == NULL) 1207*7c478bd9Sstevel@tonic-gate return (-1); 1208*7c478bd9Sstevel@tonic-gate 1209*7c478bd9Sstevel@tonic-gate sc_list->sl_name = strdup(subclass_names[i]); 1210*7c478bd9Sstevel@tonic-gate if (sc_list->sl_name == NULL) { 1211*7c478bd9Sstevel@tonic-gate free(sc_list); 1212*7c478bd9Sstevel@tonic-gate return (-1); 1213*7c478bd9Sstevel@tonic-gate } 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 1; 1216*7c478bd9Sstevel@tonic-gate sc_list->sl_next = c_list->cl_subclass_list; 1217*7c478bd9Sstevel@tonic-gate c_list->cl_subclass_list = sc_list; 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate } 1220*7c478bd9Sstevel@tonic-gate 1221*7c478bd9Sstevel@tonic-gate return (0); 1222*7c478bd9Sstevel@tonic-gate } 1223*7c478bd9Sstevel@tonic-gate 1224*7c478bd9Sstevel@tonic-gate static int 1225*7c478bd9Sstevel@tonic-gate cache_insert_class(sysevent_handle_t *shp, char *class, 1226*7c478bd9Sstevel@tonic-gate char **subclass_names, int subclass_num, uint32_t sub_id) 1227*7c478bd9Sstevel@tonic-gate { 1228*7c478bd9Sstevel@tonic-gate class_lst_t *c_list; 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_ALL) == 0) { 1231*7c478bd9Sstevel@tonic-gate char *subclass_all = EC_SUB_ALL; 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate (void) cache_insert_subclass(SH_CLASS_HASH(shp)[0], 1234*7c478bd9Sstevel@tonic-gate (char **)&subclass_all, 1, sub_id); 1235*7c478bd9Sstevel@tonic-gate return (0); 1236*7c478bd9Sstevel@tonic-gate } 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate /* New class, add to the registration cache */ 1239*7c478bd9Sstevel@tonic-gate if ((c_list = cache_find_class(shp, class)) == NULL) { 1240*7c478bd9Sstevel@tonic-gate 1241*7c478bd9Sstevel@tonic-gate c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t)); 1242*7c478bd9Sstevel@tonic-gate if (c_list == NULL) { 1243*7c478bd9Sstevel@tonic-gate return (1); 1244*7c478bd9Sstevel@tonic-gate } 1245*7c478bd9Sstevel@tonic-gate c_list->cl_name = strdup(class); 1246*7c478bd9Sstevel@tonic-gate if (c_list->cl_name == NULL) { 1247*7c478bd9Sstevel@tonic-gate free(c_list); 1248*7c478bd9Sstevel@tonic-gate return (1); 1249*7c478bd9Sstevel@tonic-gate } 1250*7c478bd9Sstevel@tonic-gate 1251*7c478bd9Sstevel@tonic-gate c_list->cl_subclass_list = (subclass_lst_t *) 1252*7c478bd9Sstevel@tonic-gate calloc(1, sizeof (subclass_lst_t)); 1253*7c478bd9Sstevel@tonic-gate if (c_list->cl_subclass_list == NULL) { 1254*7c478bd9Sstevel@tonic-gate free(c_list->cl_name); 1255*7c478bd9Sstevel@tonic-gate free(c_list); 1256*7c478bd9Sstevel@tonic-gate return (1); 1257*7c478bd9Sstevel@tonic-gate } 1258*7c478bd9Sstevel@tonic-gate c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL); 1259*7c478bd9Sstevel@tonic-gate if (c_list->cl_subclass_list->sl_name == NULL) { 1260*7c478bd9Sstevel@tonic-gate free(c_list->cl_subclass_list); 1261*7c478bd9Sstevel@tonic-gate free(c_list->cl_name); 1262*7c478bd9Sstevel@tonic-gate free(c_list); 1263*7c478bd9Sstevel@tonic-gate return (1); 1264*7c478bd9Sstevel@tonic-gate } 1265*7c478bd9Sstevel@tonic-gate c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)]; 1266*7c478bd9Sstevel@tonic-gate SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list; 1267*7c478bd9Sstevel@tonic-gate 1268*7c478bd9Sstevel@tonic-gate } 1269*7c478bd9Sstevel@tonic-gate 1270*7c478bd9Sstevel@tonic-gate /* Update the subclass list */ 1271*7c478bd9Sstevel@tonic-gate if (cache_insert_subclass(c_list, subclass_names, subclass_num, 1272*7c478bd9Sstevel@tonic-gate sub_id) != 0) 1273*7c478bd9Sstevel@tonic-gate return (1); 1274*7c478bd9Sstevel@tonic-gate 1275*7c478bd9Sstevel@tonic-gate return (0); 1276*7c478bd9Sstevel@tonic-gate } 1277*7c478bd9Sstevel@tonic-gate 1278*7c478bd9Sstevel@tonic-gate static void 1279*7c478bd9Sstevel@tonic-gate cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id) 1280*7c478bd9Sstevel@tonic-gate { 1281*7c478bd9Sstevel@tonic-gate int i; 1282*7c478bd9Sstevel@tonic-gate class_lst_t *c_list; 1283*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 1284*7c478bd9Sstevel@tonic-gate 1285*7c478bd9Sstevel@tonic-gate for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1286*7c478bd9Sstevel@tonic-gate c_list = SH_CLASS_HASH(shp)[i]; 1287*7c478bd9Sstevel@tonic-gate while (c_list != NULL) { 1288*7c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 1289*7c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 1290*7c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 0; 1291*7c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate c_list = c_list->cl_next; 1294*7c478bd9Sstevel@tonic-gate } 1295*7c478bd9Sstevel@tonic-gate } 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate 1298*7c478bd9Sstevel@tonic-gate static void 1299*7c478bd9Sstevel@tonic-gate cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id) 1300*7c478bd9Sstevel@tonic-gate { 1301*7c478bd9Sstevel@tonic-gate class_lst_t *c_list; 1302*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 1303*7c478bd9Sstevel@tonic-gate 1304*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_ALL) == 0) { 1305*7c478bd9Sstevel@tonic-gate cache_remove_all_class(shp, sub_id); 1306*7c478bd9Sstevel@tonic-gate return; 1307*7c478bd9Sstevel@tonic-gate } 1308*7c478bd9Sstevel@tonic-gate 1309*7c478bd9Sstevel@tonic-gate if ((c_list = cache_find_class(shp, class)) == NULL) { 1310*7c478bd9Sstevel@tonic-gate return; 1311*7c478bd9Sstevel@tonic-gate } 1312*7c478bd9Sstevel@tonic-gate 1313*7c478bd9Sstevel@tonic-gate sc_list = c_list->cl_subclass_list; 1314*7c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 1315*7c478bd9Sstevel@tonic-gate sc_list->sl_num[sub_id] = 0; 1316*7c478bd9Sstevel@tonic-gate sc_list = sc_list->sl_next; 1317*7c478bd9Sstevel@tonic-gate } 1318*7c478bd9Sstevel@tonic-gate } 1319*7c478bd9Sstevel@tonic-gate 1320*7c478bd9Sstevel@tonic-gate static void 1321*7c478bd9Sstevel@tonic-gate free_cached_registration(sysevent_handle_t *shp) 1322*7c478bd9Sstevel@tonic-gate { 1323*7c478bd9Sstevel@tonic-gate int i; 1324*7c478bd9Sstevel@tonic-gate class_lst_t *clist, *next_clist; 1325*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list, *next_sc; 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate for (i = 0; i < CLASS_HASH_SZ + 1; i++) { 1328*7c478bd9Sstevel@tonic-gate clist = SH_CLASS_HASH(shp)[i]; 1329*7c478bd9Sstevel@tonic-gate while (clist != NULL) { 1330*7c478bd9Sstevel@tonic-gate sc_list = clist->cl_subclass_list; 1331*7c478bd9Sstevel@tonic-gate while (sc_list != NULL) { 1332*7c478bd9Sstevel@tonic-gate free(sc_list->sl_name); 1333*7c478bd9Sstevel@tonic-gate next_sc = sc_list->sl_next; 1334*7c478bd9Sstevel@tonic-gate free(sc_list); 1335*7c478bd9Sstevel@tonic-gate sc_list = next_sc; 1336*7c478bd9Sstevel@tonic-gate } 1337*7c478bd9Sstevel@tonic-gate free(clist->cl_name); 1338*7c478bd9Sstevel@tonic-gate next_clist = clist->cl_next; 1339*7c478bd9Sstevel@tonic-gate free(clist); 1340*7c478bd9Sstevel@tonic-gate clist = next_clist; 1341*7c478bd9Sstevel@tonic-gate } 1342*7c478bd9Sstevel@tonic-gate SH_CLASS_HASH(shp)[i] = NULL; 1343*7c478bd9Sstevel@tonic-gate } 1344*7c478bd9Sstevel@tonic-gate } 1345*7c478bd9Sstevel@tonic-gate 1346*7c478bd9Sstevel@tonic-gate static int 1347*7c478bd9Sstevel@tonic-gate create_cached_registration(sysevent_handle_t *shp, 1348*7c478bd9Sstevel@tonic-gate class_lst_t **class_hash) 1349*7c478bd9Sstevel@tonic-gate { 1350*7c478bd9Sstevel@tonic-gate int i, j, new_class; 1351*7c478bd9Sstevel@tonic-gate char *class_name; 1352*7c478bd9Sstevel@tonic-gate uint_t num_elem; 1353*7c478bd9Sstevel@tonic-gate uchar_t *subscribers; 1354*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 1355*7c478bd9Sstevel@tonic-gate nvpair_t *nvpair; 1356*7c478bd9Sstevel@tonic-gate class_lst_t *clist; 1357*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_list; 1358*7c478bd9Sstevel@tonic-gate 1359*7c478bd9Sstevel@tonic-gate for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i)) 1362*7c478bd9Sstevel@tonic-gate == NULL) { 1363*7c478bd9Sstevel@tonic-gate if (errno == ENOENT) { 1364*7c478bd9Sstevel@tonic-gate class_hash[i] = NULL; 1365*7c478bd9Sstevel@tonic-gate continue; 1366*7c478bd9Sstevel@tonic-gate } else { 1367*7c478bd9Sstevel@tonic-gate goto create_failed; 1368*7c478bd9Sstevel@tonic-gate } 1369*7c478bd9Sstevel@tonic-gate } 1370*7c478bd9Sstevel@tonic-gate 1371*7c478bd9Sstevel@tonic-gate 1372*7c478bd9Sstevel@tonic-gate nvpair = NULL; 1373*7c478bd9Sstevel@tonic-gate if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1374*7c478bd9Sstevel@tonic-gate goto create_failed; 1375*7c478bd9Sstevel@tonic-gate } 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate new_class = 1; 1378*7c478bd9Sstevel@tonic-gate while (new_class) { 1379*7c478bd9Sstevel@tonic-gate /* Extract the class name from the nvpair */ 1380*7c478bd9Sstevel@tonic-gate if (nvpair_value_string(nvpair, &class_name) != 0) { 1381*7c478bd9Sstevel@tonic-gate goto create_failed; 1382*7c478bd9Sstevel@tonic-gate } 1383*7c478bd9Sstevel@tonic-gate clist = (class_lst_t *) 1384*7c478bd9Sstevel@tonic-gate calloc(1, sizeof (class_lst_t)); 1385*7c478bd9Sstevel@tonic-gate if (clist == NULL) { 1386*7c478bd9Sstevel@tonic-gate goto create_failed; 1387*7c478bd9Sstevel@tonic-gate } 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate clist->cl_name = strdup(class_name); 1390*7c478bd9Sstevel@tonic-gate if (clist->cl_name == NULL) { 1391*7c478bd9Sstevel@tonic-gate free(clist); 1392*7c478bd9Sstevel@tonic-gate goto create_failed; 1393*7c478bd9Sstevel@tonic-gate } 1394*7c478bd9Sstevel@tonic-gate 1395*7c478bd9Sstevel@tonic-gate /* 1396*7c478bd9Sstevel@tonic-gate * Extract the subclass name and registration 1397*7c478bd9Sstevel@tonic-gate * from the nvpair 1398*7c478bd9Sstevel@tonic-gate */ 1399*7c478bd9Sstevel@tonic-gate if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1400*7c478bd9Sstevel@tonic-gate == NULL) { 1401*7c478bd9Sstevel@tonic-gate free(clist->cl_name); 1402*7c478bd9Sstevel@tonic-gate free(clist); 1403*7c478bd9Sstevel@tonic-gate goto create_failed; 1404*7c478bd9Sstevel@tonic-gate } 1405*7c478bd9Sstevel@tonic-gate 1406*7c478bd9Sstevel@tonic-gate clist->cl_next = class_hash[i]; 1407*7c478bd9Sstevel@tonic-gate class_hash[i] = clist; 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate for (;;) { 1410*7c478bd9Sstevel@tonic-gate 1411*7c478bd9Sstevel@tonic-gate sc_list = (subclass_lst_t *)calloc(1, 1412*7c478bd9Sstevel@tonic-gate sizeof (subclass_lst_t)); 1413*7c478bd9Sstevel@tonic-gate if (sc_list == NULL) { 1414*7c478bd9Sstevel@tonic-gate goto create_failed; 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate 1417*7c478bd9Sstevel@tonic-gate sc_list->sl_next = clist->cl_subclass_list; 1418*7c478bd9Sstevel@tonic-gate clist->cl_subclass_list = sc_list; 1419*7c478bd9Sstevel@tonic-gate 1420*7c478bd9Sstevel@tonic-gate sc_list->sl_name = strdup(nvpair_name(nvpair)); 1421*7c478bd9Sstevel@tonic-gate if (sc_list->sl_name == NULL) { 1422*7c478bd9Sstevel@tonic-gate goto create_failed; 1423*7c478bd9Sstevel@tonic-gate } 1424*7c478bd9Sstevel@tonic-gate 1425*7c478bd9Sstevel@tonic-gate if (nvpair_value_byte_array(nvpair, 1426*7c478bd9Sstevel@tonic-gate &subscribers, &num_elem) != 0) { 1427*7c478bd9Sstevel@tonic-gate goto create_failed; 1428*7c478bd9Sstevel@tonic-gate } 1429*7c478bd9Sstevel@tonic-gate bcopy(subscribers, (uchar_t *)sc_list->sl_num, 1430*7c478bd9Sstevel@tonic-gate MAX_SUBSCRIBERS + 1); 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate for (j = 1; j <= MAX_SUBSCRIBERS; ++j) { 1433*7c478bd9Sstevel@tonic-gate if (sc_list->sl_num[j] == 0) 1434*7c478bd9Sstevel@tonic-gate continue; 1435*7c478bd9Sstevel@tonic-gate 1436*7c478bd9Sstevel@tonic-gate if (alloc_subscriber(shp, j, 1) != 0) { 1437*7c478bd9Sstevel@tonic-gate goto create_failed; 1438*7c478bd9Sstevel@tonic-gate } 1439*7c478bd9Sstevel@tonic-gate } 1440*7c478bd9Sstevel@tonic-gate 1441*7c478bd9Sstevel@tonic-gate /* 1442*7c478bd9Sstevel@tonic-gate * Check next nvpair - either subclass or 1443*7c478bd9Sstevel@tonic-gate * class 1444*7c478bd9Sstevel@tonic-gate */ 1445*7c478bd9Sstevel@tonic-gate if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1446*7c478bd9Sstevel@tonic-gate == NULL) { 1447*7c478bd9Sstevel@tonic-gate new_class = 0; 1448*7c478bd9Sstevel@tonic-gate break; 1449*7c478bd9Sstevel@tonic-gate } else if (strcmp(nvpair_name(nvpair), 1450*7c478bd9Sstevel@tonic-gate CLASS_NAME) == 0) { 1451*7c478bd9Sstevel@tonic-gate break; 1452*7c478bd9Sstevel@tonic-gate } 1453*7c478bd9Sstevel@tonic-gate } 1454*7c478bd9Sstevel@tonic-gate } 1455*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate return (0); 1458*7c478bd9Sstevel@tonic-gate 1459*7c478bd9Sstevel@tonic-gate create_failed: 1460*7c478bd9Sstevel@tonic-gate dealloc_subscribers(shp); 1461*7c478bd9Sstevel@tonic-gate free_cached_registration(shp); 1462*7c478bd9Sstevel@tonic-gate if (nvl) 1463*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1464*7c478bd9Sstevel@tonic-gate return (-1); 1465*7c478bd9Sstevel@tonic-gate 1466*7c478bd9Sstevel@tonic-gate } 1467*7c478bd9Sstevel@tonic-gate 1468*7c478bd9Sstevel@tonic-gate /* 1469*7c478bd9Sstevel@tonic-gate * cache_update_service - generic event publisher service routine. This routine 1470*7c478bd9Sstevel@tonic-gate * is called in response to a registration cache update. 1471*7c478bd9Sstevel@tonic-gate * 1472*7c478bd9Sstevel@tonic-gate */ 1473*7c478bd9Sstevel@tonic-gate static void 1474*7c478bd9Sstevel@tonic-gate cache_update_service(void *cookie, char *args, size_t alen, 1475*7c478bd9Sstevel@tonic-gate door_desc_t *ddp, uint_t ndid) 1476*7c478bd9Sstevel@tonic-gate { 1477*7c478bd9Sstevel@tonic-gate int ret = 0; 1478*7c478bd9Sstevel@tonic-gate uint_t num_elem; 1479*7c478bd9Sstevel@tonic-gate char *class, **event_list; 1480*7c478bd9Sstevel@tonic-gate size_t datalen; 1481*7c478bd9Sstevel@tonic-gate uint32_t sub_id; 1482*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 1483*7c478bd9Sstevel@tonic-gate nvpair_t *nvpair = NULL; 1484*7c478bd9Sstevel@tonic-gate struct reg_args *rargs; 1485*7c478bd9Sstevel@tonic-gate sysevent_handle_t *shp; 1486*7c478bd9Sstevel@tonic-gate subscriber_data_t *sub; 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate if (alen < sizeof (struct reg_args) || cookie == NULL) { 1489*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1490*7c478bd9Sstevel@tonic-gate goto return_from_door; 1491*7c478bd9Sstevel@tonic-gate } 1492*7c478bd9Sstevel@tonic-gate 1493*7c478bd9Sstevel@tonic-gate rargs = (struct reg_args *)args; 1494*7c478bd9Sstevel@tonic-gate shp = (sysevent_handle_t *)cookie; 1495*7c478bd9Sstevel@tonic-gate 1496*7c478bd9Sstevel@tonic-gate datalen = alen - sizeof (struct reg_args); 1497*7c478bd9Sstevel@tonic-gate sub_id = rargs->ra_sub_id; 1498*7c478bd9Sstevel@tonic-gate 1499*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 1500*7c478bd9Sstevel@tonic-gate 1501*7c478bd9Sstevel@tonic-gate switch (rargs->ra_op) { 1502*7c478bd9Sstevel@tonic-gate case SE_UNREGISTER: 1503*7c478bd9Sstevel@tonic-gate class = (char *)&rargs->ra_buf_ptr; 1504*7c478bd9Sstevel@tonic-gate cache_remove_class(shp, (char *)class, 1505*7c478bd9Sstevel@tonic-gate sub_id); 1506*7c478bd9Sstevel@tonic-gate break; 1507*7c478bd9Sstevel@tonic-gate case SE_UNBIND_REGISTRATION: 1508*7c478bd9Sstevel@tonic-gate 1509*7c478bd9Sstevel@tonic-gate sub = SH_SUBSCRIBER(shp, sub_id); 1510*7c478bd9Sstevel@tonic-gate if (sub == NULL) 1511*7c478bd9Sstevel@tonic-gate break; 1512*7c478bd9Sstevel@tonic-gate 1513*7c478bd9Sstevel@tonic-gate free(sub->sd_door_name); 1514*7c478bd9Sstevel@tonic-gate free(sub); 1515*7c478bd9Sstevel@tonic-gate cache_remove_class(shp, EC_ALL, sub_id); 1516*7c478bd9Sstevel@tonic-gate SH_SUBSCRIBER(shp, sub_id) = NULL; 1517*7c478bd9Sstevel@tonic-gate 1518*7c478bd9Sstevel@tonic-gate break; 1519*7c478bd9Sstevel@tonic-gate case SE_BIND_REGISTRATION: 1520*7c478bd9Sstevel@tonic-gate 1521*7c478bd9Sstevel@tonic-gate /* New subscriber */ 1522*7c478bd9Sstevel@tonic-gate if (alloc_subscriber(shp, sub_id, 0) != 0) { 1523*7c478bd9Sstevel@tonic-gate ret = ENOMEM; 1524*7c478bd9Sstevel@tonic-gate break; 1525*7c478bd9Sstevel@tonic-gate } 1526*7c478bd9Sstevel@tonic-gate break; 1527*7c478bd9Sstevel@tonic-gate case SE_REGISTER: 1528*7c478bd9Sstevel@tonic-gate 1529*7c478bd9Sstevel@tonic-gate if (SH_SUBSCRIBER(shp, sub_id) == NULL) { 1530*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1531*7c478bd9Sstevel@tonic-gate break; 1532*7c478bd9Sstevel@tonic-gate } 1533*7c478bd9Sstevel@tonic-gate /* Get new registration data */ 1534*7c478bd9Sstevel@tonic-gate if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen, 1535*7c478bd9Sstevel@tonic-gate &nvl, 0) != 0) { 1536*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1537*7c478bd9Sstevel@tonic-gate break; 1538*7c478bd9Sstevel@tonic-gate } 1539*7c478bd9Sstevel@tonic-gate if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1540*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1541*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1542*7c478bd9Sstevel@tonic-gate break; 1543*7c478bd9Sstevel@tonic-gate } 1544*7c478bd9Sstevel@tonic-gate if (nvpair_value_string_array(nvpair, &event_list, &num_elem) 1545*7c478bd9Sstevel@tonic-gate != 0) { 1546*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1547*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1548*7c478bd9Sstevel@tonic-gate break; 1549*7c478bd9Sstevel@tonic-gate } 1550*7c478bd9Sstevel@tonic-gate class = nvpair_name(nvpair); 1551*7c478bd9Sstevel@tonic-gate 1552*7c478bd9Sstevel@tonic-gate ret = cache_insert_class(shp, class, 1553*7c478bd9Sstevel@tonic-gate event_list, num_elem, sub_id); 1554*7c478bd9Sstevel@tonic-gate if (ret != 0) { 1555*7c478bd9Sstevel@tonic-gate cache_remove_class(shp, class, sub_id); 1556*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1557*7c478bd9Sstevel@tonic-gate ret = EFAULT; 1558*7c478bd9Sstevel@tonic-gate break; 1559*7c478bd9Sstevel@tonic-gate } 1560*7c478bd9Sstevel@tonic-gate 1561*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 1562*7c478bd9Sstevel@tonic-gate 1563*7c478bd9Sstevel@tonic-gate break; 1564*7c478bd9Sstevel@tonic-gate case SE_CLEANUP: 1565*7c478bd9Sstevel@tonic-gate /* Cleanup stale subscribers */ 1566*7c478bd9Sstevel@tonic-gate sysevent_cleanup_subscribers(shp); 1567*7c478bd9Sstevel@tonic-gate break; 1568*7c478bd9Sstevel@tonic-gate default: 1569*7c478bd9Sstevel@tonic-gate ret = EINVAL; 1570*7c478bd9Sstevel@tonic-gate } 1571*7c478bd9Sstevel@tonic-gate 1572*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1573*7c478bd9Sstevel@tonic-gate 1574*7c478bd9Sstevel@tonic-gate return_from_door: 1575*7c478bd9Sstevel@tonic-gate (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 1576*7c478bd9Sstevel@tonic-gate (void) door_return(NULL, 0, NULL, 0); 1577*7c478bd9Sstevel@tonic-gate } 1578*7c478bd9Sstevel@tonic-gate 1579*7c478bd9Sstevel@tonic-gate /* 1580*7c478bd9Sstevel@tonic-gate * sysevent_send_event - 1581*7c478bd9Sstevel@tonic-gate * Send an event via the communication channel associated with the sysevent 1582*7c478bd9Sstevel@tonic-gate * handle. Event notifications are broadcast to all subscribers based upon 1583*7c478bd9Sstevel@tonic-gate * the event class and subclass. The handle must have been previously 1584*7c478bd9Sstevel@tonic-gate * allocated and bound by 1585*7c478bd9Sstevel@tonic-gate * sysevent_open_channel() and sysevent_bind_publisher() 1586*7c478bd9Sstevel@tonic-gate */ 1587*7c478bd9Sstevel@tonic-gate int 1588*7c478bd9Sstevel@tonic-gate sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev) 1589*7c478bd9Sstevel@tonic-gate { 1590*7c478bd9Sstevel@tonic-gate int i, error, sub_fd, result = 0; 1591*7c478bd9Sstevel@tonic-gate int deliver_error = 0; 1592*7c478bd9Sstevel@tonic-gate int subscribers_sent = 0; 1593*7c478bd9Sstevel@tonic-gate int want_resend, resend_cnt = 0; 1594*7c478bd9Sstevel@tonic-gate char *event_class, *event_subclass; 1595*7c478bd9Sstevel@tonic-gate uchar_t *all_class_subscribers, *all_subclass_subscribers; 1596*7c478bd9Sstevel@tonic-gate uchar_t *subclass_subscribers; 1597*7c478bd9Sstevel@tonic-gate subscriber_data_t *sub; 1598*7c478bd9Sstevel@tonic-gate subclass_lst_t *sc_lst; 1599*7c478bd9Sstevel@tonic-gate 1600*7c478bd9Sstevel@tonic-gate /* Check for proper registration */ 1601*7c478bd9Sstevel@tonic-gate event_class = sysevent_get_class_name(ev); 1602*7c478bd9Sstevel@tonic-gate event_subclass = sysevent_get_subclass_name(ev); 1603*7c478bd9Sstevel@tonic-gate 1604*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 1605*7c478bd9Sstevel@tonic-gate 1606*7c478bd9Sstevel@tonic-gate send_event: 1607*7c478bd9Sstevel@tonic-gate 1608*7c478bd9Sstevel@tonic-gate want_resend = 0; 1609*7c478bd9Sstevel@tonic-gate if (!SH_BOUND(shp)) { 1610*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1611*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1612*7c478bd9Sstevel@tonic-gate return (-1); 1613*7c478bd9Sstevel@tonic-gate } 1614*7c478bd9Sstevel@tonic-gate 1615*7c478bd9Sstevel@tonic-gate /* Find all subscribers for this event class/subclass */ 1616*7c478bd9Sstevel@tonic-gate sc_lst = cache_find_subclass( 1617*7c478bd9Sstevel@tonic-gate cache_find_class(shp, EC_ALL), EC_SUB_ALL); 1618*7c478bd9Sstevel@tonic-gate all_class_subscribers = sc_lst->sl_num; 1619*7c478bd9Sstevel@tonic-gate 1620*7c478bd9Sstevel@tonic-gate sc_lst = cache_find_subclass( 1621*7c478bd9Sstevel@tonic-gate cache_find_class(shp, event_class), EC_SUB_ALL); 1622*7c478bd9Sstevel@tonic-gate if (sc_lst) 1623*7c478bd9Sstevel@tonic-gate all_subclass_subscribers = sc_lst->sl_num; 1624*7c478bd9Sstevel@tonic-gate else 1625*7c478bd9Sstevel@tonic-gate all_subclass_subscribers = NULL; 1626*7c478bd9Sstevel@tonic-gate 1627*7c478bd9Sstevel@tonic-gate sc_lst = cache_find_subclass( 1628*7c478bd9Sstevel@tonic-gate cache_find_class(shp, event_class), event_subclass); 1629*7c478bd9Sstevel@tonic-gate if (sc_lst) 1630*7c478bd9Sstevel@tonic-gate subclass_subscribers = sc_lst->sl_num; 1631*7c478bd9Sstevel@tonic-gate else 1632*7c478bd9Sstevel@tonic-gate subclass_subscribers = NULL; 1633*7c478bd9Sstevel@tonic-gate 1634*7c478bd9Sstevel@tonic-gate /* Send event buffer to all valid subscribers */ 1635*7c478bd9Sstevel@tonic-gate for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1636*7c478bd9Sstevel@tonic-gate if ((all_class_subscribers[i] | 1637*7c478bd9Sstevel@tonic-gate (all_subclass_subscribers && all_subclass_subscribers[i]) | 1638*7c478bd9Sstevel@tonic-gate (subclass_subscribers && subclass_subscribers[i])) == 0) 1639*7c478bd9Sstevel@tonic-gate continue; 1640*7c478bd9Sstevel@tonic-gate 1641*7c478bd9Sstevel@tonic-gate sub = SH_SUBSCRIBER(shp, i); 1642*7c478bd9Sstevel@tonic-gate assert(sub != NULL); 1643*7c478bd9Sstevel@tonic-gate 1644*7c478bd9Sstevel@tonic-gate /* Check for active subscriber */ 1645*7c478bd9Sstevel@tonic-gate if (!(sub->sd_flag & ACTIVE)) { 1646*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: subscriber %d inactive\n", 1647*7c478bd9Sstevel@tonic-gate i); 1648*7c478bd9Sstevel@tonic-gate continue; 1649*7c478bd9Sstevel@tonic-gate } 1650*7c478bd9Sstevel@tonic-gate 1651*7c478bd9Sstevel@tonic-gate /* Process only resend requests */ 1652*7c478bd9Sstevel@tonic-gate if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) { 1653*7c478bd9Sstevel@tonic-gate continue; 1654*7c478bd9Sstevel@tonic-gate } 1655*7c478bd9Sstevel@tonic-gate 1656*7c478bd9Sstevel@tonic-gate if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) { 1657*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: Failed to open " 1658*7c478bd9Sstevel@tonic-gate "%s: %s\n", sub->sd_door_name, strerror(errno)); 1659*7c478bd9Sstevel@tonic-gate continue; 1660*7c478bd9Sstevel@tonic-gate } 1661*7c478bd9Sstevel@tonic-gate result = 0; 1662*7c478bd9Sstevel@tonic-gate error = clnt_deliver_event(sub_fd, ev, 1663*7c478bd9Sstevel@tonic-gate sysevent_get_size(ev), &result, sizeof (result)); 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate (void) close(sub_fd); 1666*7c478bd9Sstevel@tonic-gate 1667*7c478bd9Sstevel@tonic-gate /* Successful door call */ 1668*7c478bd9Sstevel@tonic-gate if (error == 0) { 1669*7c478bd9Sstevel@tonic-gate switch (result) { 1670*7c478bd9Sstevel@tonic-gate /* Subscriber requested EAGAIN */ 1671*7c478bd9Sstevel@tonic-gate case EAGAIN: 1672*7c478bd9Sstevel@tonic-gate if (resend_cnt > SE_MAX_RETRY_LIMIT) { 1673*7c478bd9Sstevel@tonic-gate deliver_error = 1; 1674*7c478bd9Sstevel@tonic-gate } else { 1675*7c478bd9Sstevel@tonic-gate want_resend = 1; 1676*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: resend " 1677*7c478bd9Sstevel@tonic-gate "requested for %d\n", i); 1678*7c478bd9Sstevel@tonic-gate sub->sd_flag |= SEND_AGAIN; 1679*7c478bd9Sstevel@tonic-gate } 1680*7c478bd9Sstevel@tonic-gate break; 1681*7c478bd9Sstevel@tonic-gate /* Bad sysevent handle for subscriber */ 1682*7c478bd9Sstevel@tonic-gate case EBADF: 1683*7c478bd9Sstevel@tonic-gate case EINVAL: 1684*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: Bad sysevent " 1685*7c478bd9Sstevel@tonic-gate "handle for %s", sub->sd_door_name); 1686*7c478bd9Sstevel@tonic-gate sub->sd_flag = 0; 1687*7c478bd9Sstevel@tonic-gate deliver_error = 1; 1688*7c478bd9Sstevel@tonic-gate break; 1689*7c478bd9Sstevel@tonic-gate /* Successful delivery */ 1690*7c478bd9Sstevel@tonic-gate default: 1691*7c478bd9Sstevel@tonic-gate sub->sd_flag &= ~SEND_AGAIN; 1692*7c478bd9Sstevel@tonic-gate ++subscribers_sent; 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate } else { 1695*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: Failed door call " 1696*7c478bd9Sstevel@tonic-gate "to %s: %s: %d\n", sub->sd_door_name, 1697*7c478bd9Sstevel@tonic-gate strerror(errno), result); 1698*7c478bd9Sstevel@tonic-gate sub->sd_flag = 0; 1699*7c478bd9Sstevel@tonic-gate deliver_error = 1; 1700*7c478bd9Sstevel@tonic-gate } 1701*7c478bd9Sstevel@tonic-gate } 1702*7c478bd9Sstevel@tonic-gate 1703*7c478bd9Sstevel@tonic-gate if (want_resend) { 1704*7c478bd9Sstevel@tonic-gate resend_cnt++; 1705*7c478bd9Sstevel@tonic-gate goto send_event; 1706*7c478bd9Sstevel@tonic-gate } 1707*7c478bd9Sstevel@tonic-gate 1708*7c478bd9Sstevel@tonic-gate if (deliver_error) { 1709*7c478bd9Sstevel@tonic-gate sysevent_cleanup_subscribers(shp); 1710*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1711*7c478bd9Sstevel@tonic-gate errno = EFAULT; 1712*7c478bd9Sstevel@tonic-gate return (-1); 1713*7c478bd9Sstevel@tonic-gate } 1714*7c478bd9Sstevel@tonic-gate 1715*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate if (subscribers_sent == 0) { 1718*7c478bd9Sstevel@tonic-gate dprint("sysevent_send_event: No subscribers for %s:%s\n", 1719*7c478bd9Sstevel@tonic-gate event_class, event_subclass); 1720*7c478bd9Sstevel@tonic-gate errno = ENOENT; 1721*7c478bd9Sstevel@tonic-gate return (-1); 1722*7c478bd9Sstevel@tonic-gate } 1723*7c478bd9Sstevel@tonic-gate 1724*7c478bd9Sstevel@tonic-gate return (0); 1725*7c478bd9Sstevel@tonic-gate } 1726*7c478bd9Sstevel@tonic-gate 1727*7c478bd9Sstevel@tonic-gate /* 1728*7c478bd9Sstevel@tonic-gate * Common routine to establish an event channel through which an event 1729*7c478bd9Sstevel@tonic-gate * publisher or subscriber may post or receive events. 1730*7c478bd9Sstevel@tonic-gate */ 1731*7c478bd9Sstevel@tonic-gate static sysevent_handle_t * 1732*7c478bd9Sstevel@tonic-gate sysevent_open_channel_common(const char *channel_path) 1733*7c478bd9Sstevel@tonic-gate { 1734*7c478bd9Sstevel@tonic-gate uint32_t sub_id = 0; 1735*7c478bd9Sstevel@tonic-gate char *begin_path; 1736*7c478bd9Sstevel@tonic-gate struct stat chan_stat; 1737*7c478bd9Sstevel@tonic-gate sysevent_handle_t *shp; 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate 1740*7c478bd9Sstevel@tonic-gate if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) { 1741*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1742*7c478bd9Sstevel@tonic-gate return (NULL); 1743*7c478bd9Sstevel@tonic-gate } 1744*7c478bd9Sstevel@tonic-gate 1745*7c478bd9Sstevel@tonic-gate if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) { 1746*7c478bd9Sstevel@tonic-gate if (errno != EEXIST) { 1747*7c478bd9Sstevel@tonic-gate errno = EACCES; 1748*7c478bd9Sstevel@tonic-gate return (NULL); 1749*7c478bd9Sstevel@tonic-gate } 1750*7c478bd9Sstevel@tonic-gate } 1751*7c478bd9Sstevel@tonic-gate 1752*7c478bd9Sstevel@tonic-gate /* Check channel file permissions */ 1753*7c478bd9Sstevel@tonic-gate if (stat(channel_path, &chan_stat) != 0) { 1754*7c478bd9Sstevel@tonic-gate dprint("sysevent_open_channel: Invalid permissions for channel " 1755*7c478bd9Sstevel@tonic-gate "%s\n", channel_path); 1756*7c478bd9Sstevel@tonic-gate errno = EACCES; 1757*7c478bd9Sstevel@tonic-gate return (NULL); 1758*7c478bd9Sstevel@tonic-gate } else if (chan_stat.st_uid != getuid() || 1759*7c478bd9Sstevel@tonic-gate !(chan_stat.st_mode & S_IFDIR)) { 1760*7c478bd9Sstevel@tonic-gate dprint("sysevent_open_channel: Invalid " 1761*7c478bd9Sstevel@tonic-gate "permissions for channel %s\n: %d:%d:%d", channel_path, 1762*7c478bd9Sstevel@tonic-gate (int)chan_stat.st_uid, (int)chan_stat.st_gid, 1763*7c478bd9Sstevel@tonic-gate (int)chan_stat.st_mode); 1764*7c478bd9Sstevel@tonic-gate 1765*7c478bd9Sstevel@tonic-gate errno = EACCES; 1766*7c478bd9Sstevel@tonic-gate return (NULL); 1767*7c478bd9Sstevel@tonic-gate } 1768*7c478bd9Sstevel@tonic-gate 1769*7c478bd9Sstevel@tonic-gate shp = calloc(1, sizeof (sysevent_impl_hdl_t)); 1770*7c478bd9Sstevel@tonic-gate if (shp == NULL) { 1771*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1772*7c478bd9Sstevel@tonic-gate return (NULL); 1773*7c478bd9Sstevel@tonic-gate } 1774*7c478bd9Sstevel@tonic-gate 1775*7c478bd9Sstevel@tonic-gate SH_CHANNEL_NAME(shp) = NULL; 1776*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp) = strdup(channel_path); 1777*7c478bd9Sstevel@tonic-gate if (SH_CHANNEL_PATH(shp) == NULL) { 1778*7c478bd9Sstevel@tonic-gate free(shp); 1779*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1780*7c478bd9Sstevel@tonic-gate return (NULL); 1781*7c478bd9Sstevel@tonic-gate } 1782*7c478bd9Sstevel@tonic-gate 1783*7c478bd9Sstevel@tonic-gate /* Extract the channel name */ 1784*7c478bd9Sstevel@tonic-gate begin_path = SH_CHANNEL_PATH(shp); 1785*7c478bd9Sstevel@tonic-gate while (*begin_path != '\0' && 1786*7c478bd9Sstevel@tonic-gate (begin_path = strpbrk(begin_path, "/")) != NULL) { 1787*7c478bd9Sstevel@tonic-gate ++begin_path; 1788*7c478bd9Sstevel@tonic-gate SH_CHANNEL_NAME(shp) = begin_path; 1789*7c478bd9Sstevel@tonic-gate } 1790*7c478bd9Sstevel@tonic-gate 1791*7c478bd9Sstevel@tonic-gate if (update_kernel_registration(shp, 0, 1792*7c478bd9Sstevel@tonic-gate SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) { 1793*7c478bd9Sstevel@tonic-gate dprint("sysevent_open_channel: Failed for channel %s\n", 1794*7c478bd9Sstevel@tonic-gate SH_CHANNEL_NAME(shp)); 1795*7c478bd9Sstevel@tonic-gate free(SH_CHANNEL_PATH(shp)); 1796*7c478bd9Sstevel@tonic-gate free(shp); 1797*7c478bd9Sstevel@tonic-gate errno = EFAULT; 1798*7c478bd9Sstevel@tonic-gate return (NULL); 1799*7c478bd9Sstevel@tonic-gate } 1800*7c478bd9Sstevel@tonic-gate 1801*7c478bd9Sstevel@tonic-gate (void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL); 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate return (shp); 1804*7c478bd9Sstevel@tonic-gate } 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate /* 1807*7c478bd9Sstevel@tonic-gate * Establish a sysevent channel for publication and subscription 1808*7c478bd9Sstevel@tonic-gate */ 1809*7c478bd9Sstevel@tonic-gate sysevent_handle_t * 1810*7c478bd9Sstevel@tonic-gate sysevent_open_channel(const char *channel) 1811*7c478bd9Sstevel@tonic-gate { 1812*7c478bd9Sstevel@tonic-gate int var_run_mounted = 0; 1813*7c478bd9Sstevel@tonic-gate char full_channel[MAXPATHLEN + 1]; 1814*7c478bd9Sstevel@tonic-gate FILE *fp; 1815*7c478bd9Sstevel@tonic-gate struct stat chan_stat; 1816*7c478bd9Sstevel@tonic-gate struct extmnttab m; 1817*7c478bd9Sstevel@tonic-gate 1818*7c478bd9Sstevel@tonic-gate if (channel == NULL) { 1819*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1820*7c478bd9Sstevel@tonic-gate return (NULL); 1821*7c478bd9Sstevel@tonic-gate } 1822*7c478bd9Sstevel@tonic-gate 1823*7c478bd9Sstevel@tonic-gate /* 1824*7c478bd9Sstevel@tonic-gate * Check that /var/run is mounted as tmpfs before allowing a channel 1825*7c478bd9Sstevel@tonic-gate * to be opened. 1826*7c478bd9Sstevel@tonic-gate */ 1827*7c478bd9Sstevel@tonic-gate if ((fp = fopen(MNTTAB, "r")) == NULL) { 1828*7c478bd9Sstevel@tonic-gate errno = EACCES; 1829*7c478bd9Sstevel@tonic-gate return (NULL); 1830*7c478bd9Sstevel@tonic-gate } 1831*7c478bd9Sstevel@tonic-gate 1832*7c478bd9Sstevel@tonic-gate resetmnttab(fp); 1833*7c478bd9Sstevel@tonic-gate 1834*7c478bd9Sstevel@tonic-gate while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) { 1835*7c478bd9Sstevel@tonic-gate if (strcmp(m.mnt_mountp, "/var/run") == 0 && 1836*7c478bd9Sstevel@tonic-gate strcmp(m.mnt_fstype, "tmpfs") == 0) { 1837*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1838*7c478bd9Sstevel@tonic-gate var_run_mounted = 1; 1839*7c478bd9Sstevel@tonic-gate break; 1840*7c478bd9Sstevel@tonic-gate } 1841*7c478bd9Sstevel@tonic-gate } 1842*7c478bd9Sstevel@tonic-gate (void) fclose(fp); 1843*7c478bd9Sstevel@tonic-gate 1844*7c478bd9Sstevel@tonic-gate if (!var_run_mounted) { 1845*7c478bd9Sstevel@tonic-gate errno = EACCES; 1846*7c478bd9Sstevel@tonic-gate return (NULL); 1847*7c478bd9Sstevel@tonic-gate } 1848*7c478bd9Sstevel@tonic-gate 1849*7c478bd9Sstevel@tonic-gate if (stat(CHAN_PATH, &chan_stat) < 0) { 1850*7c478bd9Sstevel@tonic-gate if (mkdir(CHAN_PATH, 1851*7c478bd9Sstevel@tonic-gate S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) { 1852*7c478bd9Sstevel@tonic-gate dprint("sysevent_open_channel: Unable " 1853*7c478bd9Sstevel@tonic-gate "to create channel directory %s:%s\n", CHAN_PATH, 1854*7c478bd9Sstevel@tonic-gate strerror(errno)); 1855*7c478bd9Sstevel@tonic-gate if (errno != EEXIST) { 1856*7c478bd9Sstevel@tonic-gate errno = EACCES; 1857*7c478bd9Sstevel@tonic-gate return (NULL); 1858*7c478bd9Sstevel@tonic-gate } 1859*7c478bd9Sstevel@tonic-gate } 1860*7c478bd9Sstevel@tonic-gate } 1861*7c478bd9Sstevel@tonic-gate 1862*7c478bd9Sstevel@tonic-gate if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >= 1863*7c478bd9Sstevel@tonic-gate MAXPATHLEN) { 1864*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1865*7c478bd9Sstevel@tonic-gate return (NULL); 1866*7c478bd9Sstevel@tonic-gate } 1867*7c478bd9Sstevel@tonic-gate 1868*7c478bd9Sstevel@tonic-gate return (sysevent_open_channel_common(full_channel)); 1869*7c478bd9Sstevel@tonic-gate } 1870*7c478bd9Sstevel@tonic-gate 1871*7c478bd9Sstevel@tonic-gate /* 1872*7c478bd9Sstevel@tonic-gate * Establish a sysevent channel for publication and subscription 1873*7c478bd9Sstevel@tonic-gate * Full path to the channel determined by the caller 1874*7c478bd9Sstevel@tonic-gate */ 1875*7c478bd9Sstevel@tonic-gate sysevent_handle_t * 1876*7c478bd9Sstevel@tonic-gate sysevent_open_channel_alt(const char *channel_path) 1877*7c478bd9Sstevel@tonic-gate { 1878*7c478bd9Sstevel@tonic-gate return (sysevent_open_channel_common(channel_path)); 1879*7c478bd9Sstevel@tonic-gate } 1880*7c478bd9Sstevel@tonic-gate 1881*7c478bd9Sstevel@tonic-gate /* 1882*7c478bd9Sstevel@tonic-gate * sysevent_close_channel - Clean up resources associated with a previously 1883*7c478bd9Sstevel@tonic-gate * opened sysevent channel 1884*7c478bd9Sstevel@tonic-gate */ 1885*7c478bd9Sstevel@tonic-gate void 1886*7c478bd9Sstevel@tonic-gate sysevent_close_channel(sysevent_handle_t *shp) 1887*7c478bd9Sstevel@tonic-gate { 1888*7c478bd9Sstevel@tonic-gate int error = errno; 1889*7c478bd9Sstevel@tonic-gate uint32_t sub_id = 0; 1890*7c478bd9Sstevel@tonic-gate 1891*7c478bd9Sstevel@tonic-gate if (shp == NULL) { 1892*7c478bd9Sstevel@tonic-gate return; 1893*7c478bd9Sstevel@tonic-gate } 1894*7c478bd9Sstevel@tonic-gate 1895*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 1896*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp)) { 1897*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1898*7c478bd9Sstevel@tonic-gate if (SH_TYPE(shp) == PUBLISHER) 1899*7c478bd9Sstevel@tonic-gate sysevent_unbind_publisher(shp); 1900*7c478bd9Sstevel@tonic-gate else if (SH_TYPE(shp) == SUBSCRIBER) 1901*7c478bd9Sstevel@tonic-gate sysevent_unbind_subscriber(shp); 1902*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 1903*7c478bd9Sstevel@tonic-gate } 1904*7c478bd9Sstevel@tonic-gate 1905*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, 0, 1906*7c478bd9Sstevel@tonic-gate SE_CLOSE_REGISTRATION, &sub_id, 0, NULL); 1907*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1908*7c478bd9Sstevel@tonic-gate 1909*7c478bd9Sstevel@tonic-gate free(SH_CHANNEL_PATH(shp)); 1910*7c478bd9Sstevel@tonic-gate free(shp); 1911*7c478bd9Sstevel@tonic-gate errno = error; 1912*7c478bd9Sstevel@tonic-gate } 1913*7c478bd9Sstevel@tonic-gate 1914*7c478bd9Sstevel@tonic-gate /* 1915*7c478bd9Sstevel@tonic-gate * sysevent_bind_publisher - Bind an event publisher to an event channel 1916*7c478bd9Sstevel@tonic-gate */ 1917*7c478bd9Sstevel@tonic-gate int 1918*7c478bd9Sstevel@tonic-gate sysevent_bind_publisher(sysevent_handle_t *shp) 1919*7c478bd9Sstevel@tonic-gate { 1920*7c478bd9Sstevel@tonic-gate int error = 0; 1921*7c478bd9Sstevel@tonic-gate int fd = -1; 1922*7c478bd9Sstevel@tonic-gate char door_name[MAXPATHLEN]; 1923*7c478bd9Sstevel@tonic-gate uint32_t pub_id; 1924*7c478bd9Sstevel@tonic-gate struct stat reg_stat; 1925*7c478bd9Sstevel@tonic-gate publisher_priv_t *pub; 1926*7c478bd9Sstevel@tonic-gate 1927*7c478bd9Sstevel@tonic-gate if (shp == NULL) { 1928*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1929*7c478bd9Sstevel@tonic-gate return (-1); 1930*7c478bd9Sstevel@tonic-gate } 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 1933*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp)) { 1934*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1935*7c478bd9Sstevel@tonic-gate errno = EINVAL; 1936*7c478bd9Sstevel@tonic-gate return (-1); 1937*7c478bd9Sstevel@tonic-gate } 1938*7c478bd9Sstevel@tonic-gate 1939*7c478bd9Sstevel@tonic-gate if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) == 1940*7c478bd9Sstevel@tonic-gate NULL) { 1941*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1942*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1943*7c478bd9Sstevel@tonic-gate return (-1); 1944*7c478bd9Sstevel@tonic-gate } 1945*7c478bd9Sstevel@tonic-gate SH_PRIV_DATA(shp) = (void *)pub; 1946*7c478bd9Sstevel@tonic-gate 1947*7c478bd9Sstevel@tonic-gate if (snprintf(door_name, MAXPATHLEN, "%s/%s", 1948*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 1949*7c478bd9Sstevel@tonic-gate free(pub); 1950*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1951*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1952*7c478bd9Sstevel@tonic-gate return (-1); 1953*7c478bd9Sstevel@tonic-gate } 1954*7c478bd9Sstevel@tonic-gate if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) { 1955*7c478bd9Sstevel@tonic-gate free(pub); 1956*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 1957*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 1958*7c478bd9Sstevel@tonic-gate return (-1); 1959*7c478bd9Sstevel@tonic-gate } 1960*7c478bd9Sstevel@tonic-gate 1961*7c478bd9Sstevel@tonic-gate /* Only one publisher allowed per channel */ 1962*7c478bd9Sstevel@tonic-gate if (stat(SH_DOOR_NAME(shp), ®_stat) != 0) { 1963*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 1964*7c478bd9Sstevel@tonic-gate error = EINVAL; 1965*7c478bd9Sstevel@tonic-gate goto fail; 1966*7c478bd9Sstevel@tonic-gate } 1967*7c478bd9Sstevel@tonic-gate } 1968*7c478bd9Sstevel@tonic-gate 1969*7c478bd9Sstevel@tonic-gate /* 1970*7c478bd9Sstevel@tonic-gate * Remove door file for robustness. 1971*7c478bd9Sstevel@tonic-gate */ 1972*7c478bd9Sstevel@tonic-gate if (unlink(SH_DOOR_NAME(shp)) != 0) 1973*7c478bd9Sstevel@tonic-gate dprint("sysevent_bind_publisher: Unlink of %s failed.\n", 1974*7c478bd9Sstevel@tonic-gate SH_DOOR_NAME(shp)); 1975*7c478bd9Sstevel@tonic-gate 1976*7c478bd9Sstevel@tonic-gate /* Open channel registration door */ 1977*7c478bd9Sstevel@tonic-gate fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, 1978*7c478bd9Sstevel@tonic-gate S_IREAD|S_IWRITE); 1979*7c478bd9Sstevel@tonic-gate if (fd == -1) { 1980*7c478bd9Sstevel@tonic-gate error = EINVAL; 1981*7c478bd9Sstevel@tonic-gate goto fail; 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate /* 1985*7c478bd9Sstevel@tonic-gate * Create the registration service for this publisher. 1986*7c478bd9Sstevel@tonic-gate */ 1987*7c478bd9Sstevel@tonic-gate if ((SH_DOOR_DESC(shp) = door_create(cache_update_service, 1988*7c478bd9Sstevel@tonic-gate (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1989*7c478bd9Sstevel@tonic-gate dprint("sysevent_bind_publisher: door create failed: " 1990*7c478bd9Sstevel@tonic-gate "%s\n", strerror(errno)); 1991*7c478bd9Sstevel@tonic-gate error = EFAULT; 1992*7c478bd9Sstevel@tonic-gate goto fail; 1993*7c478bd9Sstevel@tonic-gate } 1994*7c478bd9Sstevel@tonic-gate 1995*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 1996*7c478bd9Sstevel@tonic-gate if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) { 1997*7c478bd9Sstevel@tonic-gate dprint("sysevent_bind_publisher: unable to " 1998*7c478bd9Sstevel@tonic-gate "bind event channel: fattach: %s\n", 1999*7c478bd9Sstevel@tonic-gate SH_DOOR_NAME(shp)); 2000*7c478bd9Sstevel@tonic-gate error = EACCES; 2001*7c478bd9Sstevel@tonic-gate goto fail; 2002*7c478bd9Sstevel@tonic-gate } 2003*7c478bd9Sstevel@tonic-gate 2004*7c478bd9Sstevel@tonic-gate /* Bind this publisher in the kernel registration database */ 2005*7c478bd9Sstevel@tonic-gate if (update_kernel_registration(shp, PUBLISHER, 2006*7c478bd9Sstevel@tonic-gate SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) { 2007*7c478bd9Sstevel@tonic-gate error = errno; 2008*7c478bd9Sstevel@tonic-gate goto fail; 2009*7c478bd9Sstevel@tonic-gate } 2010*7c478bd9Sstevel@tonic-gate 2011*7c478bd9Sstevel@tonic-gate SH_ID(shp) = pub_id; 2012*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 1; 2013*7c478bd9Sstevel@tonic-gate SH_TYPE(shp) = PUBLISHER; 2014*7c478bd9Sstevel@tonic-gate 2015*7c478bd9Sstevel@tonic-gate 2016*7c478bd9Sstevel@tonic-gate /* Create the subscription registration cache */ 2017*7c478bd9Sstevel@tonic-gate if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) { 2018*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, 2019*7c478bd9Sstevel@tonic-gate PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL); 2020*7c478bd9Sstevel@tonic-gate error = EFAULT; 2021*7c478bd9Sstevel@tonic-gate goto fail; 2022*7c478bd9Sstevel@tonic-gate } 2023*7c478bd9Sstevel@tonic-gate (void) close(fd); 2024*7c478bd9Sstevel@tonic-gate 2025*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2026*7c478bd9Sstevel@tonic-gate 2027*7c478bd9Sstevel@tonic-gate return (0); 2028*7c478bd9Sstevel@tonic-gate 2029*7c478bd9Sstevel@tonic-gate fail: 2030*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 0; 2031*7c478bd9Sstevel@tonic-gate (void) door_revoke(SH_DOOR_DESC(shp)); 2032*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 2033*7c478bd9Sstevel@tonic-gate free(SH_DOOR_NAME(shp)); 2034*7c478bd9Sstevel@tonic-gate free(pub); 2035*7c478bd9Sstevel@tonic-gate (void) close(fd); 2036*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2037*7c478bd9Sstevel@tonic-gate errno = error; 2038*7c478bd9Sstevel@tonic-gate return (-1); 2039*7c478bd9Sstevel@tonic-gate } 2040*7c478bd9Sstevel@tonic-gate 2041*7c478bd9Sstevel@tonic-gate /* 2042*7c478bd9Sstevel@tonic-gate * sysevent_bind_subscriber - Bind an event receiver to an event channel 2043*7c478bd9Sstevel@tonic-gate */ 2044*7c478bd9Sstevel@tonic-gate int 2045*7c478bd9Sstevel@tonic-gate sysevent_bind_subscriber(sysevent_handle_t *shp, 2046*7c478bd9Sstevel@tonic-gate void (*event_handler)(sysevent_t *ev)) 2047*7c478bd9Sstevel@tonic-gate { 2048*7c478bd9Sstevel@tonic-gate int fd = -1; 2049*7c478bd9Sstevel@tonic-gate int error = 0; 2050*7c478bd9Sstevel@tonic-gate uint32_t sub_id = 0; 2051*7c478bd9Sstevel@tonic-gate char door_name[MAXPATHLEN]; 2052*7c478bd9Sstevel@tonic-gate subscriber_priv_t *sub_info; 2053*7c478bd9Sstevel@tonic-gate 2054*7c478bd9Sstevel@tonic-gate if (shp == NULL || event_handler == NULL) { 2055*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2056*7c478bd9Sstevel@tonic-gate return (-1); 2057*7c478bd9Sstevel@tonic-gate } 2058*7c478bd9Sstevel@tonic-gate 2059*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 2060*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp)) { 2061*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2062*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2063*7c478bd9Sstevel@tonic-gate return (-1); 2064*7c478bd9Sstevel@tonic-gate } 2065*7c478bd9Sstevel@tonic-gate 2066*7c478bd9Sstevel@tonic-gate if ((sub_info = (subscriber_priv_t *)calloc(1, 2067*7c478bd9Sstevel@tonic-gate sizeof (subscriber_priv_t))) == NULL) { 2068*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 2069*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2070*7c478bd9Sstevel@tonic-gate return (-1); 2071*7c478bd9Sstevel@tonic-gate } 2072*7c478bd9Sstevel@tonic-gate 2073*7c478bd9Sstevel@tonic-gate if (snprintf(door_name, MAXPATHLEN, "%s/%s", 2074*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 2075*7c478bd9Sstevel@tonic-gate free(sub_info); 2076*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2077*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2078*7c478bd9Sstevel@tonic-gate return (-1); 2079*7c478bd9Sstevel@tonic-gate } 2080*7c478bd9Sstevel@tonic-gate 2081*7c478bd9Sstevel@tonic-gate if ((sub_info->sp_door_name = strdup(door_name)) == NULL) { 2082*7c478bd9Sstevel@tonic-gate free(sub_info); 2083*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 2084*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2085*7c478bd9Sstevel@tonic-gate return (-1); 2086*7c478bd9Sstevel@tonic-gate } 2087*7c478bd9Sstevel@tonic-gate (void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL); 2088*7c478bd9Sstevel@tonic-gate (void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL); 2089*7c478bd9Sstevel@tonic-gate sub_info->sp_func = event_handler; 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate /* Update the in-kernel registration */ 2092*7c478bd9Sstevel@tonic-gate if (update_kernel_registration(shp, SUBSCRIBER, 2093*7c478bd9Sstevel@tonic-gate SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) { 2094*7c478bd9Sstevel@tonic-gate error = errno; 2095*7c478bd9Sstevel@tonic-gate goto fail; 2096*7c478bd9Sstevel@tonic-gate } 2097*7c478bd9Sstevel@tonic-gate SH_ID(shp) = sub_id; 2098*7c478bd9Sstevel@tonic-gate 2099*7c478bd9Sstevel@tonic-gate if (snprintf(door_name, MAXPATHLEN, "%s/%d", 2100*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) { 2101*7c478bd9Sstevel@tonic-gate error = EINVAL; 2102*7c478bd9Sstevel@tonic-gate goto fail; 2103*7c478bd9Sstevel@tonic-gate } 2104*7c478bd9Sstevel@tonic-gate if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) { 2105*7c478bd9Sstevel@tonic-gate error = ENOMEM; 2106*7c478bd9Sstevel@tonic-gate goto fail; 2107*7c478bd9Sstevel@tonic-gate } 2108*7c478bd9Sstevel@tonic-gate 2109*7c478bd9Sstevel@tonic-gate /* 2110*7c478bd9Sstevel@tonic-gate * Remove door file for robustness. 2111*7c478bd9Sstevel@tonic-gate */ 2112*7c478bd9Sstevel@tonic-gate if (unlink(SH_DOOR_NAME(shp)) != 0) 2113*7c478bd9Sstevel@tonic-gate dprint("sysevent_bind_subscriber: Unlink of %s failed.\n", 2114*7c478bd9Sstevel@tonic-gate SH_DOOR_NAME(shp)); 2115*7c478bd9Sstevel@tonic-gate 2116*7c478bd9Sstevel@tonic-gate fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE); 2117*7c478bd9Sstevel@tonic-gate if (fd == -1) { 2118*7c478bd9Sstevel@tonic-gate error = EFAULT; 2119*7c478bd9Sstevel@tonic-gate goto fail; 2120*7c478bd9Sstevel@tonic-gate } 2121*7c478bd9Sstevel@tonic-gate 2122*7c478bd9Sstevel@tonic-gate /* 2123*7c478bd9Sstevel@tonic-gate * Create the sysevent door service for this client. 2124*7c478bd9Sstevel@tonic-gate * syseventd will use this door service to propagate 2125*7c478bd9Sstevel@tonic-gate * events to the client. 2126*7c478bd9Sstevel@tonic-gate */ 2127*7c478bd9Sstevel@tonic-gate if ((SH_DOOR_DESC(shp) = door_create(event_deliver_service, 2128*7c478bd9Sstevel@tonic-gate (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 2129*7c478bd9Sstevel@tonic-gate dprint("sysevent_bind_subscriber: door create failed: " 2130*7c478bd9Sstevel@tonic-gate "%s\n", strerror(errno)); 2131*7c478bd9Sstevel@tonic-gate error = EFAULT; 2132*7c478bd9Sstevel@tonic-gate goto fail; 2133*7c478bd9Sstevel@tonic-gate } 2134*7c478bd9Sstevel@tonic-gate 2135*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 2136*7c478bd9Sstevel@tonic-gate if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) { 2137*7c478bd9Sstevel@tonic-gate error = EFAULT; 2138*7c478bd9Sstevel@tonic-gate goto fail; 2139*7c478bd9Sstevel@tonic-gate } 2140*7c478bd9Sstevel@tonic-gate (void) close(fd); 2141*7c478bd9Sstevel@tonic-gate 2142*7c478bd9Sstevel@tonic-gate if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION, 2143*7c478bd9Sstevel@tonic-gate sub_id, 0, NULL) != 0) { 2144*7c478bd9Sstevel@tonic-gate error = errno; 2145*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, SUBSCRIBER, 2146*7c478bd9Sstevel@tonic-gate SE_UNBIND_REGISTRATION, &sub_id, 0, NULL); 2147*7c478bd9Sstevel@tonic-gate goto fail; 2148*7c478bd9Sstevel@tonic-gate } 2149*7c478bd9Sstevel@tonic-gate 2150*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 1; 2151*7c478bd9Sstevel@tonic-gate SH_TYPE(shp) = SUBSCRIBER; 2152*7c478bd9Sstevel@tonic-gate SH_PRIV_DATA(shp) = (void *)sub_info; 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate 2155*7c478bd9Sstevel@tonic-gate /* Create an event handler thread */ 2156*7c478bd9Sstevel@tonic-gate if (thr_create(NULL, NULL, (void *(*)(void *))subscriber_event_handler, 2157*7c478bd9Sstevel@tonic-gate shp, THR_BOUND, &sub_info->sp_handler_tid) != 0) { 2158*7c478bd9Sstevel@tonic-gate error = EFAULT; 2159*7c478bd9Sstevel@tonic-gate goto fail; 2160*7c478bd9Sstevel@tonic-gate } 2161*7c478bd9Sstevel@tonic-gate 2162*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2163*7c478bd9Sstevel@tonic-gate 2164*7c478bd9Sstevel@tonic-gate return (0); 2165*7c478bd9Sstevel@tonic-gate 2166*7c478bd9Sstevel@tonic-gate fail: 2167*7c478bd9Sstevel@tonic-gate (void) close(fd); 2168*7c478bd9Sstevel@tonic-gate (void) door_revoke(SH_DOOR_DESC(shp)); 2169*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 2170*7c478bd9Sstevel@tonic-gate (void) cond_destroy(&sub_info->sp_cv); 2171*7c478bd9Sstevel@tonic-gate (void) mutex_destroy(&sub_info->sp_qlock); 2172*7c478bd9Sstevel@tonic-gate free(sub_info->sp_door_name); 2173*7c478bd9Sstevel@tonic-gate free(sub_info); 2174*7c478bd9Sstevel@tonic-gate if (SH_ID(shp)) { 2175*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, SUBSCRIBER, 2176*7c478bd9Sstevel@tonic-gate SE_UNBIND_REGISTRATION, &sub_id, 0, NULL); 2177*7c478bd9Sstevel@tonic-gate SH_ID(shp) = 0; 2178*7c478bd9Sstevel@tonic-gate } 2179*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp)) { 2180*7c478bd9Sstevel@tonic-gate (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION, 2181*7c478bd9Sstevel@tonic-gate sub_id, 0, NULL); 2182*7c478bd9Sstevel@tonic-gate free(SH_DOOR_NAME(shp)); 2183*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 0; 2184*7c478bd9Sstevel@tonic-gate } 2185*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2186*7c478bd9Sstevel@tonic-gate 2187*7c478bd9Sstevel@tonic-gate errno = error; 2188*7c478bd9Sstevel@tonic-gate 2189*7c478bd9Sstevel@tonic-gate return (-1); 2190*7c478bd9Sstevel@tonic-gate } 2191*7c478bd9Sstevel@tonic-gate 2192*7c478bd9Sstevel@tonic-gate /* 2193*7c478bd9Sstevel@tonic-gate * sysevent_register_event - register an event class and associated subclasses 2194*7c478bd9Sstevel@tonic-gate * for an event subscriber 2195*7c478bd9Sstevel@tonic-gate */ 2196*7c478bd9Sstevel@tonic-gate int 2197*7c478bd9Sstevel@tonic-gate sysevent_register_event(sysevent_handle_t *shp, 2198*7c478bd9Sstevel@tonic-gate const char *ev_class, const char **ev_subclass, 2199*7c478bd9Sstevel@tonic-gate int subclass_num) 2200*7c478bd9Sstevel@tonic-gate { 2201*7c478bd9Sstevel@tonic-gate int error; 2202*7c478bd9Sstevel@tonic-gate char *event_class = (char *)ev_class; 2203*7c478bd9Sstevel@tonic-gate char **event_subclass_list = (char **)ev_subclass; 2204*7c478bd9Sstevel@tonic-gate char *nvlbuf = NULL; 2205*7c478bd9Sstevel@tonic-gate size_t datalen; 2206*7c478bd9Sstevel@tonic-gate nvlist_t *nvl; 2207*7c478bd9Sstevel@tonic-gate 2208*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 2209*7c478bd9Sstevel@tonic-gate if (event_class == NULL || event_subclass_list == NULL || 2210*7c478bd9Sstevel@tonic-gate event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 || 2211*7c478bd9Sstevel@tonic-gate subclass_num <= 0) { 2212*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2213*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2214*7c478bd9Sstevel@tonic-gate return (-1); 2215*7c478bd9Sstevel@tonic-gate } 2216*7c478bd9Sstevel@tonic-gate 2217*7c478bd9Sstevel@tonic-gate if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) { 2218*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2219*7c478bd9Sstevel@tonic-gate return (-1); 2220*7c478bd9Sstevel@tonic-gate } 2221*7c478bd9Sstevel@tonic-gate if (nvlist_add_string_array(nvl, event_class, event_subclass_list, 2222*7c478bd9Sstevel@tonic-gate subclass_num) != 0) { 2223*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 2224*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2225*7c478bd9Sstevel@tonic-gate return (-1); 2226*7c478bd9Sstevel@tonic-gate } 2227*7c478bd9Sstevel@tonic-gate if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) { 2228*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 2229*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2230*7c478bd9Sstevel@tonic-gate return (-1); 2231*7c478bd9Sstevel@tonic-gate } 2232*7c478bd9Sstevel@tonic-gate nvlist_free(nvl); 2233*7c478bd9Sstevel@tonic-gate 2234*7c478bd9Sstevel@tonic-gate /* Store new subscriber in in-kernel registration */ 2235*7c478bd9Sstevel@tonic-gate if (update_kernel_registration(shp, SUBSCRIBER, 2236*7c478bd9Sstevel@tonic-gate SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf) 2237*7c478bd9Sstevel@tonic-gate != 0) { 2238*7c478bd9Sstevel@tonic-gate error = errno; 2239*7c478bd9Sstevel@tonic-gate free(nvlbuf); 2240*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2241*7c478bd9Sstevel@tonic-gate errno = error; 2242*7c478bd9Sstevel@tonic-gate return (-1); 2243*7c478bd9Sstevel@tonic-gate } 2244*7c478bd9Sstevel@tonic-gate /* Update the publisher's cached registration */ 2245*7c478bd9Sstevel@tonic-gate if (update_publisher_cache( 2246*7c478bd9Sstevel@tonic-gate (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER, 2247*7c478bd9Sstevel@tonic-gate SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) { 2248*7c478bd9Sstevel@tonic-gate error = errno; 2249*7c478bd9Sstevel@tonic-gate free(nvlbuf); 2250*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2251*7c478bd9Sstevel@tonic-gate errno = error; 2252*7c478bd9Sstevel@tonic-gate return (-1); 2253*7c478bd9Sstevel@tonic-gate } 2254*7c478bd9Sstevel@tonic-gate 2255*7c478bd9Sstevel@tonic-gate free(nvlbuf); 2256*7c478bd9Sstevel@tonic-gate 2257*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate return (0); 2260*7c478bd9Sstevel@tonic-gate } 2261*7c478bd9Sstevel@tonic-gate 2262*7c478bd9Sstevel@tonic-gate /* 2263*7c478bd9Sstevel@tonic-gate * sysevent_unregister_event - Unregister an event class and associated 2264*7c478bd9Sstevel@tonic-gate * subclasses for an event subscriber 2265*7c478bd9Sstevel@tonic-gate */ 2266*7c478bd9Sstevel@tonic-gate void 2267*7c478bd9Sstevel@tonic-gate sysevent_unregister_event(sysevent_handle_t *shp, const char *class) 2268*7c478bd9Sstevel@tonic-gate { 2269*7c478bd9Sstevel@tonic-gate size_t class_sz; 2270*7c478bd9Sstevel@tonic-gate 2271*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 2272*7c478bd9Sstevel@tonic-gate 2273*7c478bd9Sstevel@tonic-gate if (!SH_BOUND(shp)) { 2274*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2275*7c478bd9Sstevel@tonic-gate return; 2276*7c478bd9Sstevel@tonic-gate } 2277*7c478bd9Sstevel@tonic-gate 2278*7c478bd9Sstevel@tonic-gate /* Remove subscriber from in-kernel registration */ 2279*7c478bd9Sstevel@tonic-gate class_sz = strlen(class) + 1; 2280*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, SUBSCRIBER, 2281*7c478bd9Sstevel@tonic-gate SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class); 2282*7c478bd9Sstevel@tonic-gate /* Update the publisher's cached registration */ 2283*7c478bd9Sstevel@tonic-gate (void) update_publisher_cache( 2284*7c478bd9Sstevel@tonic-gate (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER, 2285*7c478bd9Sstevel@tonic-gate SH_ID(shp), class_sz, (uchar_t *)class); 2286*7c478bd9Sstevel@tonic-gate 2287*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2288*7c478bd9Sstevel@tonic-gate } 2289*7c478bd9Sstevel@tonic-gate 2290*7c478bd9Sstevel@tonic-gate static int 2291*7c478bd9Sstevel@tonic-gate cleanup_id(sysevent_handle_t *shp, uint32_t id, int type) 2292*7c478bd9Sstevel@tonic-gate { 2293*7c478bd9Sstevel@tonic-gate dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id); 2294*7c478bd9Sstevel@tonic-gate 2295*7c478bd9Sstevel@tonic-gate /* Remove registration from the kernel */ 2296*7c478bd9Sstevel@tonic-gate if (update_kernel_registration(shp, type, SE_CLEANUP, &id, 2297*7c478bd9Sstevel@tonic-gate 0, NULL) != 0) { 2298*7c478bd9Sstevel@tonic-gate dprint("cleanup_id: Unable to clean " 2299*7c478bd9Sstevel@tonic-gate "up %s/%d\n", SH_CHANNEL_NAME(shp), id); 2300*7c478bd9Sstevel@tonic-gate return (-1); 2301*7c478bd9Sstevel@tonic-gate } 2302*7c478bd9Sstevel@tonic-gate 2303*7c478bd9Sstevel@tonic-gate return (0); 2304*7c478bd9Sstevel@tonic-gate } 2305*7c478bd9Sstevel@tonic-gate 2306*7c478bd9Sstevel@tonic-gate /* 2307*7c478bd9Sstevel@tonic-gate * sysevent_cleanup_subscribers: Allows the caller to cleanup resources 2308*7c478bd9Sstevel@tonic-gate * allocated to unresponsive subscribers. 2309*7c478bd9Sstevel@tonic-gate */ 2310*7c478bd9Sstevel@tonic-gate void 2311*7c478bd9Sstevel@tonic-gate sysevent_cleanup_subscribers(sysevent_handle_t *shp) 2312*7c478bd9Sstevel@tonic-gate { 2313*7c478bd9Sstevel@tonic-gate uint32_t ping, result; 2314*7c478bd9Sstevel@tonic-gate int i, error, sub_fd; 2315*7c478bd9Sstevel@tonic-gate subscriber_data_t *sub; 2316*7c478bd9Sstevel@tonic-gate 2317*7c478bd9Sstevel@tonic-gate if (!SH_BOUND(shp)) { 2318*7c478bd9Sstevel@tonic-gate return; 2319*7c478bd9Sstevel@tonic-gate } 2320*7c478bd9Sstevel@tonic-gate 2321*7c478bd9Sstevel@tonic-gate for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 2322*7c478bd9Sstevel@tonic-gate 2323*7c478bd9Sstevel@tonic-gate sub = SH_SUBSCRIBER(shp, i); 2324*7c478bd9Sstevel@tonic-gate if (sub == NULL) { 2325*7c478bd9Sstevel@tonic-gate continue; 2326*7c478bd9Sstevel@tonic-gate } 2327*7c478bd9Sstevel@tonic-gate 2328*7c478bd9Sstevel@tonic-gate if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) { 2329*7c478bd9Sstevel@tonic-gate continue; 2330*7c478bd9Sstevel@tonic-gate } 2331*7c478bd9Sstevel@tonic-gate /* Check for valid and responsive subscriber */ 2332*7c478bd9Sstevel@tonic-gate error = clnt_deliver_event(sub_fd, &ping, 2333*7c478bd9Sstevel@tonic-gate sizeof (uint32_t), &result, sizeof (result)); 2334*7c478bd9Sstevel@tonic-gate (void) close(sub_fd); 2335*7c478bd9Sstevel@tonic-gate 2336*7c478bd9Sstevel@tonic-gate /* Only cleanup on EBADF (Invalid door descriptor) */ 2337*7c478bd9Sstevel@tonic-gate if (error != EBADF) 2338*7c478bd9Sstevel@tonic-gate continue; 2339*7c478bd9Sstevel@tonic-gate 2340*7c478bd9Sstevel@tonic-gate if (cleanup_id(shp, i, SUBSCRIBER) != 0) 2341*7c478bd9Sstevel@tonic-gate continue; 2342*7c478bd9Sstevel@tonic-gate 2343*7c478bd9Sstevel@tonic-gate cache_remove_class(shp, EC_ALL, i); 2344*7c478bd9Sstevel@tonic-gate 2345*7c478bd9Sstevel@tonic-gate free(sub->sd_door_name); 2346*7c478bd9Sstevel@tonic-gate free(sub); 2347*7c478bd9Sstevel@tonic-gate SH_SUBSCRIBER(shp, i) = NULL; 2348*7c478bd9Sstevel@tonic-gate } 2349*7c478bd9Sstevel@tonic-gate 2350*7c478bd9Sstevel@tonic-gate } 2351*7c478bd9Sstevel@tonic-gate 2352*7c478bd9Sstevel@tonic-gate /* 2353*7c478bd9Sstevel@tonic-gate * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated 2354*7c478bd9Sstevel@tonic-gate * as needed. 2355*7c478bd9Sstevel@tonic-gate */ 2356*7c478bd9Sstevel@tonic-gate void 2357*7c478bd9Sstevel@tonic-gate sysevent_cleanup_publishers(sysevent_handle_t *shp) 2358*7c478bd9Sstevel@tonic-gate { 2359*7c478bd9Sstevel@tonic-gate (void) cleanup_id(shp, 1, PUBLISHER); 2360*7c478bd9Sstevel@tonic-gate } 2361*7c478bd9Sstevel@tonic-gate 2362*7c478bd9Sstevel@tonic-gate /* 2363*7c478bd9Sstevel@tonic-gate * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel. 2364*7c478bd9Sstevel@tonic-gate */ 2365*7c478bd9Sstevel@tonic-gate void 2366*7c478bd9Sstevel@tonic-gate sysevent_unbind_subscriber(sysevent_handle_t *shp) 2367*7c478bd9Sstevel@tonic-gate { 2368*7c478bd9Sstevel@tonic-gate subscriber_priv_t *sub_info; 2369*7c478bd9Sstevel@tonic-gate 2370*7c478bd9Sstevel@tonic-gate if (shp == NULL) 2371*7c478bd9Sstevel@tonic-gate return; 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 2374*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp) == 0) { 2375*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2376*7c478bd9Sstevel@tonic-gate return; 2377*7c478bd9Sstevel@tonic-gate } 2378*7c478bd9Sstevel@tonic-gate 2379*7c478bd9Sstevel@tonic-gate /* Update the in-kernel registration */ 2380*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, SUBSCRIBER, 2381*7c478bd9Sstevel@tonic-gate SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL); 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate /* Update the sysevent channel publisher */ 2384*7c478bd9Sstevel@tonic-gate sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 2385*7c478bd9Sstevel@tonic-gate (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION, 2386*7c478bd9Sstevel@tonic-gate SH_ID(shp), 0, NULL); 2387*7c478bd9Sstevel@tonic-gate 2388*7c478bd9Sstevel@tonic-gate /* Close down event delivery facilities */ 2389*7c478bd9Sstevel@tonic-gate (void) door_revoke(SH_DOOR_DESC(shp)); 2390*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 2391*7c478bd9Sstevel@tonic-gate 2392*7c478bd9Sstevel@tonic-gate 2393*7c478bd9Sstevel@tonic-gate /* 2394*7c478bd9Sstevel@tonic-gate * Release resources and wait for pending event delivery to 2395*7c478bd9Sstevel@tonic-gate * complete. 2396*7c478bd9Sstevel@tonic-gate */ 2397*7c478bd9Sstevel@tonic-gate (void) mutex_lock(&sub_info->sp_qlock); 2398*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 0; 2399*7c478bd9Sstevel@tonic-gate /* Signal event handler and drain the subscriber's event queue */ 2400*7c478bd9Sstevel@tonic-gate (void) cond_signal(&sub_info->sp_cv); 2401*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(&sub_info->sp_qlock); 2402*7c478bd9Sstevel@tonic-gate (void) thr_join(sub_info->sp_handler_tid, NULL, NULL); 2403*7c478bd9Sstevel@tonic-gate 2404*7c478bd9Sstevel@tonic-gate (void) cond_destroy(&sub_info->sp_cv); 2405*7c478bd9Sstevel@tonic-gate (void) mutex_destroy(&sub_info->sp_qlock); 2406*7c478bd9Sstevel@tonic-gate free(sub_info->sp_door_name); 2407*7c478bd9Sstevel@tonic-gate free(sub_info); 2408*7c478bd9Sstevel@tonic-gate free(SH_DOOR_NAME(shp)); 2409*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2410*7c478bd9Sstevel@tonic-gate } 2411*7c478bd9Sstevel@tonic-gate 2412*7c478bd9Sstevel@tonic-gate /* 2413*7c478bd9Sstevel@tonic-gate * sysevent_unbind_publisher: Unbind publisher from the sysevent channel. 2414*7c478bd9Sstevel@tonic-gate */ 2415*7c478bd9Sstevel@tonic-gate void 2416*7c478bd9Sstevel@tonic-gate sysevent_unbind_publisher(sysevent_handle_t *shp) 2417*7c478bd9Sstevel@tonic-gate { 2418*7c478bd9Sstevel@tonic-gate if (shp == NULL) 2419*7c478bd9Sstevel@tonic-gate return; 2420*7c478bd9Sstevel@tonic-gate 2421*7c478bd9Sstevel@tonic-gate (void) mutex_lock(SH_LOCK(shp)); 2422*7c478bd9Sstevel@tonic-gate if (SH_BOUND(shp) == 0) { 2423*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2424*7c478bd9Sstevel@tonic-gate return; 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate 2427*7c478bd9Sstevel@tonic-gate /* Close down the registration facilities */ 2428*7c478bd9Sstevel@tonic-gate (void) door_revoke(SH_DOOR_DESC(shp)); 2429*7c478bd9Sstevel@tonic-gate (void) fdetach(SH_DOOR_NAME(shp)); 2430*7c478bd9Sstevel@tonic-gate 2431*7c478bd9Sstevel@tonic-gate /* Update the in-kernel registration */ 2432*7c478bd9Sstevel@tonic-gate (void) update_kernel_registration(shp, PUBLISHER, 2433*7c478bd9Sstevel@tonic-gate SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL); 2434*7c478bd9Sstevel@tonic-gate SH_BOUND(shp) = 0; 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate /* Free resources associated with bind */ 2437*7c478bd9Sstevel@tonic-gate free_cached_registration(shp); 2438*7c478bd9Sstevel@tonic-gate dealloc_subscribers(shp); 2439*7c478bd9Sstevel@tonic-gate 2440*7c478bd9Sstevel@tonic-gate free(SH_PRIV_DATA(shp)); 2441*7c478bd9Sstevel@tonic-gate free(SH_DOOR_NAME(shp)); 2442*7c478bd9Sstevel@tonic-gate SH_ID(shp) = 0; 2443*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(SH_LOCK(shp)); 2444*7c478bd9Sstevel@tonic-gate } 2445*7c478bd9Sstevel@tonic-gate 2446*7c478bd9Sstevel@tonic-gate /* 2447*7c478bd9Sstevel@tonic-gate * Evolving APIs to subscribe to syseventd(1M) system events. 2448*7c478bd9Sstevel@tonic-gate */ 2449*7c478bd9Sstevel@tonic-gate 2450*7c478bd9Sstevel@tonic-gate /* 2451*7c478bd9Sstevel@tonic-gate * sysevent_bind_handle - Bind application event handler for syseventd 2452*7c478bd9Sstevel@tonic-gate * subscription. 2453*7c478bd9Sstevel@tonic-gate */ 2454*7c478bd9Sstevel@tonic-gate sysevent_handle_t * 2455*7c478bd9Sstevel@tonic-gate sysevent_bind_handle(void (*event_handler)(sysevent_t *ev)) 2456*7c478bd9Sstevel@tonic-gate { 2457*7c478bd9Sstevel@tonic-gate sysevent_handle_t *shp; 2458*7c478bd9Sstevel@tonic-gate 2459*7c478bd9Sstevel@tonic-gate if (getuid() != 0) { 2460*7c478bd9Sstevel@tonic-gate errno = EACCES; 2461*7c478bd9Sstevel@tonic-gate return (NULL); 2462*7c478bd9Sstevel@tonic-gate } 2463*7c478bd9Sstevel@tonic-gate 2464*7c478bd9Sstevel@tonic-gate if (event_handler == NULL) { 2465*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2466*7c478bd9Sstevel@tonic-gate return (NULL); 2467*7c478bd9Sstevel@tonic-gate } 2468*7c478bd9Sstevel@tonic-gate 2469*7c478bd9Sstevel@tonic-gate if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) { 2470*7c478bd9Sstevel@tonic-gate return (NULL); 2471*7c478bd9Sstevel@tonic-gate } 2472*7c478bd9Sstevel@tonic-gate 2473*7c478bd9Sstevel@tonic-gate if (sysevent_bind_subscriber(shp, event_handler) != 0) { 2474*7c478bd9Sstevel@tonic-gate 2475*7c478bd9Sstevel@tonic-gate /* 2476*7c478bd9Sstevel@tonic-gate * Ask syseventd to clean-up any stale subcribers and try to 2477*7c478bd9Sstevel@tonic-gate * to bind again 2478*7c478bd9Sstevel@tonic-gate */ 2479*7c478bd9Sstevel@tonic-gate if (errno == EBUSY) { 2480*7c478bd9Sstevel@tonic-gate int pub_fd; 2481*7c478bd9Sstevel@tonic-gate char door_name[MAXPATHLEN]; 2482*7c478bd9Sstevel@tonic-gate uint32_t result; 2483*7c478bd9Sstevel@tonic-gate struct reg_args rargs; 2484*7c478bd9Sstevel@tonic-gate 2485*7c478bd9Sstevel@tonic-gate if (snprintf(door_name, MAXPATHLEN, "%s/%s", 2486*7c478bd9Sstevel@tonic-gate SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 2487*7c478bd9Sstevel@tonic-gate sysevent_close_channel(shp); 2488*7c478bd9Sstevel@tonic-gate errno = EINVAL; 2489*7c478bd9Sstevel@tonic-gate return (NULL); 2490*7c478bd9Sstevel@tonic-gate } 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate rargs.ra_op = SE_CLEANUP; 2493*7c478bd9Sstevel@tonic-gate pub_fd = open(door_name, O_RDONLY); 2494*7c478bd9Sstevel@tonic-gate (void) clnt_deliver_event(pub_fd, (void *)&rargs, 2495*7c478bd9Sstevel@tonic-gate sizeof (struct reg_args), &result, sizeof (result)); 2496*7c478bd9Sstevel@tonic-gate (void) close(pub_fd); 2497*7c478bd9Sstevel@tonic-gate 2498*7c478bd9Sstevel@tonic-gate /* Try to bind again */ 2499*7c478bd9Sstevel@tonic-gate if (sysevent_bind_subscriber(shp, event_handler) != 0) { 2500*7c478bd9Sstevel@tonic-gate sysevent_close_channel(shp); 2501*7c478bd9Sstevel@tonic-gate return (NULL); 2502*7c478bd9Sstevel@tonic-gate } 2503*7c478bd9Sstevel@tonic-gate } else { 2504*7c478bd9Sstevel@tonic-gate sysevent_close_channel(shp); 2505*7c478bd9Sstevel@tonic-gate return (NULL); 2506*7c478bd9Sstevel@tonic-gate } 2507*7c478bd9Sstevel@tonic-gate } 2508*7c478bd9Sstevel@tonic-gate 2509*7c478bd9Sstevel@tonic-gate return (shp); 2510*7c478bd9Sstevel@tonic-gate } 2511*7c478bd9Sstevel@tonic-gate 2512*7c478bd9Sstevel@tonic-gate /* 2513*7c478bd9Sstevel@tonic-gate * sysevent_unbind_handle - Unbind caller from syseventd subscriptions 2514*7c478bd9Sstevel@tonic-gate */ 2515*7c478bd9Sstevel@tonic-gate void 2516*7c478bd9Sstevel@tonic-gate sysevent_unbind_handle(sysevent_handle_t *shp) 2517*7c478bd9Sstevel@tonic-gate { 2518*7c478bd9Sstevel@tonic-gate sysevent_unbind_subscriber(shp); 2519*7c478bd9Sstevel@tonic-gate sysevent_close_channel(shp); 2520*7c478bd9Sstevel@tonic-gate } 2521*7c478bd9Sstevel@tonic-gate 2522*7c478bd9Sstevel@tonic-gate /* 2523*7c478bd9Sstevel@tonic-gate * sysevent_subscribe_event - Subscribe to system event notification from 2524*7c478bd9Sstevel@tonic-gate * syseventd(1M) for the class and subclasses specified. 2525*7c478bd9Sstevel@tonic-gate */ 2526*7c478bd9Sstevel@tonic-gate int 2527*7c478bd9Sstevel@tonic-gate sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class, 2528*7c478bd9Sstevel@tonic-gate const char **event_subclass_list, int num_subclasses) 2529*7c478bd9Sstevel@tonic-gate { 2530*7c478bd9Sstevel@tonic-gate return (sysevent_register_event(shp, event_class, 2531*7c478bd9Sstevel@tonic-gate event_subclass_list, num_subclasses)); 2532*7c478bd9Sstevel@tonic-gate } 2533*7c478bd9Sstevel@tonic-gate 2534*7c478bd9Sstevel@tonic-gate void 2535*7c478bd9Sstevel@tonic-gate sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class) 2536*7c478bd9Sstevel@tonic-gate { 2537*7c478bd9Sstevel@tonic-gate sysevent_unregister_event(shp, event_class); 2538*7c478bd9Sstevel@tonic-gate } 2539