main.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1994, by Sun Microsytems, Inc.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <tnf/tnf.h>
#include <errno.h>
#include <stdlib.h>
#include <libintl.h>
#include <locale.h>
#include "state.h"
static caddr_t g_file_base; /* base address of file */
static char *g_cmdname; /* name of this command */
static int g_raw = B_FALSE; /* output format */
static int g_status = EXIT_SUCCESS; /* exit status (from stdlib.h) */
static const char *print_unsigned = "%u";
static const char *print_unsigned64 = "%llu";
#define OFF(p) (p - g_file_base)
static void describe_array (tnf_datum_t);
static void describe_brief (tnf_datum_t);
static void describe_record (tnf_datum_t);
static void describe_struct (tnf_datum_t);
static void describe_type (tnf_datum_t);
static void read_tnf_file (int, char *);
static void usage (void);
static void scanargs (int, char **, int *, char ***);
int
main(int ac, char *av[])
{
int numfiles; /* number of files to be printed */
char **filenames; /* start of file names list */
int i;
/* internationalization stuff */
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
#endif
(void) textdomain(TEXT_DOMAIN);
g_cmdname = av[0];
scanargs(ac, av, &numfiles, &filenames);
for (i = 0; i < numfiles; i++) {
read_tnf_file(g_raw, filenames[i]);
}
if (!g_raw) {
if (table_get_num_elements() > 0) {
print_c_header();
print_sorted_events();
}
}
exit(g_status);
return (0);
}
static void
scanargs(int argc, char **argv, int *nfiles, char ***files)
{
int c;
int errflg = B_FALSE;
char *optstr = "rx";
while ((c = getopt(argc, argv, optstr)) != EOF) {
switch (c) {
case 'r':
g_raw = B_TRUE;
break;
case 'x':
print_unsigned = "0x%x";
print_unsigned64 = "0x%llx";
break;
case '?':
errflg = B_TRUE;
break;
}
}
*files = &argv[optind];
*nfiles = argc - optind;
if (*nfiles <= 0) {
errflg = B_TRUE;
}
if (errflg) {
usage();
}
}
static void
read_tnf_file(int raw, char *path)
{
int fd;
struct stat st;
caddr_t p, curr_p, end_p;
TNF *tnf;
tnf_errcode_t err;
tnf_datum_t record;
void (*desc_func)(tnf_datum_t) = describe_c_record;
if ((fd = open(path, O_RDONLY, 0777)) == -1) {
(void) fprintf(stderr, gettext("%s: cannot open %s\n"),
g_cmdname, path);
g_status = EXIT_FAILURE;
return;
}
if (fstat(fd, &st) != 0) {
(void) fprintf(stderr, gettext("%s: fstat error on %s\n"),
g_cmdname, path);
(void) close(fd);
g_status = EXIT_FAILURE;
return;
}
if (st.st_size == 0) {
(void) fprintf(stderr, gettext("%s: %s is empty\n"),
g_cmdname, path);
(void) close(fd);
g_status = EXIT_FAILURE;
return;
}
if ((p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0))
== (caddr_t)-1) {
(void) fprintf(stderr, gettext("%s: mmap error on %s\n"),
g_cmdname, path);
(void) close(fd);
g_status = EXIT_FAILURE;
return;
}
if (raw)
g_file_base = p; /* for OFF() */
if (*p == 0) {
/*
* magic word is 0 - catch the error if entire file is zero.
* tnf_reader_begin() will catch the "not a TNF file" error.
*/
curr_p = p;
end_p = p + st.st_size;
while ((curr_p < end_p) && (*curr_p == 0))
curr_p++;
if (curr_p == end_p) {
(void) fprintf(stderr,
gettext("%s: %s is an empty TNF file\n"),
g_cmdname, path);
(void) munmap(p, st.st_size);
(void) close(fd);
return;
}
}
if ((err = tnf_reader_begin(p, st.st_size, &tnf)) != TNF_ERR_NONE) {
(void) fprintf(stderr, gettext("%s: error in %s: %s\n"),
g_cmdname, path, tnf_error_message(err));
(void) munmap(p, st.st_size);
(void) close(fd);
g_status = EXIT_FAILURE;
return;
}
/* Describe file header */
record = tnf_get_file_header(tnf);
if (raw) {
describe_record(record);
desc_func = describe_record;
}
/* Describe all other records */
while ((record = tnf_get_next_record(record)) != TNF_DATUM_NULL)
desc_func(record);
/* Don't munmap for cooked output because we access records later */
if (raw)
(void) munmap(p, st.st_size);
(void) close(fd);
}
static void
describe_record(tnf_datum_t datum)
{
(void) printf("0x%-8x: {\n", OFF(tnf_get_raw(datum)));
switch (tnf_get_kind(datum)) {
case TNF_K_STRUCT:
describe_struct(datum);
break;
case TNF_K_STRING:
case TNF_K_ARRAY:
describe_array(datum);
break;
case TNF_K_TYPE:
describe_type(datum);
break;
default:
fail(0, gettext("illegal record at %x (%d)"),
tnf_get_raw(datum), tnf_get_kind(datum));
break;
}
(void) printf("\t}\n");
}
void
describe_scalar(tnf_datum_t datum)
{
switch (tnf_get_kind(datum)) {
case TNF_K_CHAR:
(void) printf("%c", tnf_get_char(datum));
break;
case TNF_K_INT8:
(void) printf("%d", tnf_get_int8(datum));
break;
case TNF_K_UINT8:
(void) printf(print_unsigned, (tnf_uint8_t)tnf_get_int8(datum));
break;
case TNF_K_INT16:
(void) printf("%d", tnf_get_int16(datum));
break;
case TNF_K_UINT16:
(void) printf(print_unsigned,
(tnf_uint16_t)tnf_get_int16(datum));
break;
case TNF_K_INT32:
(void) printf("%d", (int)tnf_get_int32(datum));
break;
case TNF_K_UINT32:
if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
!= TNF_DATUM_NULL) {
/* XXX */
(void) printf("0x%x",
(tnf_uint32_t)tnf_get_int32(datum));
} else {
(void) printf(print_unsigned,
(tnf_uint32_t)tnf_get_int32(datum));
}
break;
case TNF_K_INT64:
/* lint not updated, it complains: malformed format string */
(void) printf("%lld", tnf_get_int64(datum));
break;
case TNF_K_UINT64:
if ((tnf_type_get_property(tnf_get_type(datum), TNF_N_OPAQUE))
!= TNF_DATUM_NULL) {
(void) printf("0x%llx",
(tnf_uint64_t)tnf_get_int64(datum));
} else {
/* lint not updated, it complains: malformed format string */
(void) printf(print_unsigned64,
(tnf_uint64_t)tnf_get_int64(datum));
}
break;
case TNF_K_FLOAT32:
(void) printf("%f", tnf_get_float32(datum));
break;
case TNF_K_FLOAT64:
(void) printf("%f", tnf_get_float64(datum));
break;
case TNF_K_SCALAR:
(void) printf("unhandled scalar");
break;
default:
fail(0, gettext("not a scalar"));
break;
}
}
static void
describe_struct(tnf_datum_t datum)
{
unsigned n, i;
char *slotname;
n = tnf_get_slot_count(datum);
for (i = 0; i < n; i++) {
slotname = tnf_get_slot_name(datum, i);
(void) printf("%24s ", slotname);
describe_brief(tnf_get_slot_indexed(datum, i));
(void) printf("\n");
/* tag_arg heuristic */
if ((i == 0) && tnf_is_record(datum)) {
tnf_datum_t tag_arg;
if ((tag_arg = tnf_get_tag_arg(datum))
!= TNF_DATUM_NULL) {
(void) printf("%24s ", TNF_N_TAG_ARG);
describe_brief(tag_arg);
(void) printf("\n");
}
}
}
}
static void
describe_array(tnf_datum_t datum)
{
unsigned n, i;
describe_struct(datum); /* XXX */
if (tnf_is_string(datum))
(void) printf("%24s \"%s\"\n", "chars", tnf_get_chars(datum));
else {
n = tnf_get_element_count(datum);
for (i = 0; i < n; i++) {
(void) printf("%24d ", i);
describe_brief(tnf_get_element(datum, i));
(void) printf("\n");
}
}
}
static void
describe_type(tnf_datum_t datum)
{
describe_struct(datum);
}
static void
describe_brief(tnf_datum_t datum)
{
if (datum == TNF_DATUM_NULL) /* allowed */
(void) printf("0x%-8x <NULL>", 0);
else if (tnf_is_scalar(datum))
describe_scalar(datum);
else if (tnf_is_record(datum)) {
(void) printf("0x%-8x ",
OFF(tnf_get_raw(datum))); /* common */
switch (tnf_get_kind(datum)) {
case TNF_K_TYPE:
(void) printf("%s", tnf_type_get_name(datum));
break;
case TNF_K_STRING:
(void) printf("\"%s\"", tnf_get_chars(datum));
break;
default:
(void) printf("<%s>", tnf_get_type_name(datum));
}
} else
fail(0, gettext("inline aggregate slots/elements unhandled"));
}
void
fail(int do_perror, char *message, ...)
{
va_list args;
va_start(args, message);
(void) fprintf(stderr, gettext("%s: "), g_cmdname);
(void) vfprintf(stderr, message, args);
va_end(args);
if (do_perror)
(void) fprintf(stderr, gettext(": %s"), strerror(errno));
(void) fprintf(stderr, gettext("\n"));
exit(EXIT_FAILURE);
}
static void
usage(void)
{
(void) fprintf(stderr,
gettext("Usage: %s [-r] <tnf_file> [<tnf_file> ...]\n"),
g_cmdname);
exit(EXIT_FAILURE);
}