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