6659 nvlist_free(NULL) is a no-op

   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  24  */
  25 
  26 #include <stdio.h>
  27 #include <fcntl.h>
  28 #include <errno.h>
  29 #include <door.h>
  30 #include <unistd.h>
  31 #include <stddef.h>
  32 #include <stdlib.h>
  33 #include <string.h>
  34 #include <strings.h>
  35 #include <synch.h>
  36 #include <pthread.h>
  37 #include <signal.h>
  38 #include <thread.h>
  39 #include <libnvpair.h>
  40 #include <assert.h>
  41 #include <sys/stat.h>
  42 #include <sys/types.h>
  43 #include <sys/modctl.h>
  44 #include <sys/mnttab.h>
  45 #include <sys/sysevent.h>
  46 #include <sys/sysevent_impl.h>
  47 
  48 #include "libsysevent.h"
  49 #include "libsysevent_impl.h"
  50 
  51 /*
  52  * libsysevent - The system event framework library
  53  *
  54  *              This library provides routines to help with marshalling
  55  *              and unmarshalling of data contained in a sysevent event
  56  *              buffer.
  57  */
  58 
  59 #define SE_ENCODE_METHOD        NV_ENCODE_NATIVE
  60 
  61 #define dprint  if (libsysevent_debug) (void) printf
  62 static int libsysevent_debug = 0;
  63 
  64 static sysevent_t *se_unpack(sysevent_t *);
  65 static int cleanup_id(sysevent_handle_t *shp, uint32_t id, int type);
  66 
  67 /*
  68  * The following routines allow system event publication to the sysevent
  69  * framework.
  70  */
  71 
  72 /*
  73  * sysevent_alloc - allocate a sysevent buffer
  74  */
  75 static sysevent_t *
  76 sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz,
  77         char *pub, int pub_sz, nvlist_t *attr_list)
  78 {
  79         int payload_sz;
  80         int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
  81         size_t nvlist_sz = 0;
  82         char *attr;
  83         uint64_t attr_offset;
  84         sysevent_t *ev;
  85 
  86         if (attr_list != NULL) {
  87                 if (nvlist_size(attr_list, &nvlist_sz, SE_ENCODE_METHOD)
  88                     != 0) {
  89                         return (NULL);
  90                 }
  91         }
  92 
  93         /*
  94          * Calculate and reserve space for the class, subclass and
  95          * publisher strings in the event buffer
  96          */
  97 
  98         /* String sizes must be 64-bit aligned in the event buffer */
  99         aligned_class_sz = SE_ALIGN(class_sz);
 100         aligned_subclass_sz = SE_ALIGN(subclass_sz);
 101         aligned_pub_sz = SE_ALIGN(pub_sz);
 102 
 103         payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
 104             (aligned_subclass_sz - sizeof (uint64_t)) +
 105             (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) +
 106             nvlist_sz;
 107 
 108         /*
 109          * Allocate event buffer plus additional payload overhead.
 110          */
 111         ev = calloc(1, sizeof (sysevent_impl_t) + payload_sz);
 112         if (ev == NULL) {
 113                 return (NULL);
 114         }
 115 
 116         /* Initialize the event buffer data */
 117         SE_VERSION(ev) = SYS_EVENT_VERSION;
 118         (void) bcopy(class, SE_CLASS_NAME(ev), class_sz);
 119 
 120         SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
 121                 + aligned_class_sz;
 122         (void) bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
 123 
 124         SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
 125         (void) bcopy(pub, SE_PUB_NAME(ev), pub_sz);
 126 
 127         SE_PAYLOAD_SZ(ev) = payload_sz;
 128         SE_ATTR_PTR(ev) = (uint64_t)0;
 129 
 130         /* Check for attribute list */
 131         if (attr_list == NULL) {
 132                 return (ev);
 133         }
 134 
 135         /* Copy attribute data to contiguous memory */
 136         SE_FLAG(ev) = SE_PACKED_BUF;
 137         attr_offset = SE_ATTR_OFF(ev);
 138         attr = (char *)((caddr_t)ev + attr_offset);
 139         if (nvlist_pack(attr_list, &attr, &nvlist_sz, SE_ENCODE_METHOD,
 140             0) != 0) {
 141                 free(ev);
 142                 return (NULL);
 143         }
 144 
 145         return (ev);
 146 }
 147 
 148 /*
 149  * sysevent_post_event - generate a system event via the sysevent framework
 150  */
 151 int
 152 sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name,
 153         nvlist_t *attr_list, sysevent_id_t *eid)
 154 {
 155         int error;
 156         sysevent_t *ev;
 157 
 158         ev = sysevent_alloc_event(class, subclass, vendor, pub_name, attr_list);
 159         if (ev == NULL) {
 160                 return (-1);
 161         }
 162 
 163         error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT,
 164             (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), (uintptr_t)eid, 0);
 165 
 166         sysevent_free(ev);
 167 
 168         if (error) {
 169                 errno = EIO;
 170                 return (-1);
 171         }
 172 
 173         return (0);
 174 }
 175 
 176 /*
 177  * The following routines are used to free or duplicate a
 178  * sysevent event buffer.
 179  */
 180 
 181 /*
 182  * sysevent_dup - Allocate and copy an event buffer
 183  *      Copies both packed and unpacked to unpacked sysevent.
 184  */
 185 sysevent_t *
 186 sysevent_dup(sysevent_t *ev)
 187 {
 188         nvlist_t *nvl, *cnvl = NULL;
 189         uint64_t attr_offset;
 190         sysevent_t *copy;
 191 
 192         if (SE_FLAG(ev) == SE_PACKED_BUF)
 193                 return (se_unpack(ev));
 194 
 195         /* Copy event header information */
 196         attr_offset = SE_ATTR_OFF(ev);
 197         copy = calloc(1, attr_offset);
 198         if (copy == NULL)
 199                 return (NULL);
 200         bcopy(ev, copy, attr_offset);
 201 
 202         nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
 203         if (nvl && nvlist_dup(nvl, &cnvl, 0) != 0) {
 204                 free(copy);
 205                 return (NULL);
 206         }
 207 
 208         SE_ATTR_PTR(copy) = (uintptr_t)cnvl;
 209         SE_FLAG(copy) = 0;      /* unpacked */
 210         return (copy);
 211 }
 212 
 213 /*
 214  * sysevent_free - Free memory allocated for an event buffer
 215  */
 216 void
 217 sysevent_free(sysevent_t *ev)
 218 {
 219         nvlist_t *attr_list = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
 220 

 221         nvlist_free(attr_list);
 222         free(ev);
 223 }
 224 
 225 /*
 226  * The following routines are used to extract attribute data from a sysevent
 227  * handle.
 228  */
 229 
 230 /*
 231  * sysevent_get_attr_list - allocate and return an attribute associated with
 232  *                      the given sysevent buffer.
 233  */
 234 int
 235 sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
 236 {
 237         int error;
 238         caddr_t attr;
 239         size_t attr_len;
 240         uint64_t attr_offset;
 241         nvlist_t *nvl;
 242 
 243         *nvlist = NULL;
 244 
 245         /* Duplicate attribute for an unpacked sysevent buffer */
 246         if (SE_FLAG(ev) != SE_PACKED_BUF) {
 247                 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
 248                 if (nvl == NULL) {
 249                         return (0);
 250                 }
 251                 if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) {
 252                         if (error == ENOMEM) {
 253                                 errno = error;
 254                         } else {
 255                                 errno = EINVAL;
 256                         }
 257                         return (-1);
 258                 }
 259                 return (0);
 260         }
 261 
 262         attr_offset = SE_ATTR_OFF(ev);
 263         if (SE_SIZE(ev) == attr_offset) {
 264                 return (0);
 265         }
 266 
 267         /* unpack nvlist */
 268         attr = (caddr_t)ev + attr_offset;
 269         attr_len = SE_SIZE(ev) - attr_offset;
 270         if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
 271                 if (error == ENOMEM) {
 272                         errno = error;
 273                 } else  {
 274                         errno = EINVAL;
 275                 }
 276                 return (-1);
 277         }
 278 
 279         return (0);
 280 }
 281 
 282 /*
 283  * sysevent_attr_name - Get name of attribute
 284  */
 285 char *
 286 sysevent_attr_name(sysevent_attr_t *attr)
 287 {
 288         if (attr == NULL) {
 289                 errno = EINVAL;
 290                 return (NULL);
 291         }
 292         return (nvpair_name((nvpair_t *)attr));
 293 }
 294 
 295 /*
 296  * sysevent_attr_value - Get attribute value data and type
 297  */
 298 int
 299 sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value)
 300 {
 301         nvpair_t *nvp = attr;
 302 
 303         if (nvp == NULL)
 304                 return (EINVAL);
 305 
 306         /* Convert DATA_TYPE_* to SE_DATA_TYPE_* */
 307         switch (nvpair_type(nvp)) {
 308         case DATA_TYPE_BYTE:
 309                 se_value->value_type = SE_DATA_TYPE_BYTE;
 310                 (void) nvpair_value_byte(nvp, &se_value->value.sv_byte);
 311                 break;
 312         case DATA_TYPE_INT16:
 313                 se_value->value_type = SE_DATA_TYPE_INT16;
 314                 (void) nvpair_value_int16(nvp, &se_value->value.sv_int16);
 315                 break;
 316         case DATA_TYPE_UINT16:
 317                 se_value->value_type = SE_DATA_TYPE_UINT16;
 318                 (void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16);
 319                 break;
 320         case DATA_TYPE_INT32:
 321                 se_value->value_type = SE_DATA_TYPE_INT32;
 322                 (void) nvpair_value_int32(nvp, &se_value->value.sv_int32);
 323                 break;
 324         case DATA_TYPE_UINT32:
 325                 se_value->value_type = SE_DATA_TYPE_UINT32;
 326                 (void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32);
 327                 break;
 328         case DATA_TYPE_INT64:
 329                 se_value->value_type = SE_DATA_TYPE_INT64;
 330                 (void) nvpair_value_int64(nvp, &se_value->value.sv_int64);
 331                 break;
 332         case DATA_TYPE_UINT64:
 333                 se_value->value_type = SE_DATA_TYPE_UINT64;
 334                 (void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64);
 335                 break;
 336         case DATA_TYPE_STRING:
 337                 se_value->value_type = SE_DATA_TYPE_STRING;
 338                 (void) nvpair_value_string(nvp, &se_value->value.sv_string);
 339                 break;
 340         case DATA_TYPE_BYTE_ARRAY:
 341                 se_value->value_type = SE_DATA_TYPE_BYTES;
 342                 (void) nvpair_value_byte_array(nvp,
 343                     &se_value->value.sv_bytes.data,
 344                     (uint_t *)&se_value->value.sv_bytes.size);
 345                 break;
 346         case DATA_TYPE_HRTIME:
 347                 se_value->value_type = SE_DATA_TYPE_TIME;
 348                 (void) nvpair_value_hrtime(nvp, &se_value->value.sv_time);
 349                 break;
 350         default:
 351                 return (ENOTSUP);
 352         }
 353         return (0);
 354 }
 355 
 356 /*
 357  * sysevent_attr_next - Get next attribute in event attribute list
 358  */
 359 sysevent_attr_t *
 360 sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr)
 361 {
 362         nvlist_t *nvl;
 363         nvpair_t *nvp = attr;
 364 
 365         /* all user visible sysevent_t's are unpacked */
 366         assert(SE_FLAG(ev) != SE_PACKED_BUF);
 367 
 368         if (SE_ATTR_PTR(ev) == (uint64_t)0) {
 369                 return (NULL);
 370         }
 371 
 372         nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
 373         return (nvlist_next_nvpair(nvl, nvp));
 374 }
 375 
 376 /*
 377  * sysevent_lookup_attr - Lookup attribute by name and datatype.
 378  */
 379 int
 380 sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype,
 381         sysevent_value_t *se_value)
 382 {
 383         nvpair_t *nvp;
 384         nvlist_t *nvl;
 385 
 386         assert(SE_FLAG(ev) != SE_PACKED_BUF);
 387 
 388         if (SE_ATTR_PTR(ev) == (uint64_t)0) {
 389                 return (ENOENT);
 390         }
 391 
 392         /*
 393          * sysevent matches on both name and datatype
 394          * nvlist_look mataches name only. So we walk
 395          * nvlist manually here.
 396          */
 397         nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
 398         nvp = nvlist_next_nvpair(nvl, NULL);
 399         while (nvp) {
 400                 if ((strcmp(name, nvpair_name(nvp)) == 0) &&
 401                     (sysevent_attr_value(nvp, se_value) == 0) &&
 402                     (se_value->value_type == datatype))
 403                         return (0);
 404                 nvp = nvlist_next_nvpair(nvl, nvp);
 405         }
 406         return (ENOENT);
 407 }
 408 
 409 /* Routines to extract event header information */
 410 
 411 /*
 412  * sysevent_get_class - Get class id
 413  */
 414 int
 415 sysevent_get_class(sysevent_t *ev)
 416 {
 417         return (SE_CLASS(ev));
 418 }
 419 
 420 /*
 421  * sysevent_get_subclass - Get subclass id
 422  */
 423 int
 424 sysevent_get_subclass(sysevent_t *ev)
 425 {
 426         return (SE_SUBCLASS(ev));
 427 }
 428 
 429 /*
 430  * sysevent_get_class_name - Get class name string
 431  */
 432 char *
 433 sysevent_get_class_name(sysevent_t *ev)
 434 {
 435         return (SE_CLASS_NAME(ev));
 436 }
 437 
 438 typedef enum {
 439         PUB_VEND,
 440         PUB_KEYWD,
 441         PUB_NAME,
 442         PUB_PID
 443 } se_pub_id_t;
 444 
 445 /*
 446  * sysevent_get_pub - Get publisher name string
 447  */
 448 char *
 449 sysevent_get_pub(sysevent_t *ev)
 450 {
 451         return (SE_PUB_NAME(ev));
 452 }
 453 
 454 /*
 455  * Get the requested string pointed by the token.
 456  *
 457  * Return NULL if not found or for insufficient memory.
 458  */
 459 static char *
 460 parse_pub_id(sysevent_t *ev, se_pub_id_t token)
 461 {
 462         int i;
 463         char *pub_id, *pub_element, *str, *next;
 464 
 465         next = pub_id = strdup(sysevent_get_pub(ev));
 466         for (i = 0; i <= token; ++i) {
 467                 str = strtok_r(next, ":", &next);
 468                 if (str == NULL) {
 469                         free(pub_id);
 470                         return (NULL);
 471                 }
 472         }
 473 
 474         pub_element = strdup(str);
 475         free(pub_id);
 476         return (pub_element);
 477 }
 478 
 479 /*
 480  * Return a pointer to the string following the token
 481  *
 482  * Note: This is a dedicated function for parsing
 483  * publisher strings and not for general purpose.
 484  */
 485 static const char *
 486 pub_idx(const char *pstr, int token)
 487 {
 488         int i;
 489 
 490         for (i = 1; i <= token; i++) {
 491                 if ((pstr = index(pstr, ':')) == NULL)
 492                         return (NULL);
 493                 pstr++;
 494         }
 495 
 496         /* String might be empty */
 497         if (pstr) {
 498                 if (*pstr == '\0' || *pstr == ':')
 499                         return (NULL);
 500         }
 501         return (pstr);
 502 }
 503 
 504 char *
 505 sysevent_get_vendor_name(sysevent_t *ev)
 506 {
 507         return (parse_pub_id(ev, PUB_VEND));
 508 }
 509 
 510 char *
 511 sysevent_get_pub_name(sysevent_t *ev)
 512 {
 513         return (parse_pub_id(ev, PUB_NAME));
 514 }
 515 
 516 /*
 517  * Provide the pid encoded in the publisher string
 518  * w/o allocating any resouces.
 519  */
 520 void
 521 sysevent_get_pid(sysevent_t *ev, pid_t *pid)
 522 {
 523         const char *part_str;
 524         const char *pub_str = sysevent_get_pub(ev);
 525 
 526         *pid = (pid_t)SE_KERN_PID;
 527 
 528         part_str = pub_idx(pub_str, PUB_KEYWD);
 529         if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL)
 530                 return;
 531 
 532         if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL)
 533                 return;
 534 
 535         *pid = (pid_t)atoi(part_str);
 536 }
 537 
 538 /*
 539  * sysevent_get_subclass_name - Get subclass name string
 540  */
 541 char *
 542 sysevent_get_subclass_name(sysevent_t *ev)
 543 {
 544         return (SE_SUBCLASS_NAME(ev));
 545 }
 546 
 547 /*
 548  * sysevent_get_seq - Get event sequence id
 549  */
 550 uint64_t
 551 sysevent_get_seq(sysevent_t *ev)
 552 {
 553         return (SE_SEQ(ev));
 554 }
 555 
 556 /*
 557  * sysevent_get_time - Get event timestamp
 558  */
 559 void
 560 sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
 561 {
 562         *etime = SE_TIME(ev);
 563 }
 564 
 565 /*
 566  * sysevent_get_size - Get event buffer size
 567  */
 568 size_t
 569 sysevent_get_size(sysevent_t *ev)
 570 {
 571         return ((size_t)SE_SIZE(ev));
 572 }
 573 
 574 /*
 575  * The following routines are used by devfsadm_mod.c to propagate event
 576  * buffers to devfsadmd.  These routines will serve as the basis for
 577  * event channel publication and subscription.
 578  */
 579 
 580 /*
 581  * sysevent_alloc_event -
 582  *      allocate a sysevent buffer for sending through an established event
 583  *      channel.
 584  */
 585 sysevent_t *
 586 sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name,
 587         nvlist_t *attr_list)
 588 {
 589         int class_sz, subclass_sz, pub_sz;
 590         char *pub_id;
 591         sysevent_t *ev;
 592 
 593         if ((class == NULL) || (subclass == NULL) || (vendor == NULL) ||
 594             (pub_name == NULL)) {
 595                 errno = EINVAL;
 596                 return (NULL);
 597         }
 598 
 599         class_sz = strlen(class) + 1;
 600         subclass_sz = strlen(subclass) + 1;
 601         if ((class_sz > MAX_CLASS_LEN) ||
 602             (subclass_sz > MAX_SUBCLASS_LEN)) {
 603                 errno = EINVAL;
 604                 return (NULL);
 605         }
 606 
 607         /*
 608          * Calculate the publisher size plus string seperators and maximum
 609          * pid characters
 610          */
 611         pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14;
 612         if (pub_sz > MAX_PUB_LEN) {
 613                 errno = EINVAL;
 614                 return (NULL);
 615         }
 616         pub_id = malloc(pub_sz);
 617         if (pub_id == NULL) {
 618                 errno = ENOMEM;
 619                 return (NULL);
 620         }
 621         if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB,
 622             pub_name, (int)getpid()) >= pub_sz) {
 623                 free(pub_id);
 624                 errno = EINVAL;
 625                 return (NULL);
 626         }
 627         pub_sz = strlen(pub_id) + 1;
 628 
 629         ev = sysevent_alloc(class, class_sz, subclass, subclass_sz,
 630             pub_id, pub_sz, attr_list);
 631         free(pub_id);
 632         if (ev == NULL) {
 633                 errno = ENOMEM;
 634                 return (NULL);
 635         }
 636 
 637         return (ev);
 638 }
 639 
 640 /*
 641  * se_unpack - unpack nvlist to a searchable list.
 642  *      If already unpacked, will do a dup.
 643  */
 644 static sysevent_t *
 645 se_unpack(sysevent_t *ev)
 646 {
 647         caddr_t attr;
 648         size_t attr_len;
 649         nvlist_t *attrp = NULL;
 650         uint64_t attr_offset;
 651         sysevent_t *copy;
 652 
 653         assert(SE_FLAG(ev) == SE_PACKED_BUF);
 654 
 655         /* Copy event header information */
 656         attr_offset = SE_ATTR_OFF(ev);
 657         copy = calloc(1, attr_offset);
 658         if (copy == NULL)
 659                 return (NULL);
 660         bcopy(ev, copy, attr_offset);
 661         SE_FLAG(copy) = 0;      /* unpacked */
 662 
 663         /* unpack nvlist */
 664         attr = (caddr_t)ev + attr_offset;
 665         attr_len = SE_SIZE(ev) - attr_offset;
 666         if (attr_len == 0) {
 667                 return (copy);
 668         }
 669         if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) {
 670                 free(copy);
 671                 return (NULL);
 672         }
 673 
 674         SE_ATTR_PTR(copy) = (uintptr_t)attrp;
 675         return (copy);
 676 }
 677 
 678 /*
 679  * se_print - Prints elements in an event buffer
 680  */
 681 void
 682 se_print(FILE *fp, sysevent_t *ev)
 683 {
 684         char *vendor, *pub;
 685         pid_t pid;
 686         hrtime_t hrt;
 687         nvlist_t *attr_list = NULL;
 688 
 689         (void) sysevent_get_time(ev, &hrt);
 690         (void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n",
 691             hrt, (longlong_t)sysevent_get_seq(ev));
 692         (void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev));
 693         (void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev));
 694         if ((vendor =  sysevent_get_vendor_name(ev)) != NULL) {
 695                 (void) fprintf(fp, "\tvendor = %s\n", vendor);
 696                 free(vendor);
 697         }
 698         if ((pub = sysevent_get_pub_name(ev)) != NULL) {
 699                 sysevent_get_pid(ev, &pid);
 700                 (void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid);
 701                 free(pub);
 702         }
 703 
 704         if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) {
 705                 nvlist_print(fp, attr_list);
 706                 nvlist_free(attr_list);
 707         }
 708 }
 709 
 710 /*
 711  * The following routines are provided to support establishment and use
 712  * of sysevent channels.  A sysevent channel is established between
 713  * publishers and subscribers of sysevents for an agreed upon channel name.
 714  * These routines currently support sysevent channels between user-level
 715  * applications running on the same system.
 716  *
 717  * Sysevent channels may be created by a single publisher or subscriber process.
 718  * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in
 719  * receiving sysevent notifications on the named channel.  At present, only
 720  * one publisher is allowed per sysevent channel.
 721  *
 722  * The registration information for each channel is kept in the kernel.  A
 723  * kernel-based registration was chosen for persistence and reliability reasons.
 724  * If either a publisher or a subscriber exits for any reason, the channel
 725  * properties are maintained until all publishers and subscribers have exited.
 726  * Additionally, an in-kernel registration allows the API to be extended to
 727  * include kernel subscribers as well as userland subscribers in the future.
 728  *
 729  * To insure fast lookup of subscriptions, a cached copy of the registration
 730  * is kept and maintained for the publisher process.  Updates are made
 731  * everytime a change is made in the kernel.  Changes to the registration are
 732  * expected to be infrequent.
 733  *
 734  * Channel communication between publisher and subscriber processes is
 735  * implemented primarily via doors.  Each publisher creates a door for
 736  * registration notifications and each subscriber creates a door for event
 737  * delivery.
 738  *
 739  * Most of these routines are used by syseventd(1M), the sysevent publisher
 740  * for the syseventd channel.  Processes wishing to receive sysevent
 741  * notifications from syseventd may use a set of public
 742  * APIs designed to subscribe to syseventd sysevents.  The subscription
 743  * APIs are implemented in accordance with PSARC/2001/076.
 744  *
 745  */
 746 
 747 /*
 748  * Door handlers for the channel subscribers
 749  */
 750 
 751 /*
 752  * subscriber_event_handler - generic event handling wrapper for subscribers
 753  *                      This handler is used to process incoming sysevent
 754  *                      notifications from channel publishers.
 755  *                      It is created as a seperate thread in each subscriber
 756  *                      process per subscription.
 757  */
 758 static void
 759 subscriber_event_handler(sysevent_handle_t *shp)
 760 {
 761         subscriber_priv_t *sub_info;
 762         sysevent_queue_t *evqp;
 763 
 764         sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
 765 
 766         /* See hack alert in sysevent_bind_subscriber_cmn */
 767         if (sub_info->sp_handler_tid == NULL)
 768                 sub_info->sp_handler_tid = thr_self();
 769 
 770         (void) mutex_lock(&sub_info->sp_qlock);
 771         for (;;) {
 772                 while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) {
 773                         (void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock);
 774                 }
 775                 evqp = sub_info->sp_evq_head;
 776                 while (evqp) {
 777                         (void) mutex_unlock(&sub_info->sp_qlock);
 778                         (void) sub_info->sp_func(evqp->sq_ev);
 779                         (void) mutex_lock(&sub_info->sp_qlock);
 780                         sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next;
 781                         free(evqp->sq_ev);
 782                         free(evqp);
 783                         evqp = sub_info->sp_evq_head;
 784                 }
 785                 if (!SH_BOUND(shp)) {
 786                         (void) mutex_unlock(&sub_info->sp_qlock);
 787                         return;
 788                 }
 789         }
 790 
 791         /* NOTREACHED */
 792 }
 793 
 794 /*
 795  * Data structure used to communicate event subscription cache updates
 796  * to publishers via a registration door
 797  */
 798 struct reg_args {
 799         uint32_t ra_sub_id;
 800         uint32_t ra_op;
 801         uint64_t ra_buf_ptr;
 802 };
 803 
 804 
 805 /*
 806  * event_deliver_service - generic event delivery service routine.  This routine
 807  *              is called in response to a door call to post an event.
 808  *
 809  */
 810 /*ARGSUSED*/
 811 static void
 812 event_deliver_service(void *cookie, char *args, size_t alen,
 813     door_desc_t *ddp, uint_t ndid)
 814 {
 815         int     ret = 0;
 816         subscriber_priv_t *sub_info;
 817         sysevent_handle_t *shp;
 818         sysevent_queue_t *new_eq;
 819 
 820         if (args == NULL || alen < sizeof (uint32_t)) {
 821                 ret = EINVAL;
 822                 goto return_from_door;
 823         }
 824 
 825         /* Publisher checking on subscriber */
 826         if (alen == sizeof (uint32_t)) {
 827                 ret = 0;
 828                 goto return_from_door;
 829         }
 830 
 831         shp = (sysevent_handle_t *)cookie;
 832         if (shp == NULL) {
 833                 ret = EBADF;
 834                 goto return_from_door;
 835         }
 836 
 837         /*
 838          * Mustn't block if we are trying to update the registration with
 839          * the publisher
 840          */
 841         if (mutex_trylock(SH_LOCK(shp)) != 0) {
 842                 ret = EAGAIN;
 843                 goto return_from_door;
 844         }
 845 
 846         if (!SH_BOUND(shp)) {
 847                 ret = EBADF;
 848                 (void) mutex_unlock(SH_LOCK(shp));
 849                 goto return_from_door;
 850         }
 851 
 852         sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
 853         if (sub_info == NULL) {
 854                 ret = EBADF;
 855                 (void) mutex_unlock(SH_LOCK(shp));
 856                 goto return_from_door;
 857         }
 858 
 859         new_eq = (sysevent_queue_t *)calloc(1,
 860             sizeof (sysevent_queue_t));
 861         if (new_eq == NULL) {
 862                 ret = EAGAIN;
 863                 (void) mutex_unlock(SH_LOCK(shp));
 864                 goto return_from_door;
 865         }
 866 
 867         /*
 868          * Allocate and copy the event buffer into the subscriber's
 869          * address space
 870          */
 871         new_eq->sq_ev = calloc(1, alen);
 872         if (new_eq->sq_ev == NULL) {
 873                 free(new_eq);
 874                 ret = EAGAIN;
 875                 (void) mutex_unlock(SH_LOCK(shp));
 876                 goto return_from_door;
 877         }
 878         (void) bcopy(args, new_eq->sq_ev, alen);
 879 
 880         (void) mutex_lock(&sub_info->sp_qlock);
 881         if (sub_info->sp_evq_head == NULL) {
 882                 sub_info->sp_evq_head = new_eq;
 883         } else {
 884                 sub_info->sp_evq_tail->sq_next = new_eq;
 885         }
 886         sub_info->sp_evq_tail = new_eq;
 887 
 888         (void) cond_signal(&sub_info->sp_cv);
 889         (void) mutex_unlock(&sub_info->sp_qlock);
 890         (void) mutex_unlock(SH_LOCK(shp));
 891 
 892 return_from_door:
 893         (void) door_return((void *)&ret, sizeof (ret), NULL, 0);
 894         (void) door_return(NULL, 0, NULL, 0);
 895 }
 896 
 897 /*
 898  * Sysevent subscription information is maintained in the kernel.  Updates
 899  * to the in-kernel registration database is expected to be infrequent and
 900  * offers consistency for publishers and subscribers that may come and go
 901  * for a given channel.
 902  *
 903  * To expedite registration lookups by publishers, a cached copy of the
 904  * kernel registration database is kept per-channel.  Caches are invalidated
 905  * and refreshed upon state changes to the in-kernel registration database.
 906  *
 907  * To prevent stale subscriber data, publishers may remove subsriber
 908  * registrations from the in-kernel registration database in the event
 909  * that a particular subscribing process is unresponsive.
 910  *
 911  * The following routines provide a mechanism to update publisher and subscriber
 912  * information for a specified channel.
 913  */
 914 
 915 /*
 916  * clnt_deliver_event - Deliver an event through the consumer's event
 917  *                      delivery door
 918  *
 919  * Returns -1 if message not delivered. With errno set to cause of error.
 920  * Returns 0 for success with the results returned in posting buffer.
 921  */
 922 static int
 923 clnt_deliver_event(int service_door, void *data, size_t datalen,
 924         void *result, size_t rlen)
 925 {
 926         int error = 0;
 927         door_arg_t door_arg;
 928 
 929         door_arg.rbuf = result;
 930         door_arg.rsize = rlen;
 931         door_arg.data_ptr = data;
 932         door_arg.data_size = datalen;
 933         door_arg.desc_ptr = NULL;
 934         door_arg.desc_num = 0;
 935 
 936         /*
 937          * Make door call
 938          */
 939         while ((error = door_call(service_door, &door_arg)) != 0) {
 940                 if (errno == EAGAIN || errno == EINTR) {
 941                         continue;
 942                 } else {
 943                         error = errno;
 944                         break;
 945                 }
 946         }
 947 
 948         return (error);
 949 }
 950 
 951 static int
 952 update_publisher_cache(subscriber_priv_t *sub_info, int update_op,
 953         uint32_t sub_id, size_t datasz, uchar_t *data)
 954 {
 955         int pub_fd;
 956         uint32_t result = 0;
 957         struct reg_args *rargs;
 958 
 959         rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) +
 960             datasz);
 961         if (rargs == NULL) {
 962                 errno = ENOMEM;
 963                 return (-1);
 964         }
 965 
 966         rargs->ra_sub_id = sub_id;
 967         rargs->ra_op = update_op;
 968         bcopy(data, (char *)&rargs->ra_buf_ptr, datasz);
 969 
 970         pub_fd = open(sub_info->sp_door_name, O_RDONLY);
 971         (void) clnt_deliver_event(pub_fd, (void *)rargs,
 972             sizeof (struct reg_args) + datasz, &result, sizeof (result));
 973         (void) close(pub_fd);
 974 
 975         free(rargs);
 976         if (result != 0) {
 977                 errno = result;
 978                 return (-1);
 979         }
 980 
 981         return (0);
 982 }
 983 
 984 
 985 /*
 986  * update_kernel_registration - update the in-kernel registration for the
 987  * given channel.
 988  */
 989 static int
 990 update_kernel_registration(sysevent_handle_t *shp, int update_type,
 991         int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data)
 992 {
 993         int error;
 994         char *channel_name = SH_CHANNEL_NAME(shp);
 995         se_pubsub_t udata;
 996 
 997         udata.ps_channel_name_len = strlen(channel_name) + 1;
 998         udata.ps_op = update_op;
 999         udata.ps_type = update_type;
1000         udata.ps_buflen = datasz;
1001         udata.ps_id = *sub_id;
1002 
1003         if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
1004             (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0))
1005             != 0) {
1006                 return (error);
1007         }
1008 
1009         *sub_id = udata.ps_id;
1010 
1011         return (error);
1012 }
1013 
1014 /*
1015  * get_kernel_registration - get the current subscriber registration for
1016  * the given channel
1017  */
1018 static nvlist_t *
1019 get_kernel_registration(char *channel_name, uint32_t class_id)
1020 {
1021         char *nvlbuf;
1022         nvlist_t *nvl;
1023         se_pubsub_t udata;
1024 
1025         nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ);
1026         if (nvlbuf == NULL) {
1027                 return (NULL);
1028         }
1029 
1030         udata.ps_buflen = MAX_SUBSCRIPTION_SZ;
1031         udata.ps_channel_name_len = strlen(channel_name) + 1;
1032         udata.ps_id = class_id;
1033         udata.ps_op = SE_GET_REGISTRATION;
1034         udata.ps_type = PUBLISHER;
1035 
1036         if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
1037             (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0)
1038             != 0) {
1039 
1040                 /* Need a bigger buffer to hold channel registration */
1041                 if (errno == EAGAIN) {
1042                         free(nvlbuf);
1043                         nvlbuf = calloc(1, udata.ps_buflen);
1044                         if (nvlbuf == NULL)
1045                                 return (NULL);
1046 
1047                         /* Try again */
1048                         if (modctl(MODEVENTS,
1049                             (uintptr_t)MODEVENTS_REGISTER_EVENT,
1050                             (uintptr_t)channel_name, (uintptr_t)nvlbuf,
1051                             (uintptr_t)&udata, 0) != 0) {
1052                                 free(nvlbuf);
1053                                 return (NULL);
1054                         }
1055                 } else {
1056                         free(nvlbuf);
1057                         return (NULL);
1058                 }
1059         }
1060 
1061         if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) {
1062                 free(nvlbuf);
1063                 return (NULL);
1064         }
1065         free(nvlbuf);
1066 
1067         return (nvl);
1068 }
1069 
1070 /*
1071  * The following routines provide a mechanism for publishers to maintain
1072  * subscriber information.
1073  */
1074 
1075 static void
1076 dealloc_subscribers(sysevent_handle_t *shp)
1077 {
1078         int i;
1079         subscriber_data_t *sub;
1080 
1081         for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1082                 sub = SH_SUBSCRIBER(shp, i);
1083                 if (sub != NULL) {
1084                         free(sub->sd_door_name);
1085                         free(sub);
1086                 }
1087                 SH_SUBSCRIBER(shp, i) = NULL;
1088         }
1089 }
1090 
1091 /*ARGSUSED*/
1092 static int
1093 alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag)
1094 {
1095         subscriber_data_t *sub;
1096         char door_name[MAXPATHLEN];
1097 
1098         if (SH_SUBSCRIBER(shp, sub_id) != NULL) {
1099                 return (0);
1100         }
1101 
1102         /* Allocate and initialize the subscriber data */
1103         sub = (subscriber_data_t *)calloc(1,
1104             sizeof (subscriber_data_t));
1105         if (sub == NULL) {
1106                 return (-1);
1107         }
1108         if (snprintf(door_name, MAXPATHLEN, "%s/%d",
1109             SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
1110                 free(sub);
1111                 return (-1);
1112         }
1113 
1114         sub->sd_flag = ACTIVE;
1115         sub->sd_door_name = strdup(door_name);
1116         if (sub->sd_door_name == NULL) {
1117                 free(sub);
1118                 return (-1);
1119         }
1120 
1121         SH_SUBSCRIBER(shp, sub_id) = sub;
1122         return (0);
1123 
1124 }
1125 
1126 /*
1127  * The following routines are used to update and maintain the registration cache
1128  * for a particular sysevent channel.
1129  */
1130 
1131 static uint32_t
1132 hash_func(const char *s)
1133 {
1134         uint32_t result = 0;
1135         uint_t g;
1136 
1137         while (*s != '\0') {
1138                 result <<= 4;
1139                 result += (uint32_t)*s++;
1140                 g = result & 0xf0000000;
1141                 if (g != 0) {
1142                         result ^= g >> 24;
1143                         result ^= g;
1144                 }
1145         }
1146 
1147         return (result);
1148 }
1149 
1150 subclass_lst_t *
1151 cache_find_subclass(class_lst_t *c_list, char *subclass)
1152 {
1153         subclass_lst_t *sc_list;
1154 
1155         if (c_list == NULL)
1156                 return (NULL);
1157 
1158         sc_list = c_list->cl_subclass_list;
1159 
1160         while (sc_list != NULL) {
1161                 if (strcmp(sc_list->sl_name, subclass) == 0) {
1162                         return (sc_list);
1163                 }
1164                 sc_list = sc_list->sl_next;
1165         }
1166 
1167         return (NULL);
1168 }
1169 
1170 
1171 static class_lst_t *
1172 cache_find_class(sysevent_handle_t *shp, char *class)
1173 {
1174         int index;
1175         class_lst_t *c_list;
1176         class_lst_t **class_hash = SH_CLASS_HASH(shp);
1177 
1178         if (strcmp(class, EC_ALL) == 0) {
1179                 return (class_hash[0]);
1180         }
1181 
1182         index = CLASS_HASH(class);
1183         c_list = class_hash[index];
1184         while (c_list != NULL) {
1185                 if (strcmp(class, c_list->cl_name) == 0) {
1186                         break;
1187                 }
1188                 c_list = c_list->cl_next;
1189         }
1190 
1191         return (c_list);
1192 }
1193 
1194 static int
1195 cache_insert_subclass(class_lst_t *c_list, char **subclass_names,
1196         int subclass_num, uint32_t sub_id)
1197 {
1198         int i;
1199         subclass_lst_t *sc_list;
1200 
1201         for (i = 0; i < subclass_num; ++i) {
1202                 if ((sc_list = cache_find_subclass(c_list, subclass_names[i]))
1203                     != NULL) {
1204                         sc_list->sl_num[sub_id] = 1;
1205                 } else {
1206                         sc_list = (subclass_lst_t *)calloc(1,
1207                             sizeof (subclass_lst_t));
1208                         if (sc_list == NULL)
1209                                 return (-1);
1210 
1211                         sc_list->sl_name = strdup(subclass_names[i]);
1212                         if (sc_list->sl_name == NULL) {
1213                                 free(sc_list);
1214                                 return (-1);
1215                         }
1216 
1217                         sc_list->sl_num[sub_id] = 1;
1218                         sc_list->sl_next = c_list->cl_subclass_list;
1219                         c_list->cl_subclass_list = sc_list;
1220                 }
1221         }
1222 
1223         return (0);
1224 }
1225 
1226 static int
1227 cache_insert_class(sysevent_handle_t *shp, char *class,
1228         char **subclass_names, int subclass_num, uint32_t sub_id)
1229 {
1230         class_lst_t *c_list;
1231 
1232         if (strcmp(class, EC_ALL) == 0) {
1233                 char *subclass_all = EC_SUB_ALL;
1234 
1235                 (void) cache_insert_subclass(SH_CLASS_HASH(shp)[0],
1236                     (char **)&subclass_all, 1, sub_id);
1237                 return (0);
1238         }
1239 
1240         /* New class, add to the registration cache */
1241         if ((c_list = cache_find_class(shp, class)) == NULL) {
1242 
1243                 c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t));
1244                 if (c_list == NULL) {
1245                         return (1);
1246                 }
1247                 c_list->cl_name = strdup(class);
1248                 if (c_list->cl_name == NULL) {
1249                         free(c_list);
1250                         return (1);
1251                 }
1252 
1253                 c_list->cl_subclass_list = (subclass_lst_t *)
1254                     calloc(1, sizeof (subclass_lst_t));
1255                 if (c_list->cl_subclass_list == NULL) {
1256                         free(c_list->cl_name);
1257                         free(c_list);
1258                         return (1);
1259                 }
1260                 c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL);
1261                 if (c_list->cl_subclass_list->sl_name == NULL) {
1262                         free(c_list->cl_subclass_list);
1263                         free(c_list->cl_name);
1264                         free(c_list);
1265                         return (1);
1266                 }
1267                 c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)];
1268                 SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list;
1269 
1270         }
1271 
1272         /* Update the subclass list */
1273         if (cache_insert_subclass(c_list, subclass_names, subclass_num,
1274             sub_id) != 0)
1275                 return (1);
1276 
1277         return (0);
1278 }
1279 
1280 static void
1281 cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id)
1282 {
1283         int i;
1284         class_lst_t *c_list;
1285         subclass_lst_t *sc_list;
1286 
1287         for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
1288                 c_list = SH_CLASS_HASH(shp)[i];
1289                 while (c_list != NULL) {
1290                         sc_list = c_list->cl_subclass_list;
1291                         while (sc_list != NULL) {
1292                                 sc_list->sl_num[sub_id] = 0;
1293                                 sc_list = sc_list->sl_next;
1294                         }
1295                         c_list = c_list->cl_next;
1296                 }
1297         }
1298 }
1299 
1300 static void
1301 cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id)
1302 {
1303         class_lst_t *c_list;
1304         subclass_lst_t *sc_list;
1305 
1306         if (strcmp(class, EC_ALL) == 0) {
1307                 cache_remove_all_class(shp, sub_id);
1308                 return;
1309         }
1310 
1311         if ((c_list = cache_find_class(shp, class)) == NULL) {
1312                 return;
1313         }
1314 
1315         sc_list = c_list->cl_subclass_list;
1316         while (sc_list != NULL) {
1317                 sc_list->sl_num[sub_id] = 0;
1318                 sc_list = sc_list->sl_next;
1319         }
1320 }
1321 
1322 static void
1323 free_cached_registration(sysevent_handle_t *shp)
1324 {
1325         int i;
1326         class_lst_t *clist, *next_clist;
1327         subclass_lst_t *sc_list, *next_sc;
1328 
1329         for (i = 0; i < CLASS_HASH_SZ + 1; i++) {
1330                 clist = SH_CLASS_HASH(shp)[i];
1331                 while (clist != NULL) {
1332                         sc_list = clist->cl_subclass_list;
1333                         while (sc_list != NULL) {
1334                                 free(sc_list->sl_name);
1335                                 next_sc = sc_list->sl_next;
1336                                 free(sc_list);
1337                                 sc_list = next_sc;
1338                         }
1339                         free(clist->cl_name);
1340                         next_clist = clist->cl_next;
1341                         free(clist);
1342                         clist = next_clist;
1343                 }
1344                 SH_CLASS_HASH(shp)[i] = NULL;
1345         }
1346 }
1347 
1348 static int
1349 create_cached_registration(sysevent_handle_t *shp,
1350         class_lst_t **class_hash)
1351 {
1352         int i, j, new_class;
1353         char *class_name;
1354         uint_t num_elem;
1355         uchar_t *subscribers;
1356         nvlist_t *nvl;
1357         nvpair_t *nvpair;
1358         class_lst_t *clist;
1359         subclass_lst_t *sc_list;
1360 
1361         for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
1362 
1363                 if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i))
1364                     == NULL) {
1365                         if (errno == ENOENT) {
1366                                 class_hash[i] = NULL;
1367                                 continue;
1368                         } else {
1369                                 goto create_failed;
1370                         }
1371                 }
1372 
1373 
1374                 nvpair = NULL;
1375                 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1376                         goto create_failed;
1377                 }
1378 
1379                 new_class = 1;
1380                 while (new_class) {
1381                         /* Extract the class name from the nvpair */
1382                         if (nvpair_value_string(nvpair, &class_name) != 0) {
1383                                 goto create_failed;
1384                         }
1385                         clist = (class_lst_t *)
1386                             calloc(1, sizeof (class_lst_t));
1387                         if (clist == NULL) {
1388                                 goto create_failed;
1389                         }
1390 
1391                         clist->cl_name = strdup(class_name);
1392                         if (clist->cl_name == NULL) {
1393                                 free(clist);
1394                                 goto create_failed;
1395                         }
1396 
1397                         /*
1398                          * Extract the subclass name and registration
1399                          * from the nvpair
1400                          */
1401                         if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
1402                             == NULL) {
1403                                 free(clist->cl_name);
1404                                 free(clist);
1405                                 goto create_failed;
1406                         }
1407 
1408                         clist->cl_next = class_hash[i];
1409                         class_hash[i] = clist;
1410 
1411                         for (;;) {
1412 
1413                                 sc_list = (subclass_lst_t *)calloc(1,
1414                                     sizeof (subclass_lst_t));
1415                                 if (sc_list == NULL) {
1416                                         goto create_failed;
1417                                 }
1418 
1419                                 sc_list->sl_next = clist->cl_subclass_list;
1420                                 clist->cl_subclass_list = sc_list;
1421 
1422                                 sc_list->sl_name = strdup(nvpair_name(nvpair));
1423                                 if (sc_list->sl_name == NULL) {
1424                                         goto create_failed;
1425                                 }
1426 
1427                                 if (nvpair_value_byte_array(nvpair,
1428                                     &subscribers, &num_elem) != 0) {
1429                                         goto create_failed;
1430                                 }
1431                                 bcopy(subscribers, (uchar_t *)sc_list->sl_num,
1432                                     MAX_SUBSCRIBERS + 1);
1433 
1434                                 for (j = 1; j <= MAX_SUBSCRIBERS; ++j) {
1435                                         if (sc_list->sl_num[j] == 0)
1436                                                 continue;
1437 
1438                                         if (alloc_subscriber(shp, j, 1) != 0) {
1439                                                 goto create_failed;
1440                                         }
1441                                 }
1442 
1443                                 /*
1444                                  * Check next nvpair - either subclass or
1445                                  * class
1446                                  */
1447                                 if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
1448                                     == NULL) {
1449                                         new_class = 0;
1450                                         break;
1451                                 } else if (strcmp(nvpair_name(nvpair),
1452                                     CLASS_NAME) == 0) {
1453                                         break;
1454                                 }
1455                         }
1456                 }
1457                 nvlist_free(nvl);
1458         }
1459         return (0);
1460 
1461 create_failed:
1462         dealloc_subscribers(shp);
1463         free_cached_registration(shp);

1464         nvlist_free(nvl);
1465         return (-1);
1466 
1467 }
1468 
1469 /*
1470  * cache_update_service - generic event publisher service routine.  This routine
1471  *              is called in response to a registration cache update.
1472  *
1473  */
1474 /*ARGSUSED*/
1475 static void
1476 cache_update_service(void *cookie, char *args, size_t alen,
1477     door_desc_t *ddp, uint_t ndid)
1478 {
1479         int ret = 0;
1480         uint_t num_elem;
1481         char *class, **event_list;
1482         size_t datalen;
1483         uint32_t sub_id;
1484         nvlist_t *nvl;
1485         nvpair_t *nvpair = NULL;
1486         struct reg_args *rargs;
1487         sysevent_handle_t *shp;
1488         subscriber_data_t *sub;
1489 
1490         if (alen < sizeof (struct reg_args) || cookie == NULL) {
1491                 ret = EINVAL;
1492                 goto return_from_door;
1493         }
1494 
1495         /* LINTED: E_BAD_PTR_CAST_ALIGN */
1496         rargs = (struct reg_args *)args;
1497         shp = (sysevent_handle_t *)cookie;
1498 
1499         datalen = alen - sizeof (struct reg_args);
1500         sub_id = rargs->ra_sub_id;
1501 
1502         (void) mutex_lock(SH_LOCK(shp));
1503 
1504         switch (rargs->ra_op) {
1505         case SE_UNREGISTER:
1506                 class = (char *)&rargs->ra_buf_ptr;
1507                 cache_remove_class(shp, (char *)class,
1508                     sub_id);
1509                 break;
1510         case SE_UNBIND_REGISTRATION:
1511 
1512                 sub = SH_SUBSCRIBER(shp, sub_id);
1513                 if (sub == NULL)
1514                         break;
1515 
1516                 free(sub->sd_door_name);
1517                 free(sub);
1518                 cache_remove_class(shp, EC_ALL, sub_id);
1519                 SH_SUBSCRIBER(shp, sub_id) = NULL;
1520 
1521                 break;
1522         case SE_BIND_REGISTRATION:
1523 
1524                 /* New subscriber */
1525                 if (alloc_subscriber(shp, sub_id, 0) != 0) {
1526                         ret = ENOMEM;
1527                         break;
1528                 }
1529                 break;
1530         case SE_REGISTER:
1531 
1532                 if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
1533                         ret = EINVAL;
1534                         break;
1535                 }
1536                 /* Get new registration data */
1537                 if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
1538                     &nvl, 0) != 0) {
1539                         ret =  EFAULT;
1540                         break;
1541                 }
1542                 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1543                         nvlist_free(nvl);
1544                         ret = EFAULT;
1545                         break;
1546                 }
1547                 if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
1548                     != 0) {
1549                         nvlist_free(nvl);
1550                         ret =  EFAULT;
1551                         break;
1552                 }
1553                 class = nvpair_name(nvpair);
1554 
1555                 ret = cache_insert_class(shp, class,
1556                     event_list, num_elem, sub_id);
1557                 if (ret != 0) {
1558                         cache_remove_class(shp, class, sub_id);
1559                         nvlist_free(nvl);
1560                         ret =  EFAULT;
1561                         break;
1562                 }
1563 
1564                 nvlist_free(nvl);
1565 
1566                 break;
1567         case SE_CLEANUP:
1568                 /* Cleanup stale subscribers */
1569                 sysevent_cleanup_subscribers(shp);
1570                 break;
1571         default:
1572                 ret =  EINVAL;
1573         }
1574 
1575         (void) mutex_unlock(SH_LOCK(shp));
1576 
1577 return_from_door:
1578         (void) door_return((void *)&ret, sizeof (ret), NULL, 0);
1579         (void) door_return(NULL, 0, NULL, 0);
1580 }
1581 
1582 /*
1583  * sysevent_send_event -
1584  * Send an event via the communication channel associated with the sysevent
1585  * handle.  Event notifications are broadcast to all subscribers based upon
1586  * the event class and subclass.  The handle must have been previously
1587  * allocated and bound by
1588  * sysevent_open_channel() and sysevent_bind_publisher()
1589  */
1590 int
1591 sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
1592 {
1593         int i, error, sub_fd, result = 0;
1594         int deliver_error = 0;
1595         int subscribers_sent = 0;
1596         int want_resend, resend_cnt = 0;
1597         char *event_class, *event_subclass;
1598         uchar_t *all_class_subscribers, *all_subclass_subscribers;
1599         uchar_t *subclass_subscribers;
1600         subscriber_data_t *sub;
1601         subclass_lst_t *sc_lst;
1602 
1603         /* Check for proper registration */
1604         event_class = sysevent_get_class_name(ev);
1605         event_subclass = sysevent_get_subclass_name(ev);
1606 
1607         (void) mutex_lock(SH_LOCK(shp));
1608 
1609 send_event:
1610 
1611         want_resend = 0;
1612         if (!SH_BOUND(shp)) {
1613                 (void) mutex_unlock(SH_LOCK(shp));
1614                 errno = EINVAL;
1615                 return (-1);
1616         }
1617 
1618         /* Find all subscribers for this event class/subclass */
1619         sc_lst = cache_find_subclass(
1620             cache_find_class(shp, EC_ALL), EC_SUB_ALL);
1621         all_class_subscribers = sc_lst->sl_num;
1622 
1623         sc_lst = cache_find_subclass(
1624             cache_find_class(shp, event_class), EC_SUB_ALL);
1625         if (sc_lst)
1626                 all_subclass_subscribers = sc_lst->sl_num;
1627         else
1628                 all_subclass_subscribers = NULL;
1629 
1630         sc_lst = cache_find_subclass(
1631             cache_find_class(shp, event_class), event_subclass);
1632         if (sc_lst)
1633                 subclass_subscribers = sc_lst->sl_num;
1634         else
1635                 subclass_subscribers = NULL;
1636 
1637         /* Send event buffer to all valid subscribers */
1638         for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1639                 if ((all_class_subscribers[i] |
1640                     (all_subclass_subscribers && all_subclass_subscribers[i]) |
1641                     (subclass_subscribers && subclass_subscribers[i])) == 0)
1642                         continue;
1643 
1644                 sub = SH_SUBSCRIBER(shp, i);
1645                 assert(sub != NULL);
1646 
1647                 /* Check for active subscriber */
1648                 if (!(sub->sd_flag & ACTIVE)) {
1649                         dprint("sysevent_send_event: subscriber %d inactive\n",
1650                             i);
1651                         continue;
1652                 }
1653 
1654                 /* Process only resend requests */
1655                 if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
1656                         continue;
1657                 }
1658 
1659                 if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
1660                         dprint("sysevent_send_event: Failed to open "
1661                             "%s: %s\n", sub->sd_door_name, strerror(errno));
1662                         continue;
1663                 }
1664                 result = 0;
1665                 error = clnt_deliver_event(sub_fd, ev,
1666                     sysevent_get_size(ev), &result, sizeof (result));
1667 
1668                 (void) close(sub_fd);
1669 
1670                 /* Successful door call */
1671                 if (error == 0) {
1672                         switch (result) {
1673                         /* Subscriber requested EAGAIN */
1674                         case EAGAIN:
1675                                 if (resend_cnt > SE_MAX_RETRY_LIMIT) {
1676                                         deliver_error = 1;
1677                                 } else {
1678                                         want_resend = 1;
1679                                         dprint("sysevent_send_event: resend "
1680                                             "requested for %d\n", i);
1681                                         sub->sd_flag |= SEND_AGAIN;
1682                                 }
1683                                 break;
1684                         /* Bad sysevent handle for subscriber */
1685                         case EBADF:
1686                         case EINVAL:
1687                                 dprint("sysevent_send_event: Bad sysevent "
1688                                     "handle for %s", sub->sd_door_name);
1689                                 sub->sd_flag = 0;
1690                                 deliver_error = 1;
1691                                 break;
1692                         /* Successful delivery */
1693                         default:
1694                                 sub->sd_flag &= ~SEND_AGAIN;
1695                                 ++subscribers_sent;
1696                         }
1697                 } else {
1698                         dprint("sysevent_send_event: Failed door call "
1699                             "to %s: %s: %d\n", sub->sd_door_name,
1700                             strerror(errno), result);
1701                         sub->sd_flag = 0;
1702                         deliver_error = 1;
1703                 }
1704         }
1705 
1706         if (want_resend) {
1707                 resend_cnt++;
1708                 goto send_event;
1709         }
1710 
1711         if (deliver_error) {
1712                 sysevent_cleanup_subscribers(shp);
1713                 (void) mutex_unlock(SH_LOCK(shp));
1714                 errno = EFAULT;
1715                 return (-1);
1716         }
1717 
1718         (void) mutex_unlock(SH_LOCK(shp));
1719 
1720         if (subscribers_sent == 0) {
1721                 dprint("sysevent_send_event: No subscribers for %s:%s\n",
1722                     event_class, event_subclass);
1723                 errno = ENOENT;
1724                 return (-1);
1725         }
1726 
1727         return (0);
1728 }
1729 
1730 /*
1731  * Common routine to establish an event channel through which an event
1732  * publisher or subscriber may post or receive events.
1733  */
1734 static sysevent_handle_t *
1735 sysevent_open_channel_common(const char *channel_path)
1736 {
1737         uint32_t sub_id = 0;
1738         char *begin_path;
1739         struct stat chan_stat;
1740         sysevent_handle_t *shp;
1741 
1742 
1743         if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
1744                 errno = EINVAL;
1745                 return (NULL);
1746         }
1747 
1748         if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1749                 if (errno != EEXIST) {
1750                         errno = EACCES;
1751                         return (NULL);
1752                 }
1753         }
1754 
1755         /* Check channel file permissions */
1756         if (stat(channel_path, &chan_stat) != 0) {
1757                 dprint("sysevent_open_channel: Invalid permissions for channel "
1758                     "%s\n", channel_path);
1759                 errno = EACCES;
1760                 return (NULL);
1761         } else if (chan_stat.st_uid != getuid() ||
1762             !S_ISDIR(chan_stat.st_mode)) {
1763                 dprint("sysevent_open_channel: Invalid "
1764                     "permissions for channel %s\n: %d:%d:%d", channel_path,
1765                     (int)chan_stat.st_uid, (int)chan_stat.st_gid,
1766                     (int)chan_stat.st_mode);
1767 
1768                 errno = EACCES;
1769                 return (NULL);
1770         }
1771 
1772         shp = calloc(1, sizeof (sysevent_impl_hdl_t));
1773         if (shp == NULL) {
1774                 errno = ENOMEM;
1775                 return (NULL);
1776         }
1777 
1778         SH_CHANNEL_NAME(shp) = NULL;
1779         SH_CHANNEL_PATH(shp) = strdup(channel_path);
1780         if (SH_CHANNEL_PATH(shp) == NULL) {
1781                 free(shp);
1782                 errno = ENOMEM;
1783                 return (NULL);
1784         }
1785 
1786         /* Extract the channel name */
1787         begin_path = SH_CHANNEL_PATH(shp);
1788         while (*begin_path != '\0' &&
1789             (begin_path = strpbrk(begin_path, "/")) != NULL) {
1790                 ++begin_path;
1791                 SH_CHANNEL_NAME(shp) = begin_path;
1792         }
1793 
1794         if (update_kernel_registration(shp, 0,
1795             SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
1796                 dprint("sysevent_open_channel: Failed for channel %s\n",
1797                     SH_CHANNEL_NAME(shp));
1798                 free(SH_CHANNEL_PATH(shp));
1799                 free(shp);
1800                 errno = EFAULT;
1801                 return (NULL);
1802         }
1803 
1804         (void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
1805 
1806         return (shp);
1807 }
1808 
1809 /*
1810  * Establish a sysevent channel for publication and subscription
1811  */
1812 sysevent_handle_t *
1813 sysevent_open_channel(const char *channel)
1814 {
1815         int var_run_mounted = 0;
1816         char full_channel[MAXPATHLEN + 1];
1817         FILE *fp;
1818         struct stat chan_stat;
1819         struct extmnttab m;
1820 
1821         if (channel == NULL) {
1822                 errno = EINVAL;
1823                 return (NULL);
1824         }
1825 
1826         /*
1827          * Check that /var/run is mounted as tmpfs before allowing a channel
1828          * to be opened.
1829          */
1830         if ((fp = fopen(MNTTAB, "rF")) == NULL) {
1831                 errno = EACCES;
1832                 return (NULL);
1833         }
1834 
1835         resetmnttab(fp);
1836 
1837         while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
1838                 if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
1839                     strcmp(m.mnt_fstype, "tmpfs") == 0) {
1840                         var_run_mounted = 1;
1841                         break;
1842                 }
1843         }
1844         (void) fclose(fp);
1845 
1846         if (!var_run_mounted) {
1847                 errno = EACCES;
1848                 return (NULL);
1849         }
1850 
1851         if (stat(CHAN_PATH, &chan_stat) < 0) {
1852                 if (mkdir(CHAN_PATH,
1853                     S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1854                         dprint("sysevent_open_channel: Unable "
1855                             "to create channel directory %s:%s\n", CHAN_PATH,
1856                             strerror(errno));
1857                         if (errno != EEXIST) {
1858                                 errno = EACCES;
1859                                 return (NULL);
1860                         }
1861                 }
1862         }
1863 
1864         if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
1865             MAXPATHLEN) {
1866                 errno = EINVAL;
1867                 return (NULL);
1868         }
1869 
1870         return (sysevent_open_channel_common(full_channel));
1871 }
1872 
1873 /*
1874  * Establish a sysevent channel for publication and subscription
1875  * Full path to the channel determined by the caller
1876  */
1877 sysevent_handle_t *
1878 sysevent_open_channel_alt(const char *channel_path)
1879 {
1880         return (sysevent_open_channel_common(channel_path));
1881 }
1882 
1883 /*
1884  * sysevent_close_channel - Clean up resources associated with a previously
1885  *                              opened sysevent channel
1886  */
1887 void
1888 sysevent_close_channel(sysevent_handle_t *shp)
1889 {
1890         int error = errno;
1891         uint32_t sub_id = 0;
1892 
1893         if (shp == NULL) {
1894                 return;
1895         }
1896 
1897         (void) mutex_lock(SH_LOCK(shp));
1898         if (SH_BOUND(shp)) {
1899                 (void) mutex_unlock(SH_LOCK(shp));
1900                 if (SH_TYPE(shp) == PUBLISHER)
1901                         sysevent_unbind_publisher(shp);
1902                 else if (SH_TYPE(shp) == SUBSCRIBER)
1903                         sysevent_unbind_subscriber(shp);
1904                 (void) mutex_lock(SH_LOCK(shp));
1905         }
1906 
1907         (void) update_kernel_registration(shp, 0,
1908             SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
1909         (void) mutex_unlock(SH_LOCK(shp));
1910 
1911         free(SH_CHANNEL_PATH(shp));
1912         free(shp);
1913         errno = error;
1914 }
1915 
1916 /*
1917  * sysevent_bind_publisher - Bind an event publisher to an event channel
1918  */
1919 int
1920 sysevent_bind_publisher(sysevent_handle_t *shp)
1921 {
1922         int error = 0;
1923         int fd = -1;
1924         char door_name[MAXPATHLEN];
1925         uint32_t pub_id;
1926         struct stat reg_stat;
1927         publisher_priv_t *pub;
1928 
1929         if (shp == NULL) {
1930                 errno = EINVAL;
1931                 return (-1);
1932         }
1933 
1934         (void) mutex_lock(SH_LOCK(shp));
1935         if (SH_BOUND(shp)) {
1936                 (void) mutex_unlock(SH_LOCK(shp));
1937                 errno = EINVAL;
1938                 return (-1);
1939         }
1940 
1941         if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
1942             NULL) {
1943                 (void) mutex_unlock(SH_LOCK(shp));
1944                 errno = ENOMEM;
1945                 return (-1);
1946         }
1947         SH_PRIV_DATA(shp) = (void *)pub;
1948 
1949         if (snprintf(door_name, MAXPATHLEN, "%s/%s",
1950             SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
1951                 free(pub);
1952                 (void) mutex_unlock(SH_LOCK(shp));
1953                 errno = ENOMEM;
1954                 return (-1);
1955         }
1956         if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
1957                 free(pub);
1958                 (void) mutex_unlock(SH_LOCK(shp));
1959                 errno = ENOMEM;
1960                 return (-1);
1961         }
1962 
1963         /* Only one publisher allowed per channel */
1964         if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
1965                 if (errno != ENOENT) {
1966                         error = EINVAL;
1967                         goto fail;
1968                 }
1969         }
1970 
1971         /*
1972          * Remove door file for robustness.
1973          */
1974         if (unlink(SH_DOOR_NAME(shp)) != 0)
1975                 dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
1976                     SH_DOOR_NAME(shp));
1977 
1978         /* Open channel registration door */
1979         fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
1980             S_IREAD|S_IWRITE);
1981         if (fd == -1) {
1982                 error = EINVAL;
1983                 goto fail;
1984         }
1985 
1986         /*
1987          * Create the registration service for this publisher.
1988          */
1989         if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
1990             (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1991                 dprint("sysevent_bind_publisher: door create failed: "
1992                     "%s\n", strerror(errno));
1993                 error = EFAULT;
1994                 goto fail;
1995         }
1996 
1997         (void) fdetach(SH_DOOR_NAME(shp));
1998         if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
1999                 dprint("sysevent_bind_publisher: unable to "
2000                     "bind event channel: fattach: %s\n",
2001                     SH_DOOR_NAME(shp));
2002                 error = EACCES;
2003                 goto fail;
2004         }
2005 
2006         /* Bind this publisher in the kernel registration database */
2007         if (update_kernel_registration(shp, PUBLISHER,
2008             SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
2009                 error = errno;
2010                 goto fail;
2011         }
2012 
2013         SH_ID(shp) = pub_id;
2014         SH_BOUND(shp) = 1;
2015         SH_TYPE(shp) = PUBLISHER;
2016 
2017 
2018         /* Create the subscription registration cache */
2019         if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
2020                 (void) update_kernel_registration(shp,
2021                     PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
2022                 error = EFAULT;
2023                 goto fail;
2024         }
2025         (void) close(fd);
2026 
2027         (void) mutex_unlock(SH_LOCK(shp));
2028 
2029         return (0);
2030 
2031 fail:
2032         SH_BOUND(shp) = 0;
2033         (void) door_revoke(SH_DOOR_DESC(shp));
2034         (void) fdetach(SH_DOOR_NAME(shp));
2035         free(SH_DOOR_NAME(shp));
2036         free(pub);
2037         (void) close(fd);
2038         (void) mutex_unlock(SH_LOCK(shp));
2039         errno = error;
2040         return (-1);
2041 }
2042 
2043 static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2044 static pthread_attr_t xdoor_thrattr;
2045 
2046 static void
2047 xdoor_thrattr_init(void)
2048 {
2049         (void) pthread_attr_init(&xdoor_thrattr);
2050         (void) pthread_attr_setdetachstate(&xdoor_thrattr,
2051             PTHREAD_CREATE_DETACHED);
2052         (void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2053 }
2054 
2055 static int
2056 xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2057     void *startfarg, void *cookie)
2058 {
2059         struct sysevent_subattr_impl *xsa = cookie;
2060         pthread_attr_t *thrattr;
2061         sigset_t oset;
2062         int err;
2063 
2064         if (xsa->xs_thrcreate) {
2065                 return (xsa->xs_thrcreate(dip, startf, startfarg,
2066                     xsa->xs_thrcreate_cookie));
2067         }
2068 
2069         if (xsa->xs_thrattr == NULL) {
2070                 (void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2071                 thrattr = &xdoor_thrattr;
2072         } else {
2073                 thrattr = xsa->xs_thrattr;
2074         }
2075 
2076         (void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2077         err = pthread_create(NULL, thrattr, startf, startfarg);
2078         (void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2079 
2080         return (err == 0 ? 1 : -1);
2081 }
2082 
2083 static void
2084 xdoor_server_setup(void *cookie)
2085 {
2086         struct sysevent_subattr_impl *xsa = cookie;
2087 
2088         if (xsa->xs_thrsetup) {
2089                 xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2090         } else {
2091                 (void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2092                 (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2093         }
2094 }
2095 
2096 static int
2097 sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
2098         void (*event_handler)(sysevent_t *ev),
2099         sysevent_subattr_t *subattr)
2100 {
2101         int fd = -1;
2102         int error = 0;
2103         uint32_t sub_id = 0;
2104         char door_name[MAXPATHLEN];
2105         subscriber_priv_t *sub_info;
2106         int created;
2107         struct sysevent_subattr_impl *xsa =
2108             (struct sysevent_subattr_impl *)subattr;
2109 
2110         if (shp == NULL || event_handler == NULL) {
2111                 errno = EINVAL;
2112                 return (-1);
2113         }
2114 
2115         (void) mutex_lock(SH_LOCK(shp));
2116         if (SH_BOUND(shp)) {
2117                 errno = EINVAL;
2118                 (void) mutex_unlock(SH_LOCK(shp));
2119                 return (-1);
2120         }
2121 
2122         if ((sub_info = (subscriber_priv_t *)calloc(1,
2123             sizeof (subscriber_priv_t))) == NULL) {
2124                 errno = ENOMEM;
2125                 (void) mutex_unlock(SH_LOCK(shp));
2126                 return (-1);
2127         }
2128 
2129         if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2130             SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2131                 free(sub_info);
2132                 errno = EINVAL;
2133                 (void) mutex_unlock(SH_LOCK(shp));
2134                 return (-1);
2135         }
2136 
2137         if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
2138                 free(sub_info);
2139                 errno = ENOMEM;
2140                 (void) mutex_unlock(SH_LOCK(shp));
2141                 return (-1);
2142         }
2143         (void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
2144         (void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
2145         sub_info->sp_func = event_handler;
2146 
2147         /* Update the in-kernel registration */
2148         if (update_kernel_registration(shp, SUBSCRIBER,
2149             SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
2150                 error = errno;
2151                 goto fail;
2152         }
2153         SH_ID(shp) = sub_id;
2154 
2155         if (snprintf(door_name, MAXPATHLEN, "%s/%d",
2156             SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
2157                 error = EINVAL;
2158                 goto fail;
2159         }
2160         if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
2161                 error = ENOMEM;
2162                 goto fail;
2163         }
2164 
2165         /*
2166          * Remove door file for robustness.
2167          */
2168         if (unlink(SH_DOOR_NAME(shp)) != 0)
2169                 dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
2170                     SH_DOOR_NAME(shp));
2171 
2172         fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
2173         if (fd == -1) {
2174                 error = EFAULT;
2175                 goto fail;
2176         }
2177 
2178         /*
2179          * Create the sysevent door service for this client.
2180          * syseventd will use this door service to propagate
2181          * events to the client.
2182          */
2183         if (subattr == NULL) {
2184                 SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2185                     (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2186         } else {
2187                 SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2188                     (void *)shp,
2189                     DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2190                     xdoor_server_create, xdoor_server_setup,
2191                     (void *)subattr, 1);
2192         }
2193 
2194         if (SH_DOOR_DESC(shp) == -1) {
2195                 dprint("sysevent_bind_subscriber: door create failed: "
2196                     "%s\n", strerror(errno));
2197                 error = EFAULT;
2198                 goto fail;
2199         }
2200 
2201         (void) fdetach(SH_DOOR_NAME(shp));
2202         if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2203                 error = EFAULT;
2204                 goto fail;
2205         }
2206         (void) close(fd);
2207 
2208         if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
2209             sub_id, 0, NULL) != 0) {
2210                 error = errno;
2211                 (void) update_kernel_registration(shp, SUBSCRIBER,
2212                     SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2213                 goto fail;
2214         }
2215 
2216         SH_BOUND(shp) = 1;
2217         SH_TYPE(shp) = SUBSCRIBER;
2218         SH_PRIV_DATA(shp) = (void *)sub_info;
2219 
2220         /* Create an event handler thread */
2221         if (xsa == NULL || xsa->xs_thrcreate == NULL) {
2222                 created = thr_create(NULL, NULL,
2223                     (void *(*)(void *))subscriber_event_handler,
2224                     shp, THR_BOUND, &sub_info->sp_handler_tid) == 0;
2225         } else {
2226                 /*
2227                  * A terrible hack.  We will use the extended private
2228                  * door thread creation function the caller passed in to
2229                  * create the event handler thread.  That function will
2230                  * be called with our chosen thread start function and arg
2231                  * instead of the usual libc-provided ones, but that's ok
2232                  * as it is required to use them verbatim anyway.  We will
2233                  * pass a NULL door_info_t pointer to the function - so
2234                  * callers depending on this hack had better be prepared
2235                  * for that.  All this allow the caller to rubberstamp
2236                  * the created thread as it wishes.  But we don't get
2237                  * the created threadid with this, so we modify the
2238                  * thread start function to stash it.
2239                  */
2240 
2241                 created = xsa->xs_thrcreate(NULL,
2242                     (void *(*)(void *))subscriber_event_handler,
2243                     shp, xsa->xs_thrcreate_cookie) == 1;
2244         }
2245 
2246         if (!created) {
2247                 error = EFAULT;
2248                 goto fail;
2249         }
2250 
2251         (void) mutex_unlock(SH_LOCK(shp));
2252 
2253         return (0);
2254 
2255 fail:
2256         (void) close(fd);
2257         (void) door_revoke(SH_DOOR_DESC(shp));
2258         (void) fdetach(SH_DOOR_NAME(shp));
2259         (void) cond_destroy(&sub_info->sp_cv);
2260         (void) mutex_destroy(&sub_info->sp_qlock);
2261         free(sub_info->sp_door_name);
2262         free(sub_info);
2263         if (SH_ID(shp)) {
2264                 (void) update_kernel_registration(shp, SUBSCRIBER,
2265                     SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2266                 SH_ID(shp) = 0;
2267         }
2268         if (SH_BOUND(shp)) {
2269                 (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2270                     sub_id, 0, NULL);
2271                 free(SH_DOOR_NAME(shp));
2272                 SH_BOUND(shp) = 0;
2273         }
2274         (void) mutex_unlock(SH_LOCK(shp));
2275 
2276         errno = error;
2277 
2278         return (-1);
2279 }
2280 
2281 /*
2282  * sysevent_bind_subscriber - Bind an event receiver to an event channel
2283  */
2284 int
2285 sysevent_bind_subscriber(sysevent_handle_t *shp,
2286         void (*event_handler)(sysevent_t *ev))
2287 {
2288         return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2289 }
2290 
2291 /*
2292  * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2293  * attributes specified.
2294  */
2295 int
2296 sysevent_bind_xsubscriber(sysevent_handle_t *shp,
2297         void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2298 {
2299         return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2300 }
2301 
2302 /*
2303  * sysevent_register_event - register an event class and associated subclasses
2304  *              for an event subscriber
2305  */
2306 int
2307 sysevent_register_event(sysevent_handle_t *shp,
2308         const char *ev_class, const char **ev_subclass,
2309         int subclass_num)
2310 {
2311         int error;
2312         char *event_class = (char *)ev_class;
2313         char **event_subclass_list = (char **)ev_subclass;
2314         char *nvlbuf = NULL;
2315         size_t datalen;
2316         nvlist_t *nvl;
2317 
2318         (void) mutex_lock(SH_LOCK(shp));
2319         if (event_class == NULL || event_subclass_list == NULL ||
2320             event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
2321             subclass_num <= 0) {
2322                 (void) mutex_unlock(SH_LOCK(shp));
2323                 errno = EINVAL;
2324                 return (-1);
2325         }
2326 
2327         if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2328                 (void) mutex_unlock(SH_LOCK(shp));
2329                 return (-1);
2330         }
2331         if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
2332             subclass_num) != 0) {
2333                 nvlist_free(nvl);
2334                 (void) mutex_unlock(SH_LOCK(shp));
2335                 return (-1);
2336         }
2337         if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
2338                 nvlist_free(nvl);
2339                 (void) mutex_unlock(SH_LOCK(shp));
2340                 return (-1);
2341         }
2342         nvlist_free(nvl);
2343 
2344         /* Store new subscriber in in-kernel registration */
2345         if (update_kernel_registration(shp, SUBSCRIBER,
2346             SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
2347             != 0) {
2348                 error = errno;
2349                 free(nvlbuf);
2350                 (void) mutex_unlock(SH_LOCK(shp));
2351                 errno = error;
2352                 return (-1);
2353         }
2354         /* Update the publisher's cached registration */
2355         if (update_publisher_cache(
2356             (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
2357             SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
2358                 error = errno;
2359                 free(nvlbuf);
2360                 (void) mutex_unlock(SH_LOCK(shp));
2361                 errno = error;
2362                 return (-1);
2363         }
2364 
2365         free(nvlbuf);
2366 
2367         (void) mutex_unlock(SH_LOCK(shp));
2368 
2369         return (0);
2370 }
2371 
2372 /*
2373  * sysevent_unregister_event - Unregister an event class and associated
2374  *                              subclasses for an event subscriber
2375  */
2376 void
2377 sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
2378 {
2379         size_t class_sz;
2380 
2381         (void) mutex_lock(SH_LOCK(shp));
2382 
2383         if (!SH_BOUND(shp)) {
2384                 (void) mutex_unlock(SH_LOCK(shp));
2385                 return;
2386         }
2387 
2388         /* Remove subscriber from in-kernel registration */
2389         class_sz = strlen(class) + 1;
2390         (void) update_kernel_registration(shp, SUBSCRIBER,
2391             SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
2392         /* Update the publisher's cached registration */
2393         (void) update_publisher_cache(
2394             (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
2395             SH_ID(shp), class_sz, (uchar_t *)class);
2396 
2397         (void) mutex_unlock(SH_LOCK(shp));
2398 }
2399 
2400 static int
2401 cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
2402 {
2403         dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2404 
2405         /* Remove registration from the kernel */
2406         if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
2407             0, NULL) != 0) {
2408                 dprint("cleanup_id: Unable to clean "
2409                     "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2410                 return (-1);
2411         }
2412 
2413         return (0);
2414 }
2415 
2416 /*
2417  * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
2418  *              allocated to unresponsive subscribers.
2419  */
2420 void
2421 sysevent_cleanup_subscribers(sysevent_handle_t *shp)
2422 {
2423         uint32_t ping, result;
2424         int i, error, sub_fd;
2425         subscriber_data_t *sub;
2426 
2427         if (!SH_BOUND(shp)) {
2428                 return;
2429         }
2430 
2431         for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
2432 
2433                 sub = SH_SUBSCRIBER(shp, i);
2434                 if (sub == NULL) {
2435                         continue;
2436                 }
2437 
2438                 if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
2439                         continue;
2440                 }
2441                 /* Check for valid and responsive subscriber */
2442                 error = clnt_deliver_event(sub_fd, &ping,
2443                     sizeof (uint32_t), &result, sizeof (result));
2444                 (void) close(sub_fd);
2445 
2446                 /* Only cleanup on EBADF (Invalid door descriptor) */
2447                 if (error != EBADF)
2448                         continue;
2449 
2450                 if (cleanup_id(shp, i, SUBSCRIBER) != 0)
2451                         continue;
2452 
2453                 cache_remove_class(shp, EC_ALL, i);
2454 
2455                 free(sub->sd_door_name);
2456                 free(sub);
2457                 SH_SUBSCRIBER(shp, i) = NULL;
2458         }
2459 
2460 }
2461 
2462 /*
2463  * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
2464  *              as needed.
2465  */
2466 void
2467 sysevent_cleanup_publishers(sysevent_handle_t *shp)
2468 {
2469         (void) cleanup_id(shp, 1, PUBLISHER);
2470 }
2471 
2472 /*
2473  * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
2474  */
2475 void
2476 sysevent_unbind_subscriber(sysevent_handle_t *shp)
2477 {
2478         subscriber_priv_t *sub_info;
2479 
2480         if (shp == NULL)
2481                 return;
2482 
2483         (void) mutex_lock(SH_LOCK(shp));
2484         if (SH_BOUND(shp) == 0) {
2485                 (void) mutex_unlock(SH_LOCK(shp));
2486                 return;
2487         }
2488 
2489         /* Update the in-kernel registration */
2490         (void) update_kernel_registration(shp, SUBSCRIBER,
2491             SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2492 
2493         /* Update the sysevent channel publisher */
2494         sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
2495         (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2496             SH_ID(shp), 0, NULL);
2497 
2498         /* Close down event delivery facilities */
2499         (void) door_revoke(SH_DOOR_DESC(shp));
2500         (void) fdetach(SH_DOOR_NAME(shp));
2501 
2502         /*
2503          * Release resources and wait for pending event delivery to
2504          * complete.
2505          */
2506         (void) mutex_lock(&sub_info->sp_qlock);
2507         SH_BOUND(shp) = 0;
2508         /* Signal event handler and drain the subscriber's event queue */
2509         (void) cond_signal(&sub_info->sp_cv);
2510         (void) mutex_unlock(&sub_info->sp_qlock);
2511         if (sub_info->sp_handler_tid != NULL)
2512                 (void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
2513 
2514         (void) cond_destroy(&sub_info->sp_cv);
2515         (void) mutex_destroy(&sub_info->sp_qlock);
2516         free(sub_info->sp_door_name);
2517         free(sub_info);
2518         free(SH_DOOR_NAME(shp));
2519         (void) mutex_unlock(SH_LOCK(shp));
2520 }
2521 
2522 /*
2523  * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
2524  */
2525 void
2526 sysevent_unbind_publisher(sysevent_handle_t *shp)
2527 {
2528         if (shp == NULL)
2529                 return;
2530 
2531         (void) mutex_lock(SH_LOCK(shp));
2532         if (SH_BOUND(shp) == 0) {
2533                 (void) mutex_unlock(SH_LOCK(shp));
2534                 return;
2535         }
2536 
2537         /* Close down the registration facilities */
2538         (void) door_revoke(SH_DOOR_DESC(shp));
2539         (void) fdetach(SH_DOOR_NAME(shp));
2540 
2541         /* Update the in-kernel registration */
2542         (void) update_kernel_registration(shp, PUBLISHER,
2543             SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2544         SH_BOUND(shp) = 0;
2545 
2546         /* Free resources associated with bind */
2547         free_cached_registration(shp);
2548         dealloc_subscribers(shp);
2549 
2550         free(SH_PRIV_DATA(shp));
2551         free(SH_DOOR_NAME(shp));
2552         SH_ID(shp) = 0;
2553         (void) mutex_unlock(SH_LOCK(shp));
2554 }
2555 
2556 /*
2557  * Evolving APIs to subscribe to syseventd(1M) system events.
2558  */
2559 
2560 static sysevent_handle_t *
2561 sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2562     sysevent_subattr_t *subattr)
2563 {
2564         sysevent_handle_t *shp;
2565 
2566         if (getuid() != 0) {
2567                 errno = EACCES;
2568                 return (NULL);
2569         }
2570 
2571         if (event_handler == NULL) {
2572                 errno = EINVAL;
2573                 return (NULL);
2574         }
2575 
2576         if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
2577                 return (NULL);
2578         }
2579 
2580         if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
2581                 /*
2582                  * Ask syseventd to clean-up any stale subcribers and try to
2583                  * to bind again
2584                  */
2585                 if (errno == EBUSY) {
2586                         int pub_fd;
2587                         char door_name[MAXPATHLEN];
2588                         uint32_t result;
2589                         struct reg_args rargs;
2590 
2591                         if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2592                             SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2593                                 sysevent_close_channel(shp);
2594                                 errno = EINVAL;
2595                                 return (NULL);
2596                         }
2597 
2598                         rargs.ra_op = SE_CLEANUP;
2599                         pub_fd = open(door_name, O_RDONLY);
2600                         (void) clnt_deliver_event(pub_fd, (void *)&rargs,
2601                             sizeof (struct reg_args), &result, sizeof (result));
2602                         (void) close(pub_fd);
2603 
2604                         /* Try to bind again */
2605                         if (sysevent_bind_xsubscriber(shp, event_handler,
2606                             subattr) != 0) {
2607                                 sysevent_close_channel(shp);
2608                                 return (NULL);
2609                         }
2610                 } else {
2611                         sysevent_close_channel(shp);
2612                         return (NULL);
2613                 }
2614         }
2615 
2616         return (shp);
2617 }
2618 
2619 /*
2620  * sysevent_bind_handle - Bind application event handler for syseventd
2621  *              subscription.
2622  */
2623 sysevent_handle_t *
2624 sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2625 {
2626         return (sysevent_bind_handle_cmn(event_handler, NULL));
2627 }
2628 
2629 /*
2630  * sysevent_bind_xhandle - Bind application event handler for syseventd
2631  *              subscription, using door_xcreate and attributes as specified.
2632  */
2633 sysevent_handle_t *
2634 sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2635     sysevent_subattr_t *subattr)
2636 {
2637         return (sysevent_bind_handle_cmn(event_handler, subattr));
2638 }
2639 
2640 /*
2641  * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
2642  */
2643 void
2644 sysevent_unbind_handle(sysevent_handle_t *shp)
2645 {
2646         sysevent_unbind_subscriber(shp);
2647         sysevent_close_channel(shp);
2648 }
2649 
2650 /*
2651  * sysevent_subscribe_event - Subscribe to system event notification from
2652  *                      syseventd(1M) for the class and subclasses specified.
2653  */
2654 int
2655 sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
2656         const char **event_subclass_list, int num_subclasses)
2657 {
2658         return (sysevent_register_event(shp, event_class,
2659             event_subclass_list, num_subclasses));
2660 }
2661 
2662 void
2663 sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
2664 {
2665         sysevent_unregister_event(shp, event_class);
2666 }
--- EOF ---