2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A/*
2N/A * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
2N/A * Use is subject to license terms.
2N/A */
2N/A
2N/A#pragma ident "%Z%%M% %I% %E% SMI"
2N/A
2N/A#include <sys/acct.h>
2N/A#include <sys/wait.h>
2N/A#include <sys/types.h>
2N/A#include <sys/socket.h>
2N/A#include <stdio.h>
2N/A#include <fcntl.h>
2N/A#include <exacct.h>
2N/A#include <pwd.h>
2N/A#include <grp.h>
2N/A#include <project.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <netinet/in.h>
2N/A#include <arpa/inet.h>
2N/A#include <netdb.h>
2N/A
2N/A#ifndef _LP64
2N/A#define FMT_UINT64 "%-15llu"
2N/A#else
2N/A#define FMT_UINT64 "%-15lu"
2N/A#endif
2N/A
2N/A#define MAX_DEPTH 25 /* maximum depth level */
2N/A
2N/Astatic int vflag = 0;
2N/A
2N/Atypedef struct catalog_item {
2N/A int type;
2N/A char *name;
2N/A} catalog_item_t;
2N/A
2N/A/*
2N/A * The actual constants are defined in <sys/exacct_catalog.h>.
2N/A */
2N/Astatic catalog_item_t catalog[] = {
2N/A { EXD_VERSION, "version" },
2N/A { EXD_FILETYPE, "filetype" },
2N/A { EXD_CREATOR, "creator" },
2N/A { EXD_HOSTNAME, "hostname" },
2N/A
2N/A { EXD_GROUP_HEADER, "group-header" },
2N/A { EXD_GROUP_PROC, "group-proc" },
2N/A { EXD_GROUP_TASK, "group-task" },
2N/A { EXD_GROUP_LWP, "group-lwp" },
2N/A { EXD_GROUP_FLOW, "group-flow" },
2N/A { EXD_GROUP_PROC_TAG, "group-proc-tag" },
2N/A { EXD_GROUP_TASK_TAG, "group-task-tag" },
2N/A { EXD_GROUP_LWP_TAG, "group-lwp-tag" },
2N/A { EXD_GROUP_PROC_PARTIAL, "group-proc-partial" },
2N/A { EXD_GROUP_TASK_PARTIAL, "group-task-partial" },
2N/A { EXD_GROUP_TASK_INTERVAL, "group-task-interval" },
2N/A
2N/A { EXD_PROC_PID, "pid" },
2N/A { EXD_PROC_ANCPID, "ppid" },
2N/A { EXD_PROC_UID, "uid" },
2N/A { EXD_PROC_GID, "gid" },
2N/A { EXD_PROC_TASKID, "taskid" },
2N/A { EXD_PROC_PROJID, "projid" },
2N/A { EXD_PROC_HOSTNAME, "hostname" },
2N/A { EXD_PROC_COMMAND, "command" },
2N/A { EXD_PROC_WAIT_STATUS, "wait-status" },
2N/A { EXD_PROC_START_SEC, "start-sec" },
2N/A { EXD_PROC_START_NSEC, "start-nsec" },
2N/A { EXD_PROC_FINISH_SEC, "finish-sec" },
2N/A { EXD_PROC_FINISH_NSEC, "finish-nsec" },
2N/A { EXD_PROC_CPU_USER_SEC, "cpu-user-sec" },
2N/A { EXD_PROC_CPU_USER_NSEC, "cpu-user-nsec" },
2N/A { EXD_PROC_CPU_SYS_SEC, "cpu-sys-sec" },
2N/A { EXD_PROC_CPU_SYS_NSEC, "cpu-sys-nsec" },
2N/A { EXD_PROC_TTY_MAJOR, "tty-major" },
2N/A { EXD_PROC_TTY_MINOR, "tty-minor" },
2N/A { EXD_PROC_FAULTS_MAJOR, "faults-major" },
2N/A { EXD_PROC_FAULTS_MINOR, "faults-minor" },
2N/A { EXD_PROC_MESSAGES_RCV, "msgs-recv" },
2N/A { EXD_PROC_MESSAGES_SND, "msgs-snd" },
2N/A { EXD_PROC_BLOCKS_IN, "blocks-in" },
2N/A { EXD_PROC_BLOCKS_OUT, "blocks-out" },
2N/A { EXD_PROC_CHARS_RDWR, "chars-rdwr" },
2N/A { EXD_PROC_CONTEXT_VOL, "ctxt-vol" },
2N/A { EXD_PROC_CONTEXT_INV, "ctxt-inv" },
2N/A { EXD_PROC_SIGNALS, "signals" },
2N/A { EXD_PROC_SWAPS, "swaps" },
2N/A { EXD_PROC_SYSCALLS, "syscalls" },
2N/A { EXD_PROC_TAG, "proc-tag" },
2N/A { EXD_PROC_ACCT_FLAGS, "acctflags" },
2N/A { EXD_PROC_ZONENAME, "zone" },
2N/A { EXD_PROC_MEM_RSS_AVG_K, "memory-rss-avg-k" },
2N/A { EXD_PROC_MEM_RSS_MAX_K, "memory-rss-max-k" },
2N/A
2N/A { EXD_TASK_TASKID, "taskid" },
2N/A { EXD_TASK_ANCTASKID, "anctaskid" },
2N/A { EXD_TASK_PROJID, "projid" },
2N/A { EXD_TASK_HOSTNAME, "hostname" },
2N/A { EXD_TASK_START_SEC, "start-sec" },
2N/A { EXD_TASK_START_NSEC, "start-nsec" },
2N/A { EXD_TASK_FINISH_SEC, "finish-sec" },
2N/A { EXD_TASK_FINISH_NSEC, "finish-nsec" },
2N/A { EXD_TASK_CPU_USER_SEC, "cpu-user-sec" },
2N/A { EXD_TASK_CPU_USER_NSEC, "cpu-user-nsec" },
2N/A { EXD_TASK_CPU_SYS_SEC, "cpu-sys-sec" },
2N/A { EXD_TASK_CPU_SYS_NSEC, "cpu-sys-nsec" },
2N/A { EXD_TASK_FAULTS_MAJOR, "faults-major" },
2N/A { EXD_TASK_FAULTS_MINOR, "faults-minor" },
2N/A { EXD_TASK_MESSAGES_RCV, "msgs-recv" },
2N/A { EXD_TASK_MESSAGES_SND, "msgs-snd" },
2N/A { EXD_TASK_BLOCKS_IN, "blocks-in" },
2N/A { EXD_TASK_BLOCKS_OUT, "blocks-out" },
2N/A { EXD_TASK_CHARS_RDWR, "chars-rdwr" },
2N/A { EXD_TASK_CONTEXT_VOL, "ctxt-vol" },
2N/A { EXD_TASK_CONTEXT_INV, "ctxt-inv" },
2N/A { EXD_TASK_SIGNALS, "signals" },
2N/A { EXD_TASK_SWAPS, "swaps" },
2N/A { EXD_TASK_SYSCALLS, "syscalls" },
2N/A { EXD_TASK_TAG, "task-tag" },
2N/A { EXD_TASK_ZONENAME, "zone" },
2N/A
2N/A { EXD_FLOW_V4SADDR, "src-addr-v4" },
2N/A { EXD_FLOW_V4DADDR, "dest-addr-v4" },
2N/A { EXD_FLOW_V6SADDR, "src-addr-v6" },
2N/A { EXD_FLOW_V6DADDR, "dest-addr-v6" },
2N/A { EXD_FLOW_SPORT, "src-port" },
2N/A { EXD_FLOW_DPORT, "dest-port" },
2N/A { EXD_FLOW_PROTOCOL, "protocol" },
2N/A { EXD_FLOW_DSFIELD, "diffserv-field" },
2N/A { EXD_FLOW_NBYTES, "total-bytes" },
2N/A { EXD_FLOW_NPKTS, "total-packets" },
2N/A { EXD_FLOW_CTIME, "creation-time" },
2N/A { EXD_FLOW_LSEEN, "last-seen" },
2N/A { EXD_FLOW_PROJID, "projid" },
2N/A { EXD_FLOW_UID, "uid" },
2N/A { EXD_FLOW_ANAME, "action-name" },
2N/A
2N/A { EXD_NONE, "none" }
2N/A};
2N/A
2N/Astatic void disp_obj(ea_object_t *o, int indent);
2N/A
2N/A/*
2N/A * Convert catalog ID into catalog name.
2N/A */
2N/Astatic char *
2N/Acatalog_name(int type)
2N/A{
2N/A int i = 0;
2N/A
2N/A while (catalog[i].type != EXD_NONE) {
2N/A if (catalog[i].type == type)
2N/A return (catalog[i].name);
2N/A i++;
2N/A }
2N/A
2N/A return ("unknown");
2N/A}
2N/A
2N/A/*
2N/A * Display port information, if available
2N/A */
2N/Astatic void
2N/Adisp_port(uint16_t port)
2N/A{
2N/A struct servent *port_info;
2N/A
2N/A port_info = getservbyport(htons(port), NULL);
2N/A if (port_info != NULL) {
2N/A (void) printf("%s", port_info->s_name);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Display host name for a given IP address if available.
2N/A */
2N/Astatic void
2N/Adisp_host(char *addr, int family)
2N/A{
2N/A struct hostent *phe;
2N/A uint_t len;
2N/A int error_num;
2N/A
2N/A len = (family == AF_INET) ? sizeof (struct in_addr) :
2N/A sizeof (struct in6_addr);
2N/A
2N/A if ((phe = getipnodebyaddr(addr, len, family, &error_num)) != NULL) {
2N/A (void) printf("%s", phe->h_name);
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Display protocol information, if available.
2N/A */
2N/Astatic void
2N/Adisp_proto(uint8_t protocol)
2N/A{
2N/A struct protoent *proto_ent;
2N/A
2N/A proto_ent = getprotobynumber(protocol);
2N/A if (proto_ent != NULL) {
2N/A (void) printf("%s", proto_ent->p_name);
2N/A }
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Display recursively exacct objects in a given embedded group.
2N/A */
2N/Astatic void
2N/Adisp_embedded_group(ea_object_t *eo, int indent)
2N/A{
2N/A while (eo != NULL) {
2N/A disp_obj(eo, indent + 1);
2N/A if (eo->eo_type == EO_GROUP)
2N/A disp_embedded_group(eo->eo_group.eg_objs, indent + 1);
2N/A eo = eo->eo_next;
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Display the data stored in a given exacct object.
2N/A */
2N/Astatic void
2N/Adisp_obj(ea_object_t *o, int indent)
2N/A{
2N/A char objname[30] = " ";
2N/A int eol = 1;
2N/A
2N/A if (indent > MAX_DEPTH) {
2N/A objname[0] = '>';
2N/A indent = 1;
2N/A }
2N/A
2N/A (void) printf("%6x\t", (o->eo_catalog & EXD_DATA_MASK));
2N/A (void) snprintf(objname + indent, 30 - indent, "%-s",
2N/A catalog_name(o->eo_catalog & EXD_DATA_MASK));
2N/A (void) printf("%-30s\t", objname);
2N/A
2N/A switch (o->eo_catalog & EXT_TYPE_MASK) {
2N/A case EXT_UINT8:
2N/A (void) printf("%-15u", o->eo_item.ei_uint8);
2N/A if (vflag &&
2N/A ((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_PROTOCOL)) {
2N/A disp_proto(o->eo_item.ei_uint8);
2N/A }
2N/A break;
2N/A case EXT_UINT16:
2N/A (void) printf("%-15u", o->eo_item.ei_uint16);
2N/A if (vflag &&
2N/A (((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_SPORT) ||
2N/A ((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_DPORT))) {
2N/A disp_port(o->eo_item.ei_uint16);
2N/A }
2N/A break;
2N/A case EXT_UINT32:
2N/A switch (o->eo_catalog & EXD_DATA_MASK) {
2N/A case EXD_PROC_WAIT_STATUS:
2N/A {
2N/A int wstat = o->eo_item.ei_uint32;
2N/A
2N/A if (vflag) {
2N/A if (WIFEXITED(wstat))
2N/A (void) printf("%-14d exit",
2N/A WEXITSTATUS(wstat));
2N/A else if (WIFSIGNALED(wstat))
2N/A (void) printf("%14d, signal",
2N/A WTERMSIG(wstat));
2N/A else
2N/A (void) printf("%d", wstat);
2N/A } else {
2N/A (void) printf("%d", wstat);
2N/A }
2N/A }
2N/A break;
2N/A case EXD_PROC_UID:
2N/A {
2N/A uid_t uid = o->eo_item.ei_uint32;
2N/A
2N/A (void) printf("%-15u", uid);
2N/A if (vflag) {
2N/A struct passwd *pwd;
2N/A if ((pwd = getpwuid(uid)) != NULL)
2N/A (void) printf("%s",
2N/A pwd->pw_name);
2N/A }
2N/A }
2N/A break;
2N/A case EXD_PROC_GID:
2N/A {
2N/A gid_t gid = o->eo_item.ei_uint32;
2N/A
2N/A (void) printf("%-15u", gid);
2N/A if (vflag) {
2N/A struct group *grp;
2N/A if ((grp = getgrgid(gid)) != NULL)
2N/A (void) printf("%s",
2N/A grp->gr_name);
2N/A }
2N/A }
2N/A break;
2N/A case EXD_PROC_PROJID:
2N/A case EXD_TASK_PROJID:
2N/A {
2N/A projid_t projid = o->eo_item.ei_uint32;
2N/A
2N/A (void) printf("%-15lu", projid);
2N/A if (vflag) {
2N/A struct project proj;
2N/A char projbuf[PROJECT_BUFSZ];
2N/A
2N/A if (getprojbyid(projid, &proj, projbuf,
2N/A PROJECT_BUFSZ) != NULL)
2N/A (void) printf("%s",
2N/A proj.pj_name);
2N/A }
2N/A }
2N/A break;
2N/A case EXD_PROC_ACCT_FLAGS:
2N/A {
2N/A int flag = o->eo_item.ei_uint32;
2N/A
2N/A (void) printf("%-15u", flag);
2N/A if (vflag) {
2N/A if (flag & AFORK)
2N/A (void) printf("FORK ");
2N/A if (flag & ASU)
2N/A (void) printf("SU");
2N/A }
2N/A }
2N/A break;
2N/A case EXD_FLOW_V4SADDR:
2N/A /* FALLTHRU */
2N/A case EXD_FLOW_V4DADDR:
2N/A {
2N/A char str[INET_ADDRSTRLEN];
2N/A uint32_t addr = htonl(o->eo_item.ei_uint32);
2N/A
2N/A (void) printf("%-15s",
2N/A inet_ntop(AF_INET, &addr, str,
2N/A INET_ADDRSTRLEN));
2N/A if (vflag) {
2N/A disp_host((char *)&addr, AF_INET);
2N/A }
2N/A }
2N/A break;
2N/A default:
2N/A (void) printf("%u", o->eo_item.ei_uint32);
2N/A }
2N/A break;
2N/A case EXT_UINT64:
2N/A {
2N/A time_t _time;
2N/A char timebuf[20];
2N/A
2N/A (void) printf(FMT_UINT64, o->eo_item.ei_uint64);
2N/A if (!vflag)
2N/A break;
2N/A if (ea_match_object_catalog(o, EXD_TASK_START_SEC) ||
2N/A ea_match_object_catalog(o, EXD_TASK_FINISH_SEC) ||
2N/A ea_match_object_catalog(o, EXD_PROC_START_SEC) ||
2N/A ea_match_object_catalog(o, EXD_PROC_FINISH_SEC) ||
2N/A ea_match_object_catalog(o, EXD_FLOW_LSEEN) ||
2N/A ea_match_object_catalog(o, EXD_FLOW_CTIME)) {
2N/A _time = o->eo_item.ei_uint64;
2N/A (void) strftime(timebuf, sizeof (timebuf),
2N/A "%D %T", localtime(&_time));
2N/A (void) fputs(timebuf, stdout);
2N/A }
2N/A }
2N/A break;
2N/A case EXT_DOUBLE:
2N/A (void) printf("%f", o->eo_item.ei_double);
2N/A break;
2N/A case EXT_STRING:
2N/A (void) printf("\"%s\"", o->eo_item.ei_string);
2N/A break;
2N/A case EXT_RAW:
2N/A switch (o->eo_catalog & EXD_DATA_MASK) {
2N/A case EXD_FLOW_V6SADDR:
2N/A /* FALLTHRU */
2N/A case EXD_FLOW_V6DADDR:
2N/A {
2N/A in6_addr_t *addr;
2N/A char str[INET6_ADDRSTRLEN];
2N/A
2N/A addr = (in6_addr_t *)o->eo_item.ei_raw;
2N/A (void) printf("%-28s", inet_ntop(AF_INET6,
2N/A &addr->s6_addr, str, INET6_ADDRSTRLEN));
2N/A if (vflag) {
2N/A disp_host((char *)&addr->s6_addr,
2N/A AF_INET6);
2N/A }
2N/A
2N/A }
2N/A break;
2N/A default:
2N/A {
2N/A ea_size_t size = o->eo_item.ei_size;
2N/A char *buf = o->eo_item.ei_raw;
2N/A uint64_t i;
2N/A
2N/A for (i = 0; i < size && i < 6; i++)
2N/A (void) printf("0x%2X ", buf[i]);
2N/A if (size > 6)
2N/A (void) printf("...");
2N/A }
2N/A }
2N/A break;
2N/A case EXT_GROUP:
2N/A (void) printf("[group of %u object(s)]", o->eo_group.eg_nobjs);
2N/A break;
2N/A case EXT_EXACCT_OBJECT:
2N/A /*
2N/A * Embedded exacct records.
2N/A */
2N/A {
2N/A ea_object_type_t ot;
2N/A ea_object_t *op;
2N/A ea_object_t *eo;
2N/A
2N/A ot = ea_unpack_object(&op, EUP_ALLOC,
2N/A o->eo_item.ei_object, o->eo_item.ei_size);
2N/A
2N/A if (ot == EO_ERROR) {
2N/A (void) printf("error: couldn't unpack embedded "
2N/A "object\n");
2N/A break;
2N/A }
2N/A eol = 0;
2N/A if (ot == EO_GROUP) {
2N/A (void) printf("[embedded group of %u "
2N/A "object(s)]\n", op->eo_group.eg_nobjs);
2N/A eo = op->eo_group.eg_objs;
2N/A disp_embedded_group(eo, indent);
2N/A } else {
2N/A (void) printf("[embedded object]\n");
2N/A disp_obj(op, indent);
2N/A }
2N/A ea_free_object(op, EUP_ALLOC);
2N/A }
2N/A break;
2N/A default:
2N/A (void) printf("[complex value]");
2N/A break;
2N/A }
2N/A
2N/A if (eol)
2N/A (void) printf("\n");
2N/A
2N/A}
2N/A
2N/A/*
2N/A * Read and display a group of exacct objects from the file.
2N/A */
2N/Astatic void
2N/Adisp_group(ea_file_t *ef, uint_t nobjs, int indent)
2N/A{
2N/A uint_t i;
2N/A
2N/A for (i = 0; i < nobjs; i++) {
2N/A ea_object_t scratch;
2N/A int res;
2N/A
2N/A if ((res = ea_get_object(ef, &scratch)) == -1) {
2N/A (void) fprintf(stderr,
2N/A "bad file: ea_get_object()==%d\n", res);
2N/A exit(2);
2N/A }
2N/A
2N/A disp_obj(&scratch, indent + 1);
2N/A
2N/A if (scratch.eo_type == EO_GROUP)
2N/A disp_group(ef, scratch.eo_group.eg_nobjs, indent + 1);
2N/A else
2N/A (void) ea_free_item(&scratch, EUP_ALLOC);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/Ausage()
2N/A{
2N/A (void) fprintf(stderr, "Usage: exdump [-v] <file>\n");
2N/A exit(2);
2N/A}
2N/A
2N/Aint
2N/Amain(int argc, char *argv[])
2N/A{
2N/A ea_file_t ef;
2N/A ea_object_t scratch;
2N/A char *fname;
2N/A int opt;
2N/A
2N/A while ((opt = getopt(argc, argv, "v")) != EOF) {
2N/A switch (opt) {
2N/A case 'v':
2N/A vflag = 1;
2N/A break;
2N/A default:
2N/A usage();
2N/A }
2N/A }
2N/A
2N/A if (argc == optind)
2N/A usage();
2N/A if (argc > optind)
2N/A fname = argv[optind++];
2N/A if (argc > optind)
2N/A usage();
2N/A
2N/A if (ea_open(&ef, fname, NULL,
2N/A vflag ? EO_NO_VALID_HDR : 0, O_RDONLY, 0) == -1) {
2N/A (void) fprintf(stderr, "exdump: cannot open %s\n", fname);
2N/A return (1);
2N/A }
2N/A
2N/A bzero(&scratch, sizeof (ea_object_t));
2N/A while (ea_get_object(&ef, &scratch) != -1) {
2N/A disp_obj(&scratch, 0);
2N/A if (scratch.eo_type == EO_GROUP)
2N/A disp_group(&ef, scratch.eo_group.eg_nobjs, 0);
2N/A else
2N/A (void) ea_free_item(&scratch, EUP_ALLOC);
2N/A (void) bzero(&scratch, sizeof (ea_object_t));
2N/A }
2N/A
2N/A (void) ea_close(&ef);
2N/A return (0);
2N/A}