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