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