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