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