xref: /titanic_52/usr/src/lib/libexacct/demo/exdump.c (revision 8793b36b40d14ad0a0fecc97738dc118a928f46c)
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 *
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
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
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
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
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
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
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
503  usage()
504  {
505  	(void) fprintf(stderr, "Usage: exdump [-v] <file>\n");
506  	exit(2);
507  }
508  
509  int
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