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