xref: /illumos-gate/usr/src/lib/libsysevent/libsysevent.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
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 	if (attr_list)
222 		nvlist_free(attr_list);
223 	free(ev);
224 }
225 
226 /*
227  * The following routines are used to extract attribute data from a sysevent
228  * handle.
229  */
230 
231 /*
232  * sysevent_get_attr_list - allocate and return an attribute associated with
233  *			the given sysevent buffer.
234  */
235 int
236 sysevent_get_attr_list(sysevent_t *ev, nvlist_t **nvlist)
237 {
238 	int error;
239 	caddr_t attr;
240 	size_t attr_len;
241 	uint64_t attr_offset;
242 	nvlist_t *nvl;
243 
244 	*nvlist = NULL;
245 
246 	/* Duplicate attribute for an unpacked sysevent buffer */
247 	if (SE_FLAG(ev) != SE_PACKED_BUF) {
248 		nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
249 		if (nvl == NULL) {
250 			return (0);
251 		}
252 		if ((error = nvlist_dup(nvl, nvlist, 0)) != 0) {
253 			if (error == ENOMEM) {
254 				errno = error;
255 			} else {
256 				errno = EINVAL;
257 			}
258 			return (-1);
259 		}
260 		return (0);
261 	}
262 
263 	attr_offset = SE_ATTR_OFF(ev);
264 	if (SE_SIZE(ev) == attr_offset) {
265 		return (0);
266 	}
267 
268 	/* unpack nvlist */
269 	attr = (caddr_t)ev + attr_offset;
270 	attr_len = SE_SIZE(ev) - attr_offset;
271 	if ((error = nvlist_unpack(attr, attr_len, nvlist, 0)) != 0) {
272 		if (error == ENOMEM) {
273 			errno = error;
274 		} else 	{
275 			errno = EINVAL;
276 		}
277 		return (-1);
278 	}
279 
280 	return (0);
281 }
282 
283 /*
284  * sysevent_attr_name - Get name of attribute
285  */
286 char *
287 sysevent_attr_name(sysevent_attr_t *attr)
288 {
289 	if (attr == NULL) {
290 		errno = EINVAL;
291 		return (NULL);
292 	}
293 	return (nvpair_name((nvpair_t *)attr));
294 }
295 
296 /*
297  * sysevent_attr_value - Get attribute value data and type
298  */
299 int
300 sysevent_attr_value(sysevent_attr_t *attr, sysevent_value_t *se_value)
301 {
302 	nvpair_t *nvp = attr;
303 
304 	if (nvp == NULL)
305 		return (EINVAL);
306 
307 	/* Convert DATA_TYPE_* to SE_DATA_TYPE_* */
308 	switch (nvpair_type(nvp)) {
309 	case DATA_TYPE_BYTE:
310 		se_value->value_type = SE_DATA_TYPE_BYTE;
311 		(void) nvpair_value_byte(nvp, &se_value->value.sv_byte);
312 		break;
313 	case DATA_TYPE_INT16:
314 		se_value->value_type = SE_DATA_TYPE_INT16;
315 		(void) nvpair_value_int16(nvp, &se_value->value.sv_int16);
316 		break;
317 	case DATA_TYPE_UINT16:
318 		se_value->value_type = SE_DATA_TYPE_UINT16;
319 		(void) nvpair_value_uint16(nvp, &se_value->value.sv_uint16);
320 		break;
321 	case DATA_TYPE_INT32:
322 		se_value->value_type = SE_DATA_TYPE_INT32;
323 		(void) nvpair_value_int32(nvp, &se_value->value.sv_int32);
324 		break;
325 	case DATA_TYPE_UINT32:
326 		se_value->value_type = SE_DATA_TYPE_UINT32;
327 		(void) nvpair_value_uint32(nvp, &se_value->value.sv_uint32);
328 		break;
329 	case DATA_TYPE_INT64:
330 		se_value->value_type = SE_DATA_TYPE_INT64;
331 		(void) nvpair_value_int64(nvp, &se_value->value.sv_int64);
332 		break;
333 	case DATA_TYPE_UINT64:
334 		se_value->value_type = SE_DATA_TYPE_UINT64;
335 		(void) nvpair_value_uint64(nvp, &se_value->value.sv_uint64);
336 		break;
337 	case DATA_TYPE_STRING:
338 		se_value->value_type = SE_DATA_TYPE_STRING;
339 		(void) nvpair_value_string(nvp, &se_value->value.sv_string);
340 		break;
341 	case DATA_TYPE_BYTE_ARRAY:
342 		se_value->value_type = SE_DATA_TYPE_BYTES;
343 		(void) nvpair_value_byte_array(nvp,
344 		    &se_value->value.sv_bytes.data,
345 		    (uint_t *)&se_value->value.sv_bytes.size);
346 		break;
347 	case DATA_TYPE_HRTIME:
348 		se_value->value_type = SE_DATA_TYPE_TIME;
349 		(void) nvpair_value_hrtime(nvp, &se_value->value.sv_time);
350 		break;
351 	default:
352 		return (ENOTSUP);
353 	}
354 	return (0);
355 }
356 
357 /*
358  * sysevent_attr_next - Get next attribute in event attribute list
359  */
360 sysevent_attr_t *
361 sysevent_attr_next(sysevent_t *ev, sysevent_attr_t *attr)
362 {
363 	nvlist_t *nvl;
364 	nvpair_t *nvp = attr;
365 
366 	/* all user visible sysevent_t's are unpacked */
367 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
368 
369 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
370 		return (NULL);
371 	}
372 
373 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
374 	return (nvlist_next_nvpair(nvl, nvp));
375 }
376 
377 /*
378  * sysevent_lookup_attr - Lookup attribute by name and datatype.
379  */
380 int
381 sysevent_lookup_attr(sysevent_t *ev, char *name, int datatype,
382 	sysevent_value_t *se_value)
383 {
384 	nvpair_t *nvp;
385 	nvlist_t *nvl;
386 
387 	assert(SE_FLAG(ev) != SE_PACKED_BUF);
388 
389 	if (SE_ATTR_PTR(ev) == (uint64_t)0) {
390 		return (ENOENT);
391 	}
392 
393 	/*
394 	 * sysevent matches on both name and datatype
395 	 * nvlist_look mataches name only. So we walk
396 	 * nvlist manually here.
397 	 */
398 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
399 	nvp = nvlist_next_nvpair(nvl, NULL);
400 	while (nvp) {
401 		if ((strcmp(name, nvpair_name(nvp)) == 0) &&
402 		    (sysevent_attr_value(nvp, se_value) == 0) &&
403 		    (se_value->value_type == datatype))
404 			return (0);
405 		nvp = nvlist_next_nvpair(nvl, nvp);
406 	}
407 	return (ENOENT);
408 }
409 
410 /* Routines to extract event header information */
411 
412 /*
413  * sysevent_get_class - Get class id
414  */
415 int
416 sysevent_get_class(sysevent_t *ev)
417 {
418 	return (SE_CLASS(ev));
419 }
420 
421 /*
422  * sysevent_get_subclass - Get subclass id
423  */
424 int
425 sysevent_get_subclass(sysevent_t *ev)
426 {
427 	return (SE_SUBCLASS(ev));
428 }
429 
430 /*
431  * sysevent_get_class_name - Get class name string
432  */
433 char *
434 sysevent_get_class_name(sysevent_t *ev)
435 {
436 	return (SE_CLASS_NAME(ev));
437 }
438 
439 typedef enum {
440 	PUB_VEND,
441 	PUB_KEYWD,
442 	PUB_NAME,
443 	PUB_PID
444 } se_pub_id_t;
445 
446 /*
447  * sysevent_get_pub - Get publisher name string
448  */
449 char *
450 sysevent_get_pub(sysevent_t *ev)
451 {
452 	return (SE_PUB_NAME(ev));
453 }
454 
455 /*
456  * Get the requested string pointed by the token.
457  *
458  * Return NULL if not found or for insufficient memory.
459  */
460 static char *
461 parse_pub_id(sysevent_t *ev, se_pub_id_t token)
462 {
463 	int i;
464 	char *pub_id, *pub_element, *str, *next;
465 
466 	next = pub_id = strdup(sysevent_get_pub(ev));
467 	for (i = 0; i <= token; ++i) {
468 		str = strtok_r(next, ":", &next);
469 		if (str == NULL) {
470 			free(pub_id);
471 			return (NULL);
472 		}
473 	}
474 
475 	pub_element = strdup(str);
476 	free(pub_id);
477 	return (pub_element);
478 }
479 
480 /*
481  * Return a pointer to the string following the token
482  *
483  * Note: This is a dedicated function for parsing
484  * publisher strings and not for general purpose.
485  */
486 static const char *
487 pub_idx(const char *pstr, int token)
488 {
489 	int i;
490 
491 	for (i = 1; i <= token; i++) {
492 		if ((pstr = index(pstr, ':')) == NULL)
493 			return (NULL);
494 		pstr++;
495 	}
496 
497 	/* String might be empty */
498 	if (pstr) {
499 		if (*pstr == '\0' || *pstr == ':')
500 			return (NULL);
501 	}
502 	return (pstr);
503 }
504 
505 char *
506 sysevent_get_vendor_name(sysevent_t *ev)
507 {
508 	return (parse_pub_id(ev, PUB_VEND));
509 }
510 
511 char *
512 sysevent_get_pub_name(sysevent_t *ev)
513 {
514 	return (parse_pub_id(ev, PUB_NAME));
515 }
516 
517 /*
518  * Provide the pid encoded in the publisher string
519  * w/o allocating any resouces.
520  */
521 void
522 sysevent_get_pid(sysevent_t *ev, pid_t *pid)
523 {
524 	const char *part_str;
525 	const char *pub_str = sysevent_get_pub(ev);
526 
527 	*pid = (pid_t)SE_KERN_PID;
528 
529 	part_str = pub_idx(pub_str, PUB_KEYWD);
530 	if (part_str != NULL && strstr(part_str, SE_KERN_PUB) != NULL)
531 		return;
532 
533 	if ((part_str = pub_idx(pub_str, PUB_PID)) == NULL)
534 		return;
535 
536 	*pid = (pid_t)atoi(part_str);
537 }
538 
539 /*
540  * sysevent_get_subclass_name - Get subclass name string
541  */
542 char *
543 sysevent_get_subclass_name(sysevent_t *ev)
544 {
545 	return (SE_SUBCLASS_NAME(ev));
546 }
547 
548 /*
549  * sysevent_get_seq - Get event sequence id
550  */
551 uint64_t
552 sysevent_get_seq(sysevent_t *ev)
553 {
554 	return (SE_SEQ(ev));
555 }
556 
557 /*
558  * sysevent_get_time - Get event timestamp
559  */
560 void
561 sysevent_get_time(sysevent_t *ev, hrtime_t *etime)
562 {
563 	*etime = SE_TIME(ev);
564 }
565 
566 /*
567  * sysevent_get_size - Get event buffer size
568  */
569 size_t
570 sysevent_get_size(sysevent_t *ev)
571 {
572 	return ((size_t)SE_SIZE(ev));
573 }
574 
575 /*
576  * The following routines are used by devfsadm_mod.c to propagate event
577  * buffers to devfsadmd.  These routines will serve as the basis for
578  * event channel publication and subscription.
579  */
580 
581 /*
582  * sysevent_alloc_event -
583  *	allocate a sysevent buffer for sending through an established event
584  *	channel.
585  */
586 sysevent_t *
587 sysevent_alloc_event(char *class, char *subclass, char *vendor, char *pub_name,
588 	nvlist_t *attr_list)
589 {
590 	int class_sz, subclass_sz, pub_sz;
591 	char *pub_id;
592 	sysevent_t *ev;
593 
594 	if ((class == NULL) || (subclass == NULL) || (vendor == NULL) ||
595 	    (pub_name == NULL)) {
596 		errno = EINVAL;
597 		return (NULL);
598 	}
599 
600 	class_sz = strlen(class) + 1;
601 	subclass_sz = strlen(subclass) + 1;
602 	if ((class_sz > MAX_CLASS_LEN) ||
603 	    (subclass_sz > MAX_SUBCLASS_LEN)) {
604 		errno = EINVAL;
605 		return (NULL);
606 	}
607 
608 	/*
609 	 * Calculate the publisher size plus string seperators and maximum
610 	 * pid characters
611 	 */
612 	pub_sz = strlen(vendor) + sizeof (SE_USR_PUB) + strlen(pub_name) + 14;
613 	if (pub_sz > MAX_PUB_LEN) {
614 		errno = EINVAL;
615 		return (NULL);
616 	}
617 	pub_id = malloc(pub_sz);
618 	if (pub_id == NULL) {
619 		errno = ENOMEM;
620 		return (NULL);
621 	}
622 	if (snprintf(pub_id, pub_sz, "%s:%s%s:%d", vendor, SE_USR_PUB,
623 	    pub_name, (int)getpid()) >= pub_sz) {
624 		free(pub_id);
625 		errno = EINVAL;
626 		return (NULL);
627 	}
628 	pub_sz = strlen(pub_id) + 1;
629 
630 	ev = sysevent_alloc(class, class_sz, subclass, subclass_sz,
631 	    pub_id, pub_sz, attr_list);
632 	free(pub_id);
633 	if (ev == NULL) {
634 		errno = ENOMEM;
635 		return (NULL);
636 	}
637 
638 	return (ev);
639 }
640 
641 /*
642  * se_unpack - unpack nvlist to a searchable list.
643  *	If already unpacked, will do a dup.
644  */
645 static sysevent_t *
646 se_unpack(sysevent_t *ev)
647 {
648 	caddr_t attr;
649 	size_t attr_len;
650 	nvlist_t *attrp = NULL;
651 	uint64_t attr_offset;
652 	sysevent_t *copy;
653 
654 	assert(SE_FLAG(ev) == SE_PACKED_BUF);
655 
656 	/* Copy event header information */
657 	attr_offset = SE_ATTR_OFF(ev);
658 	copy = calloc(1, attr_offset);
659 	if (copy == NULL)
660 		return (NULL);
661 	bcopy(ev, copy, attr_offset);
662 	SE_FLAG(copy) = 0;	/* unpacked */
663 
664 	/* unpack nvlist */
665 	attr = (caddr_t)ev + attr_offset;
666 	attr_len = SE_SIZE(ev) - attr_offset;
667 	if (attr_len == 0) {
668 		return (copy);
669 	}
670 	if (nvlist_unpack(attr, attr_len, &attrp, 0) != 0) {
671 		free(copy);
672 		return (NULL);
673 	}
674 
675 	SE_ATTR_PTR(copy) = (uintptr_t)attrp;
676 	return (copy);
677 }
678 
679 /*
680  * se_print - Prints elements in an event buffer
681  */
682 void
683 se_print(FILE *fp, sysevent_t *ev)
684 {
685 	char *vendor, *pub;
686 	pid_t pid;
687 	hrtime_t hrt;
688 	nvlist_t *attr_list = NULL;
689 
690 	(void) sysevent_get_time(ev, &hrt);
691 	(void) fprintf(fp, "received sysevent id = 0X%llx:%llx\n",
692 	    hrt, (longlong_t)sysevent_get_seq(ev));
693 	(void) fprintf(fp, "\tclass = %s\n", sysevent_get_class_name(ev));
694 	(void) fprintf(fp, "\tsubclass = %s\n", sysevent_get_subclass_name(ev));
695 	if ((vendor =  sysevent_get_vendor_name(ev)) != NULL) {
696 		(void) fprintf(fp, "\tvendor = %s\n", vendor);
697 		free(vendor);
698 	}
699 	if ((pub = sysevent_get_pub_name(ev)) != NULL) {
700 		sysevent_get_pid(ev, &pid);
701 		(void) fprintf(fp, "\tpublisher = %s:%d\n", pub, (int)pid);
702 		free(pub);
703 	}
704 
705 	if (sysevent_get_attr_list(ev, &attr_list) == 0 && attr_list != NULL) {
706 		nvlist_print(fp, attr_list);
707 		nvlist_free(attr_list);
708 	}
709 }
710 
711 /*
712  * The following routines are provided to support establishment and use
713  * of sysevent channels.  A sysevent channel is established between
714  * publishers and subscribers of sysevents for an agreed upon channel name.
715  * These routines currently support sysevent channels between user-level
716  * applications running on the same system.
717  *
718  * Sysevent channels may be created by a single publisher or subscriber process.
719  * Once established, up to MAX_SUBSRCIBERS subscribers may subscribe interest in
720  * receiving sysevent notifications on the named channel.  At present, only
721  * one publisher is allowed per sysevent channel.
722  *
723  * The registration information for each channel is kept in the kernel.  A
724  * kernel-based registration was chosen for persistence and reliability reasons.
725  * If either a publisher or a subscriber exits for any reason, the channel
726  * properties are maintained until all publishers and subscribers have exited.
727  * Additionally, an in-kernel registration allows the API to be extended to
728  * include kernel subscribers as well as userland subscribers in the future.
729  *
730  * To insure fast lookup of subscriptions, a cached copy of the registration
731  * is kept and maintained for the publisher process.  Updates are made
732  * everytime a change is made in the kernel.  Changes to the registration are
733  * expected to be infrequent.
734  *
735  * Channel communication between publisher and subscriber processes is
736  * implemented primarily via doors.  Each publisher creates a door for
737  * registration notifications and each subscriber creates a door for event
738  * delivery.
739  *
740  * Most of these routines are used by syseventd(1M), the sysevent publisher
741  * for the syseventd channel.  Processes wishing to receive sysevent
742  * notifications from syseventd may use a set of public
743  * APIs designed to subscribe to syseventd sysevents.  The subscription
744  * APIs are implemented in accordance with PSARC/2001/076.
745  *
746  */
747 
748 /*
749  * Door handlers for the channel subscribers
750  */
751 
752 /*
753  * subscriber_event_handler - generic event handling wrapper for subscribers
754  *			This handler is used to process incoming sysevent
755  *			notifications from channel publishers.
756  *			It is created as a seperate thread in each subscriber
757  *			process per subscription.
758  */
759 static void
760 subscriber_event_handler(sysevent_handle_t *shp)
761 {
762 	subscriber_priv_t *sub_info;
763 	sysevent_queue_t *evqp;
764 
765 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
766 
767 	/* See hack alert in sysevent_bind_subscriber_cmn */
768 	if (sub_info->sp_handler_tid == NULL)
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;
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 	if (nvl)
1466 		nvlist_free(nvl);
1467 	return (-1);
1468 
1469 }
1470 
1471 /*
1472  * cache_update_service - generic event publisher service routine.  This routine
1473  *		is called in response to a registration cache update.
1474  *
1475  */
1476 /*ARGSUSED*/
1477 static void
1478 cache_update_service(void *cookie, char *args, size_t alen,
1479     door_desc_t *ddp, uint_t ndid)
1480 {
1481 	int ret = 0;
1482 	uint_t num_elem;
1483 	char *class, **event_list;
1484 	size_t datalen;
1485 	uint32_t sub_id;
1486 	nvlist_t *nvl;
1487 	nvpair_t *nvpair = NULL;
1488 	struct reg_args *rargs;
1489 	sysevent_handle_t *shp;
1490 	subscriber_data_t *sub;
1491 
1492 	if (alen < sizeof (struct reg_args) || cookie == NULL) {
1493 		ret = EINVAL;
1494 		goto return_from_door;
1495 	}
1496 
1497 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
1498 	rargs = (struct reg_args *)args;
1499 	shp = (sysevent_handle_t *)cookie;
1500 
1501 	datalen = alen - sizeof (struct reg_args);
1502 	sub_id = rargs->ra_sub_id;
1503 
1504 	(void) mutex_lock(SH_LOCK(shp));
1505 
1506 	switch (rargs->ra_op) {
1507 	case SE_UNREGISTER:
1508 		class = (char *)&rargs->ra_buf_ptr;
1509 		cache_remove_class(shp, (char *)class,
1510 		    sub_id);
1511 		break;
1512 	case SE_UNBIND_REGISTRATION:
1513 
1514 		sub = SH_SUBSCRIBER(shp, sub_id);
1515 		if (sub == NULL)
1516 			break;
1517 
1518 		free(sub->sd_door_name);
1519 		free(sub);
1520 		cache_remove_class(shp, EC_ALL, sub_id);
1521 		SH_SUBSCRIBER(shp, sub_id) = NULL;
1522 
1523 		break;
1524 	case SE_BIND_REGISTRATION:
1525 
1526 		/* New subscriber */
1527 		if (alloc_subscriber(shp, sub_id, 0) != 0) {
1528 			ret = ENOMEM;
1529 			break;
1530 		}
1531 		break;
1532 	case SE_REGISTER:
1533 
1534 		if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
1535 			ret = EINVAL;
1536 			break;
1537 		}
1538 		/* Get new registration data */
1539 		if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
1540 		    &nvl, 0) != 0) {
1541 			ret =  EFAULT;
1542 			break;
1543 		}
1544 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1545 			nvlist_free(nvl);
1546 			ret = EFAULT;
1547 			break;
1548 		}
1549 		if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
1550 		    != 0) {
1551 			nvlist_free(nvl);
1552 			ret =  EFAULT;
1553 			break;
1554 		}
1555 		class = nvpair_name(nvpair);
1556 
1557 		ret = cache_insert_class(shp, class,
1558 		    event_list, num_elem, sub_id);
1559 		if (ret != 0) {
1560 			cache_remove_class(shp, class, sub_id);
1561 			nvlist_free(nvl);
1562 			ret =  EFAULT;
1563 			break;
1564 		}
1565 
1566 		nvlist_free(nvl);
1567 
1568 		break;
1569 	case SE_CLEANUP:
1570 		/* Cleanup stale subscribers */
1571 		sysevent_cleanup_subscribers(shp);
1572 		break;
1573 	default:
1574 		ret =  EINVAL;
1575 	}
1576 
1577 	(void) mutex_unlock(SH_LOCK(shp));
1578 
1579 return_from_door:
1580 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
1581 	(void) door_return(NULL, 0, NULL, 0);
1582 }
1583 
1584 /*
1585  * sysevent_send_event -
1586  * Send an event via the communication channel associated with the sysevent
1587  * handle.  Event notifications are broadcast to all subscribers based upon
1588  * the event class and subclass.  The handle must have been previously
1589  * allocated and bound by
1590  * sysevent_open_channel() and sysevent_bind_publisher()
1591  */
1592 int
1593 sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
1594 {
1595 	int i, error, sub_fd, result = 0;
1596 	int deliver_error = 0;
1597 	int subscribers_sent = 0;
1598 	int want_resend, resend_cnt = 0;
1599 	char *event_class, *event_subclass;
1600 	uchar_t *all_class_subscribers, *all_subclass_subscribers;
1601 	uchar_t *subclass_subscribers;
1602 	subscriber_data_t *sub;
1603 	subclass_lst_t *sc_lst;
1604 
1605 	/* Check for proper registration */
1606 	event_class = sysevent_get_class_name(ev);
1607 	event_subclass = sysevent_get_subclass_name(ev);
1608 
1609 	(void) mutex_lock(SH_LOCK(shp));
1610 
1611 send_event:
1612 
1613 	want_resend = 0;
1614 	if (!SH_BOUND(shp)) {
1615 		(void) mutex_unlock(SH_LOCK(shp));
1616 		errno = EINVAL;
1617 		return (-1);
1618 	}
1619 
1620 	/* Find all subscribers for this event class/subclass */
1621 	sc_lst = cache_find_subclass(
1622 	    cache_find_class(shp, EC_ALL), EC_SUB_ALL);
1623 	all_class_subscribers = sc_lst->sl_num;
1624 
1625 	sc_lst = cache_find_subclass(
1626 	    cache_find_class(shp, event_class), EC_SUB_ALL);
1627 	if (sc_lst)
1628 		all_subclass_subscribers = sc_lst->sl_num;
1629 	else
1630 		all_subclass_subscribers = NULL;
1631 
1632 	sc_lst = cache_find_subclass(
1633 	    cache_find_class(shp, event_class), event_subclass);
1634 	if (sc_lst)
1635 		subclass_subscribers = sc_lst->sl_num;
1636 	else
1637 		subclass_subscribers = NULL;
1638 
1639 	/* Send event buffer to all valid subscribers */
1640 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1641 		if ((all_class_subscribers[i] |
1642 		    (all_subclass_subscribers && all_subclass_subscribers[i]) |
1643 		    (subclass_subscribers && subclass_subscribers[i])) == 0)
1644 			continue;
1645 
1646 		sub = SH_SUBSCRIBER(shp, i);
1647 		assert(sub != NULL);
1648 
1649 		/* Check for active subscriber */
1650 		if (!(sub->sd_flag & ACTIVE)) {
1651 			dprint("sysevent_send_event: subscriber %d inactive\n",
1652 			    i);
1653 			continue;
1654 		}
1655 
1656 		/* Process only resend requests */
1657 		if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
1658 			continue;
1659 		}
1660 
1661 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
1662 			dprint("sysevent_send_event: Failed to open "
1663 			    "%s: %s\n", sub->sd_door_name, strerror(errno));
1664 			continue;
1665 		}
1666 		result = 0;
1667 		error = clnt_deliver_event(sub_fd, ev,
1668 		    sysevent_get_size(ev), &result, sizeof (result));
1669 
1670 		(void) close(sub_fd);
1671 
1672 		/* Successful door call */
1673 		if (error == 0) {
1674 			switch (result) {
1675 			/* Subscriber requested EAGAIN */
1676 			case EAGAIN:
1677 				if (resend_cnt > SE_MAX_RETRY_LIMIT) {
1678 					deliver_error = 1;
1679 				} else {
1680 					want_resend = 1;
1681 					dprint("sysevent_send_event: resend "
1682 					    "requested for %d\n", i);
1683 					sub->sd_flag |= SEND_AGAIN;
1684 				}
1685 				break;
1686 			/* Bad sysevent handle for subscriber */
1687 			case EBADF:
1688 			case EINVAL:
1689 				dprint("sysevent_send_event: Bad sysevent "
1690 				    "handle for %s", sub->sd_door_name);
1691 				sub->sd_flag = 0;
1692 				deliver_error = 1;
1693 				break;
1694 			/* Successful delivery */
1695 			default:
1696 				sub->sd_flag &= ~SEND_AGAIN;
1697 				++subscribers_sent;
1698 			}
1699 		} else {
1700 			dprint("sysevent_send_event: Failed door call "
1701 			    "to %s: %s: %d\n", sub->sd_door_name,
1702 			    strerror(errno), result);
1703 			sub->sd_flag = 0;
1704 			deliver_error = 1;
1705 		}
1706 	}
1707 
1708 	if (want_resend) {
1709 		resend_cnt++;
1710 		goto send_event;
1711 	}
1712 
1713 	if (deliver_error) {
1714 		sysevent_cleanup_subscribers(shp);
1715 		(void) mutex_unlock(SH_LOCK(shp));
1716 		errno = EFAULT;
1717 		return (-1);
1718 	}
1719 
1720 	(void) mutex_unlock(SH_LOCK(shp));
1721 
1722 	if (subscribers_sent == 0) {
1723 		dprint("sysevent_send_event: No subscribers for %s:%s\n",
1724 		    event_class, event_subclass);
1725 		errno = ENOENT;
1726 		return (-1);
1727 	}
1728 
1729 	return (0);
1730 }
1731 
1732 /*
1733  * Common routine to establish an event channel through which an event
1734  * publisher or subscriber may post or receive events.
1735  */
1736 static sysevent_handle_t *
1737 sysevent_open_channel_common(const char *channel_path)
1738 {
1739 	uint32_t sub_id = 0;
1740 	char *begin_path;
1741 	struct stat chan_stat;
1742 	sysevent_handle_t *shp;
1743 
1744 
1745 	if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
1746 		errno = EINVAL;
1747 		return (NULL);
1748 	}
1749 
1750 	if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1751 		if (errno != EEXIST) {
1752 			errno = EACCES;
1753 			return (NULL);
1754 		}
1755 	}
1756 
1757 	/* Check channel file permissions */
1758 	if (stat(channel_path, &chan_stat) != 0) {
1759 		dprint("sysevent_open_channel: Invalid permissions for channel "
1760 		    "%s\n", channel_path);
1761 		errno = EACCES;
1762 		return (NULL);
1763 	} else if (chan_stat.st_uid != getuid() ||
1764 	    !S_ISDIR(chan_stat.st_mode)) {
1765 		dprint("sysevent_open_channel: Invalid "
1766 		    "permissions for channel %s\n: %d:%d:%d", channel_path,
1767 		    (int)chan_stat.st_uid, (int)chan_stat.st_gid,
1768 		    (int)chan_stat.st_mode);
1769 
1770 		errno = EACCES;
1771 		return (NULL);
1772 	}
1773 
1774 	shp = calloc(1, sizeof (sysevent_impl_hdl_t));
1775 	if (shp == NULL) {
1776 		errno = ENOMEM;
1777 		return (NULL);
1778 	}
1779 
1780 	SH_CHANNEL_NAME(shp) = NULL;
1781 	SH_CHANNEL_PATH(shp) = strdup(channel_path);
1782 	if (SH_CHANNEL_PATH(shp) == NULL) {
1783 		free(shp);
1784 		errno = ENOMEM;
1785 		return (NULL);
1786 	}
1787 
1788 	/* Extract the channel name */
1789 	begin_path = SH_CHANNEL_PATH(shp);
1790 	while (*begin_path != '\0' &&
1791 	    (begin_path = strpbrk(begin_path, "/")) != NULL) {
1792 		++begin_path;
1793 		SH_CHANNEL_NAME(shp) = begin_path;
1794 	}
1795 
1796 	if (update_kernel_registration(shp, 0,
1797 	    SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
1798 		dprint("sysevent_open_channel: Failed for channel %s\n",
1799 		    SH_CHANNEL_NAME(shp));
1800 		free(SH_CHANNEL_PATH(shp));
1801 		free(shp);
1802 		errno = EFAULT;
1803 		return (NULL);
1804 	}
1805 
1806 	(void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
1807 
1808 	return (shp);
1809 }
1810 
1811 /*
1812  * Establish a sysevent channel for publication and subscription
1813  */
1814 sysevent_handle_t *
1815 sysevent_open_channel(const char *channel)
1816 {
1817 	int var_run_mounted = 0;
1818 	char full_channel[MAXPATHLEN + 1];
1819 	FILE *fp;
1820 	struct stat chan_stat;
1821 	struct extmnttab m;
1822 
1823 	if (channel == NULL) {
1824 		errno = EINVAL;
1825 		return (NULL);
1826 	}
1827 
1828 	/*
1829 	 * Check that /var/run is mounted as tmpfs before allowing a channel
1830 	 * to be opened.
1831 	 */
1832 	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
1833 		errno = EACCES;
1834 		return (NULL);
1835 	}
1836 
1837 	resetmnttab(fp);
1838 
1839 	while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
1840 		if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
1841 		    strcmp(m.mnt_fstype, "tmpfs") == 0) {
1842 			var_run_mounted = 1;
1843 			break;
1844 		}
1845 	}
1846 	(void) fclose(fp);
1847 
1848 	if (!var_run_mounted) {
1849 		errno = EACCES;
1850 		return (NULL);
1851 	}
1852 
1853 	if (stat(CHAN_PATH, &chan_stat) < 0) {
1854 		if (mkdir(CHAN_PATH,
1855 		    S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1856 			dprint("sysevent_open_channel: Unable "
1857 			    "to create channel directory %s:%s\n", CHAN_PATH,
1858 			    strerror(errno));
1859 			if (errno != EEXIST) {
1860 				errno = EACCES;
1861 				return (NULL);
1862 			}
1863 		}
1864 	}
1865 
1866 	if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
1867 	    MAXPATHLEN) {
1868 		errno = EINVAL;
1869 		return (NULL);
1870 	}
1871 
1872 	return (sysevent_open_channel_common(full_channel));
1873 }
1874 
1875 /*
1876  * Establish a sysevent channel for publication and subscription
1877  * Full path to the channel determined by the caller
1878  */
1879 sysevent_handle_t *
1880 sysevent_open_channel_alt(const char *channel_path)
1881 {
1882 	return (sysevent_open_channel_common(channel_path));
1883 }
1884 
1885 /*
1886  * sysevent_close_channel - Clean up resources associated with a previously
1887  *				opened sysevent channel
1888  */
1889 void
1890 sysevent_close_channel(sysevent_handle_t *shp)
1891 {
1892 	int error = errno;
1893 	uint32_t sub_id = 0;
1894 
1895 	if (shp == NULL) {
1896 		return;
1897 	}
1898 
1899 	(void) mutex_lock(SH_LOCK(shp));
1900 	if (SH_BOUND(shp)) {
1901 		(void) mutex_unlock(SH_LOCK(shp));
1902 		if (SH_TYPE(shp) == PUBLISHER)
1903 			sysevent_unbind_publisher(shp);
1904 		else if (SH_TYPE(shp) == SUBSCRIBER)
1905 			sysevent_unbind_subscriber(shp);
1906 		(void) mutex_lock(SH_LOCK(shp));
1907 	}
1908 
1909 	(void) update_kernel_registration(shp, 0,
1910 	    SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
1911 	(void) mutex_unlock(SH_LOCK(shp));
1912 
1913 	free(SH_CHANNEL_PATH(shp));
1914 	free(shp);
1915 	errno = error;
1916 }
1917 
1918 /*
1919  * sysevent_bind_publisher - Bind an event publisher to an event channel
1920  */
1921 int
1922 sysevent_bind_publisher(sysevent_handle_t *shp)
1923 {
1924 	int error = 0;
1925 	int fd = -1;
1926 	char door_name[MAXPATHLEN];
1927 	uint32_t pub_id;
1928 	struct stat reg_stat;
1929 	publisher_priv_t *pub;
1930 
1931 	if (shp == NULL) {
1932 		errno = EINVAL;
1933 		return (-1);
1934 	}
1935 
1936 	(void) mutex_lock(SH_LOCK(shp));
1937 	if (SH_BOUND(shp)) {
1938 		(void) mutex_unlock(SH_LOCK(shp));
1939 		errno = EINVAL;
1940 		return (-1);
1941 	}
1942 
1943 	if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
1944 	    NULL) {
1945 		(void) mutex_unlock(SH_LOCK(shp));
1946 		errno = ENOMEM;
1947 		return (-1);
1948 	}
1949 	SH_PRIV_DATA(shp) = (void *)pub;
1950 
1951 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
1952 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
1953 		free(pub);
1954 		(void) mutex_unlock(SH_LOCK(shp));
1955 		errno = ENOMEM;
1956 		return (-1);
1957 	}
1958 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
1959 		free(pub);
1960 		(void) mutex_unlock(SH_LOCK(shp));
1961 		errno = ENOMEM;
1962 		return (-1);
1963 	}
1964 
1965 	/* Only one publisher allowed per channel */
1966 	if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
1967 		if (errno != ENOENT) {
1968 			error = EINVAL;
1969 			goto fail;
1970 		}
1971 	}
1972 
1973 	/*
1974 	 * Remove door file for robustness.
1975 	 */
1976 	if (unlink(SH_DOOR_NAME(shp)) != 0)
1977 		dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
1978 		    SH_DOOR_NAME(shp));
1979 
1980 	/* Open channel registration door */
1981 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
1982 	    S_IREAD|S_IWRITE);
1983 	if (fd == -1) {
1984 		error = EINVAL;
1985 		goto fail;
1986 	}
1987 
1988 	/*
1989 	 * Create the registration service for this publisher.
1990 	 */
1991 	if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
1992 	    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1993 		dprint("sysevent_bind_publisher: door create failed: "
1994 		    "%s\n", strerror(errno));
1995 		error = EFAULT;
1996 		goto fail;
1997 	}
1998 
1999 	(void) fdetach(SH_DOOR_NAME(shp));
2000 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2001 		dprint("sysevent_bind_publisher: unable to "
2002 		    "bind event channel: fattach: %s\n",
2003 		    SH_DOOR_NAME(shp));
2004 		error = EACCES;
2005 		goto fail;
2006 	}
2007 
2008 	/* Bind this publisher in the kernel registration database */
2009 	if (update_kernel_registration(shp, PUBLISHER,
2010 	    SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
2011 		error = errno;
2012 		goto fail;
2013 	}
2014 
2015 	SH_ID(shp) = pub_id;
2016 	SH_BOUND(shp) = 1;
2017 	SH_TYPE(shp) = PUBLISHER;
2018 
2019 
2020 	/* Create the subscription registration cache */
2021 	if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
2022 		(void) update_kernel_registration(shp,
2023 		    PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
2024 		error = EFAULT;
2025 		goto fail;
2026 	}
2027 	(void) close(fd);
2028 
2029 	(void) mutex_unlock(SH_LOCK(shp));
2030 
2031 	return (0);
2032 
2033 fail:
2034 	SH_BOUND(shp) = 0;
2035 	(void) door_revoke(SH_DOOR_DESC(shp));
2036 	(void) fdetach(SH_DOOR_NAME(shp));
2037 	free(SH_DOOR_NAME(shp));
2038 	free(pub);
2039 	(void) close(fd);
2040 	(void) mutex_unlock(SH_LOCK(shp));
2041 	errno = error;
2042 	return (-1);
2043 }
2044 
2045 static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2046 static pthread_attr_t xdoor_thrattr;
2047 
2048 static void
2049 xdoor_thrattr_init(void)
2050 {
2051 	(void) pthread_attr_init(&xdoor_thrattr);
2052 	(void) pthread_attr_setdetachstate(&xdoor_thrattr,
2053 	    PTHREAD_CREATE_DETACHED);
2054 	(void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2055 }
2056 
2057 static int
2058 xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2059     void *startfarg, void *cookie)
2060 {
2061 	struct sysevent_subattr_impl *xsa = cookie;
2062 	pthread_attr_t *thrattr;
2063 	sigset_t oset;
2064 	int err;
2065 
2066 	if (xsa->xs_thrcreate) {
2067 		return (xsa->xs_thrcreate(dip, startf, startfarg,
2068 		    xsa->xs_thrcreate_cookie));
2069 	}
2070 
2071 	if (xsa->xs_thrattr == NULL) {
2072 		(void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2073 		thrattr = &xdoor_thrattr;
2074 	} else {
2075 		thrattr = xsa->xs_thrattr;
2076 	}
2077 
2078 	(void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2079 	err = pthread_create(NULL, thrattr, startf, startfarg);
2080 	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2081 
2082 	return (err == 0 ? 1 : -1);
2083 }
2084 
2085 static void
2086 xdoor_server_setup(void *cookie)
2087 {
2088 	struct sysevent_subattr_impl *xsa = cookie;
2089 
2090 	if (xsa->xs_thrsetup) {
2091 		xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2092 	} else {
2093 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2094 		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2095 	}
2096 }
2097 
2098 static int
2099 sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
2100 	void (*event_handler)(sysevent_t *ev),
2101 	sysevent_subattr_t *subattr)
2102 {
2103 	int fd = -1;
2104 	int error = 0;
2105 	uint32_t sub_id = 0;
2106 	char door_name[MAXPATHLEN];
2107 	subscriber_priv_t *sub_info;
2108 	int created;
2109 	struct sysevent_subattr_impl *xsa =
2110 	    (struct sysevent_subattr_impl *)subattr;
2111 
2112 	if (shp == NULL || event_handler == NULL) {
2113 		errno = EINVAL;
2114 		return (-1);
2115 	}
2116 
2117 	(void) mutex_lock(SH_LOCK(shp));
2118 	if (SH_BOUND(shp)) {
2119 		errno = EINVAL;
2120 		(void) mutex_unlock(SH_LOCK(shp));
2121 		return (-1);
2122 	}
2123 
2124 	if ((sub_info = (subscriber_priv_t *)calloc(1,
2125 	    sizeof (subscriber_priv_t))) == NULL) {
2126 		errno = ENOMEM;
2127 		(void) mutex_unlock(SH_LOCK(shp));
2128 		return (-1);
2129 	}
2130 
2131 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2132 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2133 		free(sub_info);
2134 		errno = EINVAL;
2135 		(void) mutex_unlock(SH_LOCK(shp));
2136 		return (-1);
2137 	}
2138 
2139 	if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
2140 		free(sub_info);
2141 		errno = ENOMEM;
2142 		(void) mutex_unlock(SH_LOCK(shp));
2143 		return (-1);
2144 	}
2145 	(void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
2146 	(void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
2147 	sub_info->sp_func = event_handler;
2148 
2149 	/* Update the in-kernel registration */
2150 	if (update_kernel_registration(shp, SUBSCRIBER,
2151 	    SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
2152 		error = errno;
2153 		goto fail;
2154 	}
2155 	SH_ID(shp) = sub_id;
2156 
2157 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
2158 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
2159 		error = EINVAL;
2160 		goto fail;
2161 	}
2162 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
2163 		error = ENOMEM;
2164 		goto fail;
2165 	}
2166 
2167 	/*
2168 	 * Remove door file for robustness.
2169 	 */
2170 	if (unlink(SH_DOOR_NAME(shp)) != 0)
2171 		dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
2172 		    SH_DOOR_NAME(shp));
2173 
2174 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
2175 	if (fd == -1) {
2176 		error = EFAULT;
2177 		goto fail;
2178 	}
2179 
2180 	/*
2181 	 * Create the sysevent door service for this client.
2182 	 * syseventd will use this door service to propagate
2183 	 * events to the client.
2184 	 */
2185 	if (subattr == NULL) {
2186 		SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2187 		    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2188 	} else {
2189 		SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2190 		    (void *)shp,
2191 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2192 		    xdoor_server_create, xdoor_server_setup,
2193 		    (void *)subattr, 1);
2194 	}
2195 
2196 	if (SH_DOOR_DESC(shp) == -1) {
2197 		dprint("sysevent_bind_subscriber: door create failed: "
2198 		    "%s\n", strerror(errno));
2199 		error = EFAULT;
2200 		goto fail;
2201 	}
2202 
2203 	(void) fdetach(SH_DOOR_NAME(shp));
2204 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2205 		error = EFAULT;
2206 		goto fail;
2207 	}
2208 	(void) close(fd);
2209 
2210 	if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
2211 	    sub_id, 0, NULL) != 0) {
2212 		error = errno;
2213 		(void) update_kernel_registration(shp, SUBSCRIBER,
2214 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2215 		goto fail;
2216 	}
2217 
2218 	SH_BOUND(shp) = 1;
2219 	SH_TYPE(shp) = SUBSCRIBER;
2220 	SH_PRIV_DATA(shp) = (void *)sub_info;
2221 
2222 	/* Create an event handler thread */
2223 	if (xsa == NULL || xsa->xs_thrcreate == NULL) {
2224 		created = thr_create(NULL, NULL,
2225 		    (void *(*)(void *))subscriber_event_handler,
2226 		    shp, THR_BOUND, &sub_info->sp_handler_tid) == 0;
2227 	} else {
2228 		/*
2229 		 * A terrible hack.  We will use the extended private
2230 		 * door thread creation function the caller passed in to
2231 		 * create the event handler thread.  That function will
2232 		 * be called with our chosen thread start function and arg
2233 		 * instead of the usual libc-provided ones, but that's ok
2234 		 * as it is required to use them verbatim anyway.  We will
2235 		 * pass a NULL door_info_t pointer to the function - so
2236 		 * callers depending on this hack had better be prepared
2237 		 * for that.  All this allow the caller to rubberstamp
2238 		 * the created thread as it wishes.  But we don't get
2239 		 * the created threadid with this, so we modify the
2240 		 * thread start function to stash it.
2241 		 */
2242 
2243 		created = xsa->xs_thrcreate(NULL,
2244 		    (void *(*)(void *))subscriber_event_handler,
2245 		    shp, xsa->xs_thrcreate_cookie) == 1;
2246 	}
2247 
2248 	if (!created) {
2249 		error = EFAULT;
2250 		goto fail;
2251 	}
2252 
2253 	(void) mutex_unlock(SH_LOCK(shp));
2254 
2255 	return (0);
2256 
2257 fail:
2258 	(void) close(fd);
2259 	(void) door_revoke(SH_DOOR_DESC(shp));
2260 	(void) fdetach(SH_DOOR_NAME(shp));
2261 	(void) cond_destroy(&sub_info->sp_cv);
2262 	(void) mutex_destroy(&sub_info->sp_qlock);
2263 	free(sub_info->sp_door_name);
2264 	free(sub_info);
2265 	if (SH_ID(shp)) {
2266 		(void) update_kernel_registration(shp, SUBSCRIBER,
2267 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2268 		SH_ID(shp) = 0;
2269 	}
2270 	if (SH_BOUND(shp)) {
2271 		(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2272 		    sub_id, 0, NULL);
2273 		free(SH_DOOR_NAME(shp));
2274 		SH_BOUND(shp) = 0;
2275 	}
2276 	(void) mutex_unlock(SH_LOCK(shp));
2277 
2278 	errno = error;
2279 
2280 	return (-1);
2281 }
2282 
2283 /*
2284  * sysevent_bind_subscriber - Bind an event receiver to an event channel
2285  */
2286 int
2287 sysevent_bind_subscriber(sysevent_handle_t *shp,
2288 	void (*event_handler)(sysevent_t *ev))
2289 {
2290 	return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2291 }
2292 
2293 /*
2294  * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2295  * attributes specified.
2296  */
2297 int
2298 sysevent_bind_xsubscriber(sysevent_handle_t *shp,
2299 	void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2300 {
2301 	return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2302 }
2303 
2304 /*
2305  * sysevent_register_event - register an event class and associated subclasses
2306  *		for an event subscriber
2307  */
2308 int
2309 sysevent_register_event(sysevent_handle_t *shp,
2310 	const char *ev_class, const char **ev_subclass,
2311 	int subclass_num)
2312 {
2313 	int error;
2314 	char *event_class = (char *)ev_class;
2315 	char **event_subclass_list = (char **)ev_subclass;
2316 	char *nvlbuf = NULL;
2317 	size_t datalen;
2318 	nvlist_t *nvl;
2319 
2320 	(void) mutex_lock(SH_LOCK(shp));
2321 	if (event_class == NULL || event_subclass_list == NULL ||
2322 	    event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
2323 	    subclass_num <= 0) {
2324 		(void) mutex_unlock(SH_LOCK(shp));
2325 		errno = EINVAL;
2326 		return (-1);
2327 	}
2328 
2329 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2330 		(void) mutex_unlock(SH_LOCK(shp));
2331 		return (-1);
2332 	}
2333 	if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
2334 	    subclass_num) != 0) {
2335 		nvlist_free(nvl);
2336 		(void) mutex_unlock(SH_LOCK(shp));
2337 		return (-1);
2338 	}
2339 	if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
2340 		nvlist_free(nvl);
2341 		(void) mutex_unlock(SH_LOCK(shp));
2342 		return (-1);
2343 	}
2344 	nvlist_free(nvl);
2345 
2346 	/* Store new subscriber in in-kernel registration */
2347 	if (update_kernel_registration(shp, SUBSCRIBER,
2348 	    SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
2349 	    != 0) {
2350 		error = errno;
2351 		free(nvlbuf);
2352 		(void) mutex_unlock(SH_LOCK(shp));
2353 		errno = error;
2354 		return (-1);
2355 	}
2356 	/* Update the publisher's cached registration */
2357 	if (update_publisher_cache(
2358 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
2359 	    SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
2360 		error = errno;
2361 		free(nvlbuf);
2362 		(void) mutex_unlock(SH_LOCK(shp));
2363 		errno = error;
2364 		return (-1);
2365 	}
2366 
2367 	free(nvlbuf);
2368 
2369 	(void) mutex_unlock(SH_LOCK(shp));
2370 
2371 	return (0);
2372 }
2373 
2374 /*
2375  * sysevent_unregister_event - Unregister an event class and associated
2376  *				subclasses for an event subscriber
2377  */
2378 void
2379 sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
2380 {
2381 	size_t class_sz;
2382 
2383 	(void) mutex_lock(SH_LOCK(shp));
2384 
2385 	if (!SH_BOUND(shp)) {
2386 		(void) mutex_unlock(SH_LOCK(shp));
2387 		return;
2388 	}
2389 
2390 	/* Remove subscriber from in-kernel registration */
2391 	class_sz = strlen(class) + 1;
2392 	(void) update_kernel_registration(shp, SUBSCRIBER,
2393 	    SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
2394 	/* Update the publisher's cached registration */
2395 	(void) update_publisher_cache(
2396 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
2397 	    SH_ID(shp), class_sz, (uchar_t *)class);
2398 
2399 	(void) mutex_unlock(SH_LOCK(shp));
2400 }
2401 
2402 static int
2403 cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
2404 {
2405 	dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2406 
2407 	/* Remove registration from the kernel */
2408 	if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
2409 	    0, NULL) != 0) {
2410 		dprint("cleanup_id: Unable to clean "
2411 		    "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2412 		return (-1);
2413 	}
2414 
2415 	return (0);
2416 }
2417 
2418 /*
2419  * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
2420  *		allocated to unresponsive subscribers.
2421  */
2422 void
2423 sysevent_cleanup_subscribers(sysevent_handle_t *shp)
2424 {
2425 	uint32_t ping, result;
2426 	int i, error, sub_fd;
2427 	subscriber_data_t *sub;
2428 
2429 	if (!SH_BOUND(shp)) {
2430 		return;
2431 	}
2432 
2433 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
2434 
2435 		sub = SH_SUBSCRIBER(shp, i);
2436 		if (sub == NULL) {
2437 			continue;
2438 		}
2439 
2440 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
2441 			continue;
2442 		}
2443 		/* Check for valid and responsive subscriber */
2444 		error = clnt_deliver_event(sub_fd, &ping,
2445 		    sizeof (uint32_t), &result, sizeof (result));
2446 		(void) close(sub_fd);
2447 
2448 		/* Only cleanup on EBADF (Invalid door descriptor) */
2449 		if (error != EBADF)
2450 			continue;
2451 
2452 		if (cleanup_id(shp, i, SUBSCRIBER) != 0)
2453 			continue;
2454 
2455 		cache_remove_class(shp, EC_ALL, i);
2456 
2457 		free(sub->sd_door_name);
2458 		free(sub);
2459 		SH_SUBSCRIBER(shp, i) = NULL;
2460 	}
2461 
2462 }
2463 
2464 /*
2465  * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
2466  *		as needed.
2467  */
2468 void
2469 sysevent_cleanup_publishers(sysevent_handle_t *shp)
2470 {
2471 	(void) cleanup_id(shp, 1, PUBLISHER);
2472 }
2473 
2474 /*
2475  * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
2476  */
2477 void
2478 sysevent_unbind_subscriber(sysevent_handle_t *shp)
2479 {
2480 	subscriber_priv_t *sub_info;
2481 
2482 	if (shp == NULL)
2483 		return;
2484 
2485 	(void) mutex_lock(SH_LOCK(shp));
2486 	if (SH_BOUND(shp) == 0) {
2487 		(void) mutex_unlock(SH_LOCK(shp));
2488 		return;
2489 	}
2490 
2491 	/* Update the in-kernel registration */
2492 	(void) update_kernel_registration(shp, SUBSCRIBER,
2493 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2494 
2495 	/* Update the sysevent channel publisher */
2496 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
2497 	(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2498 	    SH_ID(shp), 0, NULL);
2499 
2500 	/* Close down event delivery facilities */
2501 	(void) door_revoke(SH_DOOR_DESC(shp));
2502 	(void) fdetach(SH_DOOR_NAME(shp));
2503 
2504 	/*
2505 	 * Release resources and wait for pending event delivery to
2506 	 * complete.
2507 	 */
2508 	(void) mutex_lock(&sub_info->sp_qlock);
2509 	SH_BOUND(shp) = 0;
2510 	/* Signal event handler and drain the subscriber's event queue */
2511 	(void) cond_signal(&sub_info->sp_cv);
2512 	(void) mutex_unlock(&sub_info->sp_qlock);
2513 	if (sub_info->sp_handler_tid != NULL)
2514 		(void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
2515 
2516 	(void) cond_destroy(&sub_info->sp_cv);
2517 	(void) mutex_destroy(&sub_info->sp_qlock);
2518 	free(sub_info->sp_door_name);
2519 	free(sub_info);
2520 	free(SH_DOOR_NAME(shp));
2521 	(void) mutex_unlock(SH_LOCK(shp));
2522 }
2523 
2524 /*
2525  * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
2526  */
2527 void
2528 sysevent_unbind_publisher(sysevent_handle_t *shp)
2529 {
2530 	if (shp == NULL)
2531 		return;
2532 
2533 	(void) mutex_lock(SH_LOCK(shp));
2534 	if (SH_BOUND(shp) == 0) {
2535 		(void) mutex_unlock(SH_LOCK(shp));
2536 		return;
2537 	}
2538 
2539 	/* Close down the registration facilities */
2540 	(void) door_revoke(SH_DOOR_DESC(shp));
2541 	(void) fdetach(SH_DOOR_NAME(shp));
2542 
2543 	/* Update the in-kernel registration */
2544 	(void) update_kernel_registration(shp, PUBLISHER,
2545 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2546 	SH_BOUND(shp) = 0;
2547 
2548 	/* Free resources associated with bind */
2549 	free_cached_registration(shp);
2550 	dealloc_subscribers(shp);
2551 
2552 	free(SH_PRIV_DATA(shp));
2553 	free(SH_DOOR_NAME(shp));
2554 	SH_ID(shp) = 0;
2555 	(void) mutex_unlock(SH_LOCK(shp));
2556 }
2557 
2558 /*
2559  * Evolving APIs to subscribe to syseventd(1M) system events.
2560  */
2561 
2562 static sysevent_handle_t *
2563 sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2564     sysevent_subattr_t *subattr)
2565 {
2566 	sysevent_handle_t *shp;
2567 
2568 	if (getuid() != 0) {
2569 		errno = EACCES;
2570 		return (NULL);
2571 	}
2572 
2573 	if (event_handler == NULL) {
2574 		errno = EINVAL;
2575 		return (NULL);
2576 	}
2577 
2578 	if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
2579 		return (NULL);
2580 	}
2581 
2582 	if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
2583 		/*
2584 		 * Ask syseventd to clean-up any stale subcribers and try to
2585 		 * to bind again
2586 		 */
2587 		if (errno == EBUSY) {
2588 			int pub_fd;
2589 			char door_name[MAXPATHLEN];
2590 			uint32_t result;
2591 			struct reg_args rargs;
2592 
2593 			if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2594 			    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2595 				sysevent_close_channel(shp);
2596 				errno = EINVAL;
2597 				return (NULL);
2598 			}
2599 
2600 			rargs.ra_op = SE_CLEANUP;
2601 			pub_fd = open(door_name, O_RDONLY);
2602 			(void) clnt_deliver_event(pub_fd, (void *)&rargs,
2603 			    sizeof (struct reg_args), &result, sizeof (result));
2604 			(void) close(pub_fd);
2605 
2606 			/* Try to bind again */
2607 			if (sysevent_bind_xsubscriber(shp, event_handler,
2608 			    subattr) != 0) {
2609 				sysevent_close_channel(shp);
2610 				return (NULL);
2611 			}
2612 		} else {
2613 			sysevent_close_channel(shp);
2614 			return (NULL);
2615 		}
2616 	}
2617 
2618 	return (shp);
2619 }
2620 
2621 /*
2622  * sysevent_bind_handle - Bind application event handler for syseventd
2623  *		subscription.
2624  */
2625 sysevent_handle_t *
2626 sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2627 {
2628 	return (sysevent_bind_handle_cmn(event_handler, NULL));
2629 }
2630 
2631 /*
2632  * sysevent_bind_xhandle - Bind application event handler for syseventd
2633  *		subscription, using door_xcreate and attributes as specified.
2634  */
2635 sysevent_handle_t *
2636 sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2637     sysevent_subattr_t *subattr)
2638 {
2639 	return (sysevent_bind_handle_cmn(event_handler, subattr));
2640 }
2641 
2642 /*
2643  * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
2644  */
2645 void
2646 sysevent_unbind_handle(sysevent_handle_t *shp)
2647 {
2648 	sysevent_unbind_subscriber(shp);
2649 	sysevent_close_channel(shp);
2650 }
2651 
2652 /*
2653  * sysevent_subscribe_event - Subscribe to system event notification from
2654  *			syseventd(1M) for the class and subclasses specified.
2655  */
2656 int
2657 sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
2658 	const char **event_subclass_list, int num_subclasses)
2659 {
2660 	return (sysevent_register_event(shp, event_class,
2661 	    event_subclass_list, num_subclasses));
2662 }
2663 
2664 void
2665 sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
2666 {
2667 	sysevent_unregister_event(shp, event_class);
2668 }
2669