xref: /titanic_50/usr/src/cmd/tnf/tnfdump/main.c (revision 9acbbeaf2a1ffe5c14b244867d427714fab43c5c)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  *	Copyright (c) 1994, by Sun Microsytems, Inc.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <unistd.h>
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <sys/mman.h>
33 #include <stdio.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <tnf/tnf.h>
37 #include <errno.h>
38 #include <stdlib.h>
39 #include <libintl.h>
40 #include <locale.h>
41 
42 #include "state.h"
43 
44 static caddr_t	g_file_base;	/* base address of file 	*/
45 static char	*g_cmdname;	/* name of this command		*/
46 static int	g_raw = B_FALSE;	/* output format */
47 static int	g_status = EXIT_SUCCESS; /* exit status (from stdlib.h) */
48 static const char	*print_unsigned = "%u";
49 static const char	*print_unsigned64 = "%llu";
50 
51 #define	OFF(p)	(p - g_file_base)
52 
53 static void describe_array		(tnf_datum_t);
54 static void describe_brief		(tnf_datum_t);
55 static void describe_record		(tnf_datum_t);
56 static void describe_struct		(tnf_datum_t);
57 static void describe_type		(tnf_datum_t);
58 static void read_tnf_file		(int, char *);
59 static void usage			(void);
60 static void scanargs			(int, char **, int *, char ***);
61 
62 int
63 main(int ac, char *av[])
64 {
65 	int 	numfiles;	/* number of files to be printed */
66 	char 	**filenames;	/* start of file names list 	*/
67 	int	i;
68 
69 	/* internationalization stuff */
70 	(void) setlocale(LC_ALL, "");
71 #if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
72 #define	TEXT_DOMAIN "SYS_TEST"	/* Use this only if it weren't */
73 #endif
74 	(void) textdomain(TEXT_DOMAIN);
75 
76 	g_cmdname = av[0];
77 	scanargs(ac, av, &numfiles, &filenames);
78 	for (i = 0; i < numfiles; i++) {
79 		read_tnf_file(g_raw, filenames[i]);
80 	}
81 
82 	if (!g_raw) {
83 		if (table_get_num_elements() > 0) {
84 			print_c_header();
85 			print_sorted_events();
86 		}
87 	}
88 
89 	exit(g_status);
90 
91 	return (0);
92 }
93 
94 static void
95 scanargs(int argc, char **argv, int *nfiles, char ***files)
96 {
97 	int c;
98 	int errflg = B_FALSE;
99 	char *optstr = "rx";
100 
101 	while ((c = getopt(argc, argv, optstr)) != EOF) {
102 		switch (c) {
103 		case 'r':
104 			g_raw = B_TRUE;
105 			break;
106 		case 'x':
107 			print_unsigned = "0x%x";
108 			print_unsigned64 = "0x%llx";
109 			break;
110 		case '?':
111 			errflg = B_TRUE;
112 			break;
113 		}
114 	}
115 	*files = &argv[optind];
116 	*nfiles = argc - optind;
117 	if (*nfiles <= 0) {
118 	    errflg = B_TRUE;
119 	}
120 	if (errflg) {
121 		usage();
122 	}
123 }
124 
125 
126 static void
127 read_tnf_file(int raw, char *path)
128 {
129 	int 		fd;
130 	struct stat 	st;
131 	caddr_t 	p, curr_p, end_p;
132 	TNF		*tnf;
133 	tnf_errcode_t	err;
134 	tnf_datum_t	record;
135 	void (*desc_func)(tnf_datum_t) = describe_c_record;
136 
137 	if ((fd = open(path, O_RDONLY, 0777)) == -1) {
138 		(void) fprintf(stderr, gettext("%s: cannot open %s\n"),
139 		    g_cmdname, path);
140 		g_status = EXIT_FAILURE;
141 		return;
142 	}
143 	if (fstat(fd, &st) != 0) {
144 		(void) fprintf(stderr, gettext("%s: fstat error on %s\n"),
145 		    g_cmdname, path);
146 		(void) close(fd);
147 		g_status = EXIT_FAILURE;
148 		return;
149 	}
150 	if (st.st_size == 0) {
151 		(void) fprintf(stderr, gettext("%s: %s is empty\n"),
152 		    g_cmdname, path);
153 		(void) close(fd);
154 		g_status = EXIT_FAILURE;
155 		return;
156 	}
157 	if ((p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
158 	    == (caddr_t)-1) {
159 		(void) fprintf(stderr, gettext("%s: mmap error on %s\n"),
160 		    g_cmdname, path);
161 		(void) close(fd);
162 		g_status = EXIT_FAILURE;
163 		return;
164 	}
165 
166 	if (raw)
167 		g_file_base = p;		/* for OFF() */
168 
169 	if (*p == 0) {
170 		/*
171 		 * magic word is 0 - catch the error if entire file is zero.
172 		 * tnf_reader_begin() will catch the "not a TNF file" error.
173 		 */
174 		curr_p = p;
175 		end_p = p + st.st_size;
176 		while ((curr_p < end_p) && (*curr_p == 0))
177 			curr_p++;
178 		if (curr_p == end_p) {
179 			(void) fprintf(stderr,
180 				gettext("%s: %s is an empty TNF file\n"),
181 				g_cmdname, path);
182 			(void) munmap(p, st.st_size);
183 			(void) close(fd);
184 			return;
185 		}
186 	}
187 
188 	if ((err = tnf_reader_begin(p, st.st_size, &tnf)) != TNF_ERR_NONE) {
189 		(void) fprintf(stderr, gettext("%s: error in %s: %s\n"),
190 		    g_cmdname, path, tnf_error_message(err));
191 		(void) munmap(p, st.st_size);
192 		(void) close(fd);
193 		g_status = EXIT_FAILURE;
194 		return;
195 	}
196 
197 	/* Describe file header */
198 	record = tnf_get_file_header(tnf);
199 	if (raw) {
200 		describe_record(record);
201 		desc_func = describe_record;
202 	}
203 
204 	/* Describe all other records */
205 	while ((record = tnf_get_next_record(record)) != TNF_DATUM_NULL)
206 		desc_func(record);
207 
208 	/* Don't munmap for cooked output because we access records later */
209 	if (raw)
210 		(void) munmap(p, st.st_size);
211 	(void) close(fd);
212 }
213 
214 static void
215 describe_record(tnf_datum_t datum)
216 {
217 	(void) printf("0x%-8x: {\n", OFF(tnf_get_raw(datum)));
218 
219 	switch (tnf_get_kind(datum)) {
220 
221 	case TNF_K_STRUCT:
222 		describe_struct(datum);
223 		break;
224 	case TNF_K_STRING:
225 	case TNF_K_ARRAY:
226 		describe_array(datum);
227 		break;
228 	case TNF_K_TYPE:
229 		describe_type(datum);
230 		break;
231 	default:
232 		fail(0, gettext("illegal record at %x (%d)"),
233 			tnf_get_raw(datum), tnf_get_kind(datum));
234 		break;
235 	}
236 
237 	(void) printf("\t}\n");
238 }
239 
240 void
241 describe_scalar(tnf_datum_t datum)
242 {
243 	switch (tnf_get_kind(datum)) {
244 
245 	case TNF_K_CHAR:
246 		(void) printf("%c", tnf_get_char(datum));
247 		break;
248 	case TNF_K_INT8:
249 		(void) printf("%d", tnf_get_int8(datum));
250 		break;
251 	case TNF_K_UINT8:
252 		(void) printf(print_unsigned, (tnf_uint8_t)tnf_get_int8(datum));
253 		break;
254 	case TNF_K_INT16:
255 		(void) printf("%d", tnf_get_int16(datum));
256 		break;
257 	case TNF_K_UINT16:
258 		(void) printf(print_unsigned,
259 			(tnf_uint16_t)tnf_get_int16(datum));
260 		break;
261 	case TNF_K_INT32:
262 		(void) printf("%d", (int)tnf_get_int32(datum));
263 		break;
264 	case TNF_K_UINT32:
265 		if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
266 				!= TNF_DATUM_NULL) {
267 			/* XXX */
268 			(void) printf("0x%x",
269 				(tnf_uint32_t)tnf_get_int32(datum));
270 		} else {
271 			(void) printf(print_unsigned,
272 				(tnf_uint32_t)tnf_get_int32(datum));
273 		}
274 		break;
275 	case TNF_K_INT64:
276 		/* lint not updated, it complains: malformed format string */
277 		(void) printf("%lld", 	tnf_get_int64(datum));
278 		break;
279 	case TNF_K_UINT64:
280 		if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
281 			!= TNF_DATUM_NULL) {
282 			(void) printf("0x%llx",
283 				(tnf_uint64_t)tnf_get_int64(datum));
284 		} else {
285 		/* lint not updated, it complains: malformed format string */
286 			(void) printf(print_unsigned64,
287 					(tnf_uint64_t)tnf_get_int64(datum));
288 		}
289 		break;
290 	case TNF_K_FLOAT32:
291 		(void) printf("%f", tnf_get_float32(datum));
292 		break;
293 	case TNF_K_FLOAT64:
294 		(void) printf("%f", tnf_get_float64(datum));
295 		break;
296 	case TNF_K_SCALAR:
297 		(void) printf("unhandled scalar");
298 		break;
299 	default:
300 		fail(0, gettext("not a scalar"));
301 		break;
302 	}
303 }
304 
305 static void
306 describe_struct(tnf_datum_t datum)
307 {
308 	unsigned n, i;
309 	char *slotname;
310 
311 	n = tnf_get_slot_count(datum);
312 	for (i = 0; i < n; i++) {
313 		slotname = tnf_get_slot_name(datum, i);
314 		(void) printf("%24s ", slotname);
315 		describe_brief(tnf_get_slot_indexed(datum, i));
316 		(void) printf("\n");
317 		/* tag_arg heuristic */
318 		if ((i == 0) && tnf_is_record(datum)) {
319 			tnf_datum_t tag_arg;
320 
321 			if ((tag_arg = tnf_get_tag_arg(datum))
322 			    != TNF_DATUM_NULL) {
323 				(void) printf("%24s ", TNF_N_TAG_ARG);
324 				describe_brief(tag_arg);
325 				(void) printf("\n");
326 			}
327 		}
328 	}
329 }
330 
331 static void
332 describe_array(tnf_datum_t datum)
333 {
334 	unsigned n, i;
335 
336 	describe_struct(datum);	/* XXX */
337 
338 	if (tnf_is_string(datum))
339 		(void) printf("%24s \"%s\"\n", "chars", tnf_get_chars(datum));
340 	else {
341 		n = tnf_get_element_count(datum);
342 		for (i = 0; i < n; i++) {
343 			(void) printf("%24d ", i);
344 			describe_brief(tnf_get_element(datum, i));
345 			(void) printf("\n");
346 		}
347 	}
348 }
349 
350 static void
351 describe_type(tnf_datum_t datum)
352 {
353 	describe_struct(datum);
354 }
355 
356 static void
357 describe_brief(tnf_datum_t datum)
358 {
359 	if (datum == TNF_DATUM_NULL) /* allowed */
360 		(void) printf("0x%-8x <NULL>", 0);
361 
362 	else if (tnf_is_scalar(datum))
363 		describe_scalar(datum);
364 
365 	else if (tnf_is_record(datum)) {
366 
367 		(void) printf("0x%-8x ",
368 			OFF(tnf_get_raw(datum))); /* common */
369 
370 		switch (tnf_get_kind(datum)) {
371 		case TNF_K_TYPE:
372 			(void) printf("%s", tnf_type_get_name(datum));
373 			break;
374 		case TNF_K_STRING:
375 			(void) printf("\"%s\"", tnf_get_chars(datum));
376 			break;
377 		default:
378 			(void) printf("<%s>", tnf_get_type_name(datum));
379 		}
380 	} else
381 		fail(0, gettext("inline aggregate slots/elements unhandled"));
382 }
383 
384 void
385 fail(int do_perror, char *message, ...)
386 {
387 	va_list args;
388 
389 	va_start(args, message);
390 	(void) fprintf(stderr, gettext("%s: "), g_cmdname);
391 	(void) vfprintf(stderr, message, args);
392 	va_end(args);
393 	if (do_perror)
394 		(void) fprintf(stderr, gettext(": %s"), strerror(errno));
395 	(void) fprintf(stderr, gettext("\n"));
396 	exit(EXIT_FAILURE);
397 }
398 
399 static void
400 usage(void)
401 {
402 	(void) fprintf(stderr,
403 			gettext("Usage: %s [-r] <tnf_file> [<tnf_file> ...]\n"),
404 			g_cmdname);
405 	exit(EXIT_FAILURE);
406 }
407