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