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