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