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
62static int libsysevent_debug = 0;
63
64static sysevent_t *se_unpack(sysevent_t *);
65static 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 */
75static sysevent_t *
76sysevent_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 */
151int
152sysevent_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 */
185sysevent_t *
186sysevent_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 */
216void
217sysevent_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 */
234int
235sysevent_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 */
285char *
286sysevent_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 */
298int
299sysevent_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 */
359sysevent_attr_t *
360sysevent_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 */
379int
380sysevent_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 */
414int
415sysevent_get_class(sysevent_t *ev)
416{
417	return (SE_CLASS(ev));
418}
419
420/*
421 * sysevent_get_subclass - Get subclass id
422 */
423int
424sysevent_get_subclass(sysevent_t *ev)
425{
426	return (SE_SUBCLASS(ev));
427}
428
429/*
430 * sysevent_get_class_name - Get class name string
431 */
432char *
433sysevent_get_class_name(sysevent_t *ev)
434{
435	return (SE_CLASS_NAME(ev));
436}
437
438typedef 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 */
448char *
449sysevent_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 */
459static char *
460parse_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 */
485static const char *
486pub_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
504char *
505sysevent_get_vendor_name(sysevent_t *ev)
506{
507	return (parse_pub_id(ev, PUB_VEND));
508}
509
510char *
511sysevent_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 */
520void
521sysevent_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 */
541char *
542sysevent_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 */
550uint64_t
551sysevent_get_seq(sysevent_t *ev)
552{
553	return (SE_SEQ(ev));
554}
555
556/*
557 * sysevent_get_time - Get event timestamp
558 */
559void
560sysevent_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 */
568size_t
569sysevent_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 */
585sysevent_t *
586sysevent_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 */
644static sysevent_t *
645se_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 */
681void
682se_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 */
758static void *
759subscriber_event_handler(void *arg)
760{
761	sysevent_handle_t *shp = arg;
762	subscriber_priv_t *sub_info;
763	sysevent_queue_t *evqp;
764
765	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
766
767	/* See hack alert in sysevent_bind_subscriber_cmn */
768	if (sub_info->sp_handler_tid == 0)
769		sub_info->sp_handler_tid = thr_self();
770
771	(void) mutex_lock(&sub_info->sp_qlock);
772	for (;;) {
773		while (sub_info->sp_evq_head == NULL && SH_BOUND(shp)) {
774			(void) cond_wait(&sub_info->sp_cv, &sub_info->sp_qlock);
775		}
776		evqp = sub_info->sp_evq_head;
777		while (evqp) {
778			(void) mutex_unlock(&sub_info->sp_qlock);
779			(void) sub_info->sp_func(evqp->sq_ev);
780			(void) mutex_lock(&sub_info->sp_qlock);
781			sub_info->sp_evq_head = sub_info->sp_evq_head->sq_next;
782			free(evqp->sq_ev);
783			free(evqp);
784			evqp = sub_info->sp_evq_head;
785		}
786		if (!SH_BOUND(shp)) {
787			(void) mutex_unlock(&sub_info->sp_qlock);
788			return (NULL);
789		}
790	}
791
792	/* NOTREACHED */
793}
794
795/*
796 * Data structure used to communicate event subscription cache updates
797 * to publishers via a registration door
798 */
799struct 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*/
812static void
813event_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
893return_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 */
923static int
924clnt_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
952static int
953update_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 */
990static int
991update_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 */
1019static nvlist_t *
1020get_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
1076static void
1077dealloc_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*/
1093static int
1094alloc_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
1132static uint32_t
1133hash_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
1151subclass_lst_t *
1152cache_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
1172static class_lst_t *
1173cache_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
1195static int
1196cache_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
1227static int
1228cache_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
1281static void
1282cache_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
1301static void
1302cache_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
1323static void
1324free_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
1349static int
1350create_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
1462create_failed:
1463	dealloc_subscribers(shp);
1464	free_cached_registration(shp);
1465	nvlist_free(nvl);
1466	return (-1);
1467
1468}
1469
1470/*
1471 * cache_update_service - generic event publisher service routine.  This routine
1472 *		is called in response to a registration cache update.
1473 *
1474 */
1475/*ARGSUSED*/
1476static void
1477cache_update_service(void *cookie, char *args, size_t alen,
1478    door_desc_t *ddp, uint_t ndid)
1479{
1480	int ret = 0;
1481	uint_t num_elem;
1482	char *class, **event_list;
1483	size_t datalen;
1484	uint32_t sub_id;
1485	nvlist_t *nvl;
1486	nvpair_t *nvpair = NULL;
1487	struct reg_args *rargs;
1488	sysevent_handle_t *shp;
1489	subscriber_data_t *sub;
1490
1491	if (alen < sizeof (struct reg_args) || cookie == NULL) {
1492		ret = EINVAL;
1493		goto return_from_door;
1494	}
1495
1496	/* LINTED: E_BAD_PTR_CAST_ALIGN */
1497	rargs = (struct reg_args *)args;
1498	shp = (sysevent_handle_t *)cookie;
1499
1500	datalen = alen - sizeof (struct reg_args);
1501	sub_id = rargs->ra_sub_id;
1502
1503	(void) mutex_lock(SH_LOCK(shp));
1504
1505	switch (rargs->ra_op) {
1506	case SE_UNREGISTER:
1507		class = (char *)&rargs->ra_buf_ptr;
1508		cache_remove_class(shp, (char *)class,
1509		    sub_id);
1510		break;
1511	case SE_UNBIND_REGISTRATION:
1512
1513		sub = SH_SUBSCRIBER(shp, sub_id);
1514		if (sub == NULL)
1515			break;
1516
1517		free(sub->sd_door_name);
1518		free(sub);
1519		cache_remove_class(shp, EC_ALL, sub_id);
1520		SH_SUBSCRIBER(shp, sub_id) = NULL;
1521
1522		break;
1523	case SE_BIND_REGISTRATION:
1524
1525		/* New subscriber */
1526		if (alloc_subscriber(shp, sub_id, 0) != 0) {
1527			ret = ENOMEM;
1528			break;
1529		}
1530		break;
1531	case SE_REGISTER:
1532
1533		if (SH_SUBSCRIBER(shp, sub_id) == NULL) {
1534			ret = EINVAL;
1535			break;
1536		}
1537		/* Get new registration data */
1538		if (nvlist_unpack((char *)&rargs->ra_buf_ptr, datalen,
1539		    &nvl, 0) != 0) {
1540			ret =  EFAULT;
1541			break;
1542		}
1543		if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1544			nvlist_free(nvl);
1545			ret = EFAULT;
1546			break;
1547		}
1548		if (nvpair_value_string_array(nvpair, &event_list, &num_elem)
1549		    != 0) {
1550			nvlist_free(nvl);
1551			ret =  EFAULT;
1552			break;
1553		}
1554		class = nvpair_name(nvpair);
1555
1556		ret = cache_insert_class(shp, class,
1557		    event_list, num_elem, sub_id);
1558		if (ret != 0) {
1559			cache_remove_class(shp, class, sub_id);
1560			nvlist_free(nvl);
1561			ret =  EFAULT;
1562			break;
1563		}
1564
1565		nvlist_free(nvl);
1566
1567		break;
1568	case SE_CLEANUP:
1569		/* Cleanup stale subscribers */
1570		sysevent_cleanup_subscribers(shp);
1571		break;
1572	default:
1573		ret =  EINVAL;
1574	}
1575
1576	(void) mutex_unlock(SH_LOCK(shp));
1577
1578return_from_door:
1579	(void) door_return((void *)&ret, sizeof (ret), NULL, 0);
1580	(void) door_return(NULL, 0, NULL, 0);
1581}
1582
1583/*
1584 * sysevent_send_event -
1585 * Send an event via the communication channel associated with the sysevent
1586 * handle.  Event notifications are broadcast to all subscribers based upon
1587 * the event class and subclass.  The handle must have been previously
1588 * allocated and bound by
1589 * sysevent_open_channel() and sysevent_bind_publisher()
1590 */
1591int
1592sysevent_send_event(sysevent_handle_t *shp, sysevent_t *ev)
1593{
1594	int i, error, sub_fd, result = 0;
1595	int deliver_error = 0;
1596	int subscribers_sent = 0;
1597	int want_resend, resend_cnt = 0;
1598	char *event_class, *event_subclass;
1599	uchar_t *all_class_subscribers, *all_subclass_subscribers;
1600	uchar_t *subclass_subscribers;
1601	subscriber_data_t *sub;
1602	subclass_lst_t *sc_lst;
1603
1604	/* Check for proper registration */
1605	event_class = sysevent_get_class_name(ev);
1606	event_subclass = sysevent_get_subclass_name(ev);
1607
1608	(void) mutex_lock(SH_LOCK(shp));
1609
1610send_event:
1611
1612	want_resend = 0;
1613	if (!SH_BOUND(shp)) {
1614		(void) mutex_unlock(SH_LOCK(shp));
1615		errno = EINVAL;
1616		return (-1);
1617	}
1618
1619	/* Find all subscribers for this event class/subclass */
1620	sc_lst = cache_find_subclass(
1621	    cache_find_class(shp, EC_ALL), EC_SUB_ALL);
1622	all_class_subscribers = sc_lst->sl_num;
1623
1624	sc_lst = cache_find_subclass(
1625	    cache_find_class(shp, event_class), EC_SUB_ALL);
1626	if (sc_lst)
1627		all_subclass_subscribers = sc_lst->sl_num;
1628	else
1629		all_subclass_subscribers = NULL;
1630
1631	sc_lst = cache_find_subclass(
1632	    cache_find_class(shp, event_class), event_subclass);
1633	if (sc_lst)
1634		subclass_subscribers = sc_lst->sl_num;
1635	else
1636		subclass_subscribers = NULL;
1637
1638	/* Send event buffer to all valid subscribers */
1639	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
1640		if ((all_class_subscribers[i] |
1641		    (all_subclass_subscribers && all_subclass_subscribers[i]) |
1642		    (subclass_subscribers && subclass_subscribers[i])) == 0)
1643			continue;
1644
1645		sub = SH_SUBSCRIBER(shp, i);
1646		assert(sub != NULL);
1647
1648		/* Check for active subscriber */
1649		if (!(sub->sd_flag & ACTIVE)) {
1650			dprint("sysevent_send_event: subscriber %d inactive\n",
1651			    i);
1652			continue;
1653		}
1654
1655		/* Process only resend requests */
1656		if (resend_cnt > 0 && !(sub->sd_flag & SEND_AGAIN)) {
1657			continue;
1658		}
1659
1660		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
1661			dprint("sysevent_send_event: Failed to open "
1662			    "%s: %s\n", sub->sd_door_name, strerror(errno));
1663			continue;
1664		}
1665		result = 0;
1666		error = clnt_deliver_event(sub_fd, ev,
1667		    sysevent_get_size(ev), &result, sizeof (result));
1668
1669		(void) close(sub_fd);
1670
1671		/* Successful door call */
1672		if (error == 0) {
1673			switch (result) {
1674			/* Subscriber requested EAGAIN */
1675			case EAGAIN:
1676				if (resend_cnt > SE_MAX_RETRY_LIMIT) {
1677					deliver_error = 1;
1678				} else {
1679					want_resend = 1;
1680					dprint("sysevent_send_event: resend "
1681					    "requested for %d\n", i);
1682					sub->sd_flag |= SEND_AGAIN;
1683				}
1684				break;
1685			/* Bad sysevent handle for subscriber */
1686			case EBADF:
1687			case EINVAL:
1688				dprint("sysevent_send_event: Bad sysevent "
1689				    "handle for %s", sub->sd_door_name);
1690				sub->sd_flag = 0;
1691				deliver_error = 1;
1692				break;
1693			/* Successful delivery */
1694			default:
1695				sub->sd_flag &= ~SEND_AGAIN;
1696				++subscribers_sent;
1697			}
1698		} else {
1699			dprint("sysevent_send_event: Failed door call "
1700			    "to %s: %s: %d\n", sub->sd_door_name,
1701			    strerror(errno), result);
1702			sub->sd_flag = 0;
1703			deliver_error = 1;
1704		}
1705	}
1706
1707	if (want_resend) {
1708		resend_cnt++;
1709		goto send_event;
1710	}
1711
1712	if (deliver_error) {
1713		sysevent_cleanup_subscribers(shp);
1714		(void) mutex_unlock(SH_LOCK(shp));
1715		errno = EFAULT;
1716		return (-1);
1717	}
1718
1719	(void) mutex_unlock(SH_LOCK(shp));
1720
1721	if (subscribers_sent == 0) {
1722		dprint("sysevent_send_event: No subscribers for %s:%s\n",
1723		    event_class, event_subclass);
1724		errno = ENOENT;
1725		return (-1);
1726	}
1727
1728	return (0);
1729}
1730
1731/*
1732 * Common routine to establish an event channel through which an event
1733 * publisher or subscriber may post or receive events.
1734 */
1735static sysevent_handle_t *
1736sysevent_open_channel_common(const char *channel_path)
1737{
1738	uint32_t sub_id = 0;
1739	char *begin_path;
1740	struct stat chan_stat;
1741	sysevent_handle_t *shp;
1742
1743
1744	if (channel_path == NULL || strlen(channel_path) + 1 > MAXPATHLEN) {
1745		errno = EINVAL;
1746		return (NULL);
1747	}
1748
1749	if (mkdir(channel_path, S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1750		if (errno != EEXIST) {
1751			errno = EACCES;
1752			return (NULL);
1753		}
1754	}
1755
1756	/* Check channel file permissions */
1757	if (stat(channel_path, &chan_stat) != 0) {
1758		dprint("sysevent_open_channel: Invalid permissions for channel "
1759		    "%s\n", channel_path);
1760		errno = EACCES;
1761		return (NULL);
1762	} else if (chan_stat.st_uid != getuid() ||
1763	    !S_ISDIR(chan_stat.st_mode)) {
1764		dprint("sysevent_open_channel: Invalid "
1765		    "permissions for channel %s\n: %d:%d:%d", channel_path,
1766		    (int)chan_stat.st_uid, (int)chan_stat.st_gid,
1767		    (int)chan_stat.st_mode);
1768
1769		errno = EACCES;
1770		return (NULL);
1771	}
1772
1773	shp = calloc(1, sizeof (sysevent_impl_hdl_t));
1774	if (shp == NULL) {
1775		errno = ENOMEM;
1776		return (NULL);
1777	}
1778
1779	SH_CHANNEL_NAME(shp) = NULL;
1780	SH_CHANNEL_PATH(shp) = strdup(channel_path);
1781	if (SH_CHANNEL_PATH(shp) == NULL) {
1782		free(shp);
1783		errno = ENOMEM;
1784		return (NULL);
1785	}
1786
1787	/* Extract the channel name */
1788	begin_path = SH_CHANNEL_PATH(shp);
1789	while (*begin_path != '\0' &&
1790	    (begin_path = strpbrk(begin_path, "/")) != NULL) {
1791		++begin_path;
1792		SH_CHANNEL_NAME(shp) = begin_path;
1793	}
1794
1795	if (update_kernel_registration(shp, 0,
1796	    SE_OPEN_REGISTRATION, &sub_id, 0, NULL) != 0) {
1797		dprint("sysevent_open_channel: Failed for channel %s\n",
1798		    SH_CHANNEL_NAME(shp));
1799		free(SH_CHANNEL_PATH(shp));
1800		free(shp);
1801		errno = EFAULT;
1802		return (NULL);
1803	}
1804
1805	(void) mutex_init(SH_LOCK(shp), USYNC_THREAD, NULL);
1806
1807	return (shp);
1808}
1809
1810/*
1811 * Establish a sysevent channel for publication and subscription
1812 */
1813sysevent_handle_t *
1814sysevent_open_channel(const char *channel)
1815{
1816	int var_run_mounted = 0;
1817	char full_channel[MAXPATHLEN + 1];
1818	FILE *fp;
1819	struct stat chan_stat;
1820	struct extmnttab m;
1821
1822	if (channel == NULL) {
1823		errno = EINVAL;
1824		return (NULL);
1825	}
1826
1827	/*
1828	 * Check that /var/run is mounted as tmpfs before allowing a channel
1829	 * to be opened.
1830	 */
1831	if ((fp = fopen(MNTTAB, "rF")) == NULL) {
1832		errno = EACCES;
1833		return (NULL);
1834	}
1835
1836	resetmnttab(fp);
1837
1838	while (getextmntent(fp, &m, sizeof (struct extmnttab)) == 0) {
1839		if (strcmp(m.mnt_mountp, "/var/run") == 0 &&
1840		    strcmp(m.mnt_fstype, "tmpfs") == 0) {
1841			var_run_mounted = 1;
1842			break;
1843		}
1844	}
1845	(void) fclose(fp);
1846
1847	if (!var_run_mounted) {
1848		errno = EACCES;
1849		return (NULL);
1850	}
1851
1852	if (stat(CHAN_PATH, &chan_stat) < 0) {
1853		if (mkdir(CHAN_PATH,
1854		    S_IRWXU|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) < 0) {
1855			dprint("sysevent_open_channel: Unable "
1856			    "to create channel directory %s:%s\n", CHAN_PATH,
1857			    strerror(errno));
1858			if (errno != EEXIST) {
1859				errno = EACCES;
1860				return (NULL);
1861			}
1862		}
1863	}
1864
1865	if (snprintf(full_channel, MAXPATHLEN, "%s/%s", CHAN_PATH, channel) >=
1866	    MAXPATHLEN) {
1867		errno = EINVAL;
1868		return (NULL);
1869	}
1870
1871	return (sysevent_open_channel_common(full_channel));
1872}
1873
1874/*
1875 * Establish a sysevent channel for publication and subscription
1876 * Full path to the channel determined by the caller
1877 */
1878sysevent_handle_t *
1879sysevent_open_channel_alt(const char *channel_path)
1880{
1881	return (sysevent_open_channel_common(channel_path));
1882}
1883
1884/*
1885 * sysevent_close_channel - Clean up resources associated with a previously
1886 *				opened sysevent channel
1887 */
1888void
1889sysevent_close_channel(sysevent_handle_t *shp)
1890{
1891	int error = errno;
1892	uint32_t sub_id = 0;
1893
1894	if (shp == NULL) {
1895		return;
1896	}
1897
1898	(void) mutex_lock(SH_LOCK(shp));
1899	if (SH_BOUND(shp)) {
1900		(void) mutex_unlock(SH_LOCK(shp));
1901		if (SH_TYPE(shp) == PUBLISHER)
1902			sysevent_unbind_publisher(shp);
1903		else if (SH_TYPE(shp) == SUBSCRIBER)
1904			sysevent_unbind_subscriber(shp);
1905		(void) mutex_lock(SH_LOCK(shp));
1906	}
1907
1908	(void) update_kernel_registration(shp, 0,
1909	    SE_CLOSE_REGISTRATION, &sub_id, 0, NULL);
1910	(void) mutex_unlock(SH_LOCK(shp));
1911
1912	free(SH_CHANNEL_PATH(shp));
1913	free(shp);
1914	errno = error;
1915}
1916
1917/*
1918 * sysevent_bind_publisher - Bind an event publisher to an event channel
1919 */
1920int
1921sysevent_bind_publisher(sysevent_handle_t *shp)
1922{
1923	int error = 0;
1924	int fd = -1;
1925	char door_name[MAXPATHLEN];
1926	uint32_t pub_id;
1927	struct stat reg_stat;
1928	publisher_priv_t *pub;
1929
1930	if (shp == NULL) {
1931		errno = EINVAL;
1932		return (-1);
1933	}
1934
1935	(void) mutex_lock(SH_LOCK(shp));
1936	if (SH_BOUND(shp)) {
1937		(void) mutex_unlock(SH_LOCK(shp));
1938		errno = EINVAL;
1939		return (-1);
1940	}
1941
1942	if ((pub = (publisher_priv_t *)calloc(1, sizeof (publisher_priv_t))) ==
1943	    NULL) {
1944		(void) mutex_unlock(SH_LOCK(shp));
1945		errno = ENOMEM;
1946		return (-1);
1947	}
1948	SH_PRIV_DATA(shp) = (void *)pub;
1949
1950	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
1951	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
1952		free(pub);
1953		(void) mutex_unlock(SH_LOCK(shp));
1954		errno = ENOMEM;
1955		return (-1);
1956	}
1957	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
1958		free(pub);
1959		(void) mutex_unlock(SH_LOCK(shp));
1960		errno = ENOMEM;
1961		return (-1);
1962	}
1963
1964	/* Only one publisher allowed per channel */
1965	if (stat(SH_DOOR_NAME(shp), &reg_stat) != 0) {
1966		if (errno != ENOENT) {
1967			error = EINVAL;
1968			goto fail;
1969		}
1970	}
1971
1972	/*
1973	 * Remove door file for robustness.
1974	 */
1975	if (unlink(SH_DOOR_NAME(shp)) != 0)
1976		dprint("sysevent_bind_publisher: Unlink of %s failed.\n",
1977		    SH_DOOR_NAME(shp));
1978
1979	/* Open channel registration door */
1980	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR,
1981	    S_IREAD|S_IWRITE);
1982	if (fd == -1) {
1983		error = EINVAL;
1984		goto fail;
1985	}
1986
1987	/*
1988	 * Create the registration service for this publisher.
1989	 */
1990	if ((SH_DOOR_DESC(shp) = door_create(cache_update_service,
1991	    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL)) == -1) {
1992		dprint("sysevent_bind_publisher: door create failed: "
1993		    "%s\n", strerror(errno));
1994		error = EFAULT;
1995		goto fail;
1996	}
1997
1998	(void) fdetach(SH_DOOR_NAME(shp));
1999	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2000		dprint("sysevent_bind_publisher: unable to "
2001		    "bind event channel: fattach: %s\n",
2002		    SH_DOOR_NAME(shp));
2003		error = EACCES;
2004		goto fail;
2005	}
2006
2007	/* Bind this publisher in the kernel registration database */
2008	if (update_kernel_registration(shp, PUBLISHER,
2009	    SE_BIND_REGISTRATION, &pub_id, 0, NULL) != 0) {
2010		error = errno;
2011		goto fail;
2012	}
2013
2014	SH_ID(shp) = pub_id;
2015	SH_BOUND(shp) = 1;
2016	SH_TYPE(shp) = PUBLISHER;
2017
2018
2019	/* Create the subscription registration cache */
2020	if (create_cached_registration(shp, SH_CLASS_HASH(shp)) != 0) {
2021		(void) update_kernel_registration(shp,
2022		    PUBLISHER, SE_UNBIND_REGISTRATION, &pub_id, 0, NULL);
2023		error = EFAULT;
2024		goto fail;
2025	}
2026	(void) close(fd);
2027
2028	(void) mutex_unlock(SH_LOCK(shp));
2029
2030	return (0);
2031
2032fail:
2033	SH_BOUND(shp) = 0;
2034	(void) door_revoke(SH_DOOR_DESC(shp));
2035	(void) fdetach(SH_DOOR_NAME(shp));
2036	free(SH_DOOR_NAME(shp));
2037	free(pub);
2038	(void) close(fd);
2039	(void) mutex_unlock(SH_LOCK(shp));
2040	errno = error;
2041	return (-1);
2042}
2043
2044static pthread_once_t xdoor_thrattr_once = PTHREAD_ONCE_INIT;
2045static pthread_attr_t xdoor_thrattr;
2046
2047static void
2048xdoor_thrattr_init(void)
2049{
2050	(void) pthread_attr_init(&xdoor_thrattr);
2051	(void) pthread_attr_setdetachstate(&xdoor_thrattr,
2052	    PTHREAD_CREATE_DETACHED);
2053	(void) pthread_attr_setscope(&xdoor_thrattr, PTHREAD_SCOPE_SYSTEM);
2054}
2055
2056static int
2057xdoor_server_create(door_info_t *dip, void *(*startf)(void *),
2058    void *startfarg, void *cookie)
2059{
2060	struct sysevent_subattr_impl *xsa = cookie;
2061	pthread_attr_t *thrattr;
2062	sigset_t oset;
2063	int err;
2064
2065	if (xsa->xs_thrcreate) {
2066		return (xsa->xs_thrcreate(dip, startf, startfarg,
2067		    xsa->xs_thrcreate_cookie));
2068	}
2069
2070	if (xsa->xs_thrattr == NULL) {
2071		(void) pthread_once(&xdoor_thrattr_once, xdoor_thrattr_init);
2072		thrattr = &xdoor_thrattr;
2073	} else {
2074		thrattr = xsa->xs_thrattr;
2075	}
2076
2077	(void) pthread_sigmask(SIG_SETMASK, &xsa->xs_sigmask, &oset);
2078	err = pthread_create(NULL, thrattr, startf, startfarg);
2079	(void) pthread_sigmask(SIG_SETMASK, &oset, NULL);
2080
2081	return (err == 0 ? 1 : -1);
2082}
2083
2084static void
2085xdoor_server_setup(void *cookie)
2086{
2087	struct sysevent_subattr_impl *xsa = cookie;
2088
2089	if (xsa->xs_thrsetup) {
2090		xsa->xs_thrsetup(xsa->xs_thrsetup_cookie);
2091	} else {
2092		(void) pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
2093		(void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
2094	}
2095}
2096
2097static int
2098sysevent_bind_subscriber_cmn(sysevent_handle_t *shp,
2099    void (*event_handler)(sysevent_t *ev),
2100    sysevent_subattr_t *subattr)
2101{
2102	int fd = -1;
2103	int error = 0;
2104	uint32_t sub_id = 0;
2105	char door_name[MAXPATHLEN];
2106	subscriber_priv_t *sub_info;
2107	int created;
2108	struct sysevent_subattr_impl *xsa =
2109	    (struct sysevent_subattr_impl *)subattr;
2110
2111	if (shp == NULL || event_handler == NULL) {
2112		errno = EINVAL;
2113		return (-1);
2114	}
2115
2116	(void) mutex_lock(SH_LOCK(shp));
2117	if (SH_BOUND(shp)) {
2118		errno = EINVAL;
2119		(void) mutex_unlock(SH_LOCK(shp));
2120		return (-1);
2121	}
2122
2123	if ((sub_info = (subscriber_priv_t *)calloc(1,
2124	    sizeof (subscriber_priv_t))) == NULL) {
2125		errno = ENOMEM;
2126		(void) mutex_unlock(SH_LOCK(shp));
2127		return (-1);
2128	}
2129
2130	if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2131	    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2132		free(sub_info);
2133		errno = EINVAL;
2134		(void) mutex_unlock(SH_LOCK(shp));
2135		return (-1);
2136	}
2137
2138	if ((sub_info->sp_door_name = strdup(door_name)) == NULL) {
2139		free(sub_info);
2140		errno = ENOMEM;
2141		(void) mutex_unlock(SH_LOCK(shp));
2142		return (-1);
2143	}
2144	(void) cond_init(&sub_info->sp_cv, USYNC_THREAD, NULL);
2145	(void) mutex_init(&sub_info->sp_qlock, USYNC_THREAD, NULL);
2146	sub_info->sp_func = event_handler;
2147
2148	/* Update the in-kernel registration */
2149	if (update_kernel_registration(shp, SUBSCRIBER,
2150	    SE_BIND_REGISTRATION, &sub_id, 0, NULL) != 0) {
2151		error = errno;
2152		goto fail;
2153	}
2154	SH_ID(shp) = sub_id;
2155
2156	if (snprintf(door_name, MAXPATHLEN, "%s/%d",
2157	    SH_CHANNEL_PATH(shp), sub_id) >= MAXPATHLEN) {
2158		error = EINVAL;
2159		goto fail;
2160	}
2161	if ((SH_DOOR_NAME(shp) = strdup(door_name)) == NULL) {
2162		error = ENOMEM;
2163		goto fail;
2164	}
2165
2166	/*
2167	 * Remove door file for robustness.
2168	 */
2169	if (unlink(SH_DOOR_NAME(shp)) != 0)
2170		dprint("sysevent_bind_subscriber: Unlink of %s failed.\n",
2171		    SH_DOOR_NAME(shp));
2172
2173	fd = open(SH_DOOR_NAME(shp), O_CREAT|O_RDWR, S_IREAD|S_IWRITE);
2174	if (fd == -1) {
2175		error = EFAULT;
2176		goto fail;
2177	}
2178
2179	/*
2180	 * Create the sysevent door service for this client.
2181	 * syseventd will use this door service to propagate
2182	 * events to the client.
2183	 */
2184	if (subattr == NULL) {
2185		SH_DOOR_DESC(shp) = door_create(event_deliver_service,
2186		    (void *)shp, DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
2187	} else {
2188		SH_DOOR_DESC(shp) = door_xcreate(event_deliver_service,
2189		    (void *)shp,
2190		    DOOR_REFUSE_DESC | DOOR_NO_CANCEL | DOOR_NO_DEPLETION_CB,
2191		    xdoor_server_create, xdoor_server_setup,
2192		    (void *)subattr, 1);
2193	}
2194
2195	if (SH_DOOR_DESC(shp) == -1) {
2196		dprint("sysevent_bind_subscriber: door create failed: "
2197		    "%s\n", strerror(errno));
2198		error = EFAULT;
2199		goto fail;
2200	}
2201
2202	(void) fdetach(SH_DOOR_NAME(shp));
2203	if (fattach(SH_DOOR_DESC(shp), SH_DOOR_NAME(shp)) != 0) {
2204		error = EFAULT;
2205		goto fail;
2206	}
2207	(void) close(fd);
2208
2209	if (update_publisher_cache(sub_info, SE_BIND_REGISTRATION,
2210	    sub_id, 0, NULL) != 0) {
2211		error = errno;
2212		(void) update_kernel_registration(shp, SUBSCRIBER,
2213		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2214		goto fail;
2215	}
2216
2217	SH_BOUND(shp) = 1;
2218	SH_TYPE(shp) = SUBSCRIBER;
2219	SH_PRIV_DATA(shp) = (void *)sub_info;
2220
2221	/* Create an event handler thread */
2222	if (xsa == NULL || xsa->xs_thrcreate == NULL) {
2223		created = thr_create(NULL, 0, subscriber_event_handler,
2224		    shp, THR_BOUND, &sub_info->sp_handler_tid) == 0;
2225	} else {
2226		/*
2227		 * A terrible hack.  We will use the extended private
2228		 * door thread creation function the caller passed in to
2229		 * create the event handler thread.  That function will
2230		 * be called with our chosen thread start function and arg
2231		 * instead of the usual libc-provided ones, but that's ok
2232		 * as it is required to use them verbatim anyway.  We will
2233		 * pass a NULL door_info_t pointer to the function - so
2234		 * callers depending on this hack had better be prepared
2235		 * for that.  All this allow the caller to rubberstamp
2236		 * the created thread as it wishes.  But we don't get
2237		 * the created threadid with this, so we modify the
2238		 * thread start function to stash it.
2239		 */
2240
2241		created = xsa->xs_thrcreate(NULL, subscriber_event_handler,
2242		    shp, xsa->xs_thrcreate_cookie) == 1;
2243	}
2244
2245	if (!created) {
2246		error = EFAULT;
2247		goto fail;
2248	}
2249
2250	(void) mutex_unlock(SH_LOCK(shp));
2251
2252	return (0);
2253
2254fail:
2255	(void) close(fd);
2256	(void) door_revoke(SH_DOOR_DESC(shp));
2257	(void) fdetach(SH_DOOR_NAME(shp));
2258	(void) cond_destroy(&sub_info->sp_cv);
2259	(void) mutex_destroy(&sub_info->sp_qlock);
2260	free(sub_info->sp_door_name);
2261	free(sub_info);
2262	if (SH_ID(shp)) {
2263		(void) update_kernel_registration(shp, SUBSCRIBER,
2264		    SE_UNBIND_REGISTRATION, &sub_id, 0, NULL);
2265		SH_ID(shp) = 0;
2266	}
2267	if (SH_BOUND(shp)) {
2268		(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2269		    sub_id, 0, NULL);
2270		free(SH_DOOR_NAME(shp));
2271		SH_BOUND(shp) = 0;
2272	}
2273	(void) mutex_unlock(SH_LOCK(shp));
2274
2275	errno = error;
2276
2277	return (-1);
2278}
2279
2280/*
2281 * sysevent_bind_subscriber - Bind an event receiver to an event channel
2282 */
2283int
2284sysevent_bind_subscriber(sysevent_handle_t *shp,
2285    void (*event_handler)(sysevent_t *ev))
2286{
2287	return (sysevent_bind_subscriber_cmn(shp, event_handler, NULL));
2288}
2289
2290/*
2291 * sysevent_bind_xsubscriber - Bind a subscriber using door_xcreate with
2292 * attributes specified.
2293 */
2294int
2295sysevent_bind_xsubscriber(sysevent_handle_t *shp,
2296    void (*event_handler)(sysevent_t *ev), sysevent_subattr_t *subattr)
2297{
2298	return (sysevent_bind_subscriber_cmn(shp, event_handler, subattr));
2299}
2300
2301/*
2302 * sysevent_register_event - register an event class and associated subclasses
2303 *		for an event subscriber
2304 */
2305int
2306sysevent_register_event(sysevent_handle_t *shp,
2307    const char *ev_class, const char **ev_subclass,
2308    int subclass_num)
2309{
2310	int error;
2311	char *event_class = (char *)ev_class;
2312	char **event_subclass_list = (char **)ev_subclass;
2313	char *nvlbuf = NULL;
2314	size_t datalen;
2315	nvlist_t *nvl;
2316
2317	(void) mutex_lock(SH_LOCK(shp));
2318	if (event_class == NULL || event_subclass_list == NULL ||
2319	    event_subclass_list[0] == NULL || SH_BOUND(shp) != 1 ||
2320	    subclass_num <= 0) {
2321		(void) mutex_unlock(SH_LOCK(shp));
2322		errno = EINVAL;
2323		return (-1);
2324	}
2325
2326	if (nvlist_alloc(&nvl, NV_UNIQUE_NAME_TYPE, 0) != 0) {
2327		(void) mutex_unlock(SH_LOCK(shp));
2328		return (-1);
2329	}
2330	if (nvlist_add_string_array(nvl, event_class, event_subclass_list,
2331	    subclass_num) != 0) {
2332		nvlist_free(nvl);
2333		(void) mutex_unlock(SH_LOCK(shp));
2334		return (-1);
2335	}
2336	if (nvlist_pack(nvl, &nvlbuf, &datalen, NV_ENCODE_NATIVE, 0) != 0) {
2337		nvlist_free(nvl);
2338		(void) mutex_unlock(SH_LOCK(shp));
2339		return (-1);
2340	}
2341	nvlist_free(nvl);
2342
2343	/* Store new subscriber in in-kernel registration */
2344	if (update_kernel_registration(shp, SUBSCRIBER,
2345	    SE_REGISTER, &SH_ID(shp), datalen, (uchar_t *)nvlbuf)
2346	    != 0) {
2347		error = errno;
2348		free(nvlbuf);
2349		(void) mutex_unlock(SH_LOCK(shp));
2350		errno = error;
2351		return (-1);
2352	}
2353	/* Update the publisher's cached registration */
2354	if (update_publisher_cache(
2355	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_REGISTER,
2356	    SH_ID(shp), datalen, (uchar_t *)nvlbuf) != 0) {
2357		error = errno;
2358		free(nvlbuf);
2359		(void) mutex_unlock(SH_LOCK(shp));
2360		errno = error;
2361		return (-1);
2362	}
2363
2364	free(nvlbuf);
2365
2366	(void) mutex_unlock(SH_LOCK(shp));
2367
2368	return (0);
2369}
2370
2371/*
2372 * sysevent_unregister_event - Unregister an event class and associated
2373 *				subclasses for an event subscriber
2374 */
2375void
2376sysevent_unregister_event(sysevent_handle_t *shp, const char *class)
2377{
2378	size_t class_sz;
2379
2380	(void) mutex_lock(SH_LOCK(shp));
2381
2382	if (!SH_BOUND(shp)) {
2383		(void) mutex_unlock(SH_LOCK(shp));
2384		return;
2385	}
2386
2387	/* Remove subscriber from in-kernel registration */
2388	class_sz = strlen(class) + 1;
2389	(void) update_kernel_registration(shp, SUBSCRIBER,
2390	    SE_UNREGISTER, &SH_ID(shp), class_sz, (uchar_t *)class);
2391	/* Update the publisher's cached registration */
2392	(void) update_publisher_cache(
2393	    (subscriber_priv_t *)SH_PRIV_DATA(shp), SE_UNREGISTER,
2394	    SH_ID(shp), class_sz, (uchar_t *)class);
2395
2396	(void) mutex_unlock(SH_LOCK(shp));
2397}
2398
2399static int
2400cleanup_id(sysevent_handle_t *shp, uint32_t id, int type)
2401{
2402	dprint("cleanup_id: Cleaning up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2403
2404	/* Remove registration from the kernel */
2405	if (update_kernel_registration(shp, type, SE_CLEANUP, &id,
2406	    0, NULL) != 0) {
2407		dprint("cleanup_id: Unable to clean "
2408		    "up %s/%d\n", SH_CHANNEL_NAME(shp), id);
2409		return (-1);
2410	}
2411
2412	return (0);
2413}
2414
2415/*
2416 * sysevent_cleanup_subscribers: Allows the caller to cleanup resources
2417 *		allocated to unresponsive subscribers.
2418 */
2419void
2420sysevent_cleanup_subscribers(sysevent_handle_t *shp)
2421{
2422	uint32_t ping, result;
2423	int i, error, sub_fd;
2424	subscriber_data_t *sub;
2425
2426	if (!SH_BOUND(shp)) {
2427		return;
2428	}
2429
2430	for (i = 1; i <= MAX_SUBSCRIBERS; ++i) {
2431
2432		sub = SH_SUBSCRIBER(shp, i);
2433		if (sub == NULL) {
2434			continue;
2435		}
2436
2437		if ((sub_fd = open(sub->sd_door_name, O_RDONLY)) == -1) {
2438			continue;
2439		}
2440		/* Check for valid and responsive subscriber */
2441		error = clnt_deliver_event(sub_fd, &ping,
2442		    sizeof (uint32_t), &result, sizeof (result));
2443		(void) close(sub_fd);
2444
2445		/* Only cleanup on EBADF (Invalid door descriptor) */
2446		if (error != EBADF)
2447			continue;
2448
2449		if (cleanup_id(shp, i, SUBSCRIBER) != 0)
2450			continue;
2451
2452		cache_remove_class(shp, EC_ALL, i);
2453
2454		free(sub->sd_door_name);
2455		free(sub);
2456		SH_SUBSCRIBER(shp, i) = NULL;
2457	}
2458
2459}
2460
2461/*
2462 * sysevent_cleanup_publishers: Allows stale publisher handles to be deallocated
2463 *		as needed.
2464 */
2465void
2466sysevent_cleanup_publishers(sysevent_handle_t *shp)
2467{
2468	(void) cleanup_id(shp, 1, PUBLISHER);
2469}
2470
2471/*
2472 * sysevent_unbind_subscriber: Unbind the subscriber from the sysevent channel.
2473 */
2474void
2475sysevent_unbind_subscriber(sysevent_handle_t *shp)
2476{
2477	subscriber_priv_t *sub_info;
2478
2479	if (shp == NULL)
2480		return;
2481
2482	(void) mutex_lock(SH_LOCK(shp));
2483	if (SH_BOUND(shp) == 0) {
2484		(void) mutex_unlock(SH_LOCK(shp));
2485		return;
2486	}
2487
2488	/* Update the in-kernel registration */
2489	(void) update_kernel_registration(shp, SUBSCRIBER,
2490	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2491
2492	/* Update the sysevent channel publisher */
2493	sub_info = (subscriber_priv_t *)SH_PRIV_DATA(shp);
2494	(void) update_publisher_cache(sub_info, SE_UNBIND_REGISTRATION,
2495	    SH_ID(shp), 0, NULL);
2496
2497	/* Close down event delivery facilities */
2498	(void) door_revoke(SH_DOOR_DESC(shp));
2499	(void) fdetach(SH_DOOR_NAME(shp));
2500
2501	/*
2502	 * Release resources and wait for pending event delivery to
2503	 * complete.
2504	 */
2505	(void) mutex_lock(&sub_info->sp_qlock);
2506	SH_BOUND(shp) = 0;
2507	/* Signal event handler and drain the subscriber's event queue */
2508	(void) cond_signal(&sub_info->sp_cv);
2509	(void) mutex_unlock(&sub_info->sp_qlock);
2510	if (sub_info->sp_handler_tid != 0)
2511		(void) thr_join(sub_info->sp_handler_tid, NULL, NULL);
2512
2513	(void) cond_destroy(&sub_info->sp_cv);
2514	(void) mutex_destroy(&sub_info->sp_qlock);
2515	free(sub_info->sp_door_name);
2516	free(sub_info);
2517	free(SH_DOOR_NAME(shp));
2518	(void) mutex_unlock(SH_LOCK(shp));
2519}
2520
2521/*
2522 * sysevent_unbind_publisher: Unbind publisher from the sysevent channel.
2523 */
2524void
2525sysevent_unbind_publisher(sysevent_handle_t *shp)
2526{
2527	if (shp == NULL)
2528		return;
2529
2530	(void) mutex_lock(SH_LOCK(shp));
2531	if (SH_BOUND(shp) == 0) {
2532		(void) mutex_unlock(SH_LOCK(shp));
2533		return;
2534	}
2535
2536	/* Close down the registration facilities */
2537	(void) door_revoke(SH_DOOR_DESC(shp));
2538	(void) fdetach(SH_DOOR_NAME(shp));
2539
2540	/* Update the in-kernel registration */
2541	(void) update_kernel_registration(shp, PUBLISHER,
2542	    SE_UNBIND_REGISTRATION, &SH_ID(shp), 0, NULL);
2543	SH_BOUND(shp) = 0;
2544
2545	/* Free resources associated with bind */
2546	free_cached_registration(shp);
2547	dealloc_subscribers(shp);
2548
2549	free(SH_PRIV_DATA(shp));
2550	free(SH_DOOR_NAME(shp));
2551	SH_ID(shp) = 0;
2552	(void) mutex_unlock(SH_LOCK(shp));
2553}
2554
2555/*
2556 * Evolving APIs to subscribe to syseventd(1M) system events.
2557 */
2558
2559static sysevent_handle_t *
2560sysevent_bind_handle_cmn(void (*event_handler)(sysevent_t *ev),
2561    sysevent_subattr_t *subattr)
2562{
2563	sysevent_handle_t *shp;
2564
2565	if (getuid() != 0) {
2566		errno = EACCES;
2567		return (NULL);
2568	}
2569
2570	if (event_handler == NULL) {
2571		errno = EINVAL;
2572		return (NULL);
2573	}
2574
2575	if ((shp = sysevent_open_channel(SYSEVENTD_CHAN)) == NULL) {
2576		return (NULL);
2577	}
2578
2579	if (sysevent_bind_xsubscriber(shp, event_handler, subattr) != 0) {
2580		/*
2581		 * Ask syseventd to clean-up any stale subcribers and try to
2582		 * to bind again
2583		 */
2584		if (errno == EBUSY) {
2585			int pub_fd;
2586			char door_name[MAXPATHLEN];
2587			uint32_t result;
2588			struct reg_args rargs;
2589
2590			if (snprintf(door_name, MAXPATHLEN, "%s/%s",
2591			    SH_CHANNEL_PATH(shp), REG_DOOR) >= MAXPATHLEN) {
2592				sysevent_close_channel(shp);
2593				errno = EINVAL;
2594				return (NULL);
2595			}
2596
2597			rargs.ra_op = SE_CLEANUP;
2598			pub_fd = open(door_name, O_RDONLY);
2599			(void) clnt_deliver_event(pub_fd, (void *)&rargs,
2600			    sizeof (struct reg_args), &result, sizeof (result));
2601			(void) close(pub_fd);
2602
2603			/* Try to bind again */
2604			if (sysevent_bind_xsubscriber(shp, event_handler,
2605			    subattr) != 0) {
2606				sysevent_close_channel(shp);
2607				return (NULL);
2608			}
2609		} else {
2610			sysevent_close_channel(shp);
2611			return (NULL);
2612		}
2613	}
2614
2615	return (shp);
2616}
2617
2618/*
2619 * sysevent_bind_handle - Bind application event handler for syseventd
2620 *		subscription.
2621 */
2622sysevent_handle_t *
2623sysevent_bind_handle(void (*event_handler)(sysevent_t *ev))
2624{
2625	return (sysevent_bind_handle_cmn(event_handler, NULL));
2626}
2627
2628/*
2629 * sysevent_bind_xhandle - Bind application event handler for syseventd
2630 *		subscription, using door_xcreate and attributes as specified.
2631 */
2632sysevent_handle_t *
2633sysevent_bind_xhandle(void (*event_handler)(sysevent_t *ev),
2634    sysevent_subattr_t *subattr)
2635{
2636	return (sysevent_bind_handle_cmn(event_handler, subattr));
2637}
2638
2639/*
2640 * sysevent_unbind_handle - Unbind caller from syseventd subscriptions
2641 */
2642void
2643sysevent_unbind_handle(sysevent_handle_t *shp)
2644{
2645	sysevent_unbind_subscriber(shp);
2646	sysevent_close_channel(shp);
2647}
2648
2649/*
2650 * sysevent_subscribe_event - Subscribe to system event notification from
2651 *			syseventd(1M) for the class and subclasses specified.
2652 */
2653int
2654sysevent_subscribe_event(sysevent_handle_t *shp, const char *event_class,
2655    const char **event_subclass_list, int num_subclasses)
2656{
2657	return (sysevent_register_event(shp, event_class,
2658	    event_subclass_list, num_subclasses));
2659}
2660
2661void
2662sysevent_unsubscribe_event(sysevent_handle_t *shp, const char *event_class)
2663{
2664	sysevent_unregister_event(shp, event_class);
2665}
2666