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 2010 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <fcntl.h> 29 #include <errno.h> 30 #include <door.h> 31 #include <unistd.h> 32 #include <stddef.h> 33 #include <stdlib.h> 34 #include <string.h> 35 #include <strings.h> 36 #include <synch.h> 37 #include <pthread.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 (void) mutex_lock(&sub_info->sp_qlock); 768 for (;;) { 769 while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) { 770 (void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock); 771 } 772 evqp = sub_info->sp_evq_head; 773 while (evqp) { 774 (void) mutex_unlock(&sub_info->sp_qlock); 775 (void) sub_info->sp_func(evqp->sq_ev); 776 (void) mutex_lock(&sub_info->sp_qlock); 777 sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next; 778 free(evqp->sq_ev); 779 free(evqp); 780 evqp = sub_info->sp_evq_head; 781 } 782 if (!SH_BOUND(shp)) { 783 (void) mutex_unlock(&sub_info->sp_qlock); 784 return; 785 } 786 } 787 788 /* NOTREACHED */ 789 } 790 791 /* 792 * Data structure used to communicate event subscription cache updates 793 * to publishers via a registration door 794 */ 795 struct reg_args { 796 uint32_t ra_sub_id; 797 uint32_t ra_op; 798 uint64_t ra_buf_ptr; 799 }; 800 801 802 /* 803 * event_deliver_service - generic event delivery service routine. This routine 804 * is called in response to a door call to post an event. 805 * 806 */ 807 /*ARGSUSED*/ 808 static void 809 event_deliver_service(void *cookie, char *args, size_t alen, 810 door_desc_t *ddp, uint_t ndid) 811 { 812 int ret = 0; 813 subscriber_priv_t *sub_info; 814 sysevent_handle_t *shp; 815 sysevent_queue_t *new_eq; 816 817 if (args == NULL || alen < sizeof (uint32_t)) { 818 ret = EINVAL; 819 goto return_from_door; 820 } 821 822 /* Publisher checking on subscriber */ 823 if (alen == sizeof (uint32_t)) { 824 ret = 0; 825 goto return_from_door; 826 } 827 828 shp = (sysevent_handle_t *)cookie; 829 if (shp == NULL) { 830 ret = EBADF; 831 goto return_from_door; 832 } 833 834 /* 835 * Mustn't block if we are trying to update the registration with 836 * the publisher 837 */ 838 if (mutex_trylock(SH_LOCK(shp)) != 0) { 839 ret = EAGAIN; 840 goto return_from_door; 841 } 842 843 if (!SH_BOUND(shp)) { 844 ret = EBADF; 845 (void) mutex_unlock(SH_LOCK(shp)); 846 goto return_from_door; 847 } 848 849 sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 850 if (sub_info == NULL) { 851 ret = EBADF; 852 (void) mutex_unlock(SH_LOCK(shp)); 853 goto return_from_door; 854 } 855 856 new_eq = (sysevent_queue_t *)calloc(1, 857 sizeof (sysevent_queue_t)); 858 if (new_eq == NULL) { 859 ret = EAGAIN; 860 (void) mutex_unlock(SH_LOCK(shp)); 861 goto return_from_door; 862 } 863 864 /* 865 * Allocate and copy the event buffer into the subscriber's 866 * address space 867 */ 868 new_eq->sq_ev = calloc(1, alen); 869 if (new_eq->sq_ev == NULL) { 870 free(new_eq); 871 ret = EAGAIN; 872 (void) mutex_unlock(SH_LOCK(shp)); 873 goto return_from_door; 874 } 875 (void) bcopy(args, new_eq->sq_ev, alen); 876 877 (void) mutex_lock(&sub_info->sp_qlock); 878 if (sub_info->sp_evq_head == NULL) { 879 sub_info->sp_evq_head = new_eq; 880 } else { 881 sub_info->sp_evq_tail->sq_next = new_eq; 882 } 883 sub_info->sp_evq_tail = new_eq; 884 885 (void) cond_signal(&sub_info->sp_cv); 886 (void) mutex_unlock(&sub_info->sp_qlock); 887 (void) mutex_unlock(SH_LOCK(shp)); 888 889 return_from_door: 890 (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 891 (void) door_return(NULL, 0, NULL, 0); 892 } 893 894 /* 895 * Sysevent subscription information is maintained in the kernel. Updates 896 * to the in-kernel registration database is expected to be infrequent and 897 * offers consistency for publishers and subscribers that may come and go 898 * for a given channel. 899 * 900 * To expedite registration lookups by publishers, a cached copy of the 901 * kernel registration database is kept per-channel. Caches are invalidated 902 * and refreshed upon state changes to the in-kernel registration database. 903 * 904 * To prevent stale subscriber data, publishers may remove subsriber 905 * registrations from the in-kernel registration database in the event 906 * that a particular subscribing process is unresponsive. 907 * 908 * The following routines provide a mechanism to update publisher and subscriber 909 * information for a specified channel. 910 */ 911 912 /* 913 * clnt_deliver_event - Deliver an event through the consumer's event 914 * delivery door 915 * 916 * Returns -1 if message not delivered. With errno set to cause of error. 917 * Returns 0 for success with the results returned in posting buffer. 918 */ 919 static int 920 clnt_deliver_event(int service_door, void *data, size_t datalen, 921 void *result, size_t rlen) 922 { 923 int error = 0; 924 door_arg_t door_arg; 925 926 door_arg.rbuf = result; 927 door_arg.rsize = rlen; 928 door_arg.data_ptr = data; 929 door_arg.data_size = datalen; 930 door_arg.desc_ptr = NULL; 931 door_arg.desc_num = 0; 932 933 /* 934 * Make door call 935 */ 936 while ((error = door_call(service_door, &door_arg)) != 0) { 937 if (errno == EAGAIN || errno == EINTR) { 938 continue; 939 } else { 940 error = errno; 941 break; 942 } 943 } 944 945 return (error); 946 } 947 948 static int 949 update_publisher_cache(subscriber_priv_t *sub_info, int update_op, 950 uint32_t sub_id, size_t datasz, uchar_t *data) 951 { 952 int pub_fd; 953 uint32_t result = 0; 954 struct reg_args *rargs; 955 956 rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) + 957 datasz); 958 if (rargs == NULL) { 959 errno = ENOMEM; 960 return (-1); 961 } 962 963 rargs->ra_sub_id = sub_id; 964 rargs->ra_op = update_op; 965 bcopy(data, (char *)&rargs->ra_buf_ptr, datasz); 966 967 pub_fd = open(sub_info->sp_door_name, O_RDONLY); 968 (void) clnt_deliver_event(pub_fd, (void *)rargs, 969 sizeof (struct reg_args) + datasz, &result, sizeof (result)); 970 (void) close(pub_fd); 971 972 free(rargs); 973 if (result != 0) { 974 errno = result; 975 return (-1); 976 } 977 978 return (0); 979 } 980 981 982 /* 983 * update_kernel_registration - update the in-kernel registration for the 984 * given channel. 985 */ 986 static int 987 update_kernel_registration(sysevent_handle_t *shp, int update_type, 988 int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data) 989 { 990 int error; 991 char *channel_name = SH_CHANNEL_NAME(shp); 992 se_pubsub_t udata; 993 994 udata.ps_channel_name_len = strlen(channel_name) + 1; 995 udata.ps_op = update_op; 996 udata.ps_type = update_type; 997 udata.ps_buflen = datasz; 998 udata.ps_id = *sub_id; 999 1000 if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1001 (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0)) 1002 != 0) { 1003 return (error); 1004 } 1005 1006 *sub_id = udata.ps_id; 1007 1008 return (error); 1009 } 1010 1011 /* 1012 * get_kernel_registration - get the current subscriber registration for 1013 * the given channel 1014 */ 1015 static nvlist_t * 1016 get_kernel_registration(char *channel_name, uint32_t class_id) 1017 { 1018 char *nvlbuf; 1019 nvlist_t *nvl; 1020 se_pubsub_t udata; 1021 1022 nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ); 1023 if (nvlbuf == NULL) { 1024 return (NULL); 1025 } 1026 1027 udata.ps_buflen = MAX_SUBSCRIPTION_SZ; 1028 udata.ps_channel_name_len = strlen(channel_name) + 1; 1029 udata.ps_id = class_id; 1030 udata.ps_op = SE_GET_REGISTRATION; 1031 udata.ps_type = PUBLISHER; 1032 1033 if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1034 (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0) 1035 != 0) { 1036 1037 /* Need a bigger buffer to hold channel registration */ 1038 if (errno == EAGAIN) { 1039 free(nvlbuf); 1040 nvlbuf = calloc(1, udata.ps_buflen); 1041 if (nvlbuf == NULL) 1042 return (NULL); 1043 1044 /* Try again */ 1045 if (modctl(MODEVENTS, 1046 (uintptr_t)MODEVENTS_REGISTER_EVENT, 1047 (uintptr_t)channel_name, (uintptr_t)nvlbuf, 1048 (uintptr_t)&udata, 0) != 0) { 1049 free(nvlbuf); 1050 return (NULL); 1051 } 1052 } else { 1053 free(nvlbuf); 1054 return (NULL); 1055 } 1056 } 1057 1058 if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) { 1059 free(nvlbuf); 1060 return (NULL); 1061 } 1062 free(nvlbuf); 1063 1064 return (nvl); 1065 } 1066 1067 /* 1068 * The following routines provide a mechanism for publishers to maintain 1069 * subscriber information. 1070 */ 1071 1072 static void 1073 dealloc_subscribers(sysevent_handle_t *shp) 1074 { 1075 int i; 1076 subscriber_data_t *sub; 1077 1078 for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1079 sub = SH_SUBSCRIBER(shp, i); 1080 if (sub != NULL) { 1081 free(sub->sd_door_name); 1082 free(sub); 1083 } 1084 SH_SUBSCRIBER(shp, i) = NULL; 1085 } 1086 } 1087 1088 /*ARGSUSED*/ 1089 static int 1090 alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag) 1091 { 1092 subscriber_data_t *sub; 1093 char door_name[MAXPATHLEN]; 1094 1095 if (SH_SUBSCRIBER(shp, sub_id) != NULL) { 1096 return (0); 1097 } 1098 1099 /* Allocate and initialize the subscriber data */ 1100 sub = (subscriber_data_t *)calloc(1, 1101 sizeof (subscriber_data_t)); 1102 if (sub == NULL) { 1103 return (-1); 1104 } 1105 if (snprintf(door_name, MAXPATHLEN, "%s/%d", 1106 SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) { 1107 free(sub); 1108 return (-1); 1109 } 1110 1111 sub->sd_flag = ACTIVE; 1112 sub->sd_door_name = strdup(door_name); 1113 if (sub->sd_door_name == NULL) { 1114 free(sub); 1115 return (-1); 1116 } 1117 1118 SH_SUBSCRIBER(shp, sub_id) = sub; 1119 return (0); 1120 1121 } 1122 1123 /* 1124 * The following routines are used to update and maintain the registration cache 1125 * for a particular sysevent channel. 1126 */ 1127 1128 static uint32_t 1129 hash_func(const char *s) 1130 { 1131 uint32_t result = 0; 1132 uint_t g; 1133 1134 while (*s != '\0') { 1135 result <<= 4; 1136 result += (uint32_t)*s++; 1137 g = result & 0xf0000000; 1138 if (g != 0) { 1139 result ^= g >> 24; 1140 result ^= g; 1141 } 1142 } 1143 1144 return (result); 1145 } 1146 1147 subclass_lst_t * 1148 cache_find_subclass(class_lst_t *c_list, char *subclass) 1149 { 1150 subclass_lst_t *sc_list; 1151 1152 if (c_list == NULL) 1153 return (NULL); 1154 1155 sc_list = c_list->cl_subclass_list; 1156 1157 while (sc_list != NULL) { 1158 if (strcmp(sc_list->sl_name, subclass) == 0) { 1159 return (sc_list); 1160 } 1161 sc_list = sc_list->sl_next; 1162 } 1163 1164 return (NULL); 1165 } 1166 1167 1168 static class_lst_t * 1169 cache_find_class(sysevent_handle_t *shp, char *class) 1170 { 1171 int index; 1172 class_lst_t *c_list; 1173 class_lst_t **class_hash = SH_CLASS_HASH(shp); 1174 1175 if (strcmp(class, EC_ALL) == 0) { 1176 return (class_hash[0]); 1177 } 1178 1179 index = CLASS_HASH(class); 1180 c_list = class_hash[index]; 1181 while (c_list != NULL) { 1182 if (strcmp(class, c_list->cl_name) == 0) { 1183 break; 1184 } 1185 c_list = c_list->cl_next; 1186 } 1187 1188 return (c_list); 1189 } 1190 1191 static int 1192 cache_insert_subclass(class_lst_t *c_list, char **subclass_names, 1193 int subclass_num, uint32_t sub_id) 1194 { 1195 int i; 1196 subclass_lst_t *sc_list; 1197 1198 for (i = 0; i < subclass_num; ++i) { 1199 if ((sc_list = cache_find_subclass(c_list, subclass_names[i])) 1200 != NULL) { 1201 sc_list->sl_num[sub_id] = 1; 1202 } else { 1203 sc_list = (subclass_lst_t *)calloc(1, 1204 sizeof (subclass_lst_t)); 1205 if (sc_list == NULL) 1206 return (-1); 1207 1208 sc_list->sl_name = strdup(subclass_names[i]); 1209 if (sc_list->sl_name == NULL) { 1210 free(sc_list); 1211 return (-1); 1212 } 1213 1214 sc_list->sl_num[sub_id] = 1; 1215 sc_list->sl_next = c_list->cl_subclass_list; 1216 c_list->cl_subclass_list = sc_list; 1217 } 1218 } 1219 1220 return (0); 1221 } 1222 1223 static int 1224 cache_insert_class(sysevent_handle_t *shp, char *class, 1225 char **subclass_names, int subclass_num, uint32_t sub_id) 1226 { 1227 class_lst_t *c_list; 1228 1229 if (strcmp(class, EC_ALL) == 0) { 1230 char *subclass_all = EC_SUB_ALL; 1231 1232 (void) cache_insert_subclass(SH_CLASS_HASH(shp)[0], 1233 (char **)&subclass_all, 1, sub_id); 1234 return (0); 1235 } 1236 1237 /* New class, add to the registration cache */ 1238 if ((c_list = cache_find_class(shp, class)) == NULL) { 1239 1240 c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t)); 1241 if (c_list == NULL) { 1242 return (1); 1243 } 1244 c_list->cl_name = strdup(class); 1245 if (c_list->cl_name == NULL) { 1246 free(c_list); 1247 return (1); 1248 } 1249 1250 c_list->cl_subclass_list = (subclass_lst_t *) 1251 calloc(1, sizeof (subclass_lst_t)); 1252 if (c_list->cl_subclass_list == NULL) { 1253 free(c_list->cl_name); 1254 free(c_list); 1255 return (1); 1256 } 1257 c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL); 1258 if (c_list->cl_subclass_list->sl_name == NULL) { 1259 free(c_list->cl_subclass_list); 1260 free(c_list->cl_name); 1261 free(c_list); 1262 return (1); 1263 } 1264 c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)]; 1265 SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list; 1266 1267 } 1268 1269 /* Update the subclass list */ 1270 if (cache_insert_subclass(c_list, subclass_names, subclass_num, 1271 sub_id) != 0) 1272 return (1); 1273 1274 return (0); 1275 } 1276 1277 static void 1278 cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id) 1279 { 1280 int i; 1281 class_lst_t *c_list; 1282 subclass_lst_t *sc_list; 1283 1284 for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1285 c_list = SH_CLASS_HASH(shp)[i]; 1286 while (c_list != NULL) { 1287 sc_list = c_list->cl_subclass_list; 1288 while (sc_list != NULL) { 1289 sc_list->sl_num[sub_id] = 0; 1290 sc_list = sc_list->sl_next; 1291 } 1292 c_list = c_list->cl_next; 1293 } 1294 } 1295 } 1296 1297 static void 1298 cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id) 1299 { 1300 class_lst_t *c_list; 1301 subclass_lst_t *sc_list; 1302 1303 if (strcmp(class, EC_ALL) == 0) { 1304 cache_remove_all_class(shp, sub_id); 1305 return; 1306 } 1307 1308 if ((c_list = cache_find_class(shp, class)) == NULL) { 1309 return; 1310 } 1311 1312 sc_list = c_list->cl_subclass_list; 1313 while (sc_list != NULL) { 1314 sc_list->sl_num[sub_id] = 0; 1315 sc_list = sc_list->sl_next; 1316 } 1317 } 1318 1319 static void 1320 free_cached_registration(sysevent_handle_t *shp) 1321 { 1322 int i; 1323 class_lst_t *clist, *next_clist; 1324 subclass_lst_t *sc_list, *next_sc; 1325 1326 for (i = 0; i < CLASS_HASH_SZ + 1; i++) { 1327 clist = SH_CLASS_HASH(shp)[i]; 1328 while (clist != NULL) { 1329 sc_list = clist->cl_subclass_list; 1330 while (sc_list != NULL) { 1331 free(sc_list->sl_name); 1332 next_sc = sc_list->sl_next; 1333 free(sc_list); 1334 sc_list = next_sc; 1335 } 1336 free(clist->cl_name); 1337 next_clist = clist->cl_next; 1338 free(clist); 1339 clist = next_clist; 1340 } 1341 SH_CLASS_HASH(shp)[i] = NULL; 1342 } 1343 } 1344 1345 static int 1346 create_cached_registration(sysevent_handle_t *shp, 1347 class_lst_t **class_hash) 1348 { 1349 int i, j, new_class; 1350 char *class_name; 1351 uint_t num_elem; 1352 uchar_t *subscribers; 1353 nvlist_t *nvl; 1354 nvpair_t *nvpair; 1355 class_lst_t *clist; 1356 subclass_lst_t *sc_list; 1357 1358 for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1359 1360 if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i)) 1361 == NULL) { 1362 if (errno == ENOENT) { 1363 class_hash[i] = NULL; 1364 continue; 1365 } else { 1366 goto create_failed; 1367 } 1368 } 1369 1370 1371 nvpair = NULL; 1372 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1373 goto create_failed; 1374 } 1375 1376 new_class = 1; 1377 while (new_class) { 1378 /* Extract the class name from the nvpair */ 1379 if (nvpair_value_string(nvpair, &class_name) != 0) { 1380 goto create_failed; 1381 } 1382 clist = (class_lst_t *) 1383 calloc(1, sizeof (class_lst_t)); 1384 if (clist == NULL) { 1385 goto create_failed; 1386 } 1387 1388 clist->cl_name = strdup(class_name); 1389 if (clist->cl_name == NULL) { 1390 free(clist); 1391 goto create_failed; 1392 } 1393 1394 /* 1395 * Extract the subclass name and registration 1396 * from the nvpair 1397 */ 1398 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1399 == NULL) { 1400 free(clist->cl_name); 1401 free(clist); 1402 goto create_failed; 1403 } 1404 1405 clist->cl_next = class_hash[i]; 1406 class_hash[i] = clist; 1407 1408 for (;;) { 1409 1410 sc_list = (subclass_lst_t *)calloc(1, 1411 sizeof (subclass_lst_t)); 1412 if (sc_list == NULL) { 1413 goto create_failed; 1414 } 1415 1416 sc_list->sl_next = clist->cl_subclass_list; 1417 clist->cl_subclass_list = sc_list; 1418 1419 sc_list->sl_name = strdup(nvpair_name(nvpair)); 1420 if (sc_list->sl_name == NULL) { 1421 goto create_failed; 1422 } 1423 1424 if (nvpair_value_byte_array(nvpair, 1425 &subscribers, &num_elem) != 0) { 1426 goto create_failed; 1427 } 1428 bcopy(subscribers, (uchar_t *)sc_list->sl_num, 1429 MAX_SUBSCRIBERS + 1); 1430 1431 for (j = 1; j <= MAX_SUBSCRIBERS; ++j) { 1432 if (sc_list->sl_num[j] == 0) 1433 continue; 1434 1435 if (alloc_subscriber(shp, j, 1) != 0) { 1436 goto create_failed; 1437 } 1438 } 1439 1440 /* 1441 * Check next nvpair - either subclass or 1442 * class 1443 */ 1444 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1445 == NULL) { 1446 new_class = 0; 1447 break; 1448 } else if (strcmp(nvpair_name(nvpair), 1449 CLASS_NAME) == 0) { 1450 break; 1451 } 1452 } 1453 } 1454 nvlist_free(nvl); 1455 } 1456 return (0); 1457 1458 create_failed: 1459 dealloc_subscribers(shp); 1460 free_cached_registration(shp); 1461 if (nvl) 1462 nvlist_free(nvl); 1463 return (-1); 1464 1465 } 1466 1467 /* 1468 * cache_update_service - generic event publisher service routine. This routine 1469 * is called in response to a registration cache update. 1470 * 1471 */ 1472 /*ARGSUSED*/ 1473 static void 1474 cache_update_service(void *cookie, char *args, size_t alen, 1475 door_desc_t *ddp, uint_t ndid) 1476 { 1477 int ret = 0; 1478 uint_t num_elem; 1479 char *class, **event_list; 1480 size_t datalen; 1481 uint32_t sub_id; 1482 nvlist_t *nvl; 1483 nvpair_t *nvpair = NULL; 1484 struct reg_args *rargs; 1485 sysevent_handle_t *shp; 1486 subscriber_data_t *sub; 1487 1488 if (alen < sizeof (struct reg_args) || cookie == NULL) { 1489 ret = EINVAL; 1490 goto return_from_door; 1491 } 1492 1493 /* LINTED: E_BAD_PTR_CAST_ALIGN */ 1494 rargs = (struct reg_args *)args; 1495 shp = (sysevent_handle_t *)cookie; 1496 1497 datalen = alen - sizeof (struct reg_args); 1498 sub_id = rargs->ra_sub_id; 1499 1500 (void) mutex_lock(SH_LOCK(shp)); 1501 1502 switch (rargs->ra_op) { 1503 case SE_UNREGISTER: 1504 class = (char *)&rargs->ra_buf_ptr; 1505 cache_remove_class(shp, (char *)class, 1506 sub_id); 1507 break; 1508 case SE_UNBIND_REGISTRATION: 1509 1510 sub = SH_SUBSCRIBER(shp, sub_id); 1511 if (sub == NULL) 1512 break; 1513 1514 free(sub->sd_door_name); 1515 free(sub); 1516 cache_remove_class(shp, EC_ALL, sub_id); 1517 SH_SUBSCRIBER(shp, sub_id) = NULL; 1518 1519 break; 1520 case SE_BIND_REGISTRATION: 1521 1522 /* New subscriber */ 1523 if (alloc_subscriber(shp, sub_id, 0) != 0) { 1524 ret = ENOMEM; 1525 break; 1526 } 1527 break; 1528 case SE_REGISTER: 1529 1530 if (SH_SUBSCRIBER(shp, sub_id) == NULL) { 1531 ret = EINVAL; 1532 break; 1533 } 1534 /* Get new registration data */ 1535 if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen, 1536 &nvl, 0) != 0) { 1537 ret = EFAULT; 1538 break; 1539 } 1540 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1541 nvlist_free(nvl); 1542 ret = EFAULT; 1543 break; 1544 } 1545 if (nvpair_value_string_array(nvpair, &event_list, &num_elem) 1546 != 0) { 1547 nvlist_free(nvl); 1548 ret = EFAULT; 1549 break; 1550 } 1551 class = nvpair_name(nvpair); 1552 1553 ret = cache_insert_class(shp, class, 1554 event_list, num_elem, sub_id); 1555 if (ret != 0) { 1556 cache_remove_class(shp, class, sub_id); 1557 nvlist_free(nvl); 1558 ret = EFAULT; 1559 break; 1560 } 1561 1562 nvlist_free(nvl); 1563 1564 break; 1565 case SE_CLEANUP: 1566 /* Cleanup stale subscribers */ 1567 sysevent_cleanup_subscribers(shp); 1568 break; 1569 default: 1570 ret = EINVAL; 1571 } 1572 1573 (void) mutex_unlock(SH_LOCK(shp)); 1574 1575 return_from_door: 1576 (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 1577 (void) door_return(NULL, 0, NULL, 0); 1578 } 1579 1580 /* 1581 * sysevent_send_event - 1582 * Send an event via the communication channel associated with the sysevent 1583 * handle. Event notifications are broadcast to all subscribers based upon 1584 * the event class and subclass. The handle must have been previously 1585 * allocated and bound by 1586 * sysevent_open_channel() and sysevent_bind_publisher() 1587 */ 1588 int 1589 sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev) 1590 { 1591 int i, error, sub_fd, result = 0; 1592 int deliver_error = 0; 1593 int subscribers_sent = 0; 1594 int want_resend, resend_cnt = 0; 1595 char *event_class, *event_subclass; 1596 uchar_t *all_class_subscribers, *all_subclass_subscribers; 1597 uchar_t *subclass_subscribers; 1598 subscriber_data_t *sub; 1599 subclass_lst_t *sc_lst; 1600 1601 /* Check for proper registration */ 1602 event_class = sysevent_get_class_name(ev); 1603 event_subclass = sysevent_get_subclass_name(ev); 1604 1605 (void) mutex_lock(SH_LOCK(shp)); 1606 1607 send_event: 1608 1609 want_resend = 0; 1610 if (!SH_BOUND(shp)) { 1611 (void) mutex_unlock(SH_LOCK(shp)); 1612 errno = EINVAL; 1613 return (-1); 1614 } 1615 1616 /* Find all subscribers for this event class/subclass */ 1617 sc_lst = cache_find_subclass( 1618 cache_find_class(shp, EC_ALL), EC_SUB_ALL); 1619 all_class_subscribers = sc_lst->sl_num; 1620 1621 sc_lst = cache_find_subclass( 1622 cache_find_class(shp, event_class), EC_SUB_ALL); 1623 if (sc_lst) 1624 all_subclass_subscribers = sc_lst->sl_num; 1625 else 1626 all_subclass_subscribers = NULL; 1627 1628 sc_lst = cache_find_subclass( 1629 cache_find_class(shp, event_class), event_subclass); 1630 if (sc_lst) 1631 subclass_subscribers = sc_lst->sl_num; 1632 else 1633 subclass_subscribers = NULL; 1634 1635 /* Send event buffer to all valid subscribers */ 1636 for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1637 if ((all_class_subscribers[i] | 1638 (all_subclass_subscribers && all_subclass_subscribers[i]) | 1639 (subclass_subscribers && subclass_subscribers[i])) == 0) 1640 continue; 1641 1642 sub = SH_SUBSCRIBER(shp, i); 1643 assert(sub != NULL); 1644 1645 /* Check for active subscriber */ 1646 if (!(sub->sd_flag & ACTIVE)) { 1647 dprint("sysevent_send_event: subscriber %d inactive\n", 1648 i); 1649 continue; 1650 } 1651 1652 /* Process only resend requests */ 1653 if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) { 1654 continue; 1655 } 1656 1657 if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) { 1658 dprint("sysevent_send_event: Failed to open " 1659 "%s: %s\n", sub->sd_door_name, strerror(errno)); 1660 continue; 1661 } 1662 result = 0; 1663 error = clnt_deliver_event(sub_fd, ev, 1664 sysevent_get_size(ev), &result, sizeof (result)); 1665 1666 (void) close(sub_fd); 1667 1668 /* Successful door call */ 1669 if (error == 0) { 1670 switch (result) { 1671 /* Subscriber requested EAGAIN */ 1672 case EAGAIN: 1673 if (resend_cnt > SE_MAX_RETRY_LIMIT) { 1674 deliver_error = 1; 1675 } else { 1676 want_resend = 1; 1677 dprint("sysevent_send_event: resend " 1678 "requested for %d\n", i); 1679 sub->sd_flag |= SEND_AGAIN; 1680 } 1681 break; 1682 /* Bad sysevent handle for subscriber */ 1683 case EBADF: 1684 case EINVAL: 1685 dprint("sysevent_send_event: Bad sysevent " 1686 "handle for %s", sub->sd_door_name); 1687 sub->sd_flag = 0; 1688 deliver_error = 1; 1689 break; 1690 /* Successful delivery */ 1691 default: 1692 sub->sd_flag &= ~SEND_AGAIN; 1693 ++subscribers_sent; 1694 } 1695 } else { 1696 dprint("sysevent_send_event: Failed door call " 1697 "to %s: %s: %d\n", sub->sd_door_name, 1698 strerror(errno), result); 1699 sub->sd_flag = 0; 1700 deliver_error = 1; 1701 } 1702 } 1703 1704 if (want_resend) { 1705 resend_cnt++; 1706 goto send_event; 1707 } 1708 1709 if (deliver_error) { 1710 sysevent_cleanup_subscribers(shp); 1711 (void) mutex_unlock(SH_LOCK(shp)); 1712 errno = EFAULT; 1713 return (-1); 1714 } 1715 1716 (void) mutex_unlock(SH_LOCK(shp)); 1717 1718 if (subscribers_sent == 0) { 1719 dprint("sysevent_send_event: No subscribers for %s:%s\n", 1720 event_class, event_subclass); 1721 errno = ENOENT; 1722 return (-1); 1723 } 1724 1725 return (0); 1726 } 1727 1728 /* 1729 * Common routine to establish an event channel through which an event 1730 * publisher or subscriber may post or receive events. 1731 */ 1732 static sysevent_handle_t * 1733 sysevent_open_channel_common(const char *channel_path) 1734 { 1735 uint32_t sub_id = 0; 1736 char *begin_path; 1737 struct stat chan_stat; 1738 sysevent_handle_t *shp; 1739 1740 1741 if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) { 1742 errno = EINVAL; 1743 return (NULL); 1744 } 1745 1746 if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) { 1747 if (errno != EEXIST) { 1748 errno = EACCES; 1749 return (NULL); 1750 } 1751 } 1752 1753 /* Check channel file permissions */ 1754 if (stat(channel_path, &chan_stat) != 0) { 1755 dprint("sysevent_open_channel: Invalid permissions for channel " 1756 "%s\n", channel_path); 1757 errno = EACCES; 1758 return (NULL); 1759 } else if (chan_stat.st_uid != getuid() || 1760 !S_ISDIR(chan_stat.st_mode)) { 1761 dprint("sysevent_open_channel: Invalid " 1762 "permissions for channel %s\n: %d:%d:%d", channel_path, 1763 (int)chan_stat.st_uid, (int)chan_stat.st_gid, 1764 (int)chan_stat.st_mode); 1765 1766 errno = EACCES; 1767 return (NULL); 1768 } 1769 1770 shp = calloc(1, sizeof (sysevent_impl_hdl_t)); 1771 if (shp == NULL) { 1772 errno = ENOMEM; 1773 return (NULL); 1774 } 1775 1776 SH_CHANNEL_NAME(shp) = NULL; 1777 SH_CHANNEL_PATH(shp) = strdup(channel_path); 1778 if (SH_CHANNEL_PATH(shp) == NULL) { 1779 free(shp); 1780 errno = ENOMEM; 1781 return (NULL); 1782 } 1783 1784 /* Extract the channel name */ 1785 begin_path = SH_CHANNEL_PATH(shp); 1786 while (*begin_path != '\0' && 1787 (begin_path = strpbrk(begin_path, "/")) != NULL) { 1788 ++begin_path; 1789 SH_CHANNEL_NAME(shp) = begin_path; 1790 } 1791 1792 if (update_kernel_registration(shp, 0, 1793 SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) { 1794 dprint("sysevent_open_channel: Failed for channel %s\n", 1795 SH_CHANNEL_NAME(shp)); 1796 free(SH_CHANNEL_PATH(shp)); 1797 free(shp); 1798 errno = EFAULT; 1799 return (NULL); 1800 } 1801 1802 (void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL); 1803 1804 return (shp); 1805 } 1806 1807 /* 1808 * Establish a sysevent channel for publication and subscription 1809 */ 1810 sysevent_handle_t * 1811 sysevent_open_channel(const char *channel) 1812 { 1813 int var_run_mounted = 0; 1814 char full_channel[MAXPATHLEN + 1]; 1815 FILE *fp; 1816 struct stat chan_stat; 1817 struct extmnttab m; 1818 1819 if (channel == NULL) { 1820 errno = EINVAL; 1821 return (NULL); 1822 } 1823 1824 /* 1825 * Check that /var/run is mounted as tmpfs before allowing a channel 1826 * to be opened. 1827 */ 1828 if ((fp = fopen(MNTTAB, "rF")) == NULL) { 1829 errno = EACCES; 1830 return (NULL); 1831 } 1832 1833 resetmnttab(fp); 1834 1835 while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) { 1836 if (strcmp(m.mnt_mountp, "/var/run") == 0 && 1837 strcmp(m.mnt_fstype, "tmpfs") == 0) { 1838 var_run_mounted = 1; 1839 break; 1840 } 1841 } 1842 (void) fclose(fp); 1843 1844 if (!var_run_mounted) { 1845 errno = EACCES; 1846 return (NULL); 1847 } 1848 1849 if (stat(CHAN_PATH, &chan_stat) < 0) { 1850 if (mkdir(CHAN_PATH, 1851 S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) { 1852 dprint("sysevent_open_channel: Unable " 1853 "to create channel directory %s:%s\n", CHAN_PATH, 1854 strerror(errno)); 1855 if (errno != EEXIST) { 1856 errno = EACCES; 1857 return (NULL); 1858 } 1859 } 1860 } 1861 1862 if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >= 1863 MAXPATHLEN) { 1864 errno = EINVAL; 1865 return (NULL); 1866 } 1867 1868 return (sysevent_open_channel_common(full_channel)); 1869 } 1870 1871 /* 1872 * Establish a sysevent channel for publication and subscription 1873 * Full path to the channel determined by the caller 1874 */ 1875 sysevent_handle_t * 1876 sysevent_open_channel_alt(const char *channel_path) 1877 { 1878 return (sysevent_open_channel_common(channel_path)); 1879 } 1880 1881 /* 1882 * sysevent_close_channel - Clean up resources associated with a previously 1883 * opened sysevent channel 1884 */ 1885 void 1886 sysevent_close_channel(sysevent_handle_t *shp) 1887 { 1888 int error = errno; 1889 uint32_t sub_id = 0; 1890 1891 if (shp == NULL) { 1892 return; 1893 } 1894 1895 (void) mutex_lock(SH_LOCK(shp)); 1896 if (SH_BOUND(shp)) { 1897 (void) mutex_unlock(SH_LOCK(shp)); 1898 if (SH_TYPE(shp) == PUBLISHER) 1899 sysevent_unbind_publisher(shp); 1900 else if (SH_TYPE(shp) == SUBSCRIBER) 1901 sysevent_unbind_subscriber(shp); 1902 (void) mutex_lock(SH_LOCK(shp)); 1903 } 1904 1905 (void) update_kernel_registration(shp, 0, 1906 SE_CLOSE_REGISTRATION, &sub_id, 0, NULL); 1907 (void) mutex_unlock(SH_LOCK(shp)); 1908 1909 free(SH_CHANNEL_PATH(shp)); 1910 free(shp); 1911 errno = error; 1912 } 1913 1914 /* 1915 * sysevent_bind_publisher - Bind an event publisher to an event channel 1916 */ 1917 int 1918 sysevent_bind_publisher(sysevent_handle_t *shp) 1919 { 1920 int error = 0; 1921 int fd = -1; 1922 char door_name[MAXPATHLEN]; 1923 uint32_t pub_id; 1924 struct stat reg_stat; 1925 publisher_priv_t *pub; 1926 1927 if (shp == NULL) { 1928 errno = EINVAL; 1929 return (-1); 1930 } 1931 1932 (void) mutex_lock(SH_LOCK(shp)); 1933 if (SH_BOUND(shp)) { 1934 (void) mutex_unlock(SH_LOCK(shp)); 1935 errno = EINVAL; 1936 return (-1); 1937 } 1938 1939 if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) == 1940 NULL) { 1941 (void) mutex_unlock(SH_LOCK(shp)); 1942 errno = ENOMEM; 1943 return (-1); 1944 } 1945 SH_PRIV_DATA(shp) = (void *)pub; 1946 1947 if (snprintf(door_name, MAXPATHLEN, "%s/%s", 1948 SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 1949 free(pub); 1950 (void) mutex_unlock(SH_LOCK(shp)); 1951 errno = ENOMEM; 1952 return (-1); 1953 } 1954 if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) { 1955 free(pub); 1956 (void) mutex_unlock(SH_LOCK(shp)); 1957 errno = ENOMEM; 1958 return (-1); 1959 } 1960 1961 /* Only one publisher allowed per channel */ 1962 if (stat(SH_DOOR_NAME(shp), ®_stat) != 0) { 1963 if (errno != ENOENT) { 1964 error = EINVAL; 1965 goto fail; 1966 } 1967 } 1968 1969 /* 1970 * Remove door file for robustness. 1971 */ 1972 if (unlink(SH_DOOR_NAME(shp)) != 0) 1973 dprint("sysevent_bind_publisher: Unlink of %s failed.\n", 1974 SH_DOOR_NAME(shp)); 1975 1976 /* Open channel registration door */ 1977 fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, 1978 S_IREAD|S_IWRITE); 1979 if (fd == -1) { 1980 error = EINVAL; 1981 goto fail; 1982 } 1983 1984 /* 1985 * Create the registration service for this publisher. 1986 */ 1987 if ((SH_DOOR_DESC(shp) = door_create(cache_update_service, 1988 (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 1989 dprint("sysevent_bind_publisher: door create failed: " 1990 "%s\n", strerror(errno)); 1991 error = EFAULT; 1992 goto fail; 1993 } 1994 1995 (void) fdetach(SH_DOOR_NAME(shp)); 1996 if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) { 1997 dprint("sysevent_bind_publisher: unable to " 1998 "bind event channel: fattach: %s\n", 1999 SH_DOOR_NAME(shp)); 2000 error = EACCES; 2001 goto fail; 2002 } 2003 2004 /* Bind this publisher in the kernel registration database */ 2005 if (update_kernel_registration(shp, PUBLISHER, 2006 SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) { 2007 error = errno; 2008 goto fail; 2009 } 2010 2011 SH_ID(shp) = pub_id; 2012 SH_BOUND(shp) = 1; 2013 SH_TYPE(shp) = PUBLISHER; 2014 2015 2016 /* Create the subscription registration cache */ 2017 if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) { 2018 (void) update_kernel_registration(shp, 2019 PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL); 2020 error = EFAULT; 2021 goto fail; 2022 } 2023 (void) close(fd); 2024 2025 (void) mutex_unlock(SH_LOCK(shp)); 2026 2027 return (0); 2028 2029 fail: 2030 SH_BOUND(shp) = 0; 2031 (void) door_revoke(SH_DOOR_DESC(shp)); 2032 (void) fdetach(SH_DOOR_NAME(shp)); 2033 free(SH_DOOR_NAME(shp)); 2034 free(pub); 2035 (void) close(fd); 2036 (void) mutex_unlock(SH_LOCK(shp)); 2037 errno = error; 2038 return (-1); 2039 } 2040 2041 /* 2042 * sysevent_bind_subscriber - Bind an event receiver to an event channel 2043 */ 2044 int 2045 sysevent_bind_subscriber(sysevent_handle_t *shp, 2046 void (*event_handler)(sysevent_t *ev)) 2047 { 2048 int fd = -1; 2049 int error = 0; 2050 uint32_t sub_id = 0; 2051 char door_name[MAXPATHLEN]; 2052 subscriber_priv_t *sub_info; 2053 2054 if (shp == NULL || event_handler == NULL) { 2055 errno = EINVAL; 2056 return (-1); 2057 } 2058 2059 (void) mutex_lock(SH_LOCK(shp)); 2060 if (SH_BOUND(shp)) { 2061 errno = EINVAL; 2062 (void) mutex_unlock(SH_LOCK(shp)); 2063 return (-1); 2064 } 2065 2066 if ((sub_info = (subscriber_priv_t *)calloc(1, 2067 sizeof (subscriber_priv_t))) == NULL) { 2068 errno = ENOMEM; 2069 (void) mutex_unlock(SH_LOCK(shp)); 2070 return (-1); 2071 } 2072 2073 if (snprintf(door_name, MAXPATHLEN, "%s/%s", 2074 SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 2075 free(sub_info); 2076 errno = EINVAL; 2077 (void) mutex_unlock(SH_LOCK(shp)); 2078 return (-1); 2079 } 2080 2081 if ((sub_info->sp_door_name = strdup(door_name)) == NULL) { 2082 free(sub_info); 2083 errno = ENOMEM; 2084 (void) mutex_unlock(SH_LOCK(shp)); 2085 return (-1); 2086 } 2087 (void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL); 2088 (void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL); 2089 sub_info->sp_func = event_handler; 2090 2091 /* Update the in-kernel registration */ 2092 if (update_kernel_registration(shp, SUBSCRIBER, 2093 SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) { 2094 error = errno; 2095 goto fail; 2096 } 2097 SH_ID(shp) = sub_id; 2098 2099 if (snprintf(door_name, MAXPATHLEN, "%s/%d", 2100 SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) { 2101 error = EINVAL; 2102 goto fail; 2103 } 2104 if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) { 2105 error = ENOMEM; 2106 goto fail; 2107 } 2108 2109 /* 2110 * Remove door file for robustness. 2111 */ 2112 if (unlink(SH_DOOR_NAME(shp)) != 0) 2113 dprint("sysevent_bind_subscriber: Unlink of %s failed.\n", 2114 SH_DOOR_NAME(shp)); 2115 2116 fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE); 2117 if (fd == -1) { 2118 error = EFAULT; 2119 goto fail; 2120 } 2121 2122 /* 2123 * Create the sysevent door service for this client. 2124 * syseventd will use this door service to propagate 2125 * events to the client. 2126 */ 2127 if ((SH_DOOR_DESC(shp) = door_create(event_deliver_service, 2128 (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) { 2129 dprint("sysevent_bind_subscriber: door create failed: " 2130 "%s\n", strerror(errno)); 2131 error = EFAULT; 2132 goto fail; 2133 } 2134 2135 (void) fdetach(SH_DOOR_NAME(shp)); 2136 if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) { 2137 error = EFAULT; 2138 goto fail; 2139 } 2140 (void) close(fd); 2141 2142 if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION, 2143 sub_id, 0, NULL) != 0) { 2144 error = errno; 2145 (void) update_kernel_registration(shp, SUBSCRIBER, 2146 SE_UNBIND_REGISTRATION, &sub_id, 0, NULL); 2147 goto fail; 2148 } 2149 2150 SH_BOUND(shp) = 1; 2151 SH_TYPE(shp) = SUBSCRIBER; 2152 SH_PRIV_DATA(shp) = (void *)sub_info; 2153 2154 2155 /* Create an event handler thread */ 2156 if (thr_create(NULL, NULL, (void *(*)(void *))subscriber_event_handler, 2157 shp, THR_BOUND, &sub_info->sp_handler_tid) != 0) { 2158 error = EFAULT; 2159 goto fail; 2160 } 2161 2162 (void) mutex_unlock(SH_LOCK(shp)); 2163 2164 return (0); 2165 2166 fail: 2167 (void) close(fd); 2168 (void) door_revoke(SH_DOOR_DESC(shp)); 2169 (void) fdetach(SH_DOOR_NAME(shp)); 2170 (void) cond_destroy(&sub_info->sp_cv); 2171 (void) mutex_destroy(&sub_info->sp_qlock); 2172 free(sub_info->sp_door_name); 2173 free(sub_info); 2174 if (SH_ID(shp)) { 2175 (void) update_kernel_registration(shp, SUBSCRIBER, 2176 SE_UNBIND_REGISTRATION, &sub_id, 0, NULL); 2177 SH_ID(shp) = 0; 2178 } 2179 if (SH_BOUND(shp)) { 2180 (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION, 2181 sub_id, 0, NULL); 2182 free(SH_DOOR_NAME(shp)); 2183 SH_BOUND(shp) = 0; 2184 } 2185 (void) mutex_unlock(SH_LOCK(shp)); 2186 2187 errno = error; 2188 2189 return (-1); 2190 } 2191 2192 /* 2193 * sysevent_register_event - register an event class and associated subclasses 2194 * for an event subscriber 2195 */ 2196 int 2197 sysevent_register_event(sysevent_handle_t *shp, 2198 const char *ev_class, const char **ev_subclass, 2199 int subclass_num) 2200 { 2201 int error; 2202 char *event_class = (char *)ev_class; 2203 char **event_subclass_list = (char **)ev_subclass; 2204 char *nvlbuf = NULL; 2205 size_t datalen; 2206 nvlist_t *nvl; 2207 2208 (void) mutex_lock(SH_LOCK(shp)); 2209 if (event_class == NULL || event_subclass_list == NULL || 2210 event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 || 2211 subclass_num <= 0) { 2212 (void) mutex_unlock(SH_LOCK(shp)); 2213 errno = EINVAL; 2214 return (-1); 2215 } 2216 2217 if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) { 2218 (void) mutex_unlock(SH_LOCK(shp)); 2219 return (-1); 2220 } 2221 if (nvlist_add_string_array(nvl, event_class, event_subclass_list, 2222 subclass_num) != 0) { 2223 nvlist_free(nvl); 2224 (void) mutex_unlock(SH_LOCK(shp)); 2225 return (-1); 2226 } 2227 if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) { 2228 nvlist_free(nvl); 2229 (void) mutex_unlock(SH_LOCK(shp)); 2230 return (-1); 2231 } 2232 nvlist_free(nvl); 2233 2234 /* Store new subscriber in in-kernel registration */ 2235 if (update_kernel_registration(shp, SUBSCRIBER, 2236 SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf) 2237 != 0) { 2238 error = errno; 2239 free(nvlbuf); 2240 (void) mutex_unlock(SH_LOCK(shp)); 2241 errno = error; 2242 return (-1); 2243 } 2244 /* Update the publisher's cached registration */ 2245 if (update_publisher_cache( 2246 (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER, 2247 SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) { 2248 error = errno; 2249 free(nvlbuf); 2250 (void) mutex_unlock(SH_LOCK(shp)); 2251 errno = error; 2252 return (-1); 2253 } 2254 2255 free(nvlbuf); 2256 2257 (void) mutex_unlock(SH_LOCK(shp)); 2258 2259 return (0); 2260 } 2261 2262 /* 2263 * sysevent_unregister_event - Unregister an event class and associated 2264 * subclasses for an event subscriber 2265 */ 2266 void 2267 sysevent_unregister_event(sysevent_handle_t *shp, const char *class) 2268 { 2269 size_t class_sz; 2270 2271 (void) mutex_lock(SH_LOCK(shp)); 2272 2273 if (!SH_BOUND(shp)) { 2274 (void) mutex_unlock(SH_LOCK(shp)); 2275 return; 2276 } 2277 2278 /* Remove subscriber from in-kernel registration */ 2279 class_sz = strlen(class) + 1; 2280 (void) update_kernel_registration(shp, SUBSCRIBER, 2281 SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class); 2282 /* Update the publisher's cached registration */ 2283 (void) update_publisher_cache( 2284 (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER, 2285 SH_ID(shp), class_sz, (uchar_t *)class); 2286 2287 (void) mutex_unlock(SH_LOCK(shp)); 2288 } 2289 2290 static int 2291 cleanup_id(sysevent_handle_t *shp, uint32_t id, int type) 2292 { 2293 dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id); 2294 2295 /* Remove registration from the kernel */ 2296 if (update_kernel_registration(shp, type, SE_CLEANUP, &id, 2297 0, NULL) != 0) { 2298 dprint("cleanup_id: Unable to clean " 2299 "up %s/%d\n", SH_CHANNEL_NAME(shp), id); 2300 return (-1); 2301 } 2302 2303 return (0); 2304 } 2305 2306 /* 2307 * sysevent_cleanup_subscribers: Allows the caller to cleanup resources 2308 * allocated to unresponsive subscribers. 2309 */ 2310 void 2311 sysevent_cleanup_subscribers(sysevent_handle_t *shp) 2312 { 2313 uint32_t ping, result; 2314 int i, error, sub_fd; 2315 subscriber_data_t *sub; 2316 2317 if (!SH_BOUND(shp)) { 2318 return; 2319 } 2320 2321 for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 2322 2323 sub = SH_SUBSCRIBER(shp, i); 2324 if (sub == NULL) { 2325 continue; 2326 } 2327 2328 if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) { 2329 continue; 2330 } 2331 /* Check for valid and responsive subscriber */ 2332 error = clnt_deliver_event(sub_fd, &ping, 2333 sizeof (uint32_t), &result, sizeof (result)); 2334 (void) close(sub_fd); 2335 2336 /* Only cleanup on EBADF (Invalid door descriptor) */ 2337 if (error != EBADF) 2338 continue; 2339 2340 if (cleanup_id(shp, i, SUBSCRIBER) != 0) 2341 continue; 2342 2343 cache_remove_class(shp, EC_ALL, i); 2344 2345 free(sub->sd_door_name); 2346 free(sub); 2347 SH_SUBSCRIBER(shp, i) = NULL; 2348 } 2349 2350 } 2351 2352 /* 2353 * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated 2354 * as needed. 2355 */ 2356 void 2357 sysevent_cleanup_publishers(sysevent_handle_t *shp) 2358 { 2359 (void) cleanup_id(shp, 1, PUBLISHER); 2360 } 2361 2362 /* 2363 * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel. 2364 */ 2365 void 2366 sysevent_unbind_subscriber(sysevent_handle_t *shp) 2367 { 2368 subscriber_priv_t *sub_info; 2369 2370 if (shp == NULL) 2371 return; 2372 2373 (void) mutex_lock(SH_LOCK(shp)); 2374 if (SH_BOUND(shp) == 0) { 2375 (void) mutex_unlock(SH_LOCK(shp)); 2376 return; 2377 } 2378 2379 /* Update the in-kernel registration */ 2380 (void) update_kernel_registration(shp, SUBSCRIBER, 2381 SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL); 2382 2383 /* Update the sysevent channel publisher */ 2384 sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 2385 (void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION, 2386 SH_ID(shp), 0, NULL); 2387 2388 /* Close down event delivery facilities */ 2389 (void) door_revoke(SH_DOOR_DESC(shp)); 2390 (void) fdetach(SH_DOOR_NAME(shp)); 2391 2392 2393 /* 2394 * Release resources and wait for pending event delivery to 2395 * complete. 2396 */ 2397 (void) mutex_lock(&sub_info->sp_qlock); 2398 SH_BOUND(shp) = 0; 2399 /* Signal event handler and drain the subscriber's event queue */ 2400 (void) cond_signal(&sub_info->sp_cv); 2401 (void) mutex_unlock(&sub_info->sp_qlock); 2402 (void) thr_join(sub_info->sp_handler_tid, NULL, NULL); 2403 2404 (void) cond_destroy(&sub_info->sp_cv); 2405 (void) mutex_destroy(&sub_info->sp_qlock); 2406 free(sub_info->sp_door_name); 2407 free(sub_info); 2408 free(SH_DOOR_NAME(shp)); 2409 (void) mutex_unlock(SH_LOCK(shp)); 2410 } 2411 2412 /* 2413 * sysevent_unbind_publisher: Unbind publisher from the sysevent channel. 2414 */ 2415 void 2416 sysevent_unbind_publisher(sysevent_handle_t *shp) 2417 { 2418 if (shp == NULL) 2419 return; 2420 2421 (void) mutex_lock(SH_LOCK(shp)); 2422 if (SH_BOUND(shp) == 0) { 2423 (void) mutex_unlock(SH_LOCK(shp)); 2424 return; 2425 } 2426 2427 /* Close down the registration facilities */ 2428 (void) door_revoke(SH_DOOR_DESC(shp)); 2429 (void) fdetach(SH_DOOR_NAME(shp)); 2430 2431 /* Update the in-kernel registration */ 2432 (void) update_kernel_registration(shp, PUBLISHER, 2433 SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL); 2434 SH_BOUND(shp) = 0; 2435 2436 /* Free resources associated with bind */ 2437 free_cached_registration(shp); 2438 dealloc_subscribers(shp); 2439 2440 free(SH_PRIV_DATA(shp)); 2441 free(SH_DOOR_NAME(shp)); 2442 SH_ID(shp) = 0; 2443 (void) mutex_unlock(SH_LOCK(shp)); 2444 } 2445 2446 /* 2447 * Evolving APIs to subscribe to syseventd(1M) system events. 2448 */ 2449 2450 /* 2451 * sysevent_bind_handle - Bind application event handler for syseventd 2452 * subscription. 2453 */ 2454 sysevent_handle_t * 2455 sysevent_bind_handle(void (*event_handler)(sysevent_t *ev)) 2456 { 2457 sysevent_handle_t *shp; 2458 2459 if (getuid() != 0) { 2460 errno = EACCES; 2461 return (NULL); 2462 } 2463 2464 if (event_handler == NULL) { 2465 errno = EINVAL; 2466 return (NULL); 2467 } 2468 2469 if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) { 2470 return (NULL); 2471 } 2472 2473 if (sysevent_bind_subscriber(shp, event_handler) != 0) { 2474 2475 /* 2476 * Ask syseventd to clean-up any stale subcribers and try to 2477 * to bind again 2478 */ 2479 if (errno == EBUSY) { 2480 int pub_fd; 2481 char door_name[MAXPATHLEN]; 2482 uint32_t result; 2483 struct reg_args rargs; 2484 2485 if (snprintf(door_name, MAXPATHLEN, "%s/%s", 2486 SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) { 2487 sysevent_close_channel(shp); 2488 errno = EINVAL; 2489 return (NULL); 2490 } 2491 2492 rargs.ra_op = SE_CLEANUP; 2493 pub_fd = open(door_name, O_RDONLY); 2494 (void) clnt_deliver_event(pub_fd, (void *)&rargs, 2495 sizeof (struct reg_args), &result, sizeof (result)); 2496 (void) close(pub_fd); 2497 2498 /* Try to bind again */ 2499 if (sysevent_bind_subscriber(shp, event_handler) != 0) { 2500 sysevent_close_channel(shp); 2501 return (NULL); 2502 } 2503 } else { 2504 sysevent_close_channel(shp); 2505 return (NULL); 2506 } 2507 } 2508 2509 return (shp); 2510 } 2511 2512 /* 2513 * sysevent_unbind_handle - Unbind caller from syseventd subscriptions 2514 */ 2515 void 2516 sysevent_unbind_handle(sysevent_handle_t *shp) 2517 { 2518 sysevent_unbind_subscriber(shp); 2519 sysevent_close_channel(shp); 2520 } 2521 2522 /* 2523 * sysevent_subscribe_event - Subscribe to system event notification from 2524 * syseventd(1M) for the class and subclasses specified. 2525 */ 2526 int 2527 sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class, 2528 const char **event_subclass_list, int num_subclasses) 2529 { 2530 return (sysevent_register_event(shp, event_class, 2531 event_subclass_list, num_subclasses)); 2532 } 2533 2534 void 2535 sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class) 2536 { 2537 sysevent_unregister_event(shp, event_class); 2538 } 2539