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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/acct.h> 29 #include <sys/wait.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 #include <stdio.h> 33 #include <fcntl.h> 34 #include <exacct.h> 35 #include <pwd.h> 36 #include <grp.h> 37 #include <project.h> 38 #include <stdlib.h> 39 #include <strings.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <netdb.h> 43 44 #ifndef _LP64 45 #define FMT_UINT64 "%-15llu" 46 #else 47 #define FMT_UINT64 "%-15lu" 48 #endif 49 50 #define MAX_DEPTH 25 /* maximum depth level */ 51 52 static int vflag = 0; 53 54 typedef struct catalog_item { 55 int type; 56 char *name; 57 } catalog_item_t; 58 59 /* 60 * The actual constants are defined in <sys/exacct_catalog.h>. 61 */ 62 static catalog_item_t catalog[] = { 63 { EXD_VERSION, "version" }, 64 { EXD_FILETYPE, "filetype" }, 65 { EXD_CREATOR, "creator" }, 66 { EXD_HOSTNAME, "hostname" }, 67 68 { EXD_GROUP_HEADER, "group-header" }, 69 { EXD_GROUP_PROC, "group-proc" }, 70 { EXD_GROUP_TASK, "group-task" }, 71 { EXD_GROUP_LWP, "group-lwp" }, 72 { EXD_GROUP_FLOW, "group-flow" }, 73 { EXD_GROUP_PROC_TAG, "group-proc-tag" }, 74 { EXD_GROUP_TASK_TAG, "group-task-tag" }, 75 { EXD_GROUP_LWP_TAG, "group-lwp-tag" }, 76 { EXD_GROUP_PROC_PARTIAL, "group-proc-partial" }, 77 { EXD_GROUP_TASK_PARTIAL, "group-task-partial" }, 78 { EXD_GROUP_TASK_INTERVAL, "group-task-interval" }, 79 80 { EXD_PROC_PID, "pid" }, 81 { EXD_PROC_ANCPID, "ppid" }, 82 { EXD_PROC_UID, "uid" }, 83 { EXD_PROC_GID, "gid" }, 84 { EXD_PROC_TASKID, "taskid" }, 85 { EXD_PROC_PROJID, "projid" }, 86 { EXD_PROC_HOSTNAME, "hostname" }, 87 { EXD_PROC_COMMAND, "command" }, 88 { EXD_PROC_WAIT_STATUS, "wait-status" }, 89 { EXD_PROC_START_SEC, "start-sec" }, 90 { EXD_PROC_START_NSEC, "start-nsec" }, 91 { EXD_PROC_FINISH_SEC, "finish-sec" }, 92 { EXD_PROC_FINISH_NSEC, "finish-nsec" }, 93 { EXD_PROC_CPU_USER_SEC, "cpu-user-sec" }, 94 { EXD_PROC_CPU_USER_NSEC, "cpu-user-nsec" }, 95 { EXD_PROC_CPU_SYS_SEC, "cpu-sys-sec" }, 96 { EXD_PROC_CPU_SYS_NSEC, "cpu-sys-nsec" }, 97 { EXD_PROC_TTY_MAJOR, "tty-major" }, 98 { EXD_PROC_TTY_MINOR, "tty-minor" }, 99 { EXD_PROC_FAULTS_MAJOR, "faults-major" }, 100 { EXD_PROC_FAULTS_MINOR, "faults-minor" }, 101 { EXD_PROC_MESSAGES_RCV, "msgs-recv" }, 102 { EXD_PROC_MESSAGES_SND, "msgs-snd" }, 103 { EXD_PROC_BLOCKS_IN, "blocks-in" }, 104 { EXD_PROC_BLOCKS_OUT, "blocks-out" }, 105 { EXD_PROC_CHARS_RDWR, "chars-rdwr" }, 106 { EXD_PROC_CONTEXT_VOL, "ctxt-vol" }, 107 { EXD_PROC_CONTEXT_INV, "ctxt-inv" }, 108 { EXD_PROC_SIGNALS, "signals" }, 109 { EXD_PROC_SWAPS, "swaps" }, 110 { EXD_PROC_SYSCALLS, "syscalls" }, 111 { EXD_PROC_TAG, "proc-tag" }, 112 { EXD_PROC_ACCT_FLAGS, "acctflags" }, 113 { EXD_PROC_ZONENAME, "zone" }, 114 { EXD_PROC_MEM_RSS_AVG_K, "memory-rss-avg-k" }, 115 { EXD_PROC_MEM_RSS_MAX_K, "memory-rss-max-k" }, 116 117 { EXD_TASK_TASKID, "taskid" }, 118 { EXD_TASK_ANCTASKID, "anctaskid" }, 119 { EXD_TASK_PROJID, "projid" }, 120 { EXD_TASK_HOSTNAME, "hostname" }, 121 { EXD_TASK_START_SEC, "start-sec" }, 122 { EXD_TASK_START_NSEC, "start-nsec" }, 123 { EXD_TASK_FINISH_SEC, "finish-sec" }, 124 { EXD_TASK_FINISH_NSEC, "finish-nsec" }, 125 { EXD_TASK_CPU_USER_SEC, "cpu-user-sec" }, 126 { EXD_TASK_CPU_USER_NSEC, "cpu-user-nsec" }, 127 { EXD_TASK_CPU_SYS_SEC, "cpu-sys-sec" }, 128 { EXD_TASK_CPU_SYS_NSEC, "cpu-sys-nsec" }, 129 { EXD_TASK_FAULTS_MAJOR, "faults-major" }, 130 { EXD_TASK_FAULTS_MINOR, "faults-minor" }, 131 { EXD_TASK_MESSAGES_RCV, "msgs-recv" }, 132 { EXD_TASK_MESSAGES_SND, "msgs-snd" }, 133 { EXD_TASK_BLOCKS_IN, "blocks-in" }, 134 { EXD_TASK_BLOCKS_OUT, "blocks-out" }, 135 { EXD_TASK_CHARS_RDWR, "chars-rdwr" }, 136 { EXD_TASK_CONTEXT_VOL, "ctxt-vol" }, 137 { EXD_TASK_CONTEXT_INV, "ctxt-inv" }, 138 { EXD_TASK_SIGNALS, "signals" }, 139 { EXD_TASK_SWAPS, "swaps" }, 140 { EXD_TASK_SYSCALLS, "syscalls" }, 141 { EXD_TASK_TAG, "task-tag" }, 142 { EXD_TASK_ZONENAME, "zone" }, 143 144 { EXD_FLOW_V4SADDR, "src-addr-v4" }, 145 { EXD_FLOW_V4DADDR, "dest-addr-v4" }, 146 { EXD_FLOW_V6SADDR, "src-addr-v6" }, 147 { EXD_FLOW_V6DADDR, "dest-addr-v6" }, 148 { EXD_FLOW_SPORT, "src-port" }, 149 { EXD_FLOW_DPORT, "dest-port" }, 150 { EXD_FLOW_PROTOCOL, "protocol" }, 151 { EXD_FLOW_DSFIELD, "diffserv-field" }, 152 { EXD_FLOW_NBYTES, "total-bytes" }, 153 { EXD_FLOW_NPKTS, "total-packets" }, 154 { EXD_FLOW_CTIME, "creation-time" }, 155 { EXD_FLOW_LSEEN, "last-seen" }, 156 { EXD_FLOW_PROJID, "projid" }, 157 { EXD_FLOW_UID, "uid" }, 158 { EXD_FLOW_ANAME, "action-name" }, 159 160 { EXD_NONE, "none" } 161 }; 162 163 static void disp_obj(ea_object_t *o, int indent); 164 165 /* 166 * Convert catalog ID into catalog name. 167 */ 168 static char * 169 catalog_name(int type) 170 { 171 int i = 0; 172 173 while (catalog[i].type != EXD_NONE) { 174 if (catalog[i].type == type) 175 return (catalog[i].name); 176 i++; 177 } 178 179 return ("unknown"); 180 } 181 182 /* 183 * Display port information, if available 184 */ 185 static void 186 disp_port(uint16_t port) 187 { 188 struct servent *port_info; 189 190 port_info = getservbyport(htons(port), NULL); 191 if (port_info != NULL) { 192 (void) printf("%s", port_info->s_name); 193 } 194 } 195 196 /* 197 * Display host name for a given IP address if available. 198 */ 199 static void 200 disp_host(char *addr, int family) 201 { 202 struct hostent *phe; 203 uint_t len; 204 int error_num; 205 206 len = (family == AF_INET) ? sizeof (struct in_addr) : 207 sizeof (struct in6_addr); 208 209 if ((phe = getipnodebyaddr(addr, len, family, &error_num)) != NULL) { 210 (void) printf("%s", phe->h_name); 211 } 212 } 213 214 /* 215 * Display protocol information, if available. 216 */ 217 static void 218 disp_proto(uint8_t protocol) 219 { 220 struct protoent *proto_ent; 221 222 proto_ent = getprotobynumber(protocol); 223 if (proto_ent != NULL) { 224 (void) printf("%s", proto_ent->p_name); 225 } 226 227 } 228 229 /* 230 * Display recursively exacct objects in a given embedded group. 231 */ 232 static void 233 disp_embedded_group(ea_object_t *eo, int indent) 234 { 235 while (eo != NULL) { 236 disp_obj(eo, indent + 1); 237 if (eo->eo_type == EO_GROUP) 238 disp_embedded_group(eo->eo_group.eg_objs, indent + 1); 239 eo = eo->eo_next; 240 } 241 } 242 243 /* 244 * Display the data stored in a given exacct object. 245 */ 246 static void 247 disp_obj(ea_object_t *o, int indent) 248 { 249 char objname[30] = " "; 250 int eol = 1; 251 252 if (indent > MAX_DEPTH) { 253 objname[0] = '>'; 254 indent = 1; 255 } 256 257 (void) printf("%6x\t", (o->eo_catalog & EXD_DATA_MASK)); 258 (void) snprintf(objname + indent, 30 - indent, "%-s", 259 catalog_name(o->eo_catalog & EXD_DATA_MASK)); 260 (void) printf("%-30s\t", objname); 261 262 switch (o->eo_catalog & EXT_TYPE_MASK) { 263 case EXT_UINT8: 264 (void) printf("%-15u", o->eo_item.ei_uint8); 265 if (vflag && 266 ((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_PROTOCOL)) { 267 disp_proto(o->eo_item.ei_uint8); 268 } 269 break; 270 case EXT_UINT16: 271 (void) printf("%-15u", o->eo_item.ei_uint16); 272 if (vflag && 273 (((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_SPORT) || 274 ((o->eo_catalog & EXD_DATA_MASK) == EXD_FLOW_DPORT))) { 275 disp_port(o->eo_item.ei_uint16); 276 } 277 break; 278 case EXT_UINT32: 279 switch (o->eo_catalog & EXD_DATA_MASK) { 280 case EXD_PROC_WAIT_STATUS: 281 { 282 int wstat = o->eo_item.ei_uint32; 283 284 if (vflag) { 285 if (WIFEXITED(wstat)) 286 (void) printf("%-14d exit", 287 WEXITSTATUS(wstat)); 288 else if (WIFSIGNALED(wstat)) 289 (void) printf("%14d, signal", 290 WTERMSIG(wstat)); 291 else 292 (void) printf("%d", wstat); 293 } else { 294 (void) printf("%d", wstat); 295 } 296 } 297 break; 298 case EXD_PROC_UID: 299 { 300 uid_t uid = o->eo_item.ei_uint32; 301 302 (void) printf("%-15u", uid); 303 if (vflag) { 304 struct passwd *pwd; 305 if ((pwd = getpwuid(uid)) != NULL) 306 (void) printf("%s", 307 pwd->pw_name); 308 } 309 } 310 break; 311 case EXD_PROC_GID: 312 { 313 gid_t gid = o->eo_item.ei_uint32; 314 315 (void) printf("%-15u", gid); 316 if (vflag) { 317 struct group *grp; 318 if ((grp = getgrgid(gid)) != NULL) 319 (void) printf("%s", 320 grp->gr_name); 321 } 322 } 323 break; 324 case EXD_PROC_PROJID: 325 case EXD_TASK_PROJID: 326 { 327 projid_t projid = o->eo_item.ei_uint32; 328 329 (void) printf("%-15lu", projid); 330 if (vflag) { 331 struct project proj; 332 char projbuf[PROJECT_BUFSZ]; 333 334 if (getprojbyid(projid, &proj, projbuf, 335 PROJECT_BUFSZ) != NULL) 336 (void) printf("%s", 337 proj.pj_name); 338 } 339 } 340 break; 341 case EXD_PROC_ACCT_FLAGS: 342 { 343 int flag = o->eo_item.ei_uint32; 344 345 (void) printf("%-15u", flag); 346 if (vflag) { 347 if (flag & AFORK) 348 (void) printf("FORK "); 349 if (flag & ASU) 350 (void) printf("SU"); 351 } 352 } 353 break; 354 case EXD_FLOW_V4SADDR: 355 /* FALLTHRU */ 356 case EXD_FLOW_V4DADDR: 357 { 358 char str[INET_ADDRSTRLEN]; 359 uint32_t addr = htonl(o->eo_item.ei_uint32); 360 361 (void) printf("%-15s", 362 inet_ntop(AF_INET, &addr, str, 363 INET_ADDRSTRLEN)); 364 if (vflag) { 365 disp_host((char *)&addr, AF_INET); 366 } 367 } 368 break; 369 default: 370 (void) printf("%u", o->eo_item.ei_uint32); 371 } 372 break; 373 case EXT_UINT64: 374 { 375 time_t _time; 376 char timebuf[20]; 377 378 (void) printf(FMT_UINT64, o->eo_item.ei_uint64); 379 if (!vflag) 380 break; 381 if (ea_match_object_catalog(o, EXD_TASK_START_SEC) || 382 ea_match_object_catalog(o, EXD_TASK_FINISH_SEC) || 383 ea_match_object_catalog(o, EXD_PROC_START_SEC) || 384 ea_match_object_catalog(o, EXD_PROC_FINISH_SEC) || 385 ea_match_object_catalog(o, EXD_FLOW_LSEEN) || 386 ea_match_object_catalog(o, EXD_FLOW_CTIME)) { 387 _time = o->eo_item.ei_uint64; 388 (void) strftime(timebuf, sizeof (timebuf), 389 "%D %T", localtime(&_time)); 390 (void) fputs(timebuf, stdout); 391 } 392 } 393 break; 394 case EXT_DOUBLE: 395 (void) printf("%f", o->eo_item.ei_double); 396 break; 397 case EXT_STRING: 398 (void) printf("\"%s\"", o->eo_item.ei_string); 399 break; 400 case EXT_RAW: 401 switch (o->eo_catalog & EXD_DATA_MASK) { 402 case EXD_FLOW_V6SADDR: 403 /* FALLTHRU */ 404 case EXD_FLOW_V6DADDR: 405 { 406 in6_addr_t *addr; 407 char str[INET6_ADDRSTRLEN]; 408 409 addr = (in6_addr_t *)o->eo_item.ei_raw; 410 (void) printf("%-28s", inet_ntop(AF_INET6, 411 &addr->s6_addr, str, INET6_ADDRSTRLEN)); 412 if (vflag) { 413 disp_host((char *)&addr->s6_addr, 414 AF_INET6); 415 } 416 417 } 418 break; 419 default: 420 { 421 ea_size_t size = o->eo_item.ei_size; 422 char *buf = o->eo_item.ei_raw; 423 uint64_t i; 424 425 for (i = 0; i < size && i < 6; i++) 426 (void) printf("0x%2X ", buf[i]); 427 if (size > 6) 428 (void) printf("..."); 429 } 430 } 431 break; 432 case EXT_GROUP: 433 (void) printf("[group of %u object(s)]", o->eo_group.eg_nobjs); 434 break; 435 case EXT_EXACCT_OBJECT: 436 /* 437 * Embedded exacct records. 438 */ 439 { 440 ea_object_type_t ot; 441 ea_object_t *op; 442 ea_object_t *eo; 443 444 ot = ea_unpack_object(&op, EUP_ALLOC, 445 o->eo_item.ei_object, o->eo_item.ei_size); 446 447 if (ot == EO_ERROR) { 448 (void) printf("error: couldn't unpack embedded " 449 "object\n"); 450 break; 451 } 452 eol = 0; 453 if (ot == EO_GROUP) { 454 (void) printf("[embedded group of %u " 455 "object(s)]\n", op->eo_group.eg_nobjs); 456 eo = op->eo_group.eg_objs; 457 disp_embedded_group(eo, indent); 458 } else { 459 (void) printf("[embedded object]\n"); 460 disp_obj(op, indent); 461 } 462 ea_free_object(op, EUP_ALLOC); 463 } 464 break; 465 default: 466 (void) printf("[complex value]"); 467 break; 468 } 469 470 if (eol) 471 (void) printf("\n"); 472 473 } 474 475 /* 476 * Read and display a group of exacct objects from the file. 477 */ 478 static void 479 disp_group(ea_file_t *ef, uint_t nobjs, int indent) 480 { 481 uint_t i; 482 483 for (i = 0; i < nobjs; i++) { 484 ea_object_t scratch; 485 int res; 486 487 if ((res = ea_get_object(ef, &scratch)) == -1) { 488 (void) fprintf(stderr, 489 "bad file: ea_get_object()==%d\n", res); 490 exit(2); 491 } 492 493 disp_obj(&scratch, indent + 1); 494 495 if (scratch.eo_type == EO_GROUP) 496 disp_group(ef, scratch.eo_group.eg_nobjs, indent + 1); 497 else 498 (void) ea_free_item(&scratch, EUP_ALLOC); 499 } 500 } 501 502 static void 503 usage() 504 { 505 (void) fprintf(stderr, "Usage: exdump [-v] <file>\n"); 506 exit(2); 507 } 508 509 int 510 main(int argc, char *argv[]) 511 { 512 ea_file_t ef; 513 ea_object_t scratch; 514 char *fname; 515 int opt; 516 517 while ((opt = getopt(argc, argv, "v")) != EOF) { 518 switch (opt) { 519 case 'v': 520 vflag = 1; 521 break; 522 default: 523 usage(); 524 } 525 } 526 527 if (argc == optind) 528 usage(); 529 if (argc > optind) 530 fname = argv[optind++]; 531 if (argc > optind) 532 usage(); 533 534 if (ea_open(&ef, fname, NULL, 535 vflag ? EO_NO_VALID_HDR : 0, O_RDONLY, 0) == -1) { 536 (void) fprintf(stderr, "exdump: cannot open %s\n", fname); 537 return (1); 538 } 539 540 bzero(&scratch, sizeof (ea_object_t)); 541 while (ea_get_object(&ef, &scratch) != -1) { 542 disp_obj(&scratch, 0); 543 if (scratch.eo_type == EO_GROUP) 544 disp_group(&ef, scratch.eo_group.eg_nobjs, 0); 545 else 546 (void) ea_free_item(&scratch, EUP_ALLOC); 547 (void) bzero(&scratch, sizeof (ea_object_t)); 548 } 549 550 (void) ea_close(&ef); 551 return (0); 552 } 553