xref: /illumos-gate/usr/src/lib/libexacct/demo/exdump.c (revision a5f69788de7ac07553de47f7fec8c05a9a94c105)
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