xref: /titanic_50/usr/src/lib/libsysevent/libsysevent.c (revision aab83bb83be7342f6cfccaed8d5fe0b2f404855d)
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 *
sysevent_alloc(char * class,int class_sz,char * subclass,int subclass_sz,char * pub,int pub_sz,nvlist_t * attr_list)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
sysevent_post_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list,sysevent_id_t * eid)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 *
sysevent_dup(sysevent_t * ev)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
sysevent_free(sysevent_t * ev)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
sysevent_get_attr_list(sysevent_t * ev,nvlist_t ** nvlist)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 *
sysevent_attr_name(sysevent_attr_t * attr)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
sysevent_attr_value(sysevent_attr_t * attr,sysevent_value_t * se_value)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 *
sysevent_attr_next(sysevent_t * ev,sysevent_attr_t * attr)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
sysevent_lookup_attr(sysevent_t * ev,char * name,int datatype,sysevent_value_t * se_value)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
sysevent_get_class(sysevent_t * ev)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
sysevent_get_subclass(sysevent_t * ev)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 *
sysevent_get_class_name(sysevent_t * ev)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 *
sysevent_get_pub(sysevent_t * ev)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 *
parse_pub_id(sysevent_t * ev,se_pub_id_t token)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 *
pub_idx(const char * pstr,int token)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 *
sysevent_get_vendor_name(sysevent_t * ev)505 sysevent_get_vendor_name(sysevent_t *ev)
506 {
507 	return (parse_pub_id(ev, PUB_VEND));
508 }
509 
510 char *
sysevent_get_pub_name(sysevent_t * ev)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
sysevent_get_pid(sysevent_t * ev,pid_t * pid)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 *
sysevent_get_subclass_name(sysevent_t * ev)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
sysevent_get_seq(sysevent_t * ev)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
sysevent_get_time(sysevent_t * ev,hrtime_t * etime)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
sysevent_get_size(sysevent_t * ev)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 *
sysevent_alloc_event(char * class,char * subclass,char * vendor,char * pub_name,nvlist_t * attr_list)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 *
se_unpack(sysevent_t * ev)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
se_print(FILE * fp,sysevent_t * ev)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
subscriber_event_handler(sysevent_handle_t * shp)759 subscriber_event_handler(sysevent_handle_t *shp)
760 {
761 	subscriber_priv_t *sub_info;
762 	sysevent_queue_t *evqp;
763 
764 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
765 
766 	/* See hack alert in sysevent_bind_subscriber_cmn */
767 	if (sub_info->sp_handler_tid == NULL)
768 		sub_info->sp_handler_tid = thr_self();
769 
770 	(void) mutex_lock(&sub_info->sp_qlock);
771 	for (;;) {
772 		while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) {
773 			(void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock);
774 		}
775 		evqp = sub_info->sp_evq_head;
776 		while (evqp) {
777 			(void) mutex_unlock(&sub_info->sp_qlock);
778 			(void) sub_info->sp_func(evqp->sq_ev);
779 			(void) mutex_lock(&sub_info->sp_qlock);
780 			sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next;
781 			free(evqp->sq_ev);
782 			free(evqp);
783 			evqp = sub_info->sp_evq_head;
784 		}
785 		if (!SH_BOUND(shp)) {
786 			(void) mutex_unlock(&sub_info->sp_qlock);
787 			return;
788 		}
789 	}
790 
791 	/* NOTREACHED */
792 }
793 
794 /*
795  * Data structure used to communicate event subscription cache updates
796  * to publishers via a registration door
797  */
798 struct reg_args {
799 	uint32_t ra_sub_id;
800 	uint32_t ra_op;
801 	uint64_t ra_buf_ptr;
802 };
803 
804 
805 /*
806  * event_deliver_service - generic event delivery service routine.  This routine
807  *		is called in response to a door call to post an event.
808  *
809  */
810 /*ARGSUSED*/
811 static void
event_deliver_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)812 event_deliver_service(void *cookie, char *args, size_t alen,
813     door_desc_t *ddp, uint_t ndid)
814 {
815 	int	ret = 0;
816 	subscriber_priv_t *sub_info;
817 	sysevent_handle_t *shp;
818 	sysevent_queue_t *new_eq;
819 
820 	if (args == NULL || alen < sizeof (uint32_t)) {
821 		ret = EINVAL;
822 		goto return_from_door;
823 	}
824 
825 	/* Publisher checking on subscriber */
826 	if (alen == sizeof (uint32_t)) {
827 		ret = 0;
828 		goto return_from_door;
829 	}
830 
831 	shp = (sysevent_handle_t *)cookie;
832 	if (shp == NULL) {
833 		ret = EBADF;
834 		goto return_from_door;
835 	}
836 
837 	/*
838 	 * Mustn't block if we are trying to update the registration with
839 	 * the publisher
840 	 */
841 	if (mutex_trylock(SH_LOCK(shp)) != 0) {
842 		ret = EAGAIN;
843 		goto return_from_door;
844 	}
845 
846 	if (!SH_BOUND(shp)) {
847 		ret = EBADF;
848 		(void) mutex_unlock(SH_LOCK(shp));
849 		goto return_from_door;
850 	}
851 
852 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
853 	if (sub_info == NULL) {
854 		ret = EBADF;
855 		(void) mutex_unlock(SH_LOCK(shp));
856 		goto return_from_door;
857 	}
858 
859 	new_eq = (sysevent_queue_t *)calloc(1,
860 	    sizeof (sysevent_queue_t));
861 	if (new_eq == NULL) {
862 		ret = EAGAIN;
863 		(void) mutex_unlock(SH_LOCK(shp));
864 		goto return_from_door;
865 	}
866 
867 	/*
868 	 * Allocate and copy the event buffer into the subscriber's
869 	 * address space
870 	 */
871 	new_eq->sq_ev = calloc(1, alen);
872 	if (new_eq->sq_ev == NULL) {
873 		free(new_eq);
874 		ret = EAGAIN;
875 		(void) mutex_unlock(SH_LOCK(shp));
876 		goto return_from_door;
877 	}
878 	(void) bcopy(args, new_eq->sq_ev, alen);
879 
880 	(void) mutex_lock(&sub_info->sp_qlock);
881 	if (sub_info->sp_evq_head == NULL) {
882 		sub_info->sp_evq_head = new_eq;
883 	} else {
884 		sub_info->sp_evq_tail->sq_next = new_eq;
885 	}
886 	sub_info->sp_evq_tail = new_eq;
887 
888 	(void) cond_signal(&sub_info->sp_cv);
889 	(void) mutex_unlock(&sub_info->sp_qlock);
890 	(void) mutex_unlock(SH_LOCK(shp));
891 
892 return_from_door:
893 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
894 	(void) door_return(NULL, 0, NULL, 0);
895 }
896 
897 /*
898  * Sysevent subscription information is maintained in the kernel.  Updates
899  * to the in-kernel registration database is expected to be infrequent and
900  * offers consistency for publishers and subscribers that may come and go
901  * for a given channel.
902  *
903  * To expedite registration lookups by publishers, a cached copy of the
904  * kernel registration database is kept per-channel.  Caches are invalidated
905  * and refreshed upon state changes to the in-kernel registration database.
906  *
907  * To prevent stale subscriber data, publishers may remove subsriber
908  * registrations from the in-kernel registration database in the event
909  * that a particular subscribing process is unresponsive.
910  *
911  * The following routines provide a mechanism to update publisher and subscriber
912  * information for a specified channel.
913  */
914 
915 /*
916  * clnt_deliver_event - Deliver an event through the consumer's event
917  *			delivery door
918  *
919  * Returns -1 if message not delivered. With errno set to cause of error.
920  * Returns 0 for success with the results returned in posting buffer.
921  */
922 static int
clnt_deliver_event(int service_door,void * data,size_t datalen,void * result,size_t rlen)923 clnt_deliver_event(int service_door, void *data, size_t datalen,
924 	void *result, size_t rlen)
925 {
926 	int error = 0;
927 	door_arg_t door_arg;
928 
929 	door_arg.rbuf = result;
930 	door_arg.rsize = rlen;
931 	door_arg.data_ptr = data;
932 	door_arg.data_size = datalen;
933 	door_arg.desc_ptr = NULL;
934 	door_arg.desc_num = 0;
935 
936 	/*
937 	 * Make door call
938 	 */
939 	while ((error = door_call(service_door, &door_arg)) != 0) {
940 		if (errno == EAGAIN || errno == EINTR) {
941 			continue;
942 		} else {
943 			error = errno;
944 			break;
945 		}
946 	}
947 
948 	return (error);
949 }
950 
951 static int
update_publisher_cache(subscriber_priv_t * sub_info,int update_op,uint32_t sub_id,size_t datasz,uchar_t * data)952 update_publisher_cache(subscriber_priv_t *sub_info, int update_op,
953 	uint32_t sub_id, size_t datasz, uchar_t *data)
954 {
955 	int pub_fd;
956 	uint32_t result = 0;
957 	struct reg_args *rargs;
958 
959 	rargs = (struct reg_args *)calloc(1, sizeof (struct reg_args) +
960 	    datasz);
961 	if (rargs == NULL) {
962 		errno = ENOMEM;
963 		return (-1);
964 	}
965 
966 	rargs->ra_sub_id = sub_id;
967 	rargs->ra_op = update_op;
968 	bcopy(data, (char *)&rargs->ra_buf_ptr, datasz);
969 
970 	pub_fd = open(sub_info->sp_door_name, O_RDONLY);
971 	(void) clnt_deliver_event(pub_fd, (void *)rargs,
972 	    sizeof (struct reg_args) + datasz, &result, sizeof (result));
973 	(void) close(pub_fd);
974 
975 	free(rargs);
976 	if (result != 0) {
977 		errno = result;
978 		return (-1);
979 	}
980 
981 	return (0);
982 }
983 
984 
985 /*
986  * update_kernel_registration - update the in-kernel registration for the
987  * given channel.
988  */
989 static int
update_kernel_registration(sysevent_handle_t * shp,int update_type,int update_op,uint32_t * sub_id,size_t datasz,uchar_t * data)990 update_kernel_registration(sysevent_handle_t *shp, int update_type,
991 	int update_op, uint32_t *sub_id, size_t datasz, uchar_t *data)
992 {
993 	int error;
994 	char *channel_name = SH_CHANNEL_NAME(shp);
995 	se_pubsub_t udata;
996 
997 	udata.ps_channel_name_len = strlen(channel_name) + 1;
998 	udata.ps_op = update_op;
999 	udata.ps_type = update_type;
1000 	udata.ps_buflen = datasz;
1001 	udata.ps_id = *sub_id;
1002 
1003 	if ((error = modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
1004 	    (uintptr_t)channel_name, (uintptr_t)data, (uintptr_t)&udata, 0))
1005 	    != 0) {
1006 		return (error);
1007 	}
1008 
1009 	*sub_id = udata.ps_id;
1010 
1011 	return (error);
1012 }
1013 
1014 /*
1015  * get_kernel_registration - get the current subscriber registration for
1016  * the given channel
1017  */
1018 static nvlist_t *
get_kernel_registration(char * channel_name,uint32_t class_id)1019 get_kernel_registration(char *channel_name, uint32_t class_id)
1020 {
1021 	char *nvlbuf;
1022 	nvlist_t *nvl;
1023 	se_pubsub_t udata;
1024 
1025 	nvlbuf = calloc(1, MAX_SUBSCRIPTION_SZ);
1026 	if (nvlbuf == NULL) {
1027 		return (NULL);
1028 	}
1029 
1030 	udata.ps_buflen = MAX_SUBSCRIPTION_SZ;
1031 	udata.ps_channel_name_len = strlen(channel_name) + 1;
1032 	udata.ps_id = class_id;
1033 	udata.ps_op = SE_GET_REGISTRATION;
1034 	udata.ps_type = PUBLISHER;
1035 
1036 	if (modctl(MODEVENTS, (uintptr_t)MODEVENTS_REGISTER_EVENT,
1037 	    (uintptr_t)channel_name, (uintptr_t)nvlbuf, (uintptr_t)&udata, 0)
1038 	    != 0) {
1039 
1040 		/* Need a bigger buffer to hold channel registration */
1041 		if (errno == EAGAIN) {
1042 			free(nvlbuf);
1043 			nvlbuf = calloc(1, udata.ps_buflen);
1044 			if (nvlbuf == NULL)
1045 				return (NULL);
1046 
1047 			/* Try again */
1048 			if (modctl(MODEVENTS,
1049 			    (uintptr_t)MODEVENTS_REGISTER_EVENT,
1050 			    (uintptr_t)channel_name, (uintptr_t)nvlbuf,
1051 			    (uintptr_t)&udata, 0) != 0) {
1052 				free(nvlbuf);
1053 				return (NULL);
1054 			}
1055 		} else {
1056 			free(nvlbuf);
1057 			return (NULL);
1058 		}
1059 	}
1060 
1061 	if (nvlist_unpack(nvlbuf, udata.ps_buflen, &nvl, 0) != 0) {
1062 		free(nvlbuf);
1063 		return (NULL);
1064 	}
1065 	free(nvlbuf);
1066 
1067 	return (nvl);
1068 }
1069 
1070 /*
1071  * The following routines provide a mechanism for publishers to maintain
1072  * subscriber information.
1073  */
1074 
1075 static void
dealloc_subscribers(sysevent_handle_t * shp)1076 dealloc_subscribers(sysevent_handle_t *shp)
1077 {
1078 	int i;
1079 	subscriber_data_t *sub;
1080 
1081 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1082 		sub = SH_SUBSCRIBER(shp, i);
1083 		if (sub != NULL) {
1084 			free(sub->sd_door_name);
1085 			free(sub);
1086 		}
1087 		SH_SUBSCRIBER(shp, i) = NULL;
1088 	}
1089 }
1090 
1091 /*ARGSUSED*/
1092 static int
alloc_subscriber(sysevent_handle_t * shp,uint32_t sub_id,int oflag)1093 alloc_subscriber(sysevent_handle_t *shp, uint32_t sub_id, int oflag)
1094 {
1095 	subscriber_data_t *sub;
1096 	char door_name[MAXPATHLEN];
1097 
1098 	if (SH_SUBSCRIBER(shp, sub_id) != NULL) {
1099 		return (0);
1100 	}
1101 
1102 	/* Allocate and initialize the subscriber data */
1103 	sub = (subscriber_data_t *)calloc(1,
1104 	    sizeof (subscriber_data_t));
1105 	if (sub == NULL) {
1106 		return (-1);
1107 	}
1108 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
1109 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
1110 		free(sub);
1111 		return (-1);
1112 	}
1113 
1114 	sub->sd_flag = ACTIVE;
1115 	sub->sd_door_name = strdup(door_name);
1116 	if (sub->sd_door_name == NULL) {
1117 		free(sub);
1118 		return (-1);
1119 	}
1120 
1121 	SH_SUBSCRIBER(shp, sub_id) = sub;
1122 	return (0);
1123 
1124 }
1125 
1126 /*
1127  * The following routines are used to update and maintain the registration cache
1128  * for a particular sysevent channel.
1129  */
1130 
1131 static uint32_t
hash_func(const char * s)1132 hash_func(const char *s)
1133 {
1134 	uint32_t result = 0;
1135 	uint_t g;
1136 
1137 	while (*s != '\0') {
1138 		result <<= 4;
1139 		result += (uint32_t)*s++;
1140 		g = result & 0xf0000000;
1141 		if (g != 0) {
1142 			result ^= g >> 24;
1143 			result ^= g;
1144 		}
1145 	}
1146 
1147 	return (result);
1148 }
1149 
1150 subclass_lst_t *
cache_find_subclass(class_lst_t * c_list,char * subclass)1151 cache_find_subclass(class_lst_t *c_list, char *subclass)
1152 {
1153 	subclass_lst_t *sc_list;
1154 
1155 	if (c_list == NULL)
1156 		return (NULL);
1157 
1158 	sc_list = c_list->cl_subclass_list;
1159 
1160 	while (sc_list != NULL) {
1161 		if (strcmp(sc_list->sl_name, subclass) == 0) {
1162 			return (sc_list);
1163 		}
1164 		sc_list = sc_list->sl_next;
1165 	}
1166 
1167 	return (NULL);
1168 }
1169 
1170 
1171 static class_lst_t *
cache_find_class(sysevent_handle_t * shp,char * class)1172 cache_find_class(sysevent_handle_t *shp, char *class)
1173 {
1174 	int index;
1175 	class_lst_t *c_list;
1176 	class_lst_t **class_hash = SH_CLASS_HASH(shp);
1177 
1178 	if (strcmp(class, EC_ALL) == 0) {
1179 		return (class_hash[0]);
1180 	}
1181 
1182 	index = CLASS_HASH(class);
1183 	c_list = class_hash[index];
1184 	while (c_list != NULL) {
1185 		if (strcmp(class, c_list->cl_name) == 0) {
1186 			break;
1187 		}
1188 		c_list = c_list->cl_next;
1189 	}
1190 
1191 	return (c_list);
1192 }
1193 
1194 static int
cache_insert_subclass(class_lst_t * c_list,char ** subclass_names,int subclass_num,uint32_t sub_id)1195 cache_insert_subclass(class_lst_t *c_list, char **subclass_names,
1196 	int subclass_num, uint32_t sub_id)
1197 {
1198 	int i;
1199 	subclass_lst_t *sc_list;
1200 
1201 	for (i = 0; i < subclass_num; ++i) {
1202 		if ((sc_list = cache_find_subclass(c_list, subclass_names[i]))
1203 		    != NULL) {
1204 			sc_list->sl_num[sub_id] = 1;
1205 		} else {
1206 			sc_list = (subclass_lst_t *)calloc(1,
1207 			    sizeof (subclass_lst_t));
1208 			if (sc_list == NULL)
1209 				return (-1);
1210 
1211 			sc_list->sl_name = strdup(subclass_names[i]);
1212 			if (sc_list->sl_name == NULL) {
1213 				free(sc_list);
1214 				return (-1);
1215 			}
1216 
1217 			sc_list->sl_num[sub_id] = 1;
1218 			sc_list->sl_next = c_list->cl_subclass_list;
1219 			c_list->cl_subclass_list = sc_list;
1220 		}
1221 	}
1222 
1223 	return (0);
1224 }
1225 
1226 static int
cache_insert_class(sysevent_handle_t * shp,char * class,char ** subclass_names,int subclass_num,uint32_t sub_id)1227 cache_insert_class(sysevent_handle_t *shp, char *class,
1228 	char **subclass_names, int subclass_num, uint32_t sub_id)
1229 {
1230 	class_lst_t *c_list;
1231 
1232 	if (strcmp(class, EC_ALL) == 0) {
1233 		char *subclass_all = EC_SUB_ALL;
1234 
1235 		(void) cache_insert_subclass(SH_CLASS_HASH(shp)[0],
1236 		    (char **)&subclass_all, 1, sub_id);
1237 		return (0);
1238 	}
1239 
1240 	/* New class, add to the registration cache */
1241 	if ((c_list = cache_find_class(shp, class)) == NULL) {
1242 
1243 		c_list = (class_lst_t *)calloc(1, sizeof (class_lst_t));
1244 		if (c_list == NULL) {
1245 			return (1);
1246 		}
1247 		c_list->cl_name = strdup(class);
1248 		if (c_list->cl_name == NULL) {
1249 			free(c_list);
1250 			return (1);
1251 		}
1252 
1253 		c_list->cl_subclass_list = (subclass_lst_t *)
1254 		    calloc(1, sizeof (subclass_lst_t));
1255 		if (c_list->cl_subclass_list == NULL) {
1256 			free(c_list->cl_name);
1257 			free(c_list);
1258 			return (1);
1259 		}
1260 		c_list->cl_subclass_list->sl_name = strdup(EC_SUB_ALL);
1261 		if (c_list->cl_subclass_list->sl_name == NULL) {
1262 			free(c_list->cl_subclass_list);
1263 			free(c_list->cl_name);
1264 			free(c_list);
1265 			return (1);
1266 		}
1267 		c_list->cl_next = SH_CLASS_HASH(shp)[CLASS_HASH(class)];
1268 		SH_CLASS_HASH(shp)[CLASS_HASH(class)] = c_list;
1269 
1270 	}
1271 
1272 	/* Update the subclass list */
1273 	if (cache_insert_subclass(c_list, subclass_names, subclass_num,
1274 	    sub_id) != 0)
1275 		return (1);
1276 
1277 	return (0);
1278 }
1279 
1280 static void
cache_remove_all_class(sysevent_handle_t * shp,uint32_t sub_id)1281 cache_remove_all_class(sysevent_handle_t *shp, uint32_t sub_id)
1282 {
1283 	int i;
1284 	class_lst_t *c_list;
1285 	subclass_lst_t *sc_list;
1286 
1287 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
1288 		c_list = SH_CLASS_HASH(shp)[i];
1289 		while (c_list != NULL) {
1290 			sc_list = c_list->cl_subclass_list;
1291 			while (sc_list != NULL) {
1292 				sc_list->sl_num[sub_id] = 0;
1293 				sc_list = sc_list->sl_next;
1294 			}
1295 			c_list = c_list->cl_next;
1296 		}
1297 	}
1298 }
1299 
1300 static void
cache_remove_class(sysevent_handle_t * shp,char * class,uint32_t sub_id)1301 cache_remove_class(sysevent_handle_t *shp, char *class, uint32_t sub_id)
1302 {
1303 	class_lst_t *c_list;
1304 	subclass_lst_t *sc_list;
1305 
1306 	if (strcmp(class, EC_ALL) == 0) {
1307 		cache_remove_all_class(shp, sub_id);
1308 		return;
1309 	}
1310 
1311 	if ((c_list = cache_find_class(shp, class)) == NULL) {
1312 		return;
1313 	}
1314 
1315 	sc_list = c_list->cl_subclass_list;
1316 	while (sc_list != NULL) {
1317 		sc_list->sl_num[sub_id] = 0;
1318 		sc_list = sc_list->sl_next;
1319 	}
1320 }
1321 
1322 static void
free_cached_registration(sysevent_handle_t * shp)1323 free_cached_registration(sysevent_handle_t *shp)
1324 {
1325 	int i;
1326 	class_lst_t *clist, *next_clist;
1327 	subclass_lst_t *sc_list, *next_sc;
1328 
1329 	for (i = 0; i < CLASS_HASH_SZ + 1; i++) {
1330 		clist = SH_CLASS_HASH(shp)[i];
1331 		while (clist != NULL) {
1332 			sc_list = clist->cl_subclass_list;
1333 			while (sc_list != NULL) {
1334 				free(sc_list->sl_name);
1335 				next_sc = sc_list->sl_next;
1336 				free(sc_list);
1337 				sc_list = next_sc;
1338 			}
1339 			free(clist->cl_name);
1340 			next_clist = clist->cl_next;
1341 			free(clist);
1342 			clist = next_clist;
1343 		}
1344 		SH_CLASS_HASH(shp)[i] = NULL;
1345 	}
1346 }
1347 
1348 static int
create_cached_registration(sysevent_handle_t * shp,class_lst_t ** class_hash)1349 create_cached_registration(sysevent_handle_t *shp,
1350 	class_lst_t **class_hash)
1351 {
1352 	int i, j, new_class;
1353 	char *class_name;
1354 	uint_t num_elem;
1355 	uchar_t *subscribers;
1356 	nvlist_t *nvl;
1357 	nvpair_t *nvpair;
1358 	class_lst_t *clist;
1359 	subclass_lst_t *sc_list;
1360 
1361 	for (i = 0; i < CLASS_HASH_SZ + 1; ++i) {
1362 
1363 		if ((nvl = get_kernel_registration(SH_CHANNEL_NAME(shp), i))
1364 		    == NULL) {
1365 			if (errno == ENOENT) {
1366 				class_hash[i] = NULL;
1367 				continue;
1368 			} else {
1369 				goto create_failed;
1370 			}
1371 		}
1372 
1373 
1374 		nvpair = NULL;
1375 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1376 			goto create_failed;
1377 		}
1378 
1379 		new_class = 1;
1380 		while (new_class) {
1381 			/* Extract the class name from the nvpair */
1382 			if (nvpair_value_string(nvpair, &class_name) != 0) {
1383 				goto create_failed;
1384 			}
1385 			clist = (class_lst_t *)
1386 			    calloc(1, sizeof (class_lst_t));
1387 			if (clist == NULL) {
1388 				goto create_failed;
1389 			}
1390 
1391 			clist->cl_name = strdup(class_name);
1392 			if (clist->cl_name == NULL) {
1393 				free(clist);
1394 				goto create_failed;
1395 			}
1396 
1397 			/*
1398 			 * Extract the subclass name and registration
1399 			 * from the nvpair
1400 			 */
1401 			if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
1402 			    == NULL) {
1403 				free(clist->cl_name);
1404 				free(clist);
1405 				goto create_failed;
1406 			}
1407 
1408 			clist->cl_next = class_hash[i];
1409 			class_hash[i] = clist;
1410 
1411 			for (;;) {
1412 
1413 				sc_list = (subclass_lst_t *)calloc(1,
1414 				    sizeof (subclass_lst_t));
1415 				if (sc_list == NULL) {
1416 					goto create_failed;
1417 				}
1418 
1419 				sc_list->sl_next = clist->cl_subclass_list;
1420 				clist->cl_subclass_list = sc_list;
1421 
1422 				sc_list->sl_name = strdup(nvpair_name(nvpair));
1423 				if (sc_list->sl_name == NULL) {
1424 					goto create_failed;
1425 				}
1426 
1427 				if (nvpair_value_byte_array(nvpair,
1428 				    &subscribers, &num_elem) != 0) {
1429 					goto create_failed;
1430 				}
1431 				bcopy(subscribers, (uchar_t *)sc_list->sl_num,
1432 				    MAX_SUBSCRIBERS + 1);
1433 
1434 				for (j = 1; j <= MAX_SUBSCRIBERS; ++j) {
1435 					if (sc_list->sl_num[j] == 0)
1436 						continue;
1437 
1438 					if (alloc_subscriber(shp, j, 1) != 0) {
1439 						goto create_failed;
1440 					}
1441 				}
1442 
1443 				/*
1444 				 * Check next nvpair - either subclass or
1445 				 * class
1446 				 */
1447 				if ((nvpair = nvlist_next_nvpair(nvl, nvpair))
1448 				    == NULL) {
1449 					new_class = 0;
1450 					break;
1451 				} else if (strcmp(nvpair_name(nvpair),
1452 				    CLASS_NAME) == 0) {
1453 					break;
1454 				}
1455 			}
1456 		}
1457 		nvlist_free(nvl);
1458 	}
1459 	return (0);
1460 
1461 create_failed:
1462 	dealloc_subscribers(shp);
1463 	free_cached_registration(shp);
1464 	nvlist_free(nvl);
1465 	return (-1);
1466 
1467 }
1468 
1469 /*
1470  * cache_update_service - generic event publisher service routine.  This routine
1471  *		is called in response to a registration cache update.
1472  *
1473  */
1474 /*ARGSUSED*/
1475 static void
cache_update_service(void * cookie,char * args,size_t alen,door_desc_t * ddp,uint_t ndid)1476 cache_update_service(void *cookie, char *args, size_t alen,
1477     door_desc_t *ddp, uint_t ndid)
1478 {
1479 	int ret = 0;
1480 	uint_t num_elem;
1481 	char *class, **event_list;
1482 	size_t datalen;
1483 	uint32_t sub_id;
1484 	nvlist_t *nvl;
1485 	nvpair_t *nvpair = NULL;
1486 	struct reg_args *rargs;
1487 	sysevent_handle_t *shp;
1488 	subscriber_data_t *sub;
1489 
1490 	if (alen < sizeof (struct reg_args) || cookie == NULL) {
1491 		ret = EINVAL;
1492 		goto return_from_door;
1493 	}
1494 
1495 	/* LINTED: E_BAD_PTR_CAST_ALIGN */
1496 	rargs = (struct reg_args *)args;
1497 	shp = (sysevent_handle_t *)cookie;
1498 
1499 	datalen = alen - sizeof (struct reg_args);
1500 	sub_id = rargs->ra_sub_id;
1501 
1502 	(void) mutex_lock(SH_LOCK(shp));
1503 
1504 	switch (rargs->ra_op) {
1505 	case SE_UNREGISTER:
1506 		class = (char *)&rargs->ra_buf_ptr;
1507 		cache_remove_class(shp, (char *)class,
1508 		    sub_id);
1509 		break;
1510 	case SE_UNBIND_REGISTRATION:
1511 
1512 		sub = SH_SUBSCRIBER(shp, sub_id);
1513 		if (sub == NULL)
1514 			break;
1515 
1516 		free(sub->sd_door_name);
1517 		free(sub);
1518 		cache_remove_class(shp, EC_ALL, sub_id);
1519 		SH_SUBSCRIBER(shp, sub_id) = NULL;
1520 
1521 		break;
1522 	case SE_BIND_REGISTRATION:
1523 
1524 		/* New subscriber */
1525 		if (alloc_subscriber(shp, sub_id, 0) != 0) {
1526 			ret = ENOMEM;
1527 			break;
1528 		}
1529 		break;
1530 	case SE_REGISTER:
1531 
1532 		if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
1533 			ret = EINVAL;
1534 			break;
1535 		}
1536 		/* Get new registration data */
1537 		if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
1538 		    &nvl, 0) != 0) {
1539 			ret =  EFAULT;
1540 			break;
1541 		}
1542 		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1543 			nvlist_free(nvl);
1544 			ret = EFAULT;
1545 			break;
1546 		}
1547 		if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
1548 		    != 0) {
1549 			nvlist_free(nvl);
1550 			ret =  EFAULT;
1551 			break;
1552 		}
1553 		class = nvpair_name(nvpair);
1554 
1555 		ret = cache_insert_class(shp, class,
1556 		    event_list, num_elem, sub_id);
1557 		if (ret != 0) {
1558 			cache_remove_class(shp, class, sub_id);
1559 			nvlist_free(nvl);
1560 			ret =  EFAULT;
1561 			break;
1562 		}
1563 
1564 		nvlist_free(nvl);
1565 
1566 		break;
1567 	case SE_CLEANUP:
1568 		/* Cleanup stale subscribers */
1569 		sysevent_cleanup_subscribers(shp);
1570 		break;
1571 	default:
1572 		ret =  EINVAL;
1573 	}
1574 
1575 	(void) mutex_unlock(SH_LOCK(shp));
1576 
1577 return_from_door:
1578 	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
1579 	(void) door_return(NULL, 0, NULL, 0);
1580 }
1581 
1582 /*
1583  * sysevent_send_event -
1584  * Send an event via the communication channel associated with the sysevent
1585  * handle.  Event notifications are broadcast to all subscribers based upon
1586  * the event class and subclass.  The handle must have been previously
1587  * allocated and bound by
1588  * sysevent_open_channel() and sysevent_bind_publisher()
1589  */
1590 int
sysevent_send_event(sysevent_handle_t * shp,sysevent_t * ev)1591 sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
1592 {
1593 	int i, error, sub_fd, result = 0;
1594 	int deliver_error = 0;
1595 	int subscribers_sent = 0;
1596 	int want_resend, resend_cnt = 0;
1597 	char *event_class, *event_subclass;
1598 	uchar_t *all_class_subscribers, *all_subclass_subscribers;
1599 	uchar_t *subclass_subscribers;
1600 	subscriber_data_t *sub;
1601 	subclass_lst_t *sc_lst;
1602 
1603 	/* Check for proper registration */
1604 	event_class = sysevent_get_class_name(ev);
1605 	event_subclass = sysevent_get_subclass_name(ev);
1606 
1607 	(void) mutex_lock(SH_LOCK(shp));
1608 
1609 send_event:
1610 
1611 	want_resend = 0;
1612 	if (!SH_BOUND(shp)) {
1613 		(void) mutex_unlock(SH_LOCK(shp));
1614 		errno = EINVAL;
1615 		return (-1);
1616 	}
1617 
1618 	/* Find all subscribers for this event class/subclass */
1619 	sc_lst = cache_find_subclass(
1620 	    cache_find_class(shp, EC_ALL), EC_SUB_ALL);
1621 	all_class_subscribers = sc_lst->sl_num;
1622 
1623 	sc_lst = cache_find_subclass(
1624 	    cache_find_class(shp, event_class), EC_SUB_ALL);
1625 	if (sc_lst)
1626 		all_subclass_subscribers = sc_lst->sl_num;
1627 	else
1628 		all_subclass_subscribers = NULL;
1629 
1630 	sc_lst = cache_find_subclass(
1631 	    cache_find_class(shp, event_class), event_subclass);
1632 	if (sc_lst)
1633 		subclass_subscribers = sc_lst->sl_num;
1634 	else
1635 		subclass_subscribers = NULL;
1636 
1637 	/* Send event buffer to all valid subscribers */
1638 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1639 		if ((all_class_subscribers[i] |
1640 		    (all_subclass_subscribers && all_subclass_subscribers[i]) |
1641 		    (subclass_subscribers && subclass_subscribers[i])) == 0)
1642 			continue;
1643 
1644 		sub = SH_SUBSCRIBER(shp, i);
1645 		assert(sub != NULL);
1646 
1647 		/* Check for active subscriber */
1648 		if (!(sub->sd_flag & ACTIVE)) {
1649 			dprint("sysevent_send_event: subscriber %d inactive\n",
1650 			    i);
1651 			continue;
1652 		}
1653 
1654 		/* Process only resend requests */
1655 		if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
1656 			continue;
1657 		}
1658 
1659 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
1660 			dprint("sysevent_send_event: Failed to open "
1661 			    "%s: %s\n", sub->sd_door_name, strerror(errno));
1662 			continue;
1663 		}
1664 		result = 0;
1665 		error = clnt_deliver_event(sub_fd, ev,
1666 		    sysevent_get_size(ev), &result, sizeof (result));
1667 
1668 		(void) close(sub_fd);
1669 
1670 		/* Successful door call */
1671 		if (error == 0) {
1672 			switch (result) {
1673 			/* Subscriber requested EAGAIN */
1674 			case EAGAIN:
1675 				if (resend_cnt > SE_MAX_RETRY_LIMIT) {
1676 					deliver_error = 1;
1677 				} else {
1678 					want_resend = 1;
1679 					dprint("sysevent_send_event: resend "
1680 					    "requested for %d\n", i);
1681 					sub->sd_flag |= SEND_AGAIN;
1682 				}
1683 				break;
1684 			/* Bad sysevent handle for subscriber */
1685 			case EBADF:
1686 			case EINVAL:
1687 				dprint("sysevent_send_event: Bad sysevent "
1688 				    "handle for %s", sub->sd_door_name);
1689 				sub->sd_flag = 0;
1690 				deliver_error = 1;
1691 				break;
1692 			/* Successful delivery */
1693 			default:
1694 				sub->sd_flag &= ~SEND_AGAIN;
1695 				++subscribers_sent;
1696 			}
1697 		} else {
1698 			dprint("sysevent_send_event: Failed door call "
1699 			    "to %s: %s: %d\n", sub->sd_door_name,
1700 			    strerror(errno), result);
1701 			sub->sd_flag = 0;
1702 			deliver_error = 1;
1703 		}
1704 	}
1705 
1706 	if (want_resend) {
1707 		resend_cnt++;
1708 		goto send_event;
1709 	}
1710 
1711 	if (deliver_error) {
1712 		sysevent_cleanup_subscribers(shp);
1713 		(void) mutex_unlock(SH_LOCK(shp));
1714 		errno = EFAULT;
1715 		return (-1);
1716 	}
1717 
1718 	(void) mutex_unlock(SH_LOCK(shp));
1719 
1720 	if (subscribers_sent == 0) {
1721 		dprint("sysevent_send_event: No subscribers for %s:%s\n",
1722 		    event_class, event_subclass);
1723 		errno = ENOENT;
1724 		return (-1);
1725 	}
1726 
1727 	return (0);
1728 }
1729 
1730 /*
1731  * Common routine to establish an event channel through which an event
1732  * publisher or subscriber may post or receive events.
1733  */
1734 static sysevent_handle_t *
sysevent_open_channel_common(const char * channel_path)1735 sysevent_open_channel_common(const char *channel_path)
1736 {
1737 	uint32_t sub_id = 0;
1738 	char *begin_path;
1739 	struct stat chan_stat;
1740 	sysevent_handle_t *shp;
1741 
1742 
1743 	if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
1744 		errno = EINVAL;
1745 		return (NULL);
1746 	}
1747 
1748 	if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1749 		if (errno != EEXIST) {
1750 			errno = EACCES;
1751 			return (NULL);
1752 		}
1753 	}
1754 
1755 	/* Check channel file permissions */
1756 	if (stat(channel_path, &chan_stat) != 0) {
1757 		dprint("sysevent_open_channel: Invalid permissions for channel "
1758 		    "%s\n", channel_path);
1759 		errno = EACCES;
1760 		return (NULL);
1761 	} else if (chan_stat.st_uid != getuid() ||
1762 	    !S_ISDIR(chan_stat.st_mode)) {
1763 		dprint("sysevent_open_channel: Invalid "
1764 		    "permissions for channel %s\n: %d:%d:%d", channel_path,
1765 		    (int)chan_stat.st_uid, (int)chan_stat.st_gid,
1766 		    (int)chan_stat.st_mode);
1767 
1768 		errno = EACCES;
1769 		return (NULL);
1770 	}
1771 
1772 	shp = calloc(1, sizeof (sysevent_impl_hdl_t));
1773 	if (shp == NULL) {
1774 		errno = ENOMEM;
1775 		return (NULL);
1776 	}
1777 
1778 	SH_CHANNEL_NAME(shp) = NULL;
1779 	SH_CHANNEL_PATH(shp) = strdup(channel_path);
1780 	if (SH_CHANNEL_PATH(shp) == NULL) {
1781 		free(shp);
1782 		errno = ENOMEM;
1783 		return (NULL);
1784 	}
1785 
1786 	/* Extract the channel name */
1787 	begin_path = SH_CHANNEL_PATH(shp);
1788 	while (*begin_path != '\0' &&
1789 	    (begin_path = strpbrk(begin_path, "/")) != NULL) {
1790 		++begin_path;
1791 		SH_CHANNEL_NAME(shp) = begin_path;
1792 	}
1793 
1794 	if (update_kernel_registration(shp, 0,
1795 	    SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
1796 		dprint("sysevent_open_channel: Failed for channel %s\n",
1797 		    SH_CHANNEL_NAME(shp));
1798 		free(SH_CHANNEL_PATH(shp));
1799 		free(shp);
1800 		errno = EFAULT;
1801 		return (NULL);
1802 	}
1803 
1804 	(void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
1805 
1806 	return (shp);
1807 }
1808 
1809 /*
1810  * Establish a sysevent channel for publication and subscription
1811  */
1812 sysevent_handle_t *
sysevent_open_channel(const char * channel)1813 sysevent_open_channel(const char *channel)
1814 {
1815 	int var_run_mounted = 0;
1816 	char full_channel[MAXPATHLEN + 1];
1817 	FILE *fp;
1818 	struct stat chan_stat;
1819 	struct extmnttab m;
1820 
1821 	if (channel == NULL) {
1822 		errno = EINVAL;
1823 		return (NULL);
1824 	}
1825 
1826 	/*
1827 	 * Check that /var/run is mounted as tmpfs before allowing a channel
1828 	 * to be opened.
1829 	 */
1830 	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
1831 		errno = EACCES;
1832 		return (NULL);
1833 	}
1834 
1835 	resetmnttab(fp);
1836 
1837 	while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
1838 		if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
1839 		    strcmp(m.mnt_fstype, "tmpfs") == 0) {
1840 			var_run_mounted = 1;
1841 			break;
1842 		}
1843 	}
1844 	(void) fclose(fp);
1845 
1846 	if (!var_run_mounted) {
1847 		errno = EACCES;
1848 		return (NULL);
1849 	}
1850 
1851 	if (stat(CHAN_PATH, &chan_stat) < 0) {
1852 		if (mkdir(CHAN_PATH,
1853 		    S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1854 			dprint("sysevent_open_channel: Unable "
1855 			    "to create channel directory %s:%s\n", CHAN_PATH,
1856 			    strerror(errno));
1857 			if (errno != EEXIST) {
1858 				errno = EACCES;
1859 				return (NULL);
1860 			}
1861 		}
1862 	}
1863 
1864 	if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
1865 	    MAXPATHLEN) {
1866 		errno = EINVAL;
1867 		return (NULL);
1868 	}
1869 
1870 	return (sysevent_open_channel_common(full_channel));
1871 }
1872 
1873 /*
1874  * Establish a sysevent channel for publication and subscription
1875  * Full path to the channel determined by the caller
1876  */
1877 sysevent_handle_t *
sysevent_open_channel_alt(const char * channel_path)1878 sysevent_open_channel_alt(const char *channel_path)
1879 {
1880 	return (sysevent_open_channel_common(channel_path));
1881 }
1882 
1883 /*
1884  * sysevent_close_channel - Clean up resources associated with a previously
1885  *				opened sysevent channel
1886  */
1887 void
sysevent_close_channel(sysevent_handle_t * shp)1888 sysevent_close_channel(sysevent_handle_t *shp)
1889 {
1890 	int error = errno;
1891 	uint32_t sub_id = 0;
1892 
1893 	if (shp == NULL) {
1894 		return;
1895 	}
1896 
1897 	(void) mutex_lock(SH_LOCK(shp));
1898 	if (SH_BOUND(shp)) {
1899 		(void) mutex_unlock(SH_LOCK(shp));
1900 		if (SH_TYPE(shp) == PUBLISHER)
1901 			sysevent_unbind_publisher(shp);
1902 		else if (SH_TYPE(shp) == SUBSCRIBER)
1903 			sysevent_unbind_subscriber(shp);
1904 		(void) mutex_lock(SH_LOCK(shp));
1905 	}
1906 
1907 	(void) update_kernel_registration(shp, 0,
1908 	    SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
1909 	(void) mutex_unlock(SH_LOCK(shp));
1910 
1911 	free(SH_CHANNEL_PATH(shp));
1912 	free(shp);
1913 	errno = error;
1914 }
1915 
1916 /*
1917  * sysevent_bind_publisher - Bind an event publisher to an event channel
1918  */
1919 int
sysevent_bind_publisher(sysevent_handle_t * shp)1920 sysevent_bind_publisher(sysevent_handle_t *shp)
1921 {
1922 	int error = 0;
1923 	int fd = -1;
1924 	char door_name[MAXPATHLEN];
1925 	uint32_t pub_id;
1926 	struct stat reg_stat;
1927 	publisher_priv_t *pub;
1928 
1929 	if (shp == NULL) {
1930 		errno = EINVAL;
1931 		return (-1);
1932 	}
1933 
1934 	(void) mutex_lock(SH_LOCK(shp));
1935 	if (SH_BOUND(shp)) {
1936 		(void) mutex_unlock(SH_LOCK(shp));
1937 		errno = EINVAL;
1938 		return (-1);
1939 	}
1940 
1941 	if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
1942 	    NULL) {
1943 		(void) mutex_unlock(SH_LOCK(shp));
1944 		errno = ENOMEM;
1945 		return (-1);
1946 	}
1947 	SH_PRIV_DATA(shp) = (void *)pub;
1948 
1949 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
1950 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
1951 		free(pub);
1952 		(void) mutex_unlock(SH_LOCK(shp));
1953 		errno = ENOMEM;
1954 		return (-1);
1955 	}
1956 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
1957 		free(pub);
1958 		(void) mutex_unlock(SH_LOCK(shp));
1959 		errno = ENOMEM;
1960 		return (-1);
1961 	}
1962 
1963 	/* Only one publisher allowed per channel */
1964 	if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
1965 		if (errno != ENOENT) {
1966 			error = EINVAL;
1967 			goto fail;
1968 		}
1969 	}
1970 
1971 	/*
1972 	 * Remove door file for robustness.
1973 	 */
1974 	if (unlink(SH_DOOR_NAME(shp)) != 0)
1975 		dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
1976 		    SH_DOOR_NAME(shp));
1977 
1978 	/* Open channel registration door */
1979 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
1980 	    S_IREAD|S_IWRITE);
1981 	if (fd == -1) {
1982 		error = EINVAL;
1983 		goto fail;
1984 	}
1985 
1986 	/*
1987 	 * Create the registration service for this publisher.
1988 	 */
1989 	if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
1990 	    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1991 		dprint("sysevent_bind_publisher: door create failed: "
1992 		    "%s\n", strerror(errno));
1993 		error = EFAULT;
1994 		goto fail;
1995 	}
1996 
1997 	(void) fdetach(SH_DOOR_NAME(shp));
1998 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
1999 		dprint("sysevent_bind_publisher: unable to "
2000 		    "bind event channel: fattach: %s\n",
2001 		    SH_DOOR_NAME(shp));
2002 		error = EACCES;
2003 		goto fail;
2004 	}
2005 
2006 	/* Bind this publisher in the kernel registration database */
2007 	if (update_kernel_registration(shp, PUBLISHER,
2008 	    SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
2009 		error = errno;
2010 		goto fail;
2011 	}
2012 
2013 	SH_ID(shp) = pub_id;
2014 	SH_BOUND(shp) = 1;
2015 	SH_TYPE(shp) = PUBLISHER;
2016 
2017 
2018 	/* Create the subscription registration cache */
2019 	if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
2020 		(void) update_kernel_registration(shp,
2021 		    PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
2022 		error = EFAULT;
2023 		goto fail;
2024 	}
2025 	(void) close(fd);
2026 
2027 	(void) mutex_unlock(SH_LOCK(shp));
2028 
2029 	return (0);
2030 
2031 fail:
2032 	SH_BOUND(shp) = 0;
2033 	(void) door_revoke(SH_DOOR_DESC(shp));
2034 	(void) fdetach(SH_DOOR_NAME(shp));
2035 	free(SH_DOOR_NAME(shp));
2036 	free(pub);
2037 	(void) close(fd);
2038 	(void) mutex_unlock(SH_LOCK(shp));
2039 	errno = error;
2040 	return (-1);
2041 }
2042 
2043 static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2044 static pthread_attr_t xdoor_thrattr;
2045 
2046 static void
xdoor_thrattr_init(void)2047 xdoor_thrattr_init(void)
2048 {
2049 	(void) pthread_attr_init(&xdoor_thrattr);
2050 	(void) pthread_attr_setdetachstate(&xdoor_thrattr,
2051 	    PTHREAD_CREATE_DETACHED);
2052 	(void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2053 }
2054 
2055 static int
xdoor_server_create(door_info_t * dip,void * (* startf)(void *),void * startfarg,void * cookie)2056 xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2057     void *startfarg, void *cookie)
2058 {
2059 	struct sysevent_subattr_impl *xsa = cookie;
2060 	pthread_attr_t *thrattr;
2061 	sigset_t oset;
2062 	int err;
2063 
2064 	if (xsa->xs_thrcreate) {
2065 		return (xsa->xs_thrcreate(dip, startf, startfarg,
2066 		    xsa->xs_thrcreate_cookie));
2067 	}
2068 
2069 	if (xsa->xs_thrattr == NULL) {
2070 		(void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2071 		thrattr = &xdoor_thrattr;
2072 	} else {
2073 		thrattr = xsa->xs_thrattr;
2074 	}
2075 
2076 	(void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2077 	err = pthread_create(NULL, thrattr, startf, startfarg);
2078 	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2079 
2080 	return (err == 0 ? 1 : -1);
2081 }
2082 
2083 static void
xdoor_server_setup(void * cookie)2084 xdoor_server_setup(void *cookie)
2085 {
2086 	struct sysevent_subattr_impl *xsa = cookie;
2087 
2088 	if (xsa->xs_thrsetup) {
2089 		xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2090 	} else {
2091 		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2092 		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2093 	}
2094 }
2095 
2096 static int
sysevent_bind_subscriber_cmn(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2097 sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
2098 	void (*event_handler)(sysevent_t *ev),
2099 	sysevent_subattr_t *subattr)
2100 {
2101 	int fd = -1;
2102 	int error = 0;
2103 	uint32_t sub_id = 0;
2104 	char door_name[MAXPATHLEN];
2105 	subscriber_priv_t *sub_info;
2106 	int created;
2107 	struct sysevent_subattr_impl *xsa =
2108 	    (struct sysevent_subattr_impl *)subattr;
2109 
2110 	if (shp == NULL || event_handler == NULL) {
2111 		errno = EINVAL;
2112 		return (-1);
2113 	}
2114 
2115 	(void) mutex_lock(SH_LOCK(shp));
2116 	if (SH_BOUND(shp)) {
2117 		errno = EINVAL;
2118 		(void) mutex_unlock(SH_LOCK(shp));
2119 		return (-1);
2120 	}
2121 
2122 	if ((sub_info = (subscriber_priv_t *)calloc(1,
2123 	    sizeof (subscriber_priv_t))) == NULL) {
2124 		errno = ENOMEM;
2125 		(void) mutex_unlock(SH_LOCK(shp));
2126 		return (-1);
2127 	}
2128 
2129 	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2130 	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2131 		free(sub_info);
2132 		errno = EINVAL;
2133 		(void) mutex_unlock(SH_LOCK(shp));
2134 		return (-1);
2135 	}
2136 
2137 	if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
2138 		free(sub_info);
2139 		errno = ENOMEM;
2140 		(void) mutex_unlock(SH_LOCK(shp));
2141 		return (-1);
2142 	}
2143 	(void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
2144 	(void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
2145 	sub_info->sp_func = event_handler;
2146 
2147 	/* Update the in-kernel registration */
2148 	if (update_kernel_registration(shp, SUBSCRIBER,
2149 	    SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
2150 		error = errno;
2151 		goto fail;
2152 	}
2153 	SH_ID(shp) = sub_id;
2154 
2155 	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
2156 	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
2157 		error = EINVAL;
2158 		goto fail;
2159 	}
2160 	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
2161 		error = ENOMEM;
2162 		goto fail;
2163 	}
2164 
2165 	/*
2166 	 * Remove door file for robustness.
2167 	 */
2168 	if (unlink(SH_DOOR_NAME(shp)) != 0)
2169 		dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
2170 		    SH_DOOR_NAME(shp));
2171 
2172 	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
2173 	if (fd == -1) {
2174 		error = EFAULT;
2175 		goto fail;
2176 	}
2177 
2178 	/*
2179 	 * Create the sysevent door service for this client.
2180 	 * syseventd will use this door service to propagate
2181 	 * events to the client.
2182 	 */
2183 	if (subattr == NULL) {
2184 		SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2185 		    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2186 	} else {
2187 		SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2188 		    (void *)shp,
2189 		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2190 		    xdoor_server_create, xdoor_server_setup,
2191 		    (void *)subattr, 1);
2192 	}
2193 
2194 	if (SH_DOOR_DESC(shp) == -1) {
2195 		dprint("sysevent_bind_subscriber: door create failed: "
2196 		    "%s\n", strerror(errno));
2197 		error = EFAULT;
2198 		goto fail;
2199 	}
2200 
2201 	(void) fdetach(SH_DOOR_NAME(shp));
2202 	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2203 		error = EFAULT;
2204 		goto fail;
2205 	}
2206 	(void) close(fd);
2207 
2208 	if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
2209 	    sub_id, 0, NULL) != 0) {
2210 		error = errno;
2211 		(void) update_kernel_registration(shp, SUBSCRIBER,
2212 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2213 		goto fail;
2214 	}
2215 
2216 	SH_BOUND(shp) = 1;
2217 	SH_TYPE(shp) = SUBSCRIBER;
2218 	SH_PRIV_DATA(shp) = (void *)sub_info;
2219 
2220 	/* Create an event handler thread */
2221 	if (xsa == NULL || xsa->xs_thrcreate == NULL) {
2222 		created = thr_create(NULL, NULL,
2223 		    (void *(*)(void *))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,
2242 		    (void *(*)(void *))subscriber_event_handler,
2243 		    shp, xsa->xs_thrcreate_cookie) == 1;
2244 	}
2245 
2246 	if (!created) {
2247 		error = EFAULT;
2248 		goto fail;
2249 	}
2250 
2251 	(void) mutex_unlock(SH_LOCK(shp));
2252 
2253 	return (0);
2254 
2255 fail:
2256 	(void) close(fd);
2257 	(void) door_revoke(SH_DOOR_DESC(shp));
2258 	(void) fdetach(SH_DOOR_NAME(shp));
2259 	(void) cond_destroy(&sub_info->sp_cv);
2260 	(void) mutex_destroy(&sub_info->sp_qlock);
2261 	free(sub_info->sp_door_name);
2262 	free(sub_info);
2263 	if (SH_ID(shp)) {
2264 		(void) update_kernel_registration(shp, SUBSCRIBER,
2265 		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2266 		SH_ID(shp) = 0;
2267 	}
2268 	if (SH_BOUND(shp)) {
2269 		(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2270 		    sub_id, 0, NULL);
2271 		free(SH_DOOR_NAME(shp));
2272 		SH_BOUND(shp) = 0;
2273 	}
2274 	(void) mutex_unlock(SH_LOCK(shp));
2275 
2276 	errno = error;
2277 
2278 	return (-1);
2279 }
2280 
2281 /*
2282  * sysevent_bind_subscriber - Bind an event receiver to an event channel
2283  */
2284 int
sysevent_bind_subscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev))2285 sysevent_bind_subscriber(sysevent_handle_t *shp,
2286 	void (*event_handler)(sysevent_t *ev))
2287 {
2288 	return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2289 }
2290 
2291 /*
2292  * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2293  * attributes specified.
2294  */
2295 int
sysevent_bind_xsubscriber(sysevent_handle_t * shp,void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2296 sysevent_bind_xsubscriber(sysevent_handle_t *shp,
2297 	void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2298 {
2299 	return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2300 }
2301 
2302 /*
2303  * sysevent_register_event - register an event class and associated subclasses
2304  *		for an event subscriber
2305  */
2306 int
sysevent_register_event(sysevent_handle_t * shp,const char * ev_class,const char ** ev_subclass,int subclass_num)2307 sysevent_register_event(sysevent_handle_t *shp,
2308 	const char *ev_class, const char **ev_subclass,
2309 	int subclass_num)
2310 {
2311 	int error;
2312 	char *event_class = (char *)ev_class;
2313 	char **event_subclass_list = (char **)ev_subclass;
2314 	char *nvlbuf = NULL;
2315 	size_t datalen;
2316 	nvlist_t *nvl;
2317 
2318 	(void) mutex_lock(SH_LOCK(shp));
2319 	if (event_class == NULL || event_subclass_list == NULL ||
2320 	    event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
2321 	    subclass_num <= 0) {
2322 		(void) mutex_unlock(SH_LOCK(shp));
2323 		errno = EINVAL;
2324 		return (-1);
2325 	}
2326 
2327 	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2328 		(void) mutex_unlock(SH_LOCK(shp));
2329 		return (-1);
2330 	}
2331 	if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
2332 	    subclass_num) != 0) {
2333 		nvlist_free(nvl);
2334 		(void) mutex_unlock(SH_LOCK(shp));
2335 		return (-1);
2336 	}
2337 	if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
2338 		nvlist_free(nvl);
2339 		(void) mutex_unlock(SH_LOCK(shp));
2340 		return (-1);
2341 	}
2342 	nvlist_free(nvl);
2343 
2344 	/* Store new subscriber in in-kernel registration */
2345 	if (update_kernel_registration(shp, SUBSCRIBER,
2346 	    SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
2347 	    != 0) {
2348 		error = errno;
2349 		free(nvlbuf);
2350 		(void) mutex_unlock(SH_LOCK(shp));
2351 		errno = error;
2352 		return (-1);
2353 	}
2354 	/* Update the publisher's cached registration */
2355 	if (update_publisher_cache(
2356 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
2357 	    SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
2358 		error = errno;
2359 		free(nvlbuf);
2360 		(void) mutex_unlock(SH_LOCK(shp));
2361 		errno = error;
2362 		return (-1);
2363 	}
2364 
2365 	free(nvlbuf);
2366 
2367 	(void) mutex_unlock(SH_LOCK(shp));
2368 
2369 	return (0);
2370 }
2371 
2372 /*
2373  * sysevent_unregister_event - Unregister an event class and associated
2374  *				subclasses for an event subscriber
2375  */
2376 void
sysevent_unregister_event(sysevent_handle_t * shp,const char * class)2377 sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
2378 {
2379 	size_t class_sz;
2380 
2381 	(void) mutex_lock(SH_LOCK(shp));
2382 
2383 	if (!SH_BOUND(shp)) {
2384 		(void) mutex_unlock(SH_LOCK(shp));
2385 		return;
2386 	}
2387 
2388 	/* Remove subscriber from in-kernel registration */
2389 	class_sz = strlen(class) + 1;
2390 	(void) update_kernel_registration(shp, SUBSCRIBER,
2391 	    SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
2392 	/* Update the publisher's cached registration */
2393 	(void) update_publisher_cache(
2394 	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
2395 	    SH_ID(shp), class_sz, (uchar_t *)class);
2396 
2397 	(void) mutex_unlock(SH_LOCK(shp));
2398 }
2399 
2400 static int
cleanup_id(sysevent_handle_t * shp,uint32_t id,int type)2401 cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
2402 {
2403 	dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2404 
2405 	/* Remove registration from the kernel */
2406 	if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
2407 	    0, NULL) != 0) {
2408 		dprint("cleanup_id: Unable to clean "
2409 		    "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2410 		return (-1);
2411 	}
2412 
2413 	return (0);
2414 }
2415 
2416 /*
2417  * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
2418  *		allocated to unresponsive subscribers.
2419  */
2420 void
sysevent_cleanup_subscribers(sysevent_handle_t * shp)2421 sysevent_cleanup_subscribers(sysevent_handle_t *shp)
2422 {
2423 	uint32_t ping, result;
2424 	int i, error, sub_fd;
2425 	subscriber_data_t *sub;
2426 
2427 	if (!SH_BOUND(shp)) {
2428 		return;
2429 	}
2430 
2431 	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
2432 
2433 		sub = SH_SUBSCRIBER(shp, i);
2434 		if (sub == NULL) {
2435 			continue;
2436 		}
2437 
2438 		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
2439 			continue;
2440 		}
2441 		/* Check for valid and responsive subscriber */
2442 		error = clnt_deliver_event(sub_fd, &ping,
2443 		    sizeof (uint32_t), &result, sizeof (result));
2444 		(void) close(sub_fd);
2445 
2446 		/* Only cleanup on EBADF (Invalid door descriptor) */
2447 		if (error != EBADF)
2448 			continue;
2449 
2450 		if (cleanup_id(shp, i, SUBSCRIBER) != 0)
2451 			continue;
2452 
2453 		cache_remove_class(shp, EC_ALL, i);
2454 
2455 		free(sub->sd_door_name);
2456 		free(sub);
2457 		SH_SUBSCRIBER(shp, i) = NULL;
2458 	}
2459 
2460 }
2461 
2462 /*
2463  * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
2464  *		as needed.
2465  */
2466 void
sysevent_cleanup_publishers(sysevent_handle_t * shp)2467 sysevent_cleanup_publishers(sysevent_handle_t *shp)
2468 {
2469 	(void) cleanup_id(shp, 1, PUBLISHER);
2470 }
2471 
2472 /*
2473  * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
2474  */
2475 void
sysevent_unbind_subscriber(sysevent_handle_t * shp)2476 sysevent_unbind_subscriber(sysevent_handle_t *shp)
2477 {
2478 	subscriber_priv_t *sub_info;
2479 
2480 	if (shp == NULL)
2481 		return;
2482 
2483 	(void) mutex_lock(SH_LOCK(shp));
2484 	if (SH_BOUND(shp) == 0) {
2485 		(void) mutex_unlock(SH_LOCK(shp));
2486 		return;
2487 	}
2488 
2489 	/* Update the in-kernel registration */
2490 	(void) update_kernel_registration(shp, SUBSCRIBER,
2491 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2492 
2493 	/* Update the sysevent channel publisher */
2494 	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
2495 	(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2496 	    SH_ID(shp), 0, NULL);
2497 
2498 	/* Close down event delivery facilities */
2499 	(void) door_revoke(SH_DOOR_DESC(shp));
2500 	(void) fdetach(SH_DOOR_NAME(shp));
2501 
2502 	/*
2503 	 * Release resources and wait for pending event delivery to
2504 	 * complete.
2505 	 */
2506 	(void) mutex_lock(&sub_info->sp_qlock);
2507 	SH_BOUND(shp) = 0;
2508 	/* Signal event handler and drain the subscriber's event queue */
2509 	(void) cond_signal(&sub_info->sp_cv);
2510 	(void) mutex_unlock(&sub_info->sp_qlock);
2511 	if (sub_info->sp_handler_tid != NULL)
2512 		(void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
2513 
2514 	(void) cond_destroy(&sub_info->sp_cv);
2515 	(void) mutex_destroy(&sub_info->sp_qlock);
2516 	free(sub_info->sp_door_name);
2517 	free(sub_info);
2518 	free(SH_DOOR_NAME(shp));
2519 	(void) mutex_unlock(SH_LOCK(shp));
2520 }
2521 
2522 /*
2523  * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
2524  */
2525 void
sysevent_unbind_publisher(sysevent_handle_t * shp)2526 sysevent_unbind_publisher(sysevent_handle_t *shp)
2527 {
2528 	if (shp == NULL)
2529 		return;
2530 
2531 	(void) mutex_lock(SH_LOCK(shp));
2532 	if (SH_BOUND(shp) == 0) {
2533 		(void) mutex_unlock(SH_LOCK(shp));
2534 		return;
2535 	}
2536 
2537 	/* Close down the registration facilities */
2538 	(void) door_revoke(SH_DOOR_DESC(shp));
2539 	(void) fdetach(SH_DOOR_NAME(shp));
2540 
2541 	/* Update the in-kernel registration */
2542 	(void) update_kernel_registration(shp, PUBLISHER,
2543 	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2544 	SH_BOUND(shp) = 0;
2545 
2546 	/* Free resources associated with bind */
2547 	free_cached_registration(shp);
2548 	dealloc_subscribers(shp);
2549 
2550 	free(SH_PRIV_DATA(shp));
2551 	free(SH_DOOR_NAME(shp));
2552 	SH_ID(shp) = 0;
2553 	(void) mutex_unlock(SH_LOCK(shp));
2554 }
2555 
2556 /*
2557  * Evolving APIs to subscribe to syseventd(1M) system events.
2558  */
2559 
2560 static sysevent_handle_t *
sysevent_bind_handle_cmn(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2561 sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2562     sysevent_subattr_t *subattr)
2563 {
2564 	sysevent_handle_t *shp;
2565 
2566 	if (getuid() != 0) {
2567 		errno = EACCES;
2568 		return (NULL);
2569 	}
2570 
2571 	if (event_handler == NULL) {
2572 		errno = EINVAL;
2573 		return (NULL);
2574 	}
2575 
2576 	if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
2577 		return (NULL);
2578 	}
2579 
2580 	if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
2581 		/*
2582 		 * Ask syseventd to clean-up any stale subcribers and try to
2583 		 * to bind again
2584 		 */
2585 		if (errno == EBUSY) {
2586 			int pub_fd;
2587 			char door_name[MAXPATHLEN];
2588 			uint32_t result;
2589 			struct reg_args rargs;
2590 
2591 			if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2592 			    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2593 				sysevent_close_channel(shp);
2594 				errno = EINVAL;
2595 				return (NULL);
2596 			}
2597 
2598 			rargs.ra_op = SE_CLEANUP;
2599 			pub_fd = open(door_name, O_RDONLY);
2600 			(void) clnt_deliver_event(pub_fd, (void *)&rargs,
2601 			    sizeof (struct reg_args), &result, sizeof (result));
2602 			(void) close(pub_fd);
2603 
2604 			/* Try to bind again */
2605 			if (sysevent_bind_xsubscriber(shp, event_handler,
2606 			    subattr) != 0) {
2607 				sysevent_close_channel(shp);
2608 				return (NULL);
2609 			}
2610 		} else {
2611 			sysevent_close_channel(shp);
2612 			return (NULL);
2613 		}
2614 	}
2615 
2616 	return (shp);
2617 }
2618 
2619 /*
2620  * sysevent_bind_handle - Bind application event handler for syseventd
2621  *		subscription.
2622  */
2623 sysevent_handle_t *
sysevent_bind_handle(void (* event_handler)(sysevent_t * ev))2624 sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2625 {
2626 	return (sysevent_bind_handle_cmn(event_handler, NULL));
2627 }
2628 
2629 /*
2630  * sysevent_bind_xhandle - Bind application event handler for syseventd
2631  *		subscription, using door_xcreate and attributes as specified.
2632  */
2633 sysevent_handle_t *
sysevent_bind_xhandle(void (* event_handler)(sysevent_t * ev),sysevent_subattr_t * subattr)2634 sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2635     sysevent_subattr_t *subattr)
2636 {
2637 	return (sysevent_bind_handle_cmn(event_handler, subattr));
2638 }
2639 
2640 /*
2641  * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
2642  */
2643 void
sysevent_unbind_handle(sysevent_handle_t * shp)2644 sysevent_unbind_handle(sysevent_handle_t *shp)
2645 {
2646 	sysevent_unbind_subscriber(shp);
2647 	sysevent_close_channel(shp);
2648 }
2649 
2650 /*
2651  * sysevent_subscribe_event - Subscribe to system event notification from
2652  *			syseventd(1M) for the class and subclasses specified.
2653  */
2654 int
sysevent_subscribe_event(sysevent_handle_t * shp,const char * event_class,const char ** event_subclass_list,int num_subclasses)2655 sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
2656 	const char **event_subclass_list, int num_subclasses)
2657 {
2658 	return (sysevent_register_event(shp, event_class,
2659 	    event_subclass_list, num_subclasses));
2660 }
2661 
2662 void
sysevent_unsubscribe_event(sysevent_handle_t * shp,const char * event_class)2663 sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
2664 {
2665 	sysevent_unregister_event(shp, event_class);
2666 }
2667