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 		}
265 
266 		has_output = 1;
267 
268 		safe_printf(gettext("        Notification Type: %s\n"),
269 		    nvpair_name(tnvp));
270 
271 		if (nvlist_lookup_boolean_array(nvl, PARAM_ACTIVE, &a, &n) != 0)
272 			uu_warn(gettext("Missing 'active' property"));
273 		else
274 			safe_printf(gettext("            Active: %s\n"),
275 			    *a ? "true" : "false");
276 
277 		for (nvp = nvlist_next_nvpair(nvl, NULL); nvp != NULL;
278 		    nvp = nvlist_next_nvpair(nvl, nvp)) {
279 			if (nvpair_type(nvp) != DATA_TYPE_STRING_ARRAY)
280 				continue;
281 			nvpair_print(nvp);
282 		}
283 		safe_printf("\n");
284 	}
285 }
286 
287 void
288 listnotify_print(nvlist_t *nvl, const char *event)
289 {
290 	char *fmri;
291 	nvlist_t **params;
292 	size_t n;
293 	int32_t tset;
294 	int i;
295 
296 	/*
297 	 * Check the nvl we got is from a version we understand
298 	 */
299 	if (nvl != NULL && notify_params_get_version(nvl) !=
300 	    SCF_NOTIFY_PARAMS_VERSION)
301 		uu_die(gettext("libscf(3LIB) mismatch\n"));
302 
303 	if (nvl != NULL && nvlist_lookup_nvlist_array(nvl, SCF_NOTIFY_PARAMS,
304 	    &params, &n) != 0)
305 		/* Sanity check. If we get here nvl is bad! */
306 		uu_die(gettext("nvlist_lookup_nvlist_array\n"));
307 
308 	if (event == NULL) {
309 		/* this is an SMF state transition nvlist */
310 		for (i = 0; i < n; ++i) {
311 			nvlist_t *p = *(params + i);
312 
313 			if (nvlist_lookup_string(p,
314 			    SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
315 				fmri = NULL;
316 			if (nvlist_lookup_int32(p, SCF_NOTIFY_NAME_TSET,
317 			    &tset) != 0)
318 				uu_die("nvlist_lookup_int32");
319 			params_type_print(p, tset_to_string(tset), fmri);
320 		}
321 	} else {
322 		/* this is FMA event nvlist */
323 		if (nvl == NULL) { /* preferences not found */
324 			return;
325 		}
326 		for (i = 0; i < n; ++i) {
327 			nvlist_t *p = *(params + i);
328 
329 			if (nvlist_lookup_string(p,
330 			    SCF_NOTIFY_PARAMS_SOURCE_NAME, &fmri) != 0)
331 				fmri = NULL;
332 			params_type_print(p, event, fmri);
333 		}
334 	}
335 }
336