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