1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include <stdio.h> 30*7c478bd9Sstevel@tonic-gate #include <ctype.h> 31*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 32*7c478bd9Sstevel@tonic-gate #include <errno.h> 33*7c478bd9Sstevel@tonic-gate #include <door.h> 34*7c478bd9Sstevel@tonic-gate #include <unistd.h> 35*7c478bd9Sstevel@tonic-gate #include <stddef.h> 36*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 37*7c478bd9Sstevel@tonic-gate #include <strings.h> 38*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 39*7c478bd9Sstevel@tonic-gate #include <sys/varargs.h> 40*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h> 41*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h> 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate #include "libsysevent.h" 44*7c478bd9Sstevel@tonic-gate #include "libsysevent_impl.h" 45*7c478bd9Sstevel@tonic-gate 46*7c478bd9Sstevel@tonic-gate /* 47*7c478bd9Sstevel@tonic-gate * The functions below deal with the General Purpose Event Handling framework 48*7c478bd9Sstevel@tonic-gate * 49*7c478bd9Sstevel@tonic-gate * sysevent_evc_bind - create/bind application to named channel 50*7c478bd9Sstevel@tonic-gate * sysevent_evc_unbind - unbind from previously bound/created channel 51*7c478bd9Sstevel@tonic-gate * sysevent_evc_subscribe - subscribe to existing event channel 52*7c478bd9Sstevel@tonic-gate * sysevent_evc_unsubscribe - unsubscribe from existing event channel 53*7c478bd9Sstevel@tonic-gate * sysevent_evc_publish - generate a system event via an event channel 54*7c478bd9Sstevel@tonic-gate * sysevent_evc_control - various channel based control operation 55*7c478bd9Sstevel@tonic-gate */ 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate #define misaligned(p) ((uintptr_t)(p) & 3) /* 4-byte alignment required */ 58*7c478bd9Sstevel@tonic-gate 59*7c478bd9Sstevel@tonic-gate /* 60*7c478bd9Sstevel@tonic-gate * Check syntax of a channel name 61*7c478bd9Sstevel@tonic-gate */ 62*7c478bd9Sstevel@tonic-gate static int 63*7c478bd9Sstevel@tonic-gate sysevent_is_chan_name(const char *str) 64*7c478bd9Sstevel@tonic-gate { 65*7c478bd9Sstevel@tonic-gate for (; *str != '\0'; str++) { 66*7c478bd9Sstevel@tonic-gate if (!EVCH_ISCHANCHAR(*str)) 67*7c478bd9Sstevel@tonic-gate return (0); 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate return (1); 71*7c478bd9Sstevel@tonic-gate } 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate /* 74*7c478bd9Sstevel@tonic-gate * Check for printable characters 75*7c478bd9Sstevel@tonic-gate */ 76*7c478bd9Sstevel@tonic-gate static int 77*7c478bd9Sstevel@tonic-gate strisprint(const char *s) 78*7c478bd9Sstevel@tonic-gate { 79*7c478bd9Sstevel@tonic-gate for (; *s != '\0'; s++) { 80*7c478bd9Sstevel@tonic-gate if (*s < ' ' || *s > '~') 81*7c478bd9Sstevel@tonic-gate return (0); 82*7c478bd9Sstevel@tonic-gate } 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate return (1); 85*7c478bd9Sstevel@tonic-gate } 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate /* 88*7c478bd9Sstevel@tonic-gate * sysevent_evc_bind - Create/bind application to named channel 89*7c478bd9Sstevel@tonic-gate */ 90*7c478bd9Sstevel@tonic-gate int 91*7c478bd9Sstevel@tonic-gate sysevent_evc_bind(const char *channel, evchan_t **scpp, uint32_t flags) 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate int chanlen; 94*7c478bd9Sstevel@tonic-gate evchan_t *scp; 95*7c478bd9Sstevel@tonic-gate sev_bind_args_t uargs; 96*7c478bd9Sstevel@tonic-gate int ec; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate if (scpp == NULL || misaligned(scpp)) { 99*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 100*7c478bd9Sstevel@tonic-gate } 101*7c478bd9Sstevel@tonic-gate 102*7c478bd9Sstevel@tonic-gate /* Provide useful value in error case */ 103*7c478bd9Sstevel@tonic-gate *scpp = NULL; 104*7c478bd9Sstevel@tonic-gate 105*7c478bd9Sstevel@tonic-gate if (channel == NULL || 106*7c478bd9Sstevel@tonic-gate (chanlen = strlen(channel) + 1) > MAX_CHNAME_LEN) { 107*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 108*7c478bd9Sstevel@tonic-gate } 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate /* Check channel syntax */ 111*7c478bd9Sstevel@tonic-gate if (!sysevent_is_chan_name(channel)) { 112*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 113*7c478bd9Sstevel@tonic-gate } 114*7c478bd9Sstevel@tonic-gate 115*7c478bd9Sstevel@tonic-gate if (flags & ~EVCH_B_FLAGS) { 116*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 117*7c478bd9Sstevel@tonic-gate } 118*7c478bd9Sstevel@tonic-gate 119*7c478bd9Sstevel@tonic-gate scp = calloc(1, sizeof (evchan_impl_hdl_t)); 120*7c478bd9Sstevel@tonic-gate if (scp == NULL) { 121*7c478bd9Sstevel@tonic-gate return (errno = ENOMEM); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate /* 125*7c478bd9Sstevel@tonic-gate * Enable sysevent driver. Fallback if the device link doesn't exist; 126*7c478bd9Sstevel@tonic-gate * this situation can arise if a channel is bound early in system 127*7c478bd9Sstevel@tonic-gate * startup, prior to devfsadm(1M) being invoked. 128*7c478bd9Sstevel@tonic-gate */ 129*7c478bd9Sstevel@tonic-gate EV_FD(scp) = open(DEVSYSEVENT, O_RDWR); 130*7c478bd9Sstevel@tonic-gate if (EV_FD(scp) == -1) { 131*7c478bd9Sstevel@tonic-gate if (errno != ENOENT) { 132*7c478bd9Sstevel@tonic-gate ec = errno == EACCES ? EPERM : errno; 133*7c478bd9Sstevel@tonic-gate free(scp); 134*7c478bd9Sstevel@tonic-gate return (errno = ec); 135*7c478bd9Sstevel@tonic-gate } 136*7c478bd9Sstevel@tonic-gate 137*7c478bd9Sstevel@tonic-gate EV_FD(scp) = open(DEVICESYSEVENT, O_RDWR); 138*7c478bd9Sstevel@tonic-gate if (EV_FD(scp) == -1) { 139*7c478bd9Sstevel@tonic-gate ec = errno == EACCES ? EPERM : errno; 140*7c478bd9Sstevel@tonic-gate free(scp); 141*7c478bd9Sstevel@tonic-gate return (errno = ec); 142*7c478bd9Sstevel@tonic-gate } 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * Force to close the fd's when process is doing exec. 147*7c478bd9Sstevel@tonic-gate * The driver will then release stale binding handles. 148*7c478bd9Sstevel@tonic-gate * The driver will release also the associated subscriptions 149*7c478bd9Sstevel@tonic-gate * if EVCH_SUB_KEEP flag was not set. 150*7c478bd9Sstevel@tonic-gate */ 151*7c478bd9Sstevel@tonic-gate (void) fcntl(EV_FD(scp), F_SETFD, FD_CLOEXEC); 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate uargs.chan_name.name = (uintptr_t)channel; 154*7c478bd9Sstevel@tonic-gate uargs.chan_name.len = chanlen; 155*7c478bd9Sstevel@tonic-gate uargs.flags = flags; 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate if (ioctl(EV_FD(scp), SEV_CHAN_OPEN, &uargs) != 0) { 158*7c478bd9Sstevel@tonic-gate ec = errno; 159*7c478bd9Sstevel@tonic-gate (void) close(EV_FD(scp)); 160*7c478bd9Sstevel@tonic-gate free(scp); 161*7c478bd9Sstevel@tonic-gate return (errno = ec); 162*7c478bd9Sstevel@tonic-gate } 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* Needed to detect a fork() */ 165*7c478bd9Sstevel@tonic-gate EV_PID(scp) = getpid(); 166*7c478bd9Sstevel@tonic-gate (void) mutex_init(EV_LOCK(scp), USYNC_THREAD, NULL); 167*7c478bd9Sstevel@tonic-gate 168*7c478bd9Sstevel@tonic-gate *scpp = scp; 169*7c478bd9Sstevel@tonic-gate 170*7c478bd9Sstevel@tonic-gate return (0); 171*7c478bd9Sstevel@tonic-gate } 172*7c478bd9Sstevel@tonic-gate 173*7c478bd9Sstevel@tonic-gate /* 174*7c478bd9Sstevel@tonic-gate * sysevent_evc_unbind - Unbind from previously bound/created channel 175*7c478bd9Sstevel@tonic-gate */ 176*7c478bd9Sstevel@tonic-gate void 177*7c478bd9Sstevel@tonic-gate sysevent_evc_unbind(evchan_t *scp) 178*7c478bd9Sstevel@tonic-gate { 179*7c478bd9Sstevel@tonic-gate sev_unsubscribe_args_t uargs; 180*7c478bd9Sstevel@tonic-gate evchan_subscr_t *subp, *tofree; 181*7c478bd9Sstevel@tonic-gate 182*7c478bd9Sstevel@tonic-gate if (scp == NULL || misaligned(scp)) 183*7c478bd9Sstevel@tonic-gate return; 184*7c478bd9Sstevel@tonic-gate 185*7c478bd9Sstevel@tonic-gate (void) mutex_lock(EV_LOCK(scp)); 186*7c478bd9Sstevel@tonic-gate 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * Unsubscribe, if we are in the process which did the bind. 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate if (EV_PID(scp) == getpid()) { 191*7c478bd9Sstevel@tonic-gate uargs.sid.name = NULL; 192*7c478bd9Sstevel@tonic-gate uargs.sid.len = 0; 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * The unsubscribe ioctl will block until all door upcalls have 195*7c478bd9Sstevel@tonic-gate * drained. 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate if (ioctl(EV_FD(scp), SEV_UNSUBSCRIBE, (intptr_t)&uargs) != 0) { 198*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 199*7c478bd9Sstevel@tonic-gate return; 200*7c478bd9Sstevel@tonic-gate } 201*7c478bd9Sstevel@tonic-gate } 202*7c478bd9Sstevel@tonic-gate 203*7c478bd9Sstevel@tonic-gate subp = (evchan_subscr_t *)(void*)EV_SUB(scp); 204*7c478bd9Sstevel@tonic-gate while (subp->evsub_next != NULL) { 205*7c478bd9Sstevel@tonic-gate tofree = subp->evsub_next; 206*7c478bd9Sstevel@tonic-gate subp->evsub_next = tofree->evsub_next; 207*7c478bd9Sstevel@tonic-gate if (door_revoke(tofree->evsub_door_desc) != 0 && errno == EPERM) 208*7c478bd9Sstevel@tonic-gate (void) close(tofree->evsub_door_desc); 209*7c478bd9Sstevel@tonic-gate free(tofree->evsub_sid); 210*7c478bd9Sstevel@tonic-gate free(tofree); 211*7c478bd9Sstevel@tonic-gate } 212*7c478bd9Sstevel@tonic-gate 213*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate /* 216*7c478bd9Sstevel@tonic-gate * The close of the driver will do the unsubscribe if a) it is the last 217*7c478bd9Sstevel@tonic-gate * close and b) we are in a child which inherited subscriptions. 218*7c478bd9Sstevel@tonic-gate */ 219*7c478bd9Sstevel@tonic-gate (void) close(EV_FD(scp)); 220*7c478bd9Sstevel@tonic-gate (void) mutex_destroy(EV_LOCK(scp)); 221*7c478bd9Sstevel@tonic-gate free(scp); 222*7c478bd9Sstevel@tonic-gate } 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate /* 225*7c478bd9Sstevel@tonic-gate * sysevent_evc_publish - Generate a system event via an event channel 226*7c478bd9Sstevel@tonic-gate */ 227*7c478bd9Sstevel@tonic-gate int 228*7c478bd9Sstevel@tonic-gate sysevent_evc_publish(evchan_t *scp, const char *class, 229*7c478bd9Sstevel@tonic-gate const char *subclass, const char *vendor, 230*7c478bd9Sstevel@tonic-gate const char *pub_name, nvlist_t *attr_list, 231*7c478bd9Sstevel@tonic-gate uint32_t flags) 232*7c478bd9Sstevel@tonic-gate { 233*7c478bd9Sstevel@tonic-gate sysevent_t *ev; 234*7c478bd9Sstevel@tonic-gate sev_publish_args_t uargs; 235*7c478bd9Sstevel@tonic-gate int rc; 236*7c478bd9Sstevel@tonic-gate int ec; 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate if (scp == NULL || misaligned(scp)) { 239*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 240*7c478bd9Sstevel@tonic-gate } 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* No inheritance of binding handles via fork() */ 243*7c478bd9Sstevel@tonic-gate if (EV_PID(scp) != getpid()) { 244*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 245*7c478bd9Sstevel@tonic-gate } 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate ev = sysevent_alloc_event((char *)class, (char *)subclass, 248*7c478bd9Sstevel@tonic-gate (char *)vendor, (char *)pub_name, attr_list); 249*7c478bd9Sstevel@tonic-gate if (ev == NULL) { 250*7c478bd9Sstevel@tonic-gate return (errno); 251*7c478bd9Sstevel@tonic-gate } 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate uargs.ev.name = (uintptr_t)ev; 254*7c478bd9Sstevel@tonic-gate uargs.ev.len = SE_SIZE(ev); 255*7c478bd9Sstevel@tonic-gate uargs.flags = flags; 256*7c478bd9Sstevel@tonic-gate 257*7c478bd9Sstevel@tonic-gate (void) mutex_lock(EV_LOCK(scp)); 258*7c478bd9Sstevel@tonic-gate 259*7c478bd9Sstevel@tonic-gate rc = ioctl(EV_FD(scp), SEV_PUBLISH, (intptr_t)&uargs); 260*7c478bd9Sstevel@tonic-gate ec = errno; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate sysevent_free(ev); 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate if (rc != 0) { 267*7c478bd9Sstevel@tonic-gate return (ec); 268*7c478bd9Sstevel@tonic-gate } 269*7c478bd9Sstevel@tonic-gate return (0); 270*7c478bd9Sstevel@tonic-gate } 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * Generic callback which catches events from the kernel and calls 274*7c478bd9Sstevel@tonic-gate * subscribers call back routine. 275*7c478bd9Sstevel@tonic-gate * 276*7c478bd9Sstevel@tonic-gate * Kernel guarantees that door_upcalls are disabled when unsubscription 277*7c478bd9Sstevel@tonic-gate * was issued that's why cookie points always to a valid evchan_subscr_t *. 278*7c478bd9Sstevel@tonic-gate * 279*7c478bd9Sstevel@tonic-gate * Furthermore it's not necessary to lock subp because the sysevent 280*7c478bd9Sstevel@tonic-gate * framework guarantees no unsubscription until door_return. 281*7c478bd9Sstevel@tonic-gate */ 282*7c478bd9Sstevel@tonic-gate /*ARGSUSED3*/ 283*7c478bd9Sstevel@tonic-gate static void 284*7c478bd9Sstevel@tonic-gate door_upcall(void *cookie, char *args, size_t alen, 285*7c478bd9Sstevel@tonic-gate door_desc_t *ddp, uint_t ndid) 286*7c478bd9Sstevel@tonic-gate { 287*7c478bd9Sstevel@tonic-gate evchan_subscr_t *subp = EVCHAN_SUBSCR(cookie); 288*7c478bd9Sstevel@tonic-gate int rval = 0; 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate if (args == NULL || alen <= (size_t)0) { 291*7c478bd9Sstevel@tonic-gate /* Skip callback execution */ 292*7c478bd9Sstevel@tonic-gate rval = EINVAL; 293*7c478bd9Sstevel@tonic-gate } else { 294*7c478bd9Sstevel@tonic-gate rval = subp->evsub_func((sysevent_t *)(void *)args, 295*7c478bd9Sstevel@tonic-gate subp->evsub_cookie); 296*7c478bd9Sstevel@tonic-gate } 297*7c478bd9Sstevel@tonic-gate 298*7c478bd9Sstevel@tonic-gate /* 299*7c478bd9Sstevel@tonic-gate * Fill in return values for door_return 300*7c478bd9Sstevel@tonic-gate */ 301*7c478bd9Sstevel@tonic-gate alen = sizeof (rval); 302*7c478bd9Sstevel@tonic-gate bcopy(&rval, args, alen); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate (void) door_return(args, alen, NULL, 0); 305*7c478bd9Sstevel@tonic-gate } 306*7c478bd9Sstevel@tonic-gate 307*7c478bd9Sstevel@tonic-gate /* 308*7c478bd9Sstevel@tonic-gate * sysevent_evc_subscribe - Subscribe to an existing event channel 309*7c478bd9Sstevel@tonic-gate */ 310*7c478bd9Sstevel@tonic-gate int 311*7c478bd9Sstevel@tonic-gate sysevent_evc_subscribe(evchan_t *scp, const char *sid, const char *class, 312*7c478bd9Sstevel@tonic-gate int (*event_handler)(sysevent_t *ev, void *cookie), 313*7c478bd9Sstevel@tonic-gate void *cookie, uint32_t flags) 314*7c478bd9Sstevel@tonic-gate { 315*7c478bd9Sstevel@tonic-gate evchan_subscr_t *subp; 316*7c478bd9Sstevel@tonic-gate int upcall_door; 317*7c478bd9Sstevel@tonic-gate sev_subscribe_args_t uargs; 318*7c478bd9Sstevel@tonic-gate uint32_t sid_len; 319*7c478bd9Sstevel@tonic-gate uint32_t class_len; 320*7c478bd9Sstevel@tonic-gate int ec; 321*7c478bd9Sstevel@tonic-gate 322*7c478bd9Sstevel@tonic-gate if (scp == NULL || misaligned(scp) || sid == NULL || class == NULL) { 323*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 324*7c478bd9Sstevel@tonic-gate } 325*7c478bd9Sstevel@tonic-gate 326*7c478bd9Sstevel@tonic-gate /* No inheritance of binding handles via fork() */ 327*7c478bd9Sstevel@tonic-gate if (EV_PID(scp) != getpid()) { 328*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 329*7c478bd9Sstevel@tonic-gate } 330*7c478bd9Sstevel@tonic-gate 331*7c478bd9Sstevel@tonic-gate if ((sid_len = strlen(sid) + 1) > MAX_SUBID_LEN || sid_len == 1 || 332*7c478bd9Sstevel@tonic-gate (class_len = strlen(class) + 1) > MAX_CLASS_LEN) { 333*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate /* Check for printable characters */ 337*7c478bd9Sstevel@tonic-gate if (!strisprint(sid)) { 338*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 339*7c478bd9Sstevel@tonic-gate } 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate if (event_handler == NULL) { 342*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 343*7c478bd9Sstevel@tonic-gate } 344*7c478bd9Sstevel@tonic-gate 345*7c478bd9Sstevel@tonic-gate /* Create subscriber data */ 346*7c478bd9Sstevel@tonic-gate if ((subp = calloc(1, sizeof (evchan_subscr_t))) == NULL) { 347*7c478bd9Sstevel@tonic-gate return (errno); 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate 350*7c478bd9Sstevel@tonic-gate if ((subp->evsub_sid = strdup(sid)) == NULL) { 351*7c478bd9Sstevel@tonic-gate ec = errno; 352*7c478bd9Sstevel@tonic-gate free(subp); 353*7c478bd9Sstevel@tonic-gate return (ec); 354*7c478bd9Sstevel@tonic-gate } 355*7c478bd9Sstevel@tonic-gate 356*7c478bd9Sstevel@tonic-gate /* 357*7c478bd9Sstevel@tonic-gate * EC_ALL string will not be copied to kernel - NULL is assumed 358*7c478bd9Sstevel@tonic-gate */ 359*7c478bd9Sstevel@tonic-gate if (strcmp(class, EC_ALL) == 0) { 360*7c478bd9Sstevel@tonic-gate class = NULL; 361*7c478bd9Sstevel@tonic-gate class_len = 0; 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate upcall_door = door_create(door_upcall, (void *)subp, 365*7c478bd9Sstevel@tonic-gate DOOR_REFUSE_DESC | DOOR_NO_CANCEL); 366*7c478bd9Sstevel@tonic-gate if (upcall_door == -1) { 367*7c478bd9Sstevel@tonic-gate ec = errno; 368*7c478bd9Sstevel@tonic-gate free(subp->evsub_sid); 369*7c478bd9Sstevel@tonic-gate free(subp); 370*7c478bd9Sstevel@tonic-gate return (ec); 371*7c478bd9Sstevel@tonic-gate } 372*7c478bd9Sstevel@tonic-gate 373*7c478bd9Sstevel@tonic-gate /* Complete subscriber information */ 374*7c478bd9Sstevel@tonic-gate subp->evsub_door_desc = upcall_door; 375*7c478bd9Sstevel@tonic-gate subp->evsub_func = event_handler; 376*7c478bd9Sstevel@tonic-gate subp->evsub_cookie = cookie; 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate (void) mutex_lock(EV_LOCK(scp)); 379*7c478bd9Sstevel@tonic-gate 380*7c478bd9Sstevel@tonic-gate subp->ev_subhead = EVCHAN_IMPL_HNDL(scp); 381*7c478bd9Sstevel@tonic-gate 382*7c478bd9Sstevel@tonic-gate uargs.sid.name = (uintptr_t)sid; 383*7c478bd9Sstevel@tonic-gate uargs.sid.len = sid_len; 384*7c478bd9Sstevel@tonic-gate uargs.class_info.name = (uintptr_t)class; 385*7c478bd9Sstevel@tonic-gate uargs.class_info.len = class_len; 386*7c478bd9Sstevel@tonic-gate uargs.door_desc = subp->evsub_door_desc; 387*7c478bd9Sstevel@tonic-gate uargs.flags = flags; 388*7c478bd9Sstevel@tonic-gate if (ioctl(EV_FD(scp), SEV_SUBSCRIBE, (intptr_t)&uargs) != 0) { 389*7c478bd9Sstevel@tonic-gate ec = errno; 390*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 391*7c478bd9Sstevel@tonic-gate (void) door_revoke(upcall_door); 392*7c478bd9Sstevel@tonic-gate free(subp->evsub_sid); 393*7c478bd9Sstevel@tonic-gate free(subp); 394*7c478bd9Sstevel@tonic-gate return (ec); 395*7c478bd9Sstevel@tonic-gate } 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate /* Attach to subscriber list */ 398*7c478bd9Sstevel@tonic-gate subp->evsub_next = EV_SUB_NEXT(scp); 399*7c478bd9Sstevel@tonic-gate EV_SUB_NEXT(scp) = subp; 400*7c478bd9Sstevel@tonic-gate 401*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 402*7c478bd9Sstevel@tonic-gate 403*7c478bd9Sstevel@tonic-gate return (0); 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate /* 407*7c478bd9Sstevel@tonic-gate * sysevent_evc_unsubscribe - Unsubscribe from an existing event channel 408*7c478bd9Sstevel@tonic-gate */ 409*7c478bd9Sstevel@tonic-gate void 410*7c478bd9Sstevel@tonic-gate sysevent_evc_unsubscribe(evchan_t *scp, const char *sid) 411*7c478bd9Sstevel@tonic-gate { 412*7c478bd9Sstevel@tonic-gate int all_subscribers = 0; 413*7c478bd9Sstevel@tonic-gate sev_unsubscribe_args_t uargs; 414*7c478bd9Sstevel@tonic-gate evchan_subscr_t *subp, *tofree; 415*7c478bd9Sstevel@tonic-gate int rc; 416*7c478bd9Sstevel@tonic-gate 417*7c478bd9Sstevel@tonic-gate if (scp == NULL || misaligned(scp)) 418*7c478bd9Sstevel@tonic-gate return; 419*7c478bd9Sstevel@tonic-gate 420*7c478bd9Sstevel@tonic-gate if (sid == NULL || strlen(sid) == 0 || 421*7c478bd9Sstevel@tonic-gate (strlen(sid) >= MAX_SUBID_LEN)) 422*7c478bd9Sstevel@tonic-gate return; 423*7c478bd9Sstevel@tonic-gate 424*7c478bd9Sstevel@tonic-gate /* No inheritance of binding handles via fork() */ 425*7c478bd9Sstevel@tonic-gate if (EV_PID(scp) != getpid()) { 426*7c478bd9Sstevel@tonic-gate return; 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate if (strcmp(sid, EVCH_ALLSUB) == 0) { 430*7c478bd9Sstevel@tonic-gate all_subscribers++; 431*7c478bd9Sstevel@tonic-gate /* Indicates all subscriber id's for this channel */ 432*7c478bd9Sstevel@tonic-gate uargs.sid.name = NULL; 433*7c478bd9Sstevel@tonic-gate uargs.sid.len = 0; 434*7c478bd9Sstevel@tonic-gate } else { 435*7c478bd9Sstevel@tonic-gate uargs.sid.name = (uintptr_t)sid; 436*7c478bd9Sstevel@tonic-gate uargs.sid.len = strlen(sid) + 1; 437*7c478bd9Sstevel@tonic-gate } 438*7c478bd9Sstevel@tonic-gate 439*7c478bd9Sstevel@tonic-gate (void) mutex_lock(EV_LOCK(scp)); 440*7c478bd9Sstevel@tonic-gate 441*7c478bd9Sstevel@tonic-gate /* 442*7c478bd9Sstevel@tonic-gate * The unsubscribe ioctl will block until all door upcalls have drained. 443*7c478bd9Sstevel@tonic-gate */ 444*7c478bd9Sstevel@tonic-gate rc = ioctl(EV_FD(scp), SEV_UNSUBSCRIBE, (intptr_t)&uargs); 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate if (rc != 0) { 447*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 448*7c478bd9Sstevel@tonic-gate return; 449*7c478bd9Sstevel@tonic-gate } 450*7c478bd9Sstevel@tonic-gate 451*7c478bd9Sstevel@tonic-gate /* Search for the matching subscriber */ 452*7c478bd9Sstevel@tonic-gate subp = (evchan_subscr_t *)(void*)EV_SUB(scp); 453*7c478bd9Sstevel@tonic-gate while (subp->evsub_next != NULL) { 454*7c478bd9Sstevel@tonic-gate 455*7c478bd9Sstevel@tonic-gate if (all_subscribers || 456*7c478bd9Sstevel@tonic-gate (strcmp(subp->evsub_next->evsub_sid, sid) == 0)) { 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate tofree = subp->evsub_next; 459*7c478bd9Sstevel@tonic-gate subp->evsub_next = tofree->evsub_next; 460*7c478bd9Sstevel@tonic-gate (void) door_revoke(tofree->evsub_door_desc); 461*7c478bd9Sstevel@tonic-gate free(tofree->evsub_sid); 462*7c478bd9Sstevel@tonic-gate free(tofree); 463*7c478bd9Sstevel@tonic-gate /* Freed single subscriber already */ 464*7c478bd9Sstevel@tonic-gate if (all_subscribers == 0) { 465*7c478bd9Sstevel@tonic-gate break; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate } else 468*7c478bd9Sstevel@tonic-gate subp = subp->evsub_next; 469*7c478bd9Sstevel@tonic-gate } 470*7c478bd9Sstevel@tonic-gate 471*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 472*7c478bd9Sstevel@tonic-gate } 473*7c478bd9Sstevel@tonic-gate 474*7c478bd9Sstevel@tonic-gate /* 475*7c478bd9Sstevel@tonic-gate * sysevent_evc_control - Various channel based control operation 476*7c478bd9Sstevel@tonic-gate */ 477*7c478bd9Sstevel@tonic-gate int 478*7c478bd9Sstevel@tonic-gate sysevent_evc_control(evchan_t *scp, int cmd, /* arg */ ...) 479*7c478bd9Sstevel@tonic-gate { 480*7c478bd9Sstevel@tonic-gate va_list ap; 481*7c478bd9Sstevel@tonic-gate uint32_t *chlenp; 482*7c478bd9Sstevel@tonic-gate sev_control_args_t uargs; 483*7c478bd9Sstevel@tonic-gate int rc = 0; 484*7c478bd9Sstevel@tonic-gate 485*7c478bd9Sstevel@tonic-gate if (scp == NULL || misaligned(scp)) { 486*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 487*7c478bd9Sstevel@tonic-gate } 488*7c478bd9Sstevel@tonic-gate 489*7c478bd9Sstevel@tonic-gate /* No inheritance of binding handles via fork() */ 490*7c478bd9Sstevel@tonic-gate if (EV_PID(scp) != getpid()) { 491*7c478bd9Sstevel@tonic-gate return (errno = EINVAL); 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate 494*7c478bd9Sstevel@tonic-gate va_start(ap, cmd); 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate uargs.cmd = cmd; 497*7c478bd9Sstevel@tonic-gate 498*7c478bd9Sstevel@tonic-gate (void) mutex_lock(EV_LOCK(scp)); 499*7c478bd9Sstevel@tonic-gate 500*7c478bd9Sstevel@tonic-gate switch (cmd) { 501*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN: 502*7c478bd9Sstevel@tonic-gate case EVCH_GET_CHAN_LEN_MAX: 503*7c478bd9Sstevel@tonic-gate chlenp = va_arg(ap, uint32_t *); 504*7c478bd9Sstevel@tonic-gate if (chlenp == NULL || misaligned(chlenp)) { 505*7c478bd9Sstevel@tonic-gate rc = EINVAL; 506*7c478bd9Sstevel@tonic-gate break; 507*7c478bd9Sstevel@tonic-gate } 508*7c478bd9Sstevel@tonic-gate rc = ioctl(EV_FD(scp), SEV_CHAN_CONTROL, (intptr_t)&uargs); 509*7c478bd9Sstevel@tonic-gate *chlenp = uargs.value; 510*7c478bd9Sstevel@tonic-gate break; 511*7c478bd9Sstevel@tonic-gate case EVCH_SET_CHAN_LEN: 512*7c478bd9Sstevel@tonic-gate /* Range change will be handled in framework */ 513*7c478bd9Sstevel@tonic-gate uargs.value = va_arg(ap, uint32_t); 514*7c478bd9Sstevel@tonic-gate rc = ioctl(EV_FD(scp), SEV_CHAN_CONTROL, (intptr_t)&uargs); 515*7c478bd9Sstevel@tonic-gate break; 516*7c478bd9Sstevel@tonic-gate default: 517*7c478bd9Sstevel@tonic-gate rc = EINVAL; 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate (void) mutex_unlock(EV_LOCK(scp)); 521*7c478bd9Sstevel@tonic-gate 522*7c478bd9Sstevel@tonic-gate if (rc == -1) { 523*7c478bd9Sstevel@tonic-gate rc = errno; 524*7c478bd9Sstevel@tonic-gate } 525*7c478bd9Sstevel@tonic-gate 526*7c478bd9Sstevel@tonic-gate va_end(ap); 527*7c478bd9Sstevel@tonic-gate 528*7c478bd9Sstevel@tonic-gate return (errno = rc); 529*7c478bd9Sstevel@tonic-gate } 530