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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/wait.h>
29 
30 #include <sys/fm/protocol.h>
31 #include <fm/fmd_msg.h>
32 
33 #include <unistd.h>
34 #include <signal.h>
35 #include <strings.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <errno.h>
39 
40 #define	TEST_ARR_SZ	2
41 
42 int
43 main(int argc, char *argv[])
44 {
45 	fmd_msg_hdl_t *h;
46 	pid_t pid;
47 	int i, err = 0;
48 	char *s;
49 
50 	nvlist_t *auth, *fmri, *list, *test_arr[TEST_ARR_SZ];
51 	const char *code = "TEST-8000-08";
52 	int64_t tod[] = { 0x9400000, 0 };
53 
54 	if (argc > 1) {
55 		(void) fprintf(stderr, "Usage: %s\n", argv[0]);
56 		return (2);
57 	}
58 
59 	/*
60 	 * Build up a valid list.suspect event for a fictional diagnosis
61 	 * using a diagnosis code from our test dictionary so we can format
62 	 * messages.
63 	 */
64 	if (nvlist_alloc(&auth, NV_UNIQUE_NAME, 0) != 0 ||
65 	    nvlist_alloc(&fmri, NV_UNIQUE_NAME, 0) != 0 ||
66 	    nvlist_alloc(&list, NV_UNIQUE_NAME, 0) != 0) {
67 		(void) fprintf(stderr, "%s: nvlist_alloc failed\n", argv[0]);
68 		return (1);
69 	}
70 
71 	err |= nvlist_add_uint8(auth, FM_VERSION, FM_FMRI_AUTH_VERSION);
72 	err |= nvlist_add_string(auth, FM_FMRI_AUTH_PRODUCT, "product");
73 	err |= nvlist_add_string(auth, FM_FMRI_AUTH_CHASSIS, "chassis");
74 	err |= nvlist_add_string(auth, FM_FMRI_AUTH_DOMAIN, "domain");
75 	err |= nvlist_add_string(auth, FM_FMRI_AUTH_SERVER, "server");
76 
77 	if (err != 0) {
78 		(void) fprintf(stderr, "%s: failed to build auth nvlist: %s\n",
79 		    argv[0], strerror(err));
80 		return (1);
81 	}
82 
83 	err |= nvlist_add_uint8(fmri, FM_VERSION, FM_FMD_SCHEME_VERSION);
84 	err |= nvlist_add_string(fmri, FM_FMRI_SCHEME, FM_FMRI_SCHEME_FMD);
85 	err |= nvlist_add_nvlist(fmri, FM_FMRI_AUTHORITY, auth);
86 	err |= nvlist_add_string(fmri, FM_FMRI_FMD_NAME, "fmd_msg_test");
87 	err |= nvlist_add_string(fmri, FM_FMRI_FMD_VERSION, "1.0");
88 
89 	if (err != 0) {
90 		(void) fprintf(stderr, "%s: failed to build fmri nvlist: %s\n",
91 		    argv[0], strerror(err));
92 		return (1);
93 	}
94 
95 	err |= nvlist_add_uint8(list, FM_VERSION, FM_SUSPECT_VERSION);
96 	err |= nvlist_add_string(list, FM_CLASS, FM_LIST_SUSPECT_CLASS);
97 	err |= nvlist_add_string(list, FM_SUSPECT_UUID, "12345678");
98 	err |= nvlist_add_string(list, FM_SUSPECT_DIAG_CODE, code);
99 	err |= nvlist_add_int64_array(list, FM_SUSPECT_DIAG_TIME, tod, 2);
100 	err |= nvlist_add_nvlist(list, FM_SUSPECT_DE, fmri);
101 	err |= nvlist_add_uint32(list, FM_SUSPECT_FAULT_SZ, 0);
102 
103 	/*
104 	 * Add a contrived nvlist array to our list.suspect so that we can
105 	 * exercise the expansion syntax for dereferencing nvlist array members
106 	 */
107 	for (i = 0; i < TEST_ARR_SZ; i++) {
108 		if (nvlist_alloc(&test_arr[i], NV_UNIQUE_NAME, 0) != 0) {
109 			(void) fprintf(stderr, "%s: failed to alloc nvlist "
110 			    "array: %s\n", argv[0], strerror(err));
111 			return (1);
112 		}
113 		err |= nvlist_add_uint8(test_arr[i], "index", i);
114 	}
115 	err |= nvlist_add_nvlist_array(list, "test_arr", test_arr, TEST_ARR_SZ);
116 
117 	if (err != 0) {
118 		(void) fprintf(stderr, "%s: failed to build list nvlist: %s\n",
119 		    argv[0], strerror(err));
120 		return (1);
121 	}
122 
123 	/*
124 	 * Now initialize the libfmd_msg library for testing, using the message
125 	 * catalogs found in the proto area of the current workspace.
126 	 */
127 	if ((h = fmd_msg_init(getenv("ROOT"), FMD_MSG_VERSION)) == NULL) {
128 		(void) fprintf(stderr, "%s: fmd_msg_init failed: %s\n",
129 		    argv[0], strerror(errno));
130 		return (1);
131 	}
132 
133 	/*
134 	 * Test 0: Verify that both fmd_msg_getitem_id and fmd_msg_gettext_id
135 	 * return NULL and EINVAL for an illegal message code, and NULL
136 	 * and ENOENT for a valid but not defined message code.
137 	 */
138 	s = fmd_msg_getitem_id(h, NULL, "I_AM_NOT_VALID", 0);
139 	if (s != NULL || errno != EINVAL) {
140 		(void) fprintf(stderr, "%s: test0 FAIL: illegal code returned "
141 		    "s = %p, errno = %d\n", argv[0], (void *)s, errno);
142 		return (1);
143 	}
144 
145 	s = fmd_msg_gettext_id(h, NULL, "I_AM_NOT_VALID");
146 	if (s != NULL || errno != EINVAL) {
147 		(void) fprintf(stderr, "%s: test0 FAIL: illegal code returned "
148 		    "s = %p, errno = %d\n", argv[0], (void *)s, errno);
149 		return (1);
150 	}
151 
152 	s = fmd_msg_getitem_id(h, NULL, "I_AM_NOT_HERE-0000-0000", 0);
153 	if (s != NULL || errno != ENOENT) {
154 		(void) fprintf(stderr, "%s: test0 FAIL: missing code returned "
155 		    "s = %p, errno = %d\n", argv[0], (void *)s, errno);
156 		return (1);
157 	}
158 
159 	s = fmd_msg_gettext_id(h, NULL, "I_AM_NOT_HERE-0000-0000");
160 	if (s != NULL || errno != ENOENT) {
161 		(void) fprintf(stderr, "%s: test0 FAIL: missing code returned "
162 		    "s = %p, errno = %d\n", argv[0], (void *)s, errno);
163 		return (1);
164 	}
165 
166 	/*
167 	 * Test 1: Use fmd_msg_getitem_id to retrieve the item strings for
168 	 * a known message code without having any actual event handle.
169 	 */
170 	for (i = 0; i < FMD_MSG_ITEM_MAX; i++) {
171 		if ((s = fmd_msg_getitem_id(h, NULL, code, i)) == NULL) {
172 			(void) fprintf(stderr, "%s: fmd_msg_getitem_id failed "
173 			    "for %s, item %d: %s\n",
174 			    argv[0], code, i, strerror(errno));
175 		}
176 
177 		(void) printf("code %s item %d = <<%s>>\n", code, i, s);
178 		free(s);
179 	}
180 
181 	/*
182 	 * Test 2: Use fmd_msg_gettext_id to retrieve the complete message for
183 	 * a known message code without having any actual event handle.
184 	 */
185 	if ((s = fmd_msg_gettext_id(h, NULL, code)) == NULL) {
186 		(void) fprintf(stderr, "%s: fmd_msg_gettext_id failed for %s: "
187 		    "%s\n", argv[0], code, strerror(errno));
188 		return (1);
189 	}
190 
191 	(void) printf("%s\n", s);
192 	free(s);
193 
194 	/*
195 	 * Test 3: Use fmd_msg_getitem_nv to retrieve the item strings for
196 	 * our list.suspect event handle.
197 	 */
198 	for (i = 0; i < FMD_MSG_ITEM_MAX; i++) {
199 		if ((s = fmd_msg_getitem_nv(h, NULL, list, i)) == NULL) {
200 			(void) fprintf(stderr, "%s: fmd_msg_getitem_nv failed "
201 			    "for %s, item %d: %s\n",
202 			    argv[0], code, i, strerror(errno));
203 		}
204 
205 		(void) printf("code %s item %d = <<%s>>\n", code, i, s);
206 		free(s);
207 	}
208 
209 	/*
210 	 * Test 4: Use fmd_msg_getitem_nv to retrieve the complete message for
211 	 * a known message code using our list.suspect event handle.
212 	 */
213 	if ((s = fmd_msg_gettext_nv(h, NULL, list)) == NULL) {
214 		(void) fprintf(stderr, "%s: fmd_msg_gettext_nv failed for %s: "
215 		    "%s\n", argv[0], code, strerror(errno));
216 		return (1);
217 	}
218 
219 	(void) printf("%s\n", s);
220 	free(s);
221 
222 	/*
223 	 * Test 5: Use fmd_msg_getitem_nv to retrieve the complete message for
224 	 * a known message code using our list.suspect event handle, but this
225 	 * time set the URL to our own customized URL.  Our contrived message
226 	 * has been designed to exercise the key aspects of the variable
227 	 * expansion syntax.
228 	 */
229 	if (fmd_msg_url_set(h, "http://foo.bar.com/") != 0) {
230 		(void) fprintf(stderr, "%s: fmd_msg_url_set failed: %s\n",
231 		    argv[0], strerror(errno));
232 	}
233 
234 	if ((s = fmd_msg_gettext_nv(h, NULL, list)) == NULL) {
235 		(void) fprintf(stderr, "%s: fmd_msg_gettext_nv failed for %s: "
236 		    "%s\n", argv[0], code, strerror(errno));
237 		return (1);
238 	}
239 
240 	(void) printf("%s\n", s);
241 	free(s);
242 
243 	for (i = 0; i < TEST_ARR_SZ; i++)
244 		nvlist_free(test_arr[i]);
245 	nvlist_free(fmri);
246 	nvlist_free(auth);
247 	nvlist_free(list);
248 
249 	fmd_msg_fini(h);	/* free library state before dumping core */
250 	pid = fork();		/* fork into background to not bother make(1) */
251 
252 	switch (pid) {
253 	case -1:
254 		(void) fprintf(stderr, "FAIL (failed to fork)\n");
255 		return (1);
256 	case 0:
257 		abort();
258 		return (1);
259 	}
260 
261 	if (waitpid(pid, &err, 0) == -1) {
262 		(void) fprintf(stderr, "FAIL (failed to wait for %d: %s)\n",
263 		    (int)pid, strerror(errno));
264 		return (1);
265 	}
266 
267 	if (WIFSIGNALED(err) == 0 || WTERMSIG(err) != SIGABRT) {
268 		(void) fprintf(stderr, "FAIL (child did not SIGABRT)\n");
269 		return (1);
270 	}
271 
272 	if (!WCOREDUMP(err)) {
273 		(void) fprintf(stderr, "FAIL (no core generated)\n");
274 		return (1);
275 	}
276 
277 	(void) fprintf(stderr, "done\n");
278 	return (0);
279 }
280