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