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 *
catalog_name(int type)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
disp_port(uint16_t port)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
disp_host(char * addr,int family)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
disp_proto(uint8_t protocol)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
disp_embedded_group(ea_object_t * eo,int indent)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
disp_obj(ea_object_t * o,int indent)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
disp_group(ea_file_t * ef,uint_t nobjs,int indent)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
usage()503 usage()
504 {
505 (void) fprintf(stderr, "Usage: exdump [-v] <file>\n");
506 exit(2);
507 }
508
509 int
main(int argc,char * argv[])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