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