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