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