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