xref: /titanic_50/usr/src/lib/fm/libfmnotify/common/libfmnotify.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1*f6e214c7SGavin Maltby /*
2*f6e214c7SGavin Maltby  * CDDL HEADER START
3*f6e214c7SGavin Maltby  *
4*f6e214c7SGavin Maltby  * The contents of this file are subject to the terms of the
5*f6e214c7SGavin Maltby  * Common Development and Distribution License (the "License").
6*f6e214c7SGavin Maltby  * You may not use this file except in compliance with the License.
7*f6e214c7SGavin Maltby  *
8*f6e214c7SGavin Maltby  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*f6e214c7SGavin Maltby  * or http://www.opensolaris.org/os/licensing.
10*f6e214c7SGavin Maltby  * See the License for the specific language governing permissions
11*f6e214c7SGavin Maltby  * and limitations under the License.
12*f6e214c7SGavin Maltby  *
13*f6e214c7SGavin Maltby  * When distributing Covered Code, include this CDDL HEADER in each
14*f6e214c7SGavin Maltby  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*f6e214c7SGavin Maltby  * If applicable, add the following below this CDDL HEADER, with the
16*f6e214c7SGavin Maltby  * fields enclosed by brackets "[]" replaced with your own identifying
17*f6e214c7SGavin Maltby  * information: Portions Copyright [yyyy] [name of copyright owner]
18*f6e214c7SGavin Maltby  *
19*f6e214c7SGavin Maltby  * CDDL HEADER END
20*f6e214c7SGavin Maltby  */
21*f6e214c7SGavin Maltby 
22*f6e214c7SGavin Maltby /*
23*f6e214c7SGavin Maltby  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24*f6e214c7SGavin Maltby  */
25*f6e214c7SGavin Maltby #include <alloca.h>
26*f6e214c7SGavin Maltby 
27*f6e214c7SGavin Maltby #include "libfmnotify.h"
28*f6e214c7SGavin Maltby 
29*f6e214c7SGavin Maltby /*ARGSUSED*/
30*f6e214c7SGavin Maltby void
nd_cleanup(nd_hdl_t * nhdl)31*f6e214c7SGavin Maltby nd_cleanup(nd_hdl_t *nhdl)
32*f6e214c7SGavin Maltby {
33*f6e214c7SGavin Maltby 	nd_debug(nhdl, "Cleaning up ...");
34*f6e214c7SGavin Maltby 	if (nhdl->nh_evhdl)
35*f6e214c7SGavin Maltby 		(void) fmev_shdl_fini(nhdl->nh_evhdl);
36*f6e214c7SGavin Maltby 
37*f6e214c7SGavin Maltby 	if (nhdl->nh_msghdl)
38*f6e214c7SGavin Maltby 		fmd_msg_fini(nhdl->nh_msghdl);
39*f6e214c7SGavin Maltby 
40*f6e214c7SGavin Maltby 	nhdl->nh_keep_running = B_FALSE;
41*f6e214c7SGavin Maltby 	(void) fclose(nhdl->nh_log_fd);
42*f6e214c7SGavin Maltby }
43*f6e214c7SGavin Maltby 
44*f6e214c7SGavin Maltby static void
get_timestamp(char * buf,size_t bufsize)45*f6e214c7SGavin Maltby get_timestamp(char *buf, size_t bufsize)
46*f6e214c7SGavin Maltby {
47*f6e214c7SGavin Maltby 	time_t utc_time;
48*f6e214c7SGavin Maltby 	struct tm *p_tm;
49*f6e214c7SGavin Maltby 
50*f6e214c7SGavin Maltby 	(void) time(&utc_time);
51*f6e214c7SGavin Maltby 	p_tm = localtime(&utc_time);
52*f6e214c7SGavin Maltby 
53*f6e214c7SGavin Maltby 	(void) strftime(buf, bufsize, "%b %d %H:%M:%S", p_tm);
54*f6e214c7SGavin Maltby }
55*f6e214c7SGavin Maltby 
56*f6e214c7SGavin Maltby /* PRINTFLIKE2 */
57*f6e214c7SGavin Maltby void
nd_debug(nd_hdl_t * nhdl,const char * format,...)58*f6e214c7SGavin Maltby nd_debug(nd_hdl_t *nhdl, const char *format, ...)
59*f6e214c7SGavin Maltby {
60*f6e214c7SGavin Maltby 	char timestamp[64];
61*f6e214c7SGavin Maltby 	va_list ap;
62*f6e214c7SGavin Maltby 
63*f6e214c7SGavin Maltby 	if (nhdl->nh_debug) {
64*f6e214c7SGavin Maltby 		get_timestamp(timestamp, sizeof (timestamp));
65*f6e214c7SGavin Maltby 		(void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
66*f6e214c7SGavin Maltby 		va_start(ap, format);
67*f6e214c7SGavin Maltby 		(void) vfprintf(nhdl->nh_log_fd, format, ap);
68*f6e214c7SGavin Maltby 		va_end(ap);
69*f6e214c7SGavin Maltby 		(void) fprintf(nhdl->nh_log_fd, " ]\n");
70*f6e214c7SGavin Maltby 	}
71*f6e214c7SGavin Maltby 	(void) fflush(nhdl->nh_log_fd);
72*f6e214c7SGavin Maltby }
73*f6e214c7SGavin Maltby 
74*f6e214c7SGavin Maltby void
nd_dump_nvlist(nd_hdl_t * nhdl,nvlist_t * nvl)75*f6e214c7SGavin Maltby nd_dump_nvlist(nd_hdl_t *nhdl, nvlist_t *nvl)
76*f6e214c7SGavin Maltby {
77*f6e214c7SGavin Maltby 	if (nhdl->nh_debug)
78*f6e214c7SGavin Maltby 		nvlist_print(nhdl->nh_log_fd, nvl);
79*f6e214c7SGavin Maltby }
80*f6e214c7SGavin Maltby 
81*f6e214c7SGavin Maltby /* PRINTFLIKE2 */
82*f6e214c7SGavin Maltby void
nd_error(nd_hdl_t * nhdl,const char * format,...)83*f6e214c7SGavin Maltby nd_error(nd_hdl_t *nhdl, const char *format, ...)
84*f6e214c7SGavin Maltby {
85*f6e214c7SGavin Maltby 	char timestamp[64];
86*f6e214c7SGavin Maltby 	va_list ap;
87*f6e214c7SGavin Maltby 
88*f6e214c7SGavin Maltby 	get_timestamp(timestamp, sizeof (timestamp));
89*f6e214c7SGavin Maltby 	(void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
90*f6e214c7SGavin Maltby 	va_start(ap, format);
91*f6e214c7SGavin Maltby 	(void) vfprintf(nhdl->nh_log_fd, format, ap);
92*f6e214c7SGavin Maltby 	va_end(ap);
93*f6e214c7SGavin Maltby 	(void) fprintf(nhdl->nh_log_fd, " ]\n");
94*f6e214c7SGavin Maltby 	(void) fflush(nhdl->nh_log_fd);
95*f6e214c7SGavin Maltby }
96*f6e214c7SGavin Maltby 
97*f6e214c7SGavin Maltby /* PRINTFLIKE2 */
98*f6e214c7SGavin Maltby void
nd_abort(nd_hdl_t * nhdl,const char * format,...)99*f6e214c7SGavin Maltby nd_abort(nd_hdl_t *nhdl, const char *format, ...)
100*f6e214c7SGavin Maltby {
101*f6e214c7SGavin Maltby 	char timestamp[64];
102*f6e214c7SGavin Maltby 	va_list ap;
103*f6e214c7SGavin Maltby 
104*f6e214c7SGavin Maltby 	get_timestamp(timestamp, sizeof (timestamp));
105*f6e214c7SGavin Maltby 	(void) fprintf(nhdl->nh_log_fd, "[ %s ", timestamp);
106*f6e214c7SGavin Maltby 	va_start(ap, format);
107*f6e214c7SGavin Maltby 	(void) vfprintf(nhdl->nh_log_fd, format, ap);
108*f6e214c7SGavin Maltby 	va_end(ap);
109*f6e214c7SGavin Maltby 	(void) fprintf(nhdl->nh_log_fd, " ]\n");
110*f6e214c7SGavin Maltby 	(void) fflush(nhdl->nh_log_fd);
111*f6e214c7SGavin Maltby 	nd_cleanup(nhdl);
112*f6e214c7SGavin Maltby }
113*f6e214c7SGavin Maltby 
114*f6e214c7SGavin Maltby void
nd_daemonize(nd_hdl_t * nhdl)115*f6e214c7SGavin Maltby nd_daemonize(nd_hdl_t *nhdl)
116*f6e214c7SGavin Maltby {
117*f6e214c7SGavin Maltby 	pid_t pid;
118*f6e214c7SGavin Maltby 
119*f6e214c7SGavin Maltby 	if ((pid = fork()) < 0)
120*f6e214c7SGavin Maltby 		nd_abort(nhdl, "Failed to fork child (%s)", strerror(errno));
121*f6e214c7SGavin Maltby 	else if (pid > 0)
122*f6e214c7SGavin Maltby 		exit(0);
123*f6e214c7SGavin Maltby 
124*f6e214c7SGavin Maltby 	(void) setsid();
125*f6e214c7SGavin Maltby 	(void) close(0);
126*f6e214c7SGavin Maltby 	(void) close(1);
127*f6e214c7SGavin Maltby 	/*
128*f6e214c7SGavin Maltby 	 * We leave stderr open so we can write debug/err messages to the SMF
129*f6e214c7SGavin Maltby 	 * service log
130*f6e214c7SGavin Maltby 	 */
131*f6e214c7SGavin Maltby 	nhdl->nh_is_daemon = B_TRUE;
132*f6e214c7SGavin Maltby }
133*f6e214c7SGavin Maltby 
134*f6e214c7SGavin Maltby /*
135*f6e214c7SGavin Maltby  * This function returns a pointer to the specified SMF property group for the
136*f6e214c7SGavin Maltby  * specified SMF service.  The caller is responsible for freeing the property
137*f6e214c7SGavin Maltby  * group.  On failure, the function returns NULL.
138*f6e214c7SGavin Maltby  */
139*f6e214c7SGavin Maltby static scf_propertygroup_t *
nd_get_pg(nd_hdl_t * nhdl,scf_handle_t * handle,const char * svcname,const char * pgname)140*f6e214c7SGavin Maltby nd_get_pg(nd_hdl_t *nhdl, scf_handle_t *handle, const char *svcname,
141*f6e214c7SGavin Maltby     const char *pgname)
142*f6e214c7SGavin Maltby {
143*f6e214c7SGavin Maltby 	scf_scope_t *sc = NULL;
144*f6e214c7SGavin Maltby 	scf_service_t *svc = NULL;
145*f6e214c7SGavin Maltby 	scf_propertygroup_t *pg = NULL, *ret = NULL;
146*f6e214c7SGavin Maltby 
147*f6e214c7SGavin Maltby 	sc = scf_scope_create(handle);
148*f6e214c7SGavin Maltby 	svc = scf_service_create(handle);
149*f6e214c7SGavin Maltby 	pg = scf_pg_create(handle);
150*f6e214c7SGavin Maltby 
151*f6e214c7SGavin Maltby 	if (sc == NULL || svc == NULL || pg == NULL) {
152*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to allocate libscf structures");
153*f6e214c7SGavin Maltby 		scf_pg_destroy(pg);
154*f6e214c7SGavin Maltby 		goto get_pg_done;
155*f6e214c7SGavin Maltby 	}
156*f6e214c7SGavin Maltby 
157*f6e214c7SGavin Maltby 	if (scf_handle_bind(handle) != -1 &&
158*f6e214c7SGavin Maltby 	    scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, sc) != -1 &&
159*f6e214c7SGavin Maltby 	    scf_scope_get_service(sc, svcname, svc) != -1 &&
160*f6e214c7SGavin Maltby 	    scf_service_get_pg(svc, pgname, pg) != -1)
161*f6e214c7SGavin Maltby 		ret = pg;
162*f6e214c7SGavin Maltby 	else
163*f6e214c7SGavin Maltby 		scf_pg_destroy(pg);
164*f6e214c7SGavin Maltby 
165*f6e214c7SGavin Maltby get_pg_done:
166*f6e214c7SGavin Maltby 	scf_service_destroy(svc);
167*f6e214c7SGavin Maltby 	scf_scope_destroy(sc);
168*f6e214c7SGavin Maltby 
169*f6e214c7SGavin Maltby 	return (ret);
170*f6e214c7SGavin Maltby }
171*f6e214c7SGavin Maltby 
172*f6e214c7SGavin Maltby int
nd_get_astring_prop(nd_hdl_t * nhdl,const char * svcname,const char * pgname,const char * propname,char ** val)173*f6e214c7SGavin Maltby nd_get_astring_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
174*f6e214c7SGavin Maltby     const char *propname, char **val)
175*f6e214c7SGavin Maltby {
176*f6e214c7SGavin Maltby 	scf_handle_t *handle = NULL;
177*f6e214c7SGavin Maltby 	scf_propertygroup_t *pg;
178*f6e214c7SGavin Maltby 	scf_property_t *prop = NULL;
179*f6e214c7SGavin Maltby 	scf_value_t *value = NULL;
180*f6e214c7SGavin Maltby 	char strval[255];
181*f6e214c7SGavin Maltby 	int ret = -1;
182*f6e214c7SGavin Maltby 
183*f6e214c7SGavin Maltby 	if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
184*f6e214c7SGavin Maltby 		return (ret);
185*f6e214c7SGavin Maltby 
186*f6e214c7SGavin Maltby 	if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
187*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to read retrieve %s "
188*f6e214c7SGavin Maltby 		    "property group for %s", pgname, svcname);
189*f6e214c7SGavin Maltby 		goto astring_done;
190*f6e214c7SGavin Maltby 	}
191*f6e214c7SGavin Maltby 	prop = scf_property_create(handle);
192*f6e214c7SGavin Maltby 	value = scf_value_create(handle);
193*f6e214c7SGavin Maltby 	if (prop == NULL || value == NULL) {
194*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to allocate SMF structures");
195*f6e214c7SGavin Maltby 		goto astring_done;
196*f6e214c7SGavin Maltby 	}
197*f6e214c7SGavin Maltby 	if (scf_pg_get_property(pg, propname, prop) == -1 ||
198*f6e214c7SGavin Maltby 	    scf_property_get_value(prop, value) == -1 ||
199*f6e214c7SGavin Maltby 	    scf_value_get_astring(value, strval, 255) == -1) {
200*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
201*f6e214c7SGavin Maltby 		    scf_strerror(scf_error()));
202*f6e214c7SGavin Maltby 		goto astring_done;
203*f6e214c7SGavin Maltby 	}
204*f6e214c7SGavin Maltby 	*val = strdup(strval);
205*f6e214c7SGavin Maltby 	ret = 0;
206*f6e214c7SGavin Maltby 
207*f6e214c7SGavin Maltby astring_done:
208*f6e214c7SGavin Maltby 	scf_value_destroy(value);
209*f6e214c7SGavin Maltby 	scf_property_destroy(prop);
210*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
211*f6e214c7SGavin Maltby 	scf_handle_destroy(handle);
212*f6e214c7SGavin Maltby 
213*f6e214c7SGavin Maltby 	return (ret);
214*f6e214c7SGavin Maltby }
215*f6e214c7SGavin Maltby 
216*f6e214c7SGavin Maltby int
nd_get_boolean_prop(nd_hdl_t * nhdl,const char * svcname,const char * pgname,const char * propname,uint8_t * val)217*f6e214c7SGavin Maltby nd_get_boolean_prop(nd_hdl_t *nhdl, const char *svcname, const char *pgname,
218*f6e214c7SGavin Maltby     const char *propname, uint8_t *val)
219*f6e214c7SGavin Maltby {
220*f6e214c7SGavin Maltby 	scf_handle_t *handle = NULL;
221*f6e214c7SGavin Maltby 	scf_propertygroup_t *pg;
222*f6e214c7SGavin Maltby 	scf_property_t *prop = NULL;
223*f6e214c7SGavin Maltby 	scf_value_t *value = NULL;
224*f6e214c7SGavin Maltby 	int ret = -1;
225*f6e214c7SGavin Maltby 
226*f6e214c7SGavin Maltby 	if ((handle = scf_handle_create(SCF_VERSION)) == NULL)
227*f6e214c7SGavin Maltby 		return (ret);
228*f6e214c7SGavin Maltby 
229*f6e214c7SGavin Maltby 	if ((pg = nd_get_pg(nhdl, handle, svcname, pgname)) == NULL) {
230*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to read retrieve %s "
231*f6e214c7SGavin Maltby 		    "property group for %s", pgname, svcname);
232*f6e214c7SGavin Maltby 		goto bool_done;
233*f6e214c7SGavin Maltby 	}
234*f6e214c7SGavin Maltby 	prop = scf_property_create(handle);
235*f6e214c7SGavin Maltby 	value = scf_value_create(handle);
236*f6e214c7SGavin Maltby 	if (prop == NULL || value == NULL) {
237*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to allocate SMF structures");
238*f6e214c7SGavin Maltby 		goto bool_done;
239*f6e214c7SGavin Maltby 	}
240*f6e214c7SGavin Maltby 	if (scf_pg_get_property(pg, propname, prop) == -1 ||
241*f6e214c7SGavin Maltby 	    scf_property_get_value(prop, value) == -1 ||
242*f6e214c7SGavin Maltby 	    scf_value_get_boolean(value, val) == -1) {
243*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to retrieve %s prop (%s)", propname,
244*f6e214c7SGavin Maltby 		    scf_strerror(scf_error()));
245*f6e214c7SGavin Maltby 		goto bool_done;
246*f6e214c7SGavin Maltby 	}
247*f6e214c7SGavin Maltby 	ret = 0;
248*f6e214c7SGavin Maltby 
249*f6e214c7SGavin Maltby bool_done:
250*f6e214c7SGavin Maltby 	scf_value_destroy(value);
251*f6e214c7SGavin Maltby 	scf_property_destroy(prop);
252*f6e214c7SGavin Maltby 	scf_pg_destroy(pg);
253*f6e214c7SGavin Maltby 	scf_handle_destroy(handle);
254*f6e214c7SGavin Maltby 
255*f6e214c7SGavin Maltby 	return (ret);
256*f6e214c7SGavin Maltby }
257*f6e214c7SGavin Maltby 
258*f6e214c7SGavin Maltby char *
nd_get_event_fmri(nd_hdl_t * nhdl,fmev_t ev)259*f6e214c7SGavin Maltby nd_get_event_fmri(nd_hdl_t *nhdl, fmev_t ev)
260*f6e214c7SGavin Maltby {
261*f6e214c7SGavin Maltby 	nvlist_t *ev_nvl, *attr_nvl;
262*f6e214c7SGavin Maltby 	char *svcname;
263*f6e214c7SGavin Maltby 
264*f6e214c7SGavin Maltby 	if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
265*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to lookup event attr nvlist");
266*f6e214c7SGavin Maltby 		return (NULL);
267*f6e214c7SGavin Maltby 	}
268*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist(ev_nvl, "attr", &attr_nvl) ||
269*f6e214c7SGavin Maltby 	    nvlist_lookup_string(attr_nvl, "svc-string", &svcname)) {
270*f6e214c7SGavin Maltby 		nd_error(nhdl, "Malformed event 0x%p", (void *)ev_nvl);
271*f6e214c7SGavin Maltby 		return (NULL);
272*f6e214c7SGavin Maltby 	}
273*f6e214c7SGavin Maltby 
274*f6e214c7SGavin Maltby 	return (strdup((const char *)svcname));
275*f6e214c7SGavin Maltby }
276*f6e214c7SGavin Maltby 
277*f6e214c7SGavin Maltby int
nd_get_notify_prefs(nd_hdl_t * nhdl,const char * mech,fmev_t ev,nvlist_t *** pref_nvl,uint_t * nprefs)278*f6e214c7SGavin Maltby nd_get_notify_prefs(nd_hdl_t *nhdl, const char *mech, fmev_t ev,
279*f6e214c7SGavin Maltby     nvlist_t ***pref_nvl, uint_t *nprefs)
280*f6e214c7SGavin Maltby {
281*f6e214c7SGavin Maltby 	nvlist_t *ev_nvl, *top_nvl, **np_nvlarr, *mech_nvl;
282*f6e214c7SGavin Maltby 	int ret = 1;
283*f6e214c7SGavin Maltby 	uint_t nelem;
284*f6e214c7SGavin Maltby 
285*f6e214c7SGavin Maltby 	if ((ev_nvl = fmev_attr_list(ev)) == NULL) {
286*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to lookup event attr nvlist");
287*f6e214c7SGavin Maltby 		return (-1);
288*f6e214c7SGavin Maltby 	}
289*f6e214c7SGavin Maltby 
290*f6e214c7SGavin Maltby 	if ((ret = smf_notify_get_params(&top_nvl, ev_nvl)) != SCF_SUCCESS) {
291*f6e214c7SGavin Maltby 		ret = scf_error();
292*f6e214c7SGavin Maltby 		if (ret == SCF_ERROR_NOT_FOUND) {
293*f6e214c7SGavin Maltby 			nd_debug(nhdl, "No notification preferences specified "
294*f6e214c7SGavin Maltby 			    "for this event");
295*f6e214c7SGavin Maltby 			goto pref_done;
296*f6e214c7SGavin Maltby 		} else {
297*f6e214c7SGavin Maltby 			nd_error(nhdl, "Error looking up notification "
298*f6e214c7SGavin Maltby 			    "preferences (%s)", scf_strerror(ret));
299*f6e214c7SGavin Maltby 			nd_dump_nvlist(nhdl, top_nvl);
300*f6e214c7SGavin Maltby 			goto pref_done;
301*f6e214c7SGavin Maltby 		}
302*f6e214c7SGavin Maltby 	}
303*f6e214c7SGavin Maltby 
304*f6e214c7SGavin Maltby 	if (nvlist_lookup_nvlist_array(top_nvl, SCF_NOTIFY_PARAMS, &np_nvlarr,
305*f6e214c7SGavin Maltby 	    &nelem) != 0) {
306*f6e214c7SGavin Maltby 		nd_error(nhdl, "Malformed nvlist");
307*f6e214c7SGavin Maltby 		nd_dump_nvlist(nhdl, top_nvl);
308*f6e214c7SGavin Maltby 		ret = 1;
309*f6e214c7SGavin Maltby 		goto pref_done;
310*f6e214c7SGavin Maltby 	}
311*f6e214c7SGavin Maltby 	*pref_nvl = malloc(nelem * sizeof (nvlist_t *));
312*f6e214c7SGavin Maltby 	*nprefs = 0;
313*f6e214c7SGavin Maltby 
314*f6e214c7SGavin Maltby 	for (int i = 0; i < nelem; i++) {
315*f6e214c7SGavin Maltby 		if (nvlist_lookup_nvlist(np_nvlarr[i], mech, &mech_nvl) == 0) {
316*f6e214c7SGavin Maltby 			(void) nvlist_dup(mech_nvl, *pref_nvl + *nprefs, 0);
317*f6e214c7SGavin Maltby 			++*nprefs;
318*f6e214c7SGavin Maltby 		}
319*f6e214c7SGavin Maltby 	}
320*f6e214c7SGavin Maltby 
321*f6e214c7SGavin Maltby 	if (*nprefs == 0) {
322*f6e214c7SGavin Maltby 		nd_debug(nhdl, "No %s notification preferences specified",
323*f6e214c7SGavin Maltby 		    mech);
324*f6e214c7SGavin Maltby 		free(*pref_nvl);
325*f6e214c7SGavin Maltby 		ret = SCF_ERROR_NOT_FOUND;
326*f6e214c7SGavin Maltby 		goto pref_done;
327*f6e214c7SGavin Maltby 	}
328*f6e214c7SGavin Maltby 	ret = 0;
329*f6e214c7SGavin Maltby pref_done:
330*f6e214c7SGavin Maltby 	nvlist_free(top_nvl);
331*f6e214c7SGavin Maltby 	return (ret);
332*f6e214c7SGavin Maltby }
333*f6e214c7SGavin Maltby 
334*f6e214c7SGavin Maltby static int
nd_seq_search(char * key,char ** list,uint_t nelem)335*f6e214c7SGavin Maltby nd_seq_search(char *key, char **list, uint_t nelem)
336*f6e214c7SGavin Maltby {
337*f6e214c7SGavin Maltby 	for (int i = 0; i < nelem; i++)
338*f6e214c7SGavin Maltby 		if (strcmp(key, list[i]) == 0)
339*f6e214c7SGavin Maltby 			return (1);
340*f6e214c7SGavin Maltby 	return (0);
341*f6e214c7SGavin Maltby }
342*f6e214c7SGavin Maltby 
343*f6e214c7SGavin Maltby /*
344*f6e214c7SGavin Maltby  * This function takes a single string list and splits it into
345*f6e214c7SGavin Maltby  * an string array (analogous to PERL split)
346*f6e214c7SGavin Maltby  *
347*f6e214c7SGavin Maltby  * The caller is responsible for freeing the array.
348*f6e214c7SGavin Maltby  */
349*f6e214c7SGavin Maltby int
nd_split_list(nd_hdl_t * nhdl,char * list,char * delim,char *** arr,uint_t * nelem)350*f6e214c7SGavin Maltby nd_split_list(nd_hdl_t *nhdl, char *list, char *delim, char ***arr,
351*f6e214c7SGavin Maltby     uint_t *nelem)
352*f6e214c7SGavin Maltby {
353*f6e214c7SGavin Maltby 	char *item, *tmpstr;
354*f6e214c7SGavin Maltby 	int i = 1, size = 1;
355*f6e214c7SGavin Maltby 
356*f6e214c7SGavin Maltby 	tmpstr = strdup(list);
357*f6e214c7SGavin Maltby 	item = strtok(tmpstr, delim);
358*f6e214c7SGavin Maltby 	while (item && strtok(NULL, delim) != NULL)
359*f6e214c7SGavin Maltby 		size++;
360*f6e214c7SGavin Maltby 	free(tmpstr);
361*f6e214c7SGavin Maltby 
362*f6e214c7SGavin Maltby 	if ((*arr = calloc(size, sizeof (char *))) == NULL) {
363*f6e214c7SGavin Maltby 		nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
364*f6e214c7SGavin Maltby 		return (-1);
365*f6e214c7SGavin Maltby 	}
366*f6e214c7SGavin Maltby 	if (size == 1)
367*f6e214c7SGavin Maltby 		(*arr)[0] = strdup(list);
368*f6e214c7SGavin Maltby 	else {
369*f6e214c7SGavin Maltby 		tmpstr = strdup(list);
370*f6e214c7SGavin Maltby 		item = strtok(tmpstr, delim);
371*f6e214c7SGavin Maltby 		(*arr)[0] = strdup(item);
372*f6e214c7SGavin Maltby 		while ((item = strtok(NULL, delim)) != NULL)
373*f6e214c7SGavin Maltby 			(*arr)[i++] = strdup(item);
374*f6e214c7SGavin Maltby 		free(tmpstr);
375*f6e214c7SGavin Maltby 	}
376*f6e214c7SGavin Maltby 	*nelem = size;
377*f6e214c7SGavin Maltby 	return (0);
378*f6e214c7SGavin Maltby }
379*f6e214c7SGavin Maltby 
380*f6e214c7SGavin Maltby /*
381*f6e214c7SGavin Maltby  * This function merges two string arrays into a single array, removing any
382*f6e214c7SGavin Maltby  * duplicates
383*f6e214c7SGavin Maltby  *
384*f6e214c7SGavin Maltby  * The caller is responsible for freeing the merged array.
385*f6e214c7SGavin Maltby  */
386*f6e214c7SGavin Maltby int
nd_merge_strarray(nd_hdl_t * nhdl,char ** arr1,uint_t n1,char ** arr2,uint_t n2,char *** buf)387*f6e214c7SGavin Maltby nd_merge_strarray(nd_hdl_t *nhdl, char **arr1, uint_t n1, char **arr2,
388*f6e214c7SGavin Maltby     uint_t n2, char ***buf)
389*f6e214c7SGavin Maltby {
390*f6e214c7SGavin Maltby 	char **tmparr;
391*f6e214c7SGavin Maltby 	int uniq = -1;
392*f6e214c7SGavin Maltby 
393*f6e214c7SGavin Maltby 	tmparr = alloca((n1 + n2) * sizeof (char *));
394*f6e214c7SGavin Maltby 	bzero(tmparr, (n1 + n2) * sizeof (char *));
395*f6e214c7SGavin Maltby 
396*f6e214c7SGavin Maltby 	while (++uniq < n1)
397*f6e214c7SGavin Maltby 		tmparr[uniq] = strdup(arr1[uniq]);
398*f6e214c7SGavin Maltby 
399*f6e214c7SGavin Maltby 	for (int j = 0; j < n2; j++)
400*f6e214c7SGavin Maltby 		if (!nd_seq_search(arr2[j], tmparr, uniq))
401*f6e214c7SGavin Maltby 			tmparr[uniq++] = strdup(arr2[j]);
402*f6e214c7SGavin Maltby 
403*f6e214c7SGavin Maltby 	if ((*buf = calloc(uniq, sizeof (char *))) == NULL) {
404*f6e214c7SGavin Maltby 		nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
405*f6e214c7SGavin Maltby 		for (int j = 0; j < uniq; j++) {
406*f6e214c7SGavin Maltby 			if (tmparr[j])
407*f6e214c7SGavin Maltby 				free(tmparr[j]);
408*f6e214c7SGavin Maltby 		}
409*f6e214c7SGavin Maltby 		return (-1);
410*f6e214c7SGavin Maltby 	}
411*f6e214c7SGavin Maltby 
412*f6e214c7SGavin Maltby 	bcopy(tmparr, *buf, uniq * sizeof (char *));
413*f6e214c7SGavin Maltby 	return (uniq);
414*f6e214c7SGavin Maltby }
415*f6e214c7SGavin Maltby 
416*f6e214c7SGavin Maltby void
nd_free_strarray(char ** arr,uint_t arrsz)417*f6e214c7SGavin Maltby nd_free_strarray(char **arr, uint_t arrsz)
418*f6e214c7SGavin Maltby {
419*f6e214c7SGavin Maltby 	for (uint_t i = 0; i < arrsz; i++)
420*f6e214c7SGavin Maltby 		free(arr[i]);
421*f6e214c7SGavin Maltby 	free(arr);
422*f6e214c7SGavin Maltby }
423*f6e214c7SGavin Maltby 
424*f6e214c7SGavin Maltby /*
425*f6e214c7SGavin Maltby  * This function joins all the strings in a string array into a single string
426*f6e214c7SGavin Maltby  * Each element will be delimited by a comma
427*f6e214c7SGavin Maltby  *
428*f6e214c7SGavin Maltby  * The caller is responsible for freeing the joined string.
429*f6e214c7SGavin Maltby  */
430*f6e214c7SGavin Maltby int
nd_join_strarray(nd_hdl_t * nhdl,char ** arr,uint_t arrsz,char ** buf)431*f6e214c7SGavin Maltby nd_join_strarray(nd_hdl_t *nhdl, char **arr, uint_t arrsz, char **buf)
432*f6e214c7SGavin Maltby {
433*f6e214c7SGavin Maltby 	uint_t len = 0;
434*f6e214c7SGavin Maltby 	char *jbuf;
435*f6e214c7SGavin Maltby 	int i;
436*f6e214c7SGavin Maltby 
437*f6e214c7SGavin Maltby 	/*
438*f6e214c7SGavin Maltby 	 * First, figure out how much space we need to allocate to store the
439*f6e214c7SGavin Maltby 	 * joined string.
440*f6e214c7SGavin Maltby 	 */
441*f6e214c7SGavin Maltby 	for (i = 0; i < arrsz; i++)
442*f6e214c7SGavin Maltby 		len += strlen(arr[i]) + 1;
443*f6e214c7SGavin Maltby 
444*f6e214c7SGavin Maltby 	if ((jbuf = calloc(len, sizeof (char))) == NULL) {
445*f6e214c7SGavin Maltby 		nd_error(nhdl, "Error allocating memory (%s)", strerror(errno));
446*f6e214c7SGavin Maltby 		return (-1);
447*f6e214c7SGavin Maltby 	}
448*f6e214c7SGavin Maltby 
449*f6e214c7SGavin Maltby 	(void) snprintf(jbuf, len, "%s", arr[0]);
450*f6e214c7SGavin Maltby 	for (i = 1; i < arrsz; i++)
451*f6e214c7SGavin Maltby 		(void) snprintf(jbuf, len, "%s,%s", jbuf, arr[i]);
452*f6e214c7SGavin Maltby 
453*f6e214c7SGavin Maltby 	*buf = jbuf;
454*f6e214c7SGavin Maltby 	return (0);
455*f6e214c7SGavin Maltby }
456*f6e214c7SGavin Maltby 
457*f6e214c7SGavin Maltby void
nd_free_nvlarray(nvlist_t ** arr,uint_t arrsz)458*f6e214c7SGavin Maltby nd_free_nvlarray(nvlist_t **arr, uint_t arrsz)
459*f6e214c7SGavin Maltby {
460*f6e214c7SGavin Maltby 	for (uint_t i = 0; i < arrsz; i++)
461*f6e214c7SGavin Maltby 		nvlist_free(arr[i]);
462*f6e214c7SGavin Maltby 	free(arr);
463*f6e214c7SGavin Maltby }
464*f6e214c7SGavin Maltby 
465*f6e214c7SGavin Maltby /*
466*f6e214c7SGavin Maltby  * This function takes a dictionary name and event class and then uses
467*f6e214c7SGavin Maltby  * libdiagcode to compute the MSG ID.  We need this for looking up messages
468*f6e214c7SGavin Maltby  * for the committed ireport.* events.  For FMA list.* events, the MSG ID is
469*f6e214c7SGavin Maltby  * is contained in the event payload.
470*f6e214c7SGavin Maltby  */
471*f6e214c7SGavin Maltby int
nd_get_diagcode(nd_hdl_t * nhdl,const char * dict,const char * class,char * buf,size_t buflen)472*f6e214c7SGavin Maltby nd_get_diagcode(nd_hdl_t *nhdl, const char *dict, const char *class, char *buf,
473*f6e214c7SGavin Maltby     size_t buflen)
474*f6e214c7SGavin Maltby {
475*f6e214c7SGavin Maltby 	fm_dc_handle_t *dhp;
476*f6e214c7SGavin Maltby 	size_t dlen;
477*f6e214c7SGavin Maltby 	char *dirpath;
478*f6e214c7SGavin Maltby 	const char *key[2];
479*f6e214c7SGavin Maltby 	int ret = 0;
480*f6e214c7SGavin Maltby 
481*f6e214c7SGavin Maltby 	dlen = (strlen(nhdl->nh_rootdir) + strlen(ND_DICTDIR) + 2);
482*f6e214c7SGavin Maltby 	dirpath = alloca(dlen);
483*f6e214c7SGavin Maltby 	(void) snprintf(dirpath, dlen, "%s/%s", nhdl->nh_rootdir, ND_DICTDIR);
484*f6e214c7SGavin Maltby 
485*f6e214c7SGavin Maltby 	if ((dhp = fm_dc_opendict(FM_DC_VERSION, dirpath, dict)) == NULL) {
486*f6e214c7SGavin Maltby 		nd_error(nhdl, "fm_dc_opendict failed for %s/%s",
487*f6e214c7SGavin Maltby 		    dirpath, dict);
488*f6e214c7SGavin Maltby 		return (-1);
489*f6e214c7SGavin Maltby 	}
490*f6e214c7SGavin Maltby 
491*f6e214c7SGavin Maltby 	key[0] = class;
492*f6e214c7SGavin Maltby 	key[1] = NULL;
493*f6e214c7SGavin Maltby 	if (fm_dc_key2code(dhp, key, buf, buflen) < 0) {
494*f6e214c7SGavin Maltby 		nd_error(nhdl, "fm_dc_key2code failed for %s", key[0]);
495*f6e214c7SGavin Maltby 		ret = -1;
496*f6e214c7SGavin Maltby 	}
497*f6e214c7SGavin Maltby 	fm_dc_closedict(dhp);
498*f6e214c7SGavin Maltby 	return (ret);
499*f6e214c7SGavin Maltby }
500*f6e214c7SGavin Maltby 
501*f6e214c7SGavin Maltby /*
502*f6e214c7SGavin Maltby  * This function takes an event and extracts the bits of the event payload that
503*f6e214c7SGavin Maltby  * are of interest to notification daemons and conveniently tucks them into a
504*f6e214c7SGavin Maltby  * single struct.
505*f6e214c7SGavin Maltby  *
506*f6e214c7SGavin Maltby  * The caller is responsible for freeing ev_info and any contained strings and
507*f6e214c7SGavin Maltby  * nvlists.  A convenience function, nd_free_event_info(), is provided for this
508*f6e214c7SGavin Maltby  * purpose.
509*f6e214c7SGavin Maltby  */
510*f6e214c7SGavin Maltby int
nd_get_event_info(nd_hdl_t * nhdl,const char * class,fmev_t ev,nd_ev_info_t ** ev_info)511*f6e214c7SGavin Maltby nd_get_event_info(nd_hdl_t *nhdl, const char *class, fmev_t ev,
512*f6e214c7SGavin Maltby     nd_ev_info_t **ev_info)
513*f6e214c7SGavin Maltby {
514*f6e214c7SGavin Maltby 	nvlist_t *ev_nvl, *attr_nvl;
515*f6e214c7SGavin Maltby 	nd_ev_info_t *evi;
516*f6e214c7SGavin Maltby 	char *code, *uuid, *fmri, *from_state, *to_state, *reason;
517*f6e214c7SGavin Maltby 
518*f6e214c7SGavin Maltby 	if ((evi = calloc(1, sizeof (nd_ev_info_t))) == NULL) {
519*f6e214c7SGavin Maltby 		nd_error(nhdl, "Failed to allocate memory");
520*f6e214c7SGavin Maltby 		return (-1);
521*f6e214c7SGavin Maltby 	}
522*f6e214c7SGavin Maltby 
523*f6e214c7SGavin Maltby 	/*
524*f6e214c7SGavin Maltby 	 * Hold event; class and payload will be valid for as long as
525*f6e214c7SGavin Maltby 	 * we hold the event.
526*f6e214c7SGavin Maltby 	 */
527*f6e214c7SGavin Maltby 	fmev_hold(ev);
528*f6e214c7SGavin Maltby 	evi->ei_ev = ev;
529*f6e214c7SGavin Maltby 	ev_nvl = fmev_attr_list(ev);
530*f6e214c7SGavin Maltby 
531*f6e214c7SGavin Maltby 	/*
532*f6e214c7SGavin Maltby 	 * Lookup the MSGID, event description and severity and KA URL
533*f6e214c7SGavin Maltby 	 *
534*f6e214c7SGavin Maltby 	 * For FMA list.* events we just pull it out of the the event nvlist.
535*f6e214c7SGavin Maltby 	 * For all other events we call a utility function that computes the
536*f6e214c7SGavin Maltby 	 * diagcode using the dict name and class.
537*f6e214c7SGavin Maltby 	 */
538*f6e214c7SGavin Maltby 	evi->ei_diagcode = calloc(32, sizeof (char));
539*f6e214c7SGavin Maltby 	if ((nvlist_lookup_string(ev_nvl, FM_SUSPECT_DIAG_CODE, &code) == 0 &&
540*f6e214c7SGavin Maltby 	    strcpy(evi->ei_diagcode, code)) ||
541*f6e214c7SGavin Maltby 	    nd_get_diagcode(nhdl, "SMF", class, evi->ei_diagcode, 32)
542*f6e214c7SGavin Maltby 	    == 0) {
543*f6e214c7SGavin Maltby 		evi->ei_severity = fmd_msg_getitem_id(nhdl->nh_msghdl,
544*f6e214c7SGavin Maltby 		    NULL, evi->ei_diagcode, FMD_MSG_ITEM_SEVERITY);
545*f6e214c7SGavin Maltby 		evi->ei_descr = fmd_msg_getitem_id(nhdl->nh_msghdl,
546*f6e214c7SGavin Maltby 		    NULL, evi->ei_diagcode, FMD_MSG_ITEM_DESC);
547*f6e214c7SGavin Maltby 		evi->ei_url = fmd_msg_getitem_id(nhdl->nh_msghdl,
548*f6e214c7SGavin Maltby 		    NULL, evi->ei_diagcode, FMD_MSG_ITEM_URL);
549*f6e214c7SGavin Maltby 	} else
550*f6e214c7SGavin Maltby 		(void) strcpy(evi->ei_diagcode, ND_UNKNOWN);
551*f6e214c7SGavin Maltby 
552*f6e214c7SGavin Maltby 	if (!evi->ei_severity)
553*f6e214c7SGavin Maltby 		evi->ei_severity = strdup(ND_UNKNOWN);
554*f6e214c7SGavin Maltby 	if (!evi->ei_descr)
555*f6e214c7SGavin Maltby 		evi->ei_descr = strdup(ND_UNKNOWN);
556*f6e214c7SGavin Maltby 	if (!evi->ei_url)
557*f6e214c7SGavin Maltby 		evi->ei_url = strdup(ND_UNKNOWN);
558*f6e214c7SGavin Maltby 
559*f6e214c7SGavin Maltby 	evi->ei_payload = ev_nvl;
560*f6e214c7SGavin Maltby 	evi->ei_class = fmev_class(ev);
561*f6e214c7SGavin Maltby 	if (nvlist_lookup_string(ev_nvl, FM_SUSPECT_UUID, &uuid) == 0)
562*f6e214c7SGavin Maltby 		evi->ei_uuid = strdup(uuid);
563*f6e214c7SGavin Maltby 	else {
564*f6e214c7SGavin Maltby 		nd_error(nhdl, "Malformed event");
565*f6e214c7SGavin Maltby 		nd_dump_nvlist(nhdl, evi->ei_payload);
566*f6e214c7SGavin Maltby 		nd_free_event_info(evi);
567*f6e214c7SGavin Maltby 		return (-1);
568*f6e214c7SGavin Maltby 	}
569*f6e214c7SGavin Maltby 
570*f6e214c7SGavin Maltby 	if (strncmp(class, "ireport.os.smf", 14) == 0) {
571*f6e214c7SGavin Maltby 		if ((fmri = nd_get_event_fmri(nhdl, ev)) == NULL) {
572*f6e214c7SGavin Maltby 			nd_error(nhdl, "Failed to get fmri from event payload");
573*f6e214c7SGavin Maltby 			nd_free_event_info(evi);
574*f6e214c7SGavin Maltby 			return (-1);
575*f6e214c7SGavin Maltby 		}
576*f6e214c7SGavin Maltby 		if (nvlist_lookup_nvlist(evi->ei_payload, "attr", &attr_nvl) ||
577*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr_nvl, "from-state", &from_state) ||
578*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr_nvl, "to-state", &to_state) ||
579*f6e214c7SGavin Maltby 		    nvlist_lookup_string(attr_nvl, "reason-long", &reason)) {
580*f6e214c7SGavin Maltby 			nd_error(nhdl, "Malformed event");
581*f6e214c7SGavin Maltby 			nd_dump_nvlist(nhdl, evi->ei_payload);
582*f6e214c7SGavin Maltby 			nd_free_event_info(evi);
583*f6e214c7SGavin Maltby 			free(fmri);
584*f6e214c7SGavin Maltby 			return (-1);
585*f6e214c7SGavin Maltby 		}
586*f6e214c7SGavin Maltby 		evi->ei_fmri = fmri;
587*f6e214c7SGavin Maltby 		evi->ei_to_state = strdup(to_state);
588*f6e214c7SGavin Maltby 		evi->ei_from_state = strdup(from_state);
589*f6e214c7SGavin Maltby 		evi->ei_reason = strdup(reason);
590*f6e214c7SGavin Maltby 	}
591*f6e214c7SGavin Maltby 	*ev_info = evi;
592*f6e214c7SGavin Maltby 	return (0);
593*f6e214c7SGavin Maltby }
594*f6e214c7SGavin Maltby 
595*f6e214c7SGavin Maltby static void
condfree(void * buf)596*f6e214c7SGavin Maltby condfree(void *buf)
597*f6e214c7SGavin Maltby {
598*f6e214c7SGavin Maltby 	if (buf != NULL)
599*f6e214c7SGavin Maltby 		free(buf);
600*f6e214c7SGavin Maltby }
601*f6e214c7SGavin Maltby 
602*f6e214c7SGavin Maltby void
nd_free_event_info(nd_ev_info_t * ev_info)603*f6e214c7SGavin Maltby nd_free_event_info(nd_ev_info_t *ev_info)
604*f6e214c7SGavin Maltby {
605*f6e214c7SGavin Maltby 	condfree(ev_info->ei_severity);
606*f6e214c7SGavin Maltby 	condfree(ev_info->ei_descr);
607*f6e214c7SGavin Maltby 	condfree(ev_info->ei_diagcode);
608*f6e214c7SGavin Maltby 	condfree(ev_info->ei_url);
609*f6e214c7SGavin Maltby 	condfree(ev_info->ei_uuid);
610*f6e214c7SGavin Maltby 	condfree(ev_info->ei_fmri);
611*f6e214c7SGavin Maltby 	condfree(ev_info->ei_from_state);
612*f6e214c7SGavin Maltby 	condfree(ev_info->ei_to_state);
613*f6e214c7SGavin Maltby 	condfree(ev_info->ei_reason);
614*f6e214c7SGavin Maltby 	fmev_rele(ev_info->ei_ev);
615*f6e214c7SGavin Maltby 	free(ev_info);
616*f6e214c7SGavin Maltby }
617