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) 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 #include <libintl.h>
27 #include <libnvpair.h>
28 #include <libscf.h>
29 #include <libscf_priv.h>
30 #include <libuutil.h>
31 #include <stdarg.h>
32 #include <stdio.h>
33 #include <string.h>
34 
35 #include "notify_params.h"
36 
37 static struct events {
38 	const char *s;
39 	int32_t c;
40 } smf_st_events[] = {
41 	{ "to-uninitialized", SCF_TRANS(0, SCF_STATE_UNINIT) },
42 	{ "from-uninitialized",	SCF_TRANS(SCF_STATE_UNINIT, 0) },
43 	{ "uninitialized", SCF_TRANS(SCF_STATE_UNINIT, SCF_STATE_UNINIT) },
44 	{ "to-maintenance", SCF_TRANS(0, SCF_STATE_MAINT) },
45 	{ "from-maintenance", SCF_TRANS(SCF_STATE_MAINT, 0) },
46 	{ "maintenance", SCF_TRANS(SCF_STATE_MAINT, SCF_STATE_MAINT) },
47 	{ "to-offline", SCF_TRANS(0, SCF_STATE_OFFLINE) },
48 	{ "from-offline", SCF_TRANS(SCF_STATE_OFFLINE, 0) },
49 	{ "offline", SCF_TRANS(SCF_STATE_OFFLINE, SCF_STATE_OFFLINE) },
50 	{ "to-disabled", SCF_TRANS(0, SCF_STATE_DISABLED) },
51 	{ "from-disabled", SCF_TRANS(SCF_STATE_DISABLED, 0) },
52 	{ "disabled", SCF_TRANS(SCF_STATE_DISABLED, SCF_STATE_DISABLED) },
53 	{ "to-online", SCF_TRANS(0, SCF_STATE_ONLINE) },
54 	{ "from-online", SCF_TRANS(SCF_STATE_ONLINE, 0) },
55 	{ "online", SCF_TRANS(SCF_STATE_ONLINE, SCF_STATE_ONLINE) },
56 	{ "to-degraded", SCF_TRANS(0, SCF_STATE_DEGRADED) },
57 	{ "from-degraded", SCF_TRANS(SCF_STATE_DEGRADED, 0) },
58 	{ "degraded", SCF_TRANS(SCF_STATE_DEGRADED, SCF_STATE_DEGRADED) },
59 	{ "to-all", SCF_TRANS(0, SCF_STATE_ALL) },
60 	{ "from-all", SCF_TRANS(SCF_STATE_ALL, 0) },
61 	{ "all", SCF_TRANS(SCF_STATE_ALL, SCF_STATE_ALL) },
62 	{ NULL, 0 }
63 };
64 
65 static struct fma_tags {
66 	const char *t;
67 	const char *s;
68 } fma_tags[] = {
69 	{ "problem-diagnosed", "list.suspect" },
70 	{ "problem-updated", "list.updated" },
71 	{ "problem-repaired", "list.repaired" },
72 	{ "problem-resolved", "list.resolved" },
73 	{ NULL, NULL }
74 };
75 
76 static char *fma_classes[] = {
77 	"list.",
78 	"ireport.",
79 	NULL
80 };
81 
82 /*
83  * get_fma_tag()
84  * return a pointer to the fma tag at the passed index. NULL if no entry exist
85  * for index
86  */
87 const char *
88 get_fma_tag(uint32_t index)
89 {
90 	if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
91 		return (NULL);
92 
93 	return (fma_tags[index].t);
94 }
95 
96 /*
97  * get_fma_class()
98  * return a pointer to the fma class at the passed index. NULL if no entry exist
99  * for index
100  */
101 const char *
102 get_fma_class(uint32_t index)
103 {
104 	if (index > (sizeof (fma_tags) / sizeof (struct fma_tags)))
105 		return (NULL);
106 
107 	return (fma_tags[index].s);
108 }
109 
110 /*
111  * is_fma_token()
112  * check if the parameter is an fma token by comparing with the
113  * fma_classes[] and the fma_tags[] arrays.
114  */
115 int
116 is_fma_token(const char *t)
117 {
118 	int i;
119 
120 	for (i = 0; fma_classes[i]; ++i)
121 		if (strncmp(t, fma_classes[i], strlen(fma_classes[i])) == 0)
122 			return (1);
123 
124 	for (i = 0; fma_tags[i].t; ++i)
125 		if (strcmp(t, fma_tags[i].t) == 0)
126 			return (1);
127 
128 	return (0);
129 }
130 
131 /*
132  * has_fma_tag()
133  * returns 1 if there is an fma tag for the passed class, 0 otherwise
134  */
135 int
136 has_fma_tag(const char *c)
137 {
138 	int i;
139 
140 	for (i = 0; fma_tags[i].s; ++i)
141 		if (strcmp(c, fma_tags[i].s) == 0)
142 			return (1);
143 
144 	return (0);
145 }
146 
147 const char *
148 de_tag(const char *tag)
149 {
150 	int i;
151 
152 	for (i = 0; fma_tags[i].t; ++i)
153 		if (strcmp(tag, fma_tags[i].t) == 0)
154 			return (fma_tags[i].s);
155 
156 	return (tag);
157 }
158 
159 const char *
160 re_tag(const char *fma_event)
161 {
162 	int i;
163 
164 	for (i = 0; fma_tags[i].s; ++i)
165 		if (strcmp(fma_event, fma_tags[i].s) == 0)
166 			return (fma_tags[i].t);
167 
168 	return (fma_event);
169 }
170 
171 int32_t
172 string_to_tset(const char *str)
173 {
174 	int i;
175 
176 	for (i = 0; smf_st_events[i].s != NULL; ++i) {
177 		if (strcmp(str, smf_st_events[i].s) == 0)
178 			return (smf_st_events[i].c);
179 	}
180 
181 	return (0);
182 }
183 
184 const char *
185 tset_to_string(int32_t t)
186 {
187 	int i;
188 
189 	for (i = 0; smf_st_events[i].s != NULL; ++i) {
190 		if (smf_st_events[i].c == t)
191 			return (smf_st_events[i].s);
192 	}
193 
194 	return (NULL);
195 }
196 
197 void
198 safe_printf(const char *fmt, ...)
199 {
200 	va_list va;
201 
202 	va_start(va, fmt);
203 	if (vprintf(fmt, va) < 0)
204 		uu_die(gettext("Error writing to stdout"));
205 	va_end(va);
206 }
207 
208 static uint32_t
209 notify_params_get_version(nvlist_t *nvl)
210 {
211 	uint32_t v;
212 
213 	if (nvl == NULL)
214 		return (0xFFFFFFFFU);
215 
216 	if (nvlist_lookup_uint32(nvl, SCF_NOTIFY_NAME_VERSION, &v) != 0)
217 		return (0xFFFFFFFFU);
218 	else
219 		return (v);
220 }
221 
222 static void
223 nvpair_print(nvpair_t *p)
224 {
225 	char **v;
226 	uint_t n;
227 	int i;
228 
229 	safe_printf("            %s:", nvpair_name(p));
230 	(void) nvpair_value_string_array(p, &v, &n);
231 	for (i = 0; i < n; ++i) {
232 		safe_printf(" %s", v[i]);
233 	}
234 	safe_printf("\n");
235 }
236 
237 static void
238 params_type_print(nvlist_t *p, const char *name, const char *fmri)
239 {
240 	nvpair_t *tnvp, *nvp;
241 	nvlist_t *nvl;
242 	boolean_t *a;
243 	uint_t n;
244 	int has_output = 0;
245 
246 	/* for each event e print all notification parameters */
247 	for (tnvp = nvlist_next_nvpair(p, NULL); tnvp != NULL;
248 	    tnvp = nvlist_next_nvpair(p, tnvp)) {
249 		/* We only want the NVLIST memebers */
250 		if (nvpair_type(tnvp) != DATA_TYPE_NVLIST)
251 			continue;
252 
253 		if (nvpair_value_nvlist(tnvp, &nvl) != 0)
254 			uu_die("nvpair_value_nvlist");
255 
256 		if (!has_output)
257 			if (fmri == NULL)
258 				safe_printf(gettext("    Event: %s\n"), name);
259 			else
260 				safe_printf(gettext(
261 				    "    Event: %s (source: %s)\n"),
262 				    name, fmri);
263 
264 		has_output = 1;
265 
266 		safe_printf(gettext("        Notification Type: %s\n"),
267 		    nvpair_name(tnvp));
268 
269 		if (nvlist_lookup_boolean_array(nvl, PARAM_ACTIVE, &a, &n) != 0)
270 			uu_warn(gettext("Missing 'active' property"));
271 		else
272 			safe_printf(gettext("            Active: %s\n"),
273 			    *a ? "true" : "false");
274 
275 		for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
276 		    nvp = nvlist_next_nvpair(nvl, nvp)) {
277 			if (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)
278 				continue;
279 			nvpair_print(nvp);
280 		}
281 		safe_printf("\n");
282 	}
283 }
284 
285 void
286 listnotify_print(nvlist_t *nvl, const char *event)
287 {
288 	char *fmri;
289 	nvlist_t **params;
290 	size_t n;
291 	int32_t tset;
292 	int i;
293 
294 	/*
295 	 * Check the nvl we got is from a version we understand
296 	 */
297 	if (nvl != NULL && notify_params_get_version(nvl) !=
298 	    SCF_NOTIFY_PARAMS_VERSION)
299 		uu_die(gettext("libscf(3LIB) mismatch\n"));
300 
301 	if (nvl != NULL && nvlist_lookup_nvlist_array(nvl, SCF_NOTIFY_PARAMS,
302 	    &params, &n) != 0)
303 		/* Sanity check. If we get here nvl is bad! */
304 		uu_die(gettext("nvlist_lookup_nvlist_array\n"));
305 
306 	if (event == NULL) {
307 		/* this is an SMF state transition nvlist */
308 		for (i = 0; i < n; ++i) {
309 			nvlist_t *p = *(params + i);
310 
311 			if (nvlist_lookup_string(p,
312 			    SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
313 				fmri = NULL;
314 			if (nvlist_lookup_int32(p, SCF_NOTIFY_NAME_TSET,
315 			    &tset) != 0)
316 				uu_die("nvlist_lookup_int32");
317 			params_type_print(p, tset_to_string(tset), fmri);
318 		}
319 	} else {
320 		/* this is FMA event nvlist */
321 		if (nvl == NULL) { /* preferences not found */
322 			return;
323 		}
324 		for (i = 0; i < n; ++i) {
325 			nvlist_t *p = *(params + i);
326 
327 			if (nvlist_lookup_string(p,
328 			    SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
329 				fmri = NULL;
330 			params_type_print(p, event, fmri);
331 		}
332 	}
333 }
334