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