1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * PICL plug-in that listens to sysevent and posts picl events
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <stdio.h>
34*0Sstevel@tonic-gate #include <string.h>
35*0Sstevel@tonic-gate #include <ctype.h>
36*0Sstevel@tonic-gate #include <limits.h>
37*0Sstevel@tonic-gate #include <stdlib.h>
38*0Sstevel@tonic-gate #include <assert.h>
39*0Sstevel@tonic-gate #include <alloca.h>
40*0Sstevel@tonic-gate #include <unistd.h>
41*0Sstevel@tonic-gate #include <stropts.h>
42*0Sstevel@tonic-gate #include <syslog.h>
43*0Sstevel@tonic-gate #include <libdevinfo.h>
44*0Sstevel@tonic-gate #include <sys/time.h>
45*0Sstevel@tonic-gate #include <fcntl.h>
46*0Sstevel@tonic-gate #include <picl.h>
47*0Sstevel@tonic-gate #include <picltree.h>
48*0Sstevel@tonic-gate #include <sys/types.h>
49*0Sstevel@tonic-gate #include <sys/sysinfo.h>
50*0Sstevel@tonic-gate #include <dirent.h>
51*0Sstevel@tonic-gate #include <libintl.h>
52*0Sstevel@tonic-gate #include <sys/sunddi.h>
53*0Sstevel@tonic-gate #include <sys/stat.h>
54*0Sstevel@tonic-gate #include <libsysevent.h>
55*0Sstevel@tonic-gate #include <libnvpair.h>
56*0Sstevel@tonic-gate #include "piclevent.h"
57*0Sstevel@tonic-gate 
58*0Sstevel@tonic-gate /*
59*0Sstevel@tonic-gate  * Plugin registration entry points
60*0Sstevel@tonic-gate  */
61*0Sstevel@tonic-gate static void	eventplugin_register(void);
62*0Sstevel@tonic-gate static void	eventplugin_init(void);
63*0Sstevel@tonic-gate static void	eventplugin_fini(void);
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate #pragma	init(eventplugin_register)
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate static picld_plugin_reg_t  my_reg_info = {
68*0Sstevel@tonic-gate 	PICLD_PLUGIN_VERSION_1,
69*0Sstevel@tonic-gate 	PICLD_PLUGIN_CRITICAL,
70*0Sstevel@tonic-gate 	"SUNW_piclevent plugin for sysevents",
71*0Sstevel@tonic-gate 	eventplugin_init,
72*0Sstevel@tonic-gate 	eventplugin_fini
73*0Sstevel@tonic-gate };
74*0Sstevel@tonic-gate 
75*0Sstevel@tonic-gate /*
76*0Sstevel@tonic-gate  * Log message texts
77*0Sstevel@tonic-gate  */
78*0Sstevel@tonic-gate #define	EVT_THR_FAILED		gettext("Event thread create failed!\n")
79*0Sstevel@tonic-gate #define	EVT_OPEN_FAILED		gettext("PICL SLM door create failed\n")
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate static	int		door_id = -1;
82*0Sstevel@tonic-gate #define	SUNW_PICLEVENT_PLUGIN_DEBUG	"SUNW_PICLEVENT_PLUGIN_DEBUG"
83*0Sstevel@tonic-gate static	int		piclevent_debug = 0;
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate 
86*0Sstevel@tonic-gate /*
87*0Sstevel@tonic-gate  * completion handler for the posted picl event
88*0Sstevel@tonic-gate  */
89*0Sstevel@tonic-gate /*ARGSUSED*/
90*0Sstevel@tonic-gate static void
91*0Sstevel@tonic-gate piclevent_completion_handler(char *ename, void *earg, size_t size)
92*0Sstevel@tonic-gate {
93*0Sstevel@tonic-gate 	free(earg);
94*0Sstevel@tonic-gate 	free(ename);
95*0Sstevel@tonic-gate }
96*0Sstevel@tonic-gate 
97*0Sstevel@tonic-gate /*
98*0Sstevel@tonic-gate  * This function posts the incoming piclevent
99*0Sstevel@tonic-gate  * It packs the nvlist and posts it to PICL
100*0Sstevel@tonic-gate  */
101*0Sstevel@tonic-gate static void
102*0Sstevel@tonic-gate parse_piclevent(nvlist_t *nvlp)
103*0Sstevel@tonic-gate {
104*0Sstevel@tonic-gate 	char		*enval;
105*0Sstevel@tonic-gate 	char		*ename;
106*0Sstevel@tonic-gate 	size_t		nvl_size;
107*0Sstevel@tonic-gate 	char		*packed_nvl;
108*0Sstevel@tonic-gate 	int		err;
109*0Sstevel@tonic-gate 
110*0Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_EVENT_NAME, &enval))
111*0Sstevel@tonic-gate 		return;
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	packed_nvl = NULL;
114*0Sstevel@tonic-gate 	if (nvlist_pack(nvlp, &packed_nvl, &nvl_size, NV_ENCODE_NATIVE, NULL))
115*0Sstevel@tonic-gate 		return;
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate 	ename = strdup(enval);
118*0Sstevel@tonic-gate 	if (ename == NULL) {
119*0Sstevel@tonic-gate 		free(packed_nvl);
120*0Sstevel@tonic-gate 		return;
121*0Sstevel@tonic-gate 	}
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (piclevent_debug) {
124*0Sstevel@tonic-gate 		syslog(LOG_INFO, "piclevent: posting ename:%s packed_nvl:%p "
125*0Sstevel@tonic-gate 		    "nvl_size:0x%x\n", ename, packed_nvl, nvl_size);
126*0Sstevel@tonic-gate 	}
127*0Sstevel@tonic-gate 	err = ptree_post_event(ename, packed_nvl, nvl_size,
128*0Sstevel@tonic-gate 	    piclevent_completion_handler);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	if (err != PICL_SUCCESS) {
131*0Sstevel@tonic-gate 		if (piclevent_debug)
132*0Sstevel@tonic-gate 			syslog(LOG_INFO,
133*0Sstevel@tonic-gate 			    "piclevent: posting ename:%s failed err:%d\n",
134*0Sstevel@tonic-gate 			    ename, err);
135*0Sstevel@tonic-gate 		free(ename);
136*0Sstevel@tonic-gate 		free(packed_nvl);
137*0Sstevel@tonic-gate 	}
138*0Sstevel@tonic-gate }
139*0Sstevel@tonic-gate 
140*0Sstevel@tonic-gate /*
141*0Sstevel@tonic-gate  * This is the PICL SLM door handler. It parses the event tuple received
142*0Sstevel@tonic-gate  * and posts an event to refresh the PICL tree.
143*0Sstevel@tonic-gate  */
144*0Sstevel@tonic-gate /*ARGSUSED*/
145*0Sstevel@tonic-gate static void
146*0Sstevel@tonic-gate event_handler(void *cookie, char *argp, size_t asize,
147*0Sstevel@tonic-gate     door_desc_t *dp, uint_t n_desc)
148*0Sstevel@tonic-gate {
149*0Sstevel@tonic-gate 	door_cred_t		cred;
150*0Sstevel@tonic-gate 	nvlist_t		*nvlp;
151*0Sstevel@tonic-gate 	char			*dtype;
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate 	if (piclevent_debug)
154*0Sstevel@tonic-gate 		syslog(LOG_INFO,
155*0Sstevel@tonic-gate 		    "piclevent: got SLM event cookie:%p evarg:%p size:0x%x\n",
156*0Sstevel@tonic-gate 		    cookie, argp, asize);
157*0Sstevel@tonic-gate 	if ((door_id < 0) || (argp == NULL) || (door_cred(&cred) < 0) ||
158*0Sstevel@tonic-gate 	    (cred.dc_euid != 0))
159*0Sstevel@tonic-gate 		(void) door_return(argp, 0, NULL, 0);
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	if (nvlist_unpack(argp, asize, &nvlp, NULL))
162*0Sstevel@tonic-gate 		(void) door_return(argp, 0, NULL, 0);
163*0Sstevel@tonic-gate 
164*0Sstevel@tonic-gate 	if (nvlist_lookup_string(nvlp, PICLEVENTARG_DATA_TYPE, &dtype)) {
165*0Sstevel@tonic-gate 		nvlist_free(nvlp);
166*0Sstevel@tonic-gate 		(void) door_return(argp, 0, NULL, 0);
167*0Sstevel@tonic-gate 	}
168*0Sstevel@tonic-gate 
169*0Sstevel@tonic-gate 	if (strcmp(dtype, PICLEVENTARG_PICLEVENT_DATA) == 0)
170*0Sstevel@tonic-gate 		parse_piclevent(nvlp);
171*0Sstevel@tonic-gate 	/*
172*0Sstevel@tonic-gate 	 * ignore other event data types
173*0Sstevel@tonic-gate 	 */
174*0Sstevel@tonic-gate 	nvlist_free(nvlp);
175*0Sstevel@tonic-gate 	(void) door_return(argp, 0, NULL, 0);
176*0Sstevel@tonic-gate }
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate /*
179*0Sstevel@tonic-gate  * Create the slm to picl plugin door
180*0Sstevel@tonic-gate  */
181*0Sstevel@tonic-gate static int
182*0Sstevel@tonic-gate setup_door(void)
183*0Sstevel@tonic-gate {
184*0Sstevel@tonic-gate 	struct stat	stbuf;
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 	/*
187*0Sstevel@tonic-gate 	 * Create the door
188*0Sstevel@tonic-gate 	 */
189*0Sstevel@tonic-gate 	door_id = door_create(event_handler, PICLEVENT_DOOR_COOKIE,
190*0Sstevel@tonic-gate 	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate 	if (door_id < 0)
193*0Sstevel@tonic-gate 		return (-1);
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	if (stat(PICLEVENT_DOOR, &stbuf) < 0) {
196*0Sstevel@tonic-gate 		int newfd;
197*0Sstevel@tonic-gate 		if ((newfd = creat(PICLEVENT_DOOR, 0444)) < 0) {
198*0Sstevel@tonic-gate 			(void) door_revoke(door_id);
199*0Sstevel@tonic-gate 			door_id = -1;
200*0Sstevel@tonic-gate 			return (-1);
201*0Sstevel@tonic-gate 		}
202*0Sstevel@tonic-gate 		(void) close(newfd);
203*0Sstevel@tonic-gate 	}
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	if (fattach(door_id, PICLEVENT_DOOR) < 0) {
206*0Sstevel@tonic-gate 		if ((errno != EBUSY) || (fdetach(PICLEVENT_DOOR) < 0) ||
207*0Sstevel@tonic-gate 		    (fattach(door_id, PICLEVENT_DOOR) < 0)) {
208*0Sstevel@tonic-gate 			(void) door_revoke(door_id);
209*0Sstevel@tonic-gate 			door_id = -1;
210*0Sstevel@tonic-gate 			return (-1);
211*0Sstevel@tonic-gate 		}
212*0Sstevel@tonic-gate 	}
213*0Sstevel@tonic-gate 
214*0Sstevel@tonic-gate 	return (0);
215*0Sstevel@tonic-gate }
216*0Sstevel@tonic-gate 
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /*
219*0Sstevel@tonic-gate  * This function is executed as part of .init when the plugin is
220*0Sstevel@tonic-gate  * dlopen()ed
221*0Sstevel@tonic-gate  */
222*0Sstevel@tonic-gate static void
223*0Sstevel@tonic-gate eventplugin_register(void)
224*0Sstevel@tonic-gate {
225*0Sstevel@tonic-gate 	if (getenv(SUNW_PICLEVENT_PLUGIN_DEBUG))
226*0Sstevel@tonic-gate 		piclevent_debug = 1;
227*0Sstevel@tonic-gate 	(void) picld_plugin_register(&my_reg_info);
228*0Sstevel@tonic-gate }
229*0Sstevel@tonic-gate 
230*0Sstevel@tonic-gate /*
231*0Sstevel@tonic-gate  * This function is the init entry point of the plugin.
232*0Sstevel@tonic-gate  * It creates the slm to picl plugin door.
233*0Sstevel@tonic-gate  */
234*0Sstevel@tonic-gate static void
235*0Sstevel@tonic-gate eventplugin_init(void)
236*0Sstevel@tonic-gate {
237*0Sstevel@tonic-gate 	if (setup_door() < 0) {
238*0Sstevel@tonic-gate 		syslog(LOG_ERR, EVT_OPEN_FAILED);
239*0Sstevel@tonic-gate 	}
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate /*
243*0Sstevel@tonic-gate  * This function is the fini entry point of the plugin
244*0Sstevel@tonic-gate  */
245*0Sstevel@tonic-gate static void
246*0Sstevel@tonic-gate eventplugin_fini(void)
247*0Sstevel@tonic-gate {
248*0Sstevel@tonic-gate 	if (door_id >= 0) {
249*0Sstevel@tonic-gate 		(void) door_revoke(door_id);
250*0Sstevel@tonic-gate 		door_id = -1;
251*0Sstevel@tonic-gate 	}
252*0Sstevel@tonic-gate }
253