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 2006 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <fcntl.h> 31 #include <errno.h> 32 #include <door.h> 33 #include <unistd.h> 34 #include <stddef.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <strings.h> 38 #include <synch.h> 39 #include <pthread.h> 40 #include <thread.h> 41 #include <libnvpair.h> 42 #include <assert.h> 43 #include <sys/stat.h> 44 #include <sys/types.h> 45 #include <sys/modctl.h> 46 #include <sys/mnttab.h> 47 #include <sys/sysevent.h> 48 #include <sys/sysevent_impl.h> 49 50 #include "libsysevent.h" 51 #include "libsysevent_impl.h" 52 53 /* 54 * libsysevent - The system event framework library 55 * 56 * This library provides routines to help with marshalling 57 * and unmarshalling of data contained in a sysevent event 58 * buffer. 59 */ 60 61 #define SE_ENCODE_METHOD NV_ENCODE_NATIVE 62 63 #define dprint if (libsysevent_debug) (void) printf 64 static int libsysevent_debug = 0; 65 66 static sysevent_t *se_unpack(sysevent_t *); 67 static int cleanup_id(sysevent_handle_t *shp, uint32_t id, int type); 68 69 /* 70 * The following routines allow system event publication to the sysevent 71 * framework. 72 */ 73 74 /* 75 * sysevent_alloc - allocate a sysevent buffer 76 */ 77 static sysevent_t * 78 sysevent_alloc(char *class, int class_sz, char *subclass, int subclass_sz, 79 char *pub, int pub_sz, nvlist_t *attr_list) 80 { 81 int payload_sz; 82 int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz; 83 size_t nvlist_sz = 0; 84 char *attr; 85 uint64_t attr_offset; 86 sysevent_t *ev; 87 88 if (attr_list != NULL) { 89 if (nvlist_size(attr_list, &nvlist_sz, SE_ENCODE_METHOD) 90 != 0) { 91 return (NULL); 92 } 93 } 94 95 /* 96 * Calculate and reserve space for the class, subclass and 97 * publisher strings in the event buffer 98 */ 99 100 /* String sizes must be 64-bit aligned in the event buffer */ 101 aligned_class_sz = SE_ALIGN(class_sz); 102 aligned_subclass_sz = SE_ALIGN(subclass_sz); 103 aligned_pub_sz = SE_ALIGN(pub_sz); 104 105 payload_sz = (aligned_class_sz - sizeof (uint64_t)) + 106 (aligned_subclass_sz - sizeof (uint64_t)) + 107 (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t) + 108 nvlist_sz; 109 110 /* 111 * Allocate event buffer plus additional payload overhead. 112 */ 113 ev = calloc(1, sizeof (sysevent_impl_t) + payload_sz); 114 if (ev == NULL) { 115 return (NULL); 116 } 117 118 /* Initialize the event buffer data */ 119 SE_VERSION(ev) = SYS_EVENT_VERSION; 120 (void) bcopy(class, SE_CLASS_NAME(ev), class_sz); 121 122 SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name)) 123 + aligned_class_sz; 124 (void) bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz); 125 126 SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz; 127 (void) bcopy(pub, SE_PUB_NAME(ev), pub_sz); 128 129 SE_PAYLOAD_SZ(ev) = payload_sz; 130 SE_ATTR_PTR(ev) = (uint64_t)0; 131 132 /* Check for attribute list */ 133 if (attr_list == NULL) { 134 return (ev); 135 } 136 137 /* Copy attribute data to contiguous memory */ 138 SE_FLAG(ev) = SE_PACKED_BUF; 139 attr_offset = SE_ATTR_OFF(ev); 140 attr = (char *)((caddr_t)ev + attr_offset); 141 if (nvlist_pack(attr_list, &attr, &nvlist_sz, SE_ENCODE_METHOD, 142 0) != 0) { 143 free(ev); 144 return (NULL); 145 } 146 147 return (ev); 148 } 149 150 /* 151 * sysevent_post_event - generate a system event via the sysevent framework 152 */ 153 int 154 sysevent_post_event(char *class, char *subclass, char *vendor, char *pub_name, 155 nvlist_t *attr_list, sysevent_id_t *eid) 156 { 157 int error; 158 sysevent_t *ev; 159 160 ev = sysevent_alloc_event(class, subclass, vendor, pub_name, attr_list); 161 if (ev == NULL) { 162 return (-1); 163 } 164 165 error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_POST_EVENT, 166 (uintptr_t)ev, (uintptr_t)SE_SIZE(ev), 167 (uintptr_t)eid, 0); 168 169 sysevent_free(ev); 170 171 if (error) { 172 errno = EIO; 173 return (-1); 174 } 175 176 return (0); 177 } 178 179 /* 180 * The following routines are used to free or duplicate a 181 * sysevent event buffer. 182 */ 183 184 /* 185 * sysevent_dup - Allocate and copy an event buffer 186 * Copies both packed and unpacked to unpacked sysevent. 187 */ 188 sysevent_t * 189 sysevent_dup(sysevent_t *ev) 190 { 191 nvlist_t *nvl, *cnvl = NULL; 192 uint64_t attr_offset; 193 sysevent_t *copy; 194 195 if (SE_FLAG(ev) == SE_PACKED_BUF) 196 return (se_unpack(ev)); 197 198 /* Copy event header information */ 199 attr_offset = SE_ATTR_OFF(ev); 200 copy = calloc(1, attr_offset); 201 if (copy == NULL) 202 return (NULL); 203 bcopy(ev, copy, attr_offset); 204 205 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 206 if (nvl && nvlist_dup(nvl, &cnvl, 0) != 0) { 207 free(copy); 208 return (NULL); 209 } 210 211 SE_ATTR_PTR(copy) = (uintptr_t)cnvl; 212 SE_FLAG(copy) = 0; /* unpacked */ 213 return (copy); 214 } 215 216 /* 217 * sysevent_free - Free memory allocated for an event buffer 218 */ 219 void 220 sysevent_free(sysevent_t *ev) 221 { 222 nvlist_t *attr_list = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 223 224 if (attr_list) 225 nvlist_free(attr_list); 226 free(ev); 227 } 228 229 /* 230 * The following routines are used to extract attribute data from a sysevent 231 * handle. 232 */ 233 234 /* 235 * sysevent_get_attr_list - allocate and return an attribute associated with 236 * the given sysevent buffer. 237 */ 238 int 239 sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist) 240 { 241 int error; 242 caddr_t attr; 243 size_t attr_len; 244 uint64_t attr_offset; 245 nvlist_t *nvl; 246 247 *nvlist = NULL; 248 249 /* Duplicate attribute for an unpacked sysevent buffer */ 250 if (SE_FLAG(ev) != SE_PACKED_BUF) { 251 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 252 if (nvl == NULL) { 253 return (0); 254 } 255 if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) { 256 if (error == ENOMEM) { 257 errno = error; 258 } else { 259 errno = EINVAL; 260 } 261 return (-1); 262 } 263 return (0); 264 } 265 266 attr_offset = SE_ATTR_OFF(ev); 267 if (SE_SIZE(ev) == attr_offset) { 268 return (0); 269 } 270 271 /* unpack nvlist */ 272 attr = (caddr_t)ev + attr_offset; 273 attr_len = SE_SIZE(ev) - attr_offset; 274 if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) { 275 if (error == ENOMEM) { 276 errno = error; 277 } else { 278 errno = EINVAL; 279 } 280 return (-1); 281 } 282 283 return (0); 284 } 285 286 /* 287 * sysevent_attr_name - Get name of attribute 288 */ 289 char * 290 sysevent_attr_name(sysevent_attr_t *attr) 291 { 292 if (attr == NULL) { 293 errno = EINVAL; 294 return (NULL); 295 } 296 return (nvpair_name((nvpair_t *)attr)); 297 } 298 299 /* 300 * sysevent_attr_value - Get attribute value data and type 301 */ 302 int 303 sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value) 304 { 305 nvpair_t *nvp = attr; 306 307 if (nvp == NULL) 308 return (EINVAL); 309 310 /* Convert DATA_TYPE_* to SE_DATA_TYPE_* */ 311 switch (nvpair_type(nvp)) { 312 case DATA_TYPE_BYTE: 313 se_value->value_type = SE_DATA_TYPE_BYTE; 314 (void) nvpair_value_byte(nvp, &se_value->value.sv_byte); 315 break; 316 case DATA_TYPE_INT16: 317 se_value->value_type = SE_DATA_TYPE_INT16; 318 (void) nvpair_value_int16(nvp, &se_value->value.sv_int16); 319 break; 320 case DATA_TYPE_UINT16: 321 se_value->value_type = SE_DATA_TYPE_UINT16; 322 (void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16); 323 break; 324 case DATA_TYPE_INT32: 325 se_value->value_type = SE_DATA_TYPE_INT32; 326 (void) nvpair_value_int32(nvp, &se_value->value.sv_int32); 327 break; 328 case DATA_TYPE_UINT32: 329 se_value->value_type = SE_DATA_TYPE_UINT32; 330 (void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32); 331 break; 332 case DATA_TYPE_INT64: 333 se_value->value_type = SE_DATA_TYPE_INT64; 334 (void) nvpair_value_int64(nvp, &se_value->value.sv_int64); 335 break; 336 case DATA_TYPE_UINT64: 337 se_value->value_type = SE_DATA_TYPE_UINT64; 338 (void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64); 339 break; 340 case DATA_TYPE_STRING: 341 se_value->value_type = SE_DATA_TYPE_STRING; 342 (void) nvpair_value_string(nvp, &se_value->value.sv_string); 343 break; 344 case DATA_TYPE_BYTE_ARRAY: 345 se_value->value_type = SE_DATA_TYPE_BYTES; 346 (void) nvpair_value_byte_array(nvp, 347 &se_value->value.sv_bytes.data, 348 (uint_t *)&se_value->value.sv_bytes.size); 349 break; 350 case DATA_TYPE_HRTIME: 351 se_value->value_type = SE_DATA_TYPE_TIME; 352 (void) nvpair_value_hrtime(nvp, &se_value->value.sv_time); 353 break; 354 default: 355 return (ENOTSUP); 356 } 357 return (0); 358 } 359 360 /* 361 * sysevent_attr_next - Get next attribute in event attribute list 362 */ 363 sysevent_attr_t * 364 sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr) 365 { 366 nvlist_t *nvl; 367 nvpair_t *nvp = attr; 368 369 /* all user visible sysevent_t's are unpacked */ 370 assert(SE_FLAG(ev) != SE_PACKED_BUF); 371 372 if (SE_ATTR_PTR(ev) == (uint64_t)0) { 373 return (NULL); 374 } 375 376 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 377 return (nvlist_next_nvpair(nvl, nvp)); 378 } 379 380 /* 381 * sysevent_lookup_attr - Lookup attribute by name and datatype. 382 */ 383 int 384 sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype, 385 sysevent_value_t *se_value) 386 { 387 nvpair_t *nvp; 388 nvlist_t *nvl; 389 390 assert(SE_FLAG(ev) != SE_PACKED_BUF); 391 392 if (SE_ATTR_PTR(ev) == (uint64_t)0) { 393 return (ENOENT); 394 } 395 396 /* 397 * sysevent matches on both name and datatype 398 * nvlist_look mataches name only. So we walk 399 * nvlist manually here. 400 */ 401 nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev); 402 nvp = nvlist_next_nvpair(nvl, NULL); 403 while (nvp) { 404 if ((strcmp(name, nvpair_name(nvp)) == 0) && 405 (sysevent_attr_value(nvp, se_value) == 0) && 406 (se_value->value_type == datatype)) 407 return (0); 408 nvp = nvlist_next_nvpair(nvl, nvp); 409 } 410 return (ENOENT); 411 } 412 413 /* Routines to extract event header information */ 414 415 /* 416 * sysevent_get_class - Get class id 417 */ 418 int 419 sysevent_get_class(sysevent_t *ev) 420 { 421 return (SE_CLASS(ev)); 422 } 423 424 /* 425 * sysevent_get_subclass - Get subclass id 426 */ 427 int 428 sysevent_get_subclass(sysevent_t *ev) 429 { 430 return (SE_SUBCLASS(ev)); 431 } 432 433 /* 434 * sysevent_get_class_name - Get class name string 435 */ 436 char * 437 sysevent_get_class_name(sysevent_t *ev) 438 { 439 return (SE_CLASS_NAME(ev)); 440 } 441 442 typedef enum { 443 PUB_VEND, 444 PUB_KEYWD, 445 PUB_NAME, 446 PUB_PID 447 } se_pub_id_t; 448 449 /* 450 * sysevent_get_pub - Get publisher name string 451 */ 452 char * 453 sysevent_get_pub(sysevent_t *ev) 454 { 455 return (SE_PUB_NAME(ev)); 456 } 457 458 /* 459 * Get the requested string pointed by the token. 460 * 461 * Return NULL if not found or for insufficient memory. 462 */ 463 static char * 464 parse_pub_id(sysevent_t *ev, se_pub_id_t token) 465 { 466 int i; 467 char *pub_id, *pub_element, *str, *next; 468 469 next = pub_id = strdup(sysevent_get_pub(ev)); 470 for (i = 0; i <= token; ++i) { 471 str = strtok_r(next, ":", &next); 472 if (str == NULL) { 473 free(pub_id); 474 return (NULL); 475 } 476 } 477 478 pub_element = strdup(str); 479 free(pub_id); 480 return (pub_element); 481 } 482 483 /* 484 * Return a pointer to the string following the token 485 * 486 * Note: This is a dedicated function for parsing 487 * publisher strings and not for general purpose. 488 */ 489 static const char * 490 pub_idx(const char *pstr, int token) 491 { 492 int i; 493 494 for (i = 1; i <= token; i++) { 495 if ((pstr = index(pstr, ':')) == NULL) 496 return (NULL); 497 pstr++; 498 } 499 500 /* String might be empty */ 501 if (pstr) { 502 if (*pstr == '\0' || *pstr == ':') 503 return (NULL); 504 } 505 return (pstr); 506 } 507 508 char * 509 sysevent_get_vendor_name(sysevent_t *ev) 510 { 511 return (parse_pub_id(ev, PUB_VEND)); 512 } 513 514 char * 515 sysevent_get_pub_name(sysevent_t *ev) 516 { 517 return (parse_pub_id(ev, PUB_NAME)); 518 } 519 520 /* 521 * Provide the pid encoded in the publisher string 522 * w/o allocating any resouces. 523 */ 524 void 525 sysevent_get_pid(sysevent_t *ev, pid_t *pid) 526 { 527 const char *part_str; 528 const char *pub_str = sysevent_get_pub(ev); 529 530 *pid = (pid_t)SE_KERN_PID; 531 532 part_str = pub_idx(pub_str, PUB_KEYWD); 533 if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL) 534 return; 535 536 if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL) 537 return; 538 539 *pid = (pid_t)atoi(part_str); 540 } 541 542 /* 543 * sysevent_get_subclass_name - Get subclass name string 544 */ 545 char * 546 sysevent_get_subclass_name(sysevent_t *ev) 547 { 548 return (SE_SUBCLASS_NAME(ev)); 549 } 550 551 /* 552 * sysevent_get_seq - Get event sequence id 553 */ 554 uint64_t 555 sysevent_get_seq(sysevent_t *ev) 556 { 557 return (SE_SEQ(ev)); 558 } 559 560 /* 561 * sysevent_get_time - Get event timestamp 562 */ 563 void 564 sysevent_get_time(sysevent_t *ev, hrtime_t *etime) 565 { 566 *etime = SE_TIME(ev); 567 } 568 569 /* 570 * sysevent_get_size - Get event buffer size 571 */ 572 size_t 573 sysevent_get_size(sysevent_t *ev) 574 { 575 return ((size_t)SE_SIZE(ev)); 576 } 577 578 /* 579 * The following routines are used by devfsadm_mod.c to propagate event 580 * buffers to devfsadmd. These routines will serve as the basis for 581 * event channel publication and subscription. 582 */ 583 584 /* 585 * sysevent_alloc_event - 586 * allocate a sysevent buffer for sending through an established event 587 * channel. 588 */ 589 sysevent_t * 590 sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name, 591 nvlist_t *attr_list) 592 { 593 int class_sz, subclass_sz, pub_sz; 594 char *pub_id; 595 sysevent_t *ev; 596 597 if ((class == NULL) || (subclass == NULL) || (vendor == NULL) || 598 (pub_name == NULL)) { 599 errno = EINVAL; 600 return (NULL); 601 } 602 603 class_sz = strlen(class) + 1; 604 subclass_sz = strlen(subclass) + 1; 605 if ((class_sz > MAX_CLASS_LEN) || 606 (subclass_sz > MAX_SUBCLASS_LEN)) { 607 errno = EINVAL; 608 return (NULL); 609 } 610 611 /* 612 * Calculate the publisher size plus string seperators and maximum 613 * pid characters 614 */ 615 pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14; 616 if (pub_sz > MAX_PUB_LEN) { 617 errno = EINVAL; 618 return (NULL); 619 } 620 pub_id = malloc(pub_sz); 621 if (pub_id == NULL) { 622 errno = ENOMEM; 623 return (NULL); 624 } 625 if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB, 626 pub_name, (int)getpid()) >= pub_sz) { 627 free(pub_id); 628 errno = EINVAL; 629 return (NULL); 630 } 631 pub_sz = strlen(pub_id) + 1; 632 633 ev = sysevent_alloc(class, class_sz, subclass, subclass_sz, 634 pub_id, pub_sz, attr_list); 635 free(pub_id); 636 if (ev == NULL) { 637 errno = ENOMEM; 638 return (NULL); 639 } 640 641 return (ev); 642 } 643 644 /* 645 * se_unpack - unpack nvlist to a searchable list. 646 * If already unpacked, will do a dup. 647 */ 648 static sysevent_t * 649 se_unpack(sysevent_t *ev) 650 { 651 caddr_t attr; 652 size_t attr_len; 653 nvlist_t *attrp = NULL; 654 uint64_t attr_offset; 655 sysevent_t *copy; 656 657 assert(SE_FLAG(ev) == SE_PACKED_BUF); 658 659 /* Copy event header information */ 660 attr_offset = SE_ATTR_OFF(ev); 661 copy = calloc(1, attr_offset); 662 if (copy == NULL) 663 return (NULL); 664 bcopy(ev, copy, attr_offset); 665 SE_FLAG(copy) = 0; /* unpacked */ 666 667 /* unpack nvlist */ 668 attr = (caddr_t)ev + attr_offset; 669 attr_len = SE_SIZE(ev) - attr_offset; 670 if (attr_len == 0) { 671 return (copy); 672 } 673 if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) { 674 free(copy); 675 return (NULL); 676 } 677 678 SE_ATTR_PTR(copy) = (uintptr_t)attrp; 679 return (copy); 680 } 681 682 /* 683 * se_print - Prints elements in an event buffer 684 */ 685 void 686 se_print(FILE *fp, sysevent_t *ev) 687 { 688 char *vendor, *pub; 689 pid_t pid; 690 hrtime_t hrt; 691 nvlist_t *attr_list = NULL; 692 693 (void) sysevent_get_time(ev, &hrt); 694 (void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n", 695 hrt, (longlong_t)sysevent_get_seq(ev)); 696 (void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev)); 697 (void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev)); 698 if ((vendor = sysevent_get_vendor_name(ev)) != NULL) { 699 (void) fprintf(fp, "\tvendor = %s\n", vendor); 700 free(vendor); 701 } 702 if ((pub = sysevent_get_pub_name(ev)) != NULL) { 703 sysevent_get_pid(ev, &pid); 704 (void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid); 705 free(pub); 706 } 707 708 if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) { 709 nvlist_print(fp, attr_list); 710 nvlist_free(attr_list); 711 } 712 } 713 714 /* 715 * The following routines are provided to support establishment and use 716 * of sysevent channels. A sysevent channel is established between 717 * publishers and subscribers of sysevents for an agreed upon channel name. 718 * These routines currently support sysevent channels between user-level 719 * applications running on the same system. 720 * 721 * Sysevent channels may be created by a single publisher or subscriber process. 722 * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in 723 * receiving sysevent notifications on the named channel. At present, only 724 * one publisher is allowed per sysevent channel. 725 * 726 * The registration information for each channel is kept in the kernel. A 727 * kernel-based registration was chosen for persistence and reliability reasons. 728 * If either a publisher or a subscriber exits for any reason, the channel 729 * properties are maintained until all publishers and subscribers have exited. 730 * Additionally, an in-kernel registration allows the API to be extended to 731 * include kernel subscribers as well as userland subscribers in the future. 732 * 733 * To insure fast lookup of subscriptions, a cached copy of the registration 734 * is kept and maintained for the publisher process. Updates are made 735 * everytime a change is made in the kernel. Changes to the registration are 736 * expected to be infrequent. 737 * 738 * Channel communication between publisher and subscriber processes is 739 * implemented primarily via doors. Each publisher creates a door for 740 * registration notifications and each subscriber creates a door for event 741 * delivery. 742 * 743 * Most of these routines are used by syseventd(1M), the sysevent publisher 744 * for the syseventd channel. Processes wishing to receive sysevent 745 * notifications from syseventd may use a set of public 746 * APIs designed to subscribe to syseventd sysevents. The subscription 747 * APIs are implemented in accordance with PSARC/2001/076. 748 * 749 */ 750 751 /* 752 * Door handlers for the channel subscribers 753 */ 754 755 /* 756 * subscriber_event_handler - generic event handling wrapper for subscribers 757 * This handler is used to process incoming sysevent 758 * notifications from channel publishers. 759 * It is created as a seperate thread in each subscriber 760 * process per subscription. 761 */ 762 static void 763 subscriber_event_handler(sysevent_handle_t *shp) 764 { 765 subscriber_priv_t *sub_info; 766 sysevent_queue_t *evqp; 767 768 sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 769 770 (void) mutex_lock(&sub_info->sp_qlock); 771 for (;;) { 772 while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) { 773 (void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock); 774 } 775 evqp = sub_info->sp_evq_head; 776 while (evqp) { 777 (void) mutex_unlock(&sub_info->sp_qlock); 778 (void) sub_info->sp_func(evqp->sq_ev); 779 (void) mutex_lock(&sub_info->sp_qlock); 780 sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next; 781 free(evqp->sq_ev); 782 free(evqp); 783 evqp = sub_info->sp_evq_head; 784 } 785 if (!SH_BOUND(shp)) { 786 (void) mutex_unlock(&sub_info->sp_qlock); 787 return; 788 } 789 } 790 791 /* NOTREACHED */ 792 } 793 794 /* 795 * Data structure used to communicate event subscription cache updates 796 * to publishers via a registration door 797 */ 798 struct reg_args { 799 uint32_t ra_sub_id; 800 uint32_t ra_op; 801 uint64_t ra_buf_ptr; 802 }; 803 804 805 /* 806 * event_deliver_service - generic event delivery service routine. This routine 807 * is called in response to a door call to post an event. 808 * 809 */ 810 static void 811 event_deliver_service(void *cookie, char *args, size_t alen, 812 door_desc_t *ddp, uint_t ndid) 813 { 814 int ret = 0; 815 subscriber_priv_t *sub_info; 816 sysevent_handle_t *shp; 817 sysevent_queue_t *new_eq; 818 819 if (args == NULL || alen < sizeof (uint32_t)) { 820 ret = EINVAL; 821 goto return_from_door; 822 } 823 824 /* Publisher checking on subscriber */ 825 if (alen == sizeof (uint32_t)) { 826 ret = 0; 827 goto return_from_door; 828 } 829 830 shp = (sysevent_handle_t *)cookie; 831 if (shp == NULL) { 832 ret = EBADF; 833 goto return_from_door; 834 } 835 836 /* 837 * Mustn't block if we are trying to update the registration with 838 * the publisher 839 */ 840 if (mutex_trylock(SH_LOCK(shp)) != 0) { 841 ret = EAGAIN; 842 goto return_from_door; 843 } 844 845 if (!SH_BOUND(shp)) { 846 ret = EBADF; 847 (void) mutex_unlock(SH_LOCK(shp)); 848 goto return_from_door; 849 } 850 851 sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp); 852 if (sub_info == NULL) { 853 ret = EBADF; 854 (void) mutex_unlock(SH_LOCK(shp)); 855 goto return_from_door; 856 } 857 858 new_eq = (sysevent_queue_t *)calloc(1, 859 sizeof (sysevent_queue_t)); 860 if (new_eq == NULL) { 861 ret = EAGAIN; 862 (void) mutex_unlock(SH_LOCK(shp)); 863 goto return_from_door; 864 } 865 866 /* 867 * Allocate and copy the event buffer into the subscriber's 868 * address space 869 */ 870 new_eq->sq_ev = calloc(1, alen); 871 if (new_eq->sq_ev == NULL) { 872 free(new_eq); 873 ret = EAGAIN; 874 (void) mutex_unlock(SH_LOCK(shp)); 875 goto return_from_door; 876 } 877 (void) bcopy(args, new_eq->sq_ev, alen); 878 879 (void) mutex_lock(&sub_info->sp_qlock); 880 if (sub_info->sp_evq_head == NULL) { 881 sub_info->sp_evq_head = new_eq; 882 } else { 883 sub_info->sp_evq_tail->sq_next = new_eq; 884 } 885 sub_info->sp_evq_tail = new_eq; 886 887 (void) cond_signal(&sub_info->sp_cv); 888 (void) mutex_unlock(&sub_info->sp_qlock); 889 (void) mutex_unlock(SH_LOCK(shp)); 890 891 return_from_door: 892 (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 893 (void) door_return(NULL, 0, NULL, 0); 894 } 895 896 /* 897 * Sysevent subscription information is maintained in the kernel. Updates 898 * to the in-kernel registration database is expected to be infrequent and 899 * offers consistency for publishers and subscribers that may come and go 900 * for a given channel. 901 * 902 * To expedite registration lookups by publishers, a cached copy of the 903 * kernel registration database is kept per-channel. Caches are invalidated 904 * and refreshed upon state changes to the in-kernel registration database. 905 * 906 * To prevent stale subscriber data, publishers may remove subsriber 907 * registrations from the in-kernel registration database in the event 908 * that a particular subscribing process is unresponsive. 909 * 910 * The following routines provide a mechanism to update publisher and subscriber 911 * information for a specified channel. 912 */ 913 914 /* 915 * clnt_deliver_event - Deliver an event through the consumer's event 916 * delivery door 917 * 918 * Returns -1 if message not delivered. With errno set to cause of error. 919 * Returns 0 for success with the results returned in posting buffer. 920 */ 921 static int 922 clnt_deliver_event(int service_door, void *data, size_t datalen, 923 void *result, size_t rlen) 924 { 925 int error = 0; 926 door_arg_t door_arg; 927 928 door_arg.rbuf = result; 929 door_arg.rsize = rlen; 930 door_arg.data_ptr = data; 931 door_arg.data_size = datalen; 932 door_arg.desc_ptr = NULL; 933 door_arg.desc_num = 0; 934 935 /* 936 * Make door call 937 */ 938 while ((error = door_call(service_door, &door_arg)) != 0) { 939 if (errno == EAGAIN || errno == EINTR) { 940 continue; 941 } else { 942 error = errno; 943 break; 944 } 945 } 946 947 return (error); 948 } 949 950 static int 951 update_publisher_cache(subscriber_priv_t *sub_info, int update_op, 952 uint32_t sub_id, size_t datasz, uchar_t *data) 953 { 954 int pub_fd; 955 uint32_t result = 0; 956 struct reg_args *rargs; 957 958 rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) + 959 datasz); 960 if (rargs == NULL) { 961 errno = ENOMEM; 962 return (-1); 963 } 964 965 rargs->ra_sub_id = sub_id; 966 rargs->ra_op = update_op; 967 bcopy(data, (char *)&rargs->ra_buf_ptr, datasz); 968 969 pub_fd = open(sub_info->sp_door_name, O_RDONLY); 970 (void) clnt_deliver_event(pub_fd, (void *)rargs, 971 sizeof (struct reg_args) + datasz, &result, sizeof (result)); 972 (void) close(pub_fd); 973 974 free(rargs); 975 if (result != 0) { 976 errno = result; 977 return (-1); 978 } 979 980 return (0); 981 } 982 983 984 /* 985 * update_kernel_registration - update the in-kernel registration for the 986 * given channel. 987 */ 988 static int 989 update_kernel_registration(sysevent_handle_t *shp, int update_type, 990 int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data) 991 { 992 int error; 993 char *channel_name = SH_CHANNEL_NAME(shp); 994 se_pubsub_t udata; 995 996 udata.ps_channel_name_len = strlen(channel_name) + 1; 997 udata.ps_op = update_op; 998 udata.ps_type = update_type; 999 udata.ps_buflen = datasz; 1000 udata.ps_id = *sub_id; 1001 1002 if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1003 (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0)) 1004 != 0) { 1005 return (error); 1006 } 1007 1008 *sub_id = udata.ps_id; 1009 1010 return (error); 1011 } 1012 1013 /* 1014 * get_kernel_registration - get the current subscriber registration for 1015 * the given channel 1016 */ 1017 static nvlist_t * 1018 get_kernel_registration(char *channel_name, uint32_t class_id) 1019 { 1020 char *nvlbuf; 1021 nvlist_t *nvl; 1022 se_pubsub_t udata; 1023 1024 nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ); 1025 if (nvlbuf == NULL) { 1026 return (NULL); 1027 } 1028 1029 udata.ps_buflen = MAX_SUBSCRIPTION_SZ; 1030 udata.ps_channel_name_len = strlen(channel_name) + 1; 1031 udata.ps_id = class_id; 1032 udata.ps_op = SE_GET_REGISTRATION; 1033 udata.ps_type = PUBLISHER; 1034 1035 if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT, 1036 (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0) 1037 != 0) { 1038 1039 /* Need a bigger buffer to hold channel registration */ 1040 if (errno == EAGAIN) { 1041 free(nvlbuf); 1042 nvlbuf = calloc(1, udata.ps_buflen); 1043 if (nvlbuf == NULL) 1044 return (NULL); 1045 1046 /* Try again */ 1047 if (modctl(MODEVENTS, 1048 (uintptr_t)MODEVENTS_REGISTER_EVENT, 1049 (uintptr_t)channel_name, (uintptr_t)nvlbuf, 1050 (uintptr_t)&udata, 0) != 0) { 1051 free(nvlbuf); 1052 return (NULL); 1053 } 1054 } else { 1055 free(nvlbuf); 1056 return (NULL); 1057 } 1058 } 1059 1060 if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) { 1061 free(nvlbuf); 1062 return (NULL); 1063 } 1064 free(nvlbuf); 1065 1066 return (nvl); 1067 } 1068 1069 /* 1070 * The following routines provide a mechanism for publishers to maintain 1071 * subscriber information. 1072 */ 1073 1074 static void 1075 dealloc_subscribers(sysevent_handle_t *shp) 1076 { 1077 int i; 1078 subscriber_data_t *sub; 1079 1080 for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1081 sub = SH_SUBSCRIBER(shp, i); 1082 if (sub != NULL) { 1083 free(sub->sd_door_name); 1084 free(sub); 1085 } 1086 SH_SUBSCRIBER(shp, i) = NULL; 1087 } 1088 } 1089 1090 static int 1091 alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag) 1092 { 1093 subscriber_data_t *sub; 1094 char door_name[MAXPATHLEN]; 1095 1096 if (SH_SUBSCRIBER(shp, sub_id) != NULL) { 1097 return (0); 1098 } 1099 1100 /* Allocate and initialize the subscriber data */ 1101 sub = (subscriber_data_t *)calloc(1, 1102 sizeof (subscriber_data_t)); 1103 if (sub == NULL) { 1104 return (-1); 1105 } 1106 if (snprintf(door_name, MAXPATHLEN, "%s/%d", 1107 SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) { 1108 free(sub); 1109 return (-1); 1110 } 1111 1112 sub->sd_flag = ACTIVE; 1113 sub->sd_door_name = strdup(door_name); 1114 if (sub->sd_door_name == NULL) { 1115 free(sub); 1116 return (-1); 1117 } 1118 1119 SH_SUBSCRIBER(shp, sub_id) = sub; 1120 return (0); 1121 1122 } 1123 1124 /* 1125 * The following routines are used to update and maintain the registration cache 1126 * for a particular sysevent channel. 1127 */ 1128 1129 static uint32_t 1130 hash_func(const char *s) 1131 { 1132 uint32_t result = 0; 1133 uint_t g; 1134 1135 while (*s != '\0') { 1136 result <<= 4; 1137 result += (uint32_t)*s++; 1138 g = result & 0xf0000000; 1139 if (g != 0) { 1140 result ^= g >> 24; 1141 result ^= g; 1142 } 1143 } 1144 1145 return (result); 1146 } 1147 1148 subclass_lst_t * 1149 cache_find_subclass(class_lst_t *c_list, char *subclass) 1150 { 1151 subclass_lst_t *sc_list; 1152 1153 if (c_list == NULL) 1154 return (NULL); 1155 1156 sc_list = c_list->cl_subclass_list; 1157 1158 while (sc_list != NULL) { 1159 if (strcmp(sc_list->sl_name, subclass) == 0) { 1160 return (sc_list); 1161 } 1162 sc_list = sc_list->sl_next; 1163 } 1164 1165 return (NULL); 1166 } 1167 1168 1169 static class_lst_t * 1170 cache_find_class(sysevent_handle_t *shp, char *class) 1171 { 1172 int index; 1173 class_lst_t *c_list; 1174 class_lst_t **class_hash = SH_CLASS_HASH(shp); 1175 1176 if (strcmp(class, EC_ALL) == 0) { 1177 return (class_hash[0]); 1178 } 1179 1180 index = CLASS_HASH(class); 1181 c_list = class_hash[index]; 1182 while (c_list != NULL) { 1183 if (strcmp(class, c_list->cl_name) == 0) { 1184 break; 1185 } 1186 c_list = c_list->cl_next; 1187 } 1188 1189 return (c_list); 1190 } 1191 1192 static int 1193 cache_insert_subclass(class_lst_t *c_list, char **subclass_names, 1194 int subclass_num, uint32_t sub_id) 1195 { 1196 int i; 1197 subclass_lst_t *sc_list; 1198 1199 for (i = 0; i < subclass_num; ++i) { 1200 if ((sc_list = cache_find_subclass(c_list, subclass_names[i])) 1201 != NULL) { 1202 sc_list->sl_num[sub_id] = 1; 1203 } else { 1204 sc_list = (subclass_lst_t *)calloc(1, 1205 sizeof (subclass_lst_t)); 1206 if (sc_list == NULL) 1207 return (-1); 1208 1209 sc_list->sl_name = strdup(subclass_names[i]); 1210 if (sc_list->sl_name == NULL) { 1211 free(sc_list); 1212 return (-1); 1213 } 1214 1215 sc_list->sl_num[sub_id] = 1; 1216 sc_list->sl_next = c_list->cl_subclass_list; 1217 c_list->cl_subclass_list = sc_list; 1218 } 1219 } 1220 1221 return (0); 1222 } 1223 1224 static int 1225 cache_insert_class(sysevent_handle_t *shp, char *class, 1226 char **subclass_names, int subclass_num, uint32_t sub_id) 1227 { 1228 class_lst_t *c_list; 1229 1230 if (strcmp(class, EC_ALL) == 0) { 1231 char *subclass_all = EC_SUB_ALL; 1232 1233 (void) cache_insert_subclass(SH_CLASS_HASH(shp)[0], 1234 (char **)&subclass_all, 1, sub_id); 1235 return (0); 1236 } 1237 1238 /* New class, add to the registration cache */ 1239 if ((c_list = cache_find_class(shp, class)) == NULL) { 1240 1241 c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t)); 1242 if (c_list == NULL) { 1243 return (1); 1244 } 1245 c_list->cl_name = strdup(class); 1246 if (c_list->cl_name == NULL) { 1247 free(c_list); 1248 return (1); 1249 } 1250 1251 c_list->cl_subclass_list = (subclass_lst_t *) 1252 calloc(1, sizeof (subclass_lst_t)); 1253 if (c_list->cl_subclass_list == NULL) { 1254 free(c_list->cl_name); 1255 free(c_list); 1256 return (1); 1257 } 1258 c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL); 1259 if (c_list->cl_subclass_list->sl_name == NULL) { 1260 free(c_list->cl_subclass_list); 1261 free(c_list->cl_name); 1262 free(c_list); 1263 return (1); 1264 } 1265 c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)]; 1266 SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list; 1267 1268 } 1269 1270 /* Update the subclass list */ 1271 if (cache_insert_subclass(c_list, subclass_names, subclass_num, 1272 sub_id) != 0) 1273 return (1); 1274 1275 return (0); 1276 } 1277 1278 static void 1279 cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id) 1280 { 1281 int i; 1282 class_lst_t *c_list; 1283 subclass_lst_t *sc_list; 1284 1285 for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1286 c_list = SH_CLASS_HASH(shp)[i]; 1287 while (c_list != NULL) { 1288 sc_list = c_list->cl_subclass_list; 1289 while (sc_list != NULL) { 1290 sc_list->sl_num[sub_id] = 0; 1291 sc_list = sc_list->sl_next; 1292 } 1293 c_list = c_list->cl_next; 1294 } 1295 } 1296 } 1297 1298 static void 1299 cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id) 1300 { 1301 class_lst_t *c_list; 1302 subclass_lst_t *sc_list; 1303 1304 if (strcmp(class, EC_ALL) == 0) { 1305 cache_remove_all_class(shp, sub_id); 1306 return; 1307 } 1308 1309 if ((c_list = cache_find_class(shp, class)) == NULL) { 1310 return; 1311 } 1312 1313 sc_list = c_list->cl_subclass_list; 1314 while (sc_list != NULL) { 1315 sc_list->sl_num[sub_id] = 0; 1316 sc_list = sc_list->sl_next; 1317 } 1318 } 1319 1320 static void 1321 free_cached_registration(sysevent_handle_t *shp) 1322 { 1323 int i; 1324 class_lst_t *clist, *next_clist; 1325 subclass_lst_t *sc_list, *next_sc; 1326 1327 for (i = 0; i < CLASS_HASH_SZ + 1; i++) { 1328 clist = SH_CLASS_HASH(shp)[i]; 1329 while (clist != NULL) { 1330 sc_list = clist->cl_subclass_list; 1331 while (sc_list != NULL) { 1332 free(sc_list->sl_name); 1333 next_sc = sc_list->sl_next; 1334 free(sc_list); 1335 sc_list = next_sc; 1336 } 1337 free(clist->cl_name); 1338 next_clist = clist->cl_next; 1339 free(clist); 1340 clist = next_clist; 1341 } 1342 SH_CLASS_HASH(shp)[i] = NULL; 1343 } 1344 } 1345 1346 static int 1347 create_cached_registration(sysevent_handle_t *shp, 1348 class_lst_t **class_hash) 1349 { 1350 int i, j, new_class; 1351 char *class_name; 1352 uint_t num_elem; 1353 uchar_t *subscribers; 1354 nvlist_t *nvl; 1355 nvpair_t *nvpair; 1356 class_lst_t *clist; 1357 subclass_lst_t *sc_list; 1358 1359 for (i = 0; i < CLASS_HASH_SZ + 1; ++i) { 1360 1361 if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i)) 1362 == NULL) { 1363 if (errno == ENOENT) { 1364 class_hash[i] = NULL; 1365 continue; 1366 } else { 1367 goto create_failed; 1368 } 1369 } 1370 1371 1372 nvpair = NULL; 1373 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1374 goto create_failed; 1375 } 1376 1377 new_class = 1; 1378 while (new_class) { 1379 /* Extract the class name from the nvpair */ 1380 if (nvpair_value_string(nvpair, &class_name) != 0) { 1381 goto create_failed; 1382 } 1383 clist = (class_lst_t *) 1384 calloc(1, sizeof (class_lst_t)); 1385 if (clist == NULL) { 1386 goto create_failed; 1387 } 1388 1389 clist->cl_name = strdup(class_name); 1390 if (clist->cl_name == NULL) { 1391 free(clist); 1392 goto create_failed; 1393 } 1394 1395 /* 1396 * Extract the subclass name and registration 1397 * from the nvpair 1398 */ 1399 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1400 == NULL) { 1401 free(clist->cl_name); 1402 free(clist); 1403 goto create_failed; 1404 } 1405 1406 clist->cl_next = class_hash[i]; 1407 class_hash[i] = clist; 1408 1409 for (;;) { 1410 1411 sc_list = (subclass_lst_t *)calloc(1, 1412 sizeof (subclass_lst_t)); 1413 if (sc_list == NULL) { 1414 goto create_failed; 1415 } 1416 1417 sc_list->sl_next = clist->cl_subclass_list; 1418 clist->cl_subclass_list = sc_list; 1419 1420 sc_list->sl_name = strdup(nvpair_name(nvpair)); 1421 if (sc_list->sl_name == NULL) { 1422 goto create_failed; 1423 } 1424 1425 if (nvpair_value_byte_array(nvpair, 1426 &subscribers, &num_elem) != 0) { 1427 goto create_failed; 1428 } 1429 bcopy(subscribers, (uchar_t *)sc_list->sl_num, 1430 MAX_SUBSCRIBERS + 1); 1431 1432 for (j = 1; j <= MAX_SUBSCRIBERS; ++j) { 1433 if (sc_list->sl_num[j] == 0) 1434 continue; 1435 1436 if (alloc_subscriber(shp, j, 1) != 0) { 1437 goto create_failed; 1438 } 1439 } 1440 1441 /* 1442 * Check next nvpair - either subclass or 1443 * class 1444 */ 1445 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) 1446 == NULL) { 1447 new_class = 0; 1448 break; 1449 } else if (strcmp(nvpair_name(nvpair), 1450 CLASS_NAME) == 0) { 1451 break; 1452 } 1453 } 1454 } 1455 nvlist_free(nvl); 1456 } 1457 return (0); 1458 1459 create_failed: 1460 dealloc_subscribers(shp); 1461 free_cached_registration(shp); 1462 if (nvl) 1463 nvlist_free(nvl); 1464 return (-1); 1465 1466 } 1467 1468 /* 1469 * cache_update_service - generic event publisher service routine. This routine 1470 * is called in response to a registration cache update. 1471 * 1472 */ 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 rargs = (struct reg_args *)args; 1494 shp = (sysevent_handle_t *)cookie; 1495 1496 datalen = alen - sizeof (struct reg_args); 1497 sub_id = rargs->ra_sub_id; 1498 1499 (void) mutex_lock(SH_LOCK(shp)); 1500 1501 switch (rargs->ra_op) { 1502 case SE_UNREGISTER: 1503 class = (char *)&rargs->ra_buf_ptr; 1504 cache_remove_class(shp, (char *)class, 1505 sub_id); 1506 break; 1507 case SE_UNBIND_REGISTRATION: 1508 1509 sub = SH_SUBSCRIBER(shp, sub_id); 1510 if (sub == NULL) 1511 break; 1512 1513 free(sub->sd_door_name); 1514 free(sub); 1515 cache_remove_class(shp, EC_ALL, sub_id); 1516 SH_SUBSCRIBER(shp, sub_id) = NULL; 1517 1518 break; 1519 case SE_BIND_REGISTRATION: 1520 1521 /* New subscriber */ 1522 if (alloc_subscriber(shp, sub_id, 0) != 0) { 1523 ret = ENOMEM; 1524 break; 1525 } 1526 break; 1527 case SE_REGISTER: 1528 1529 if (SH_SUBSCRIBER(shp, sub_id) == NULL) { 1530 ret = EINVAL; 1531 break; 1532 } 1533 /* Get new registration data */ 1534 if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen, 1535 &nvl, 0) != 0) { 1536 ret = EFAULT; 1537 break; 1538 } 1539 if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) { 1540 nvlist_free(nvl); 1541 ret = EFAULT; 1542 break; 1543 } 1544 if (nvpair_value_string_array(nvpair, &event_list, &num_elem) 1545 != 0) { 1546 nvlist_free(nvl); 1547 ret = EFAULT; 1548 break; 1549 } 1550 class = nvpair_name(nvpair); 1551 1552 ret = cache_insert_class(shp, class, 1553 event_list, num_elem, sub_id); 1554 if (ret != 0) { 1555 cache_remove_class(shp, class, sub_id); 1556 nvlist_free(nvl); 1557 ret = EFAULT; 1558 break; 1559 } 1560 1561 nvlist_free(nvl); 1562 1563 break; 1564 case SE_CLEANUP: 1565 /* Cleanup stale subscribers */ 1566 sysevent_cleanup_subscribers(shp); 1567 break; 1568 default: 1569 ret = EINVAL; 1570 } 1571 1572 (void) mutex_unlock(SH_LOCK(shp)); 1573 1574 return_from_door: 1575 (void) door_return((void *)&ret, sizeof (ret), NULL, 0); 1576 (void) door_return(NULL, 0, NULL, 0); 1577 } 1578 1579 /* 1580 * sysevent_send_event - 1581 * Send an event via the communication channel associated with the sysevent 1582 * handle. Event notifications are broadcast to all subscribers based upon 1583 * the event class and subclass. The handle must have been previously 1584 * allocated and bound by 1585 * sysevent_open_channel() and sysevent_bind_publisher() 1586 */ 1587 int 1588 sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev) 1589 { 1590 int i, error, sub_fd, result = 0; 1591 int deliver_error = 0; 1592 int subscribers_sent = 0; 1593 int want_resend, resend_cnt = 0; 1594 char *event_class, *event_subclass; 1595 uchar_t *all_class_subscribers, *all_subclass_subscribers; 1596 uchar_t *subclass_subscribers; 1597 subscriber_data_t *sub; 1598 subclass_lst_t *sc_lst; 1599 1600 /* Check for proper registration */ 1601 event_class = sysevent_get_class_name(ev); 1602 event_subclass = sysevent_get_subclass_name(ev); 1603 1604 (void) mutex_lock(SH_LOCK(shp)); 1605 1606 send_event: 1607 1608 want_resend = 0; 1609 if (!SH_BOUND(shp)) { 1610 (void) mutex_unlock(SH_LOCK(shp)); 1611 errno = EINVAL; 1612 return (-1); 1613 } 1614 1615 /* Find all subscribers for this event class/subclass */ 1616 sc_lst = cache_find_subclass( 1617 cache_find_class(shp, EC_ALL), EC_SUB_ALL); 1618 all_class_subscribers = sc_lst->sl_num; 1619 1620 sc_lst = cache_find_subclass( 1621 cache_find_class(shp, event_class), EC_SUB_ALL); 1622 if (sc_lst) 1623 all_subclass_subscribers = sc_lst->sl_num; 1624 else 1625 all_subclass_subscribers = NULL; 1626 1627 sc_lst = cache_find_subclass( 1628 cache_find_class(shp, event_class), event_subclass); 1629 if (sc_lst) 1630 subclass_subscribers = sc_lst->sl_num; 1631 else 1632 subclass_subscribers = NULL; 1633 1634 /* Send event buffer to all valid subscribers */ 1635 for (i = 1; i <= MAX_SUBSCRIBERS; ++i) { 1636 if ((all_class_subscribers[i] | 1637 (all_subclass_subscribers && all_subclass_subscribers[i]) | 1638 (subclass_subscribers && subclass_subscribers[i])) == 0) 1639 continue; 1640 1641 sub = SH_SUBSCRIBER(shp, i); 1642 assert(sub != NULL); 1643 1644 /* Check for active subscriber */ 1645 if (!(sub->sd_flag & ACTIVE)) { 1646 dprint("sysevent_send_event: subscriber %d inactive\n", 1647 i); 1648 continue; 1649 } 1650 1651 /* Process only resend requests */ 1652 if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) { 1653 continue; 1654 } 1655 1656 if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) { 1657 dprint("sysevent_send_event: Failed to open " 1658 "%s: %s\n", sub->sd_door_name, strerror(errno)); 1659 continue; 1660 } 1661 result = 0; 1662 error = clnt_deliver_event(sub_fd, ev, 1663 sysevent_get_size(ev), &result, sizeof (result)); 1664 1665 (void) close(sub_fd); 1666 1667 /* Successful door call */ 1668 if (error == 0) { 1669 switch (result) { 1670 /* Subscriber requested EAGAIN */ 1671 case EAGAIN: 1672 if (resend_cnt > SE_MAX_RETRY_LIMIT) { 1673 deliver_error = 1; 1674 } else { 1675 want_resend = 1; 1676 dprint("sysevent_send_event: resend " 1677 "requested for %d\n", i); 1678 sub->sd_flag |= SEND_AGAIN; 1679 } 1680 break; 1681 /* Bad sysevent handle for subscriber */ 1682 case EBADF: 1683 case EINVAL: 1684 dprint("sysevent_send_event: Bad sysevent " 1685 "handle for %s", sub->sd_door_name); 1686 sub->sd_flag = 0; 1687 deliver_error = 1; 1688 break; 1689 /* Successful delivery */ 1690 default: 1691 sub->sd_flag &= ~SEND_AGAIN; 1692 ++subscribers_sent; 1693 } 1694 } else { 1695 dprint("sysevent_send_event: Failed door call " 1696 "to %s: %s: %d\n", sub->sd_door_name, 1697 strerror(errno), result); 1698 sub->sd_flag = 0; 1699 deliver_error = 1; 1700 } 1701 } 1702 1703 if (want_resend) { 1704 resend_cnt++; 1705 goto send_event; 1706 } 1707 1708 if (deliver_error) { 1709 sysevent_cleanup_subscribers(shp); 1710 (void) mutex_unlock(SH_LOCK(shp)); 1711 errno = EFAULT; 1712 return (-1); 1713 } 1714 1715 (void) mutex_unlock(SH_LOCK(shp)); 1716 1717 if (subscribers_sent == 0) { 1718 dprint("sysevent_send_event: No subscribers for %s:%s\n", 1719 event_class, event_subclass); 1720 errno = ENOENT; 1721 return (-1); 1722 } 1723 1724 return (0); 1725 } 1726 1727 /* 1728 * Common routine to establish an event channel through which an event 1729 * publisher or subscriber may post or receive events. 1730 */ 1731 static sysevent_handle_t * 1732 sysevent_open_channel_common(const char *channel_path) 1733 { 1734 uint32_t sub_id = 0; 1735 char *begin_path; 1736 struct stat chan_stat; 1737 sysevent_handle_t *shp; 1738 1739 1740 if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) { 1741 errno = EINVAL; 1742 return (NULL); 1743 } 1744 1745 if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) { 1746 if (errno != EEXIST) { 1747 errno = EACCES; 1748 return (NULL); 1749 } 1750 } 1751 1752 /* Check channel file permissions */ 1753 if (stat(channel_path, &chan_stat) != 0) { 1754 dprint("sysevent_open_channel: Invalid permissions for channel " 1755 "%s\n", channel_path); 1756 errno = EACCES; 1757 return (NULL); 1758 } else if (chan_stat.st_uid != getuid() || 1759 !S_ISDIR(chan_stat.st_mode)) { 1760 dprint("sysevent_open_channel: Invalid " 1761 "permissions for channel %s\n: %d:%d:%d", channel_path, 1762 (int)chan_stat.st_uid, (int)chan_stat.st_gid, 1763 (int)chan_stat.st_mode); 1764 1765 errno = EACCES; 1766 return (NULL); 1767 } 1768 1769 shp = calloc(1, sizeof (sysevent_impl_hdl_t)); 1770 if (shp == NULL) { 1771 errno = ENOMEM; 1772 return (NULL); 1773 } 1774 1775 SH_CHANNEL_NAME(shp) = NULL; 1776 SH_CHANNEL_PATH(shp) = strdup(channel_path); 1777 if (SH_CHANNEL_PATH(shp) == NULL) { 1778 free(shp); 1779 errno = ENOMEM; 1780 return (NULL); 1781 } 1782 1783 /* Extract the channel name */ 1784 begin_path = SH_CHANNEL_PATH(shp); 1785 while (*begin_path != '\0' && 1786 (begin_path = strpbrk(begin_path, "/")) != NULL) { 1787 ++begin_path; 1788 SH_CHANNEL_NAME(shp) = begin_path; 1789 } 1790 1791 if (update_kernel_registration(shp, 0, 1792 SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) { 1793 dprint("sysevent_open_channel: Failed for channel %s\n", 1794 SH_CHANNEL_NAME(shp)); 1795 free(SH_CHANNEL_PATH(shp)); 1796 free(shp); 1797 errno = EFAULT; 1798 return (NULL); 1799 } 1800 1801 (void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL); 1802 1803 return (shp); 1804 } 1805 1806 /* 1807 * Establish a sysevent channel for publication and subscription 1808 */ 1809 sysevent_handle_t * 1810 sysevent_open_channel(const char *channel) 1811 { 1812 int var_run_mounted = 0; 1813 char full_channel[MAXPATHLEN + 1]; 1814 FILE *fp; 1815 struct stat chan_stat; 1816 struct extmnttab m; 1817 1818 if (channel == NULL) { 1819 errno = EINVAL; 1820 return (NULL); 1821 } 1822 1823 /* 1824 * Check that /var/run is mounted as tmpfs before allowing a channel 1825 * to be opened. 1826 */ 1827 if ((fp = fopen(MNTTAB, "r")) == NULL) { 1828 errno = EACCES; 1829 return (NULL); 1830 } 1831 1832 resetmnttab(fp); 1833 1834 while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) { 1835 if (strcmp(m.mnt_mountp, "/var/run") == 0 && 1836 strcmp(m.mnt_fstype, "tmpfs") == 0) { 1837 (void) fclose(fp); 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