xref: /aosp_15_r20/external/selinux/libselinux/utils/avcstat.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /*
2*2d543d20SAndroid Build Coastguard Worker  * avcstat - Display SELinux avc statistics.
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2004 Red Hat, Inc., James Morris <[email protected]>
5*2d543d20SAndroid Build Coastguard Worker  *
6*2d543d20SAndroid Build Coastguard Worker  * This program is free software; you can redistribute it and/or modify
7*2d543d20SAndroid Build Coastguard Worker  * it under the terms of the GNU General Public License version 2,
8*2d543d20SAndroid Build Coastguard Worker  * as published by the Free Software Foundation.
9*2d543d20SAndroid Build Coastguard Worker  *
10*2d543d20SAndroid Build Coastguard Worker  */
11*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
12*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
13*2d543d20SAndroid Build Coastguard Worker #include <libgen.h>
14*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
15*2d543d20SAndroid Build Coastguard Worker #include <errno.h>
16*2d543d20SAndroid Build Coastguard Worker #include <string.h>
17*2d543d20SAndroid Build Coastguard Worker #include <fcntl.h>
18*2d543d20SAndroid Build Coastguard Worker #include <unistd.h>
19*2d543d20SAndroid Build Coastguard Worker #include <signal.h>
20*2d543d20SAndroid Build Coastguard Worker #include <sys/types.h>
21*2d543d20SAndroid Build Coastguard Worker #include <sys/stat.h>
22*2d543d20SAndroid Build Coastguard Worker #include <sys/ioctl.h>
23*2d543d20SAndroid Build Coastguard Worker #include <linux/limits.h>
24*2d543d20SAndroid Build Coastguard Worker 
25*2d543d20SAndroid Build Coastguard Worker #define DEF_STAT_FILE	"/avc/cache_stats"
26*2d543d20SAndroid Build Coastguard Worker #define DEF_BUF_SIZE	8192
27*2d543d20SAndroid Build Coastguard Worker #define HEADERS		"lookups hits misses allocations reclaims frees"
28*2d543d20SAndroid Build Coastguard Worker 
29*2d543d20SAndroid Build Coastguard Worker struct avc_cache_stats {
30*2d543d20SAndroid Build Coastguard Worker 	unsigned long long lookups;
31*2d543d20SAndroid Build Coastguard Worker 	unsigned long long hits;
32*2d543d20SAndroid Build Coastguard Worker 	unsigned long long misses;
33*2d543d20SAndroid Build Coastguard Worker 	unsigned long long allocations;
34*2d543d20SAndroid Build Coastguard Worker 	unsigned long long reclaims;
35*2d543d20SAndroid Build Coastguard Worker 	unsigned long long frees;
36*2d543d20SAndroid Build Coastguard Worker };
37*2d543d20SAndroid Build Coastguard Worker 
38*2d543d20SAndroid Build Coastguard Worker static int interval;
39*2d543d20SAndroid Build Coastguard Worker static int rows;
40*2d543d20SAndroid Build Coastguard Worker static char *progname;
41*2d543d20SAndroid Build Coastguard Worker static char buf[DEF_BUF_SIZE];
42*2d543d20SAndroid Build Coastguard Worker 
43*2d543d20SAndroid Build Coastguard Worker /* selinuxfs mount point */
44*2d543d20SAndroid Build Coastguard Worker extern char *selinux_mnt;
45*2d543d20SAndroid Build Coastguard Worker 
die(const char * msg,...)46*2d543d20SAndroid Build Coastguard Worker static __attribute__((__format__(printf,1,2),__noreturn__)) void die(const char *msg, ...)
47*2d543d20SAndroid Build Coastguard Worker {
48*2d543d20SAndroid Build Coastguard Worker 	va_list args;
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker 	fputs("ERROR: ", stderr);
51*2d543d20SAndroid Build Coastguard Worker 
52*2d543d20SAndroid Build Coastguard Worker 	va_start(args, msg);
53*2d543d20SAndroid Build Coastguard Worker 	vfprintf(stderr, msg, args);
54*2d543d20SAndroid Build Coastguard Worker 	va_end(args);
55*2d543d20SAndroid Build Coastguard Worker 
56*2d543d20SAndroid Build Coastguard Worker 	if (errno)
57*2d543d20SAndroid Build Coastguard Worker 		fprintf(stderr, ": %s", strerror(errno));
58*2d543d20SAndroid Build Coastguard Worker 
59*2d543d20SAndroid Build Coastguard Worker 	fputc('\n', stderr);
60*2d543d20SAndroid Build Coastguard Worker 	exit(1);
61*2d543d20SAndroid Build Coastguard Worker }
62*2d543d20SAndroid Build Coastguard Worker 
usage(void)63*2d543d20SAndroid Build Coastguard Worker static void usage(void)
64*2d543d20SAndroid Build Coastguard Worker {
65*2d543d20SAndroid Build Coastguard Worker 	printf("\nUsage: %s [-c] [-f status_file] [interval]\n\n", progname);
66*2d543d20SAndroid Build Coastguard Worker 	printf
67*2d543d20SAndroid Build Coastguard Worker 	    ("Display SELinux AVC statistics.  If the interval parameter is specified, the\n");
68*2d543d20SAndroid Build Coastguard Worker 	printf
69*2d543d20SAndroid Build Coastguard Worker 	    ("program will loop, displaying updated statistics every \'interval\' seconds.\n");
70*2d543d20SAndroid Build Coastguard Worker 	printf
71*2d543d20SAndroid Build Coastguard Worker 	    ("Relative values are displayed by default. Use the -c option to specify the\n");
72*2d543d20SAndroid Build Coastguard Worker 	printf
73*2d543d20SAndroid Build Coastguard Worker 	    ("display of cumulative values.  The -f option specifies the location of the\n");
74*2d543d20SAndroid Build Coastguard Worker 	printf("AVC statistics file, defaulting to \'%s%s\'.\n\n", selinux_mnt,
75*2d543d20SAndroid Build Coastguard Worker 	       DEF_STAT_FILE);
76*2d543d20SAndroid Build Coastguard Worker }
77*2d543d20SAndroid Build Coastguard Worker 
set_window_rows(void)78*2d543d20SAndroid Build Coastguard Worker static void set_window_rows(void)
79*2d543d20SAndroid Build Coastguard Worker {
80*2d543d20SAndroid Build Coastguard Worker 	int ret;
81*2d543d20SAndroid Build Coastguard Worker 	struct winsize ws;
82*2d543d20SAndroid Build Coastguard Worker 
83*2d543d20SAndroid Build Coastguard Worker 	ret = ioctl(fileno(stdout), TIOCGWINSZ, &ws);
84*2d543d20SAndroid Build Coastguard Worker 	if (ret < 0 || ws.ws_row < 3)
85*2d543d20SAndroid Build Coastguard Worker 		ws.ws_row = 24;
86*2d543d20SAndroid Build Coastguard Worker 	rows = ws.ws_row;
87*2d543d20SAndroid Build Coastguard Worker }
88*2d543d20SAndroid Build Coastguard Worker 
sighandler(int num)89*2d543d20SAndroid Build Coastguard Worker static void sighandler(int num)
90*2d543d20SAndroid Build Coastguard Worker {
91*2d543d20SAndroid Build Coastguard Worker 	if (num == SIGWINCH)
92*2d543d20SAndroid Build Coastguard Worker 		set_window_rows();
93*2d543d20SAndroid Build Coastguard Worker }
94*2d543d20SAndroid Build Coastguard Worker 
main(int argc,char ** argv)95*2d543d20SAndroid Build Coastguard Worker int main(int argc, char **argv)
96*2d543d20SAndroid Build Coastguard Worker {
97*2d543d20SAndroid Build Coastguard Worker 	struct avc_cache_stats tot, rel, last;
98*2d543d20SAndroid Build Coastguard Worker 	int fd, i, cumulative = 0;
99*2d543d20SAndroid Build Coastguard Worker 	struct sigaction sa;
100*2d543d20SAndroid Build Coastguard Worker 	char avcstatfile[PATH_MAX];
101*2d543d20SAndroid Build Coastguard Worker 	snprintf(avcstatfile, sizeof avcstatfile, "%s%s", selinux_mnt,
102*2d543d20SAndroid Build Coastguard Worker 		 DEF_STAT_FILE);
103*2d543d20SAndroid Build Coastguard Worker 	progname = basename(argv[0]);
104*2d543d20SAndroid Build Coastguard Worker 
105*2d543d20SAndroid Build Coastguard Worker 	memset(&last, 0, sizeof(last));
106*2d543d20SAndroid Build Coastguard Worker 
107*2d543d20SAndroid Build Coastguard Worker 	while ((i = getopt(argc, argv, "cf:h?-")) != -1) {
108*2d543d20SAndroid Build Coastguard Worker 		switch (i) {
109*2d543d20SAndroid Build Coastguard Worker 		case 'c':
110*2d543d20SAndroid Build Coastguard Worker 			cumulative = 1;
111*2d543d20SAndroid Build Coastguard Worker 			break;
112*2d543d20SAndroid Build Coastguard Worker 		case 'f':
113*2d543d20SAndroid Build Coastguard Worker 			strncpy(avcstatfile, optarg, sizeof(avcstatfile) - 1);
114*2d543d20SAndroid Build Coastguard Worker 			avcstatfile[sizeof(avcstatfile)-1] = '\0';
115*2d543d20SAndroid Build Coastguard Worker 			break;
116*2d543d20SAndroid Build Coastguard Worker 		case 'h':
117*2d543d20SAndroid Build Coastguard Worker 		case '-':
118*2d543d20SAndroid Build Coastguard Worker 			usage();
119*2d543d20SAndroid Build Coastguard Worker 			exit(EXIT_SUCCESS);
120*2d543d20SAndroid Build Coastguard Worker 		default:
121*2d543d20SAndroid Build Coastguard Worker 			usage();
122*2d543d20SAndroid Build Coastguard Worker 			die("unrecognized parameter '%c'", i);
123*2d543d20SAndroid Build Coastguard Worker 		}
124*2d543d20SAndroid Build Coastguard Worker 	}
125*2d543d20SAndroid Build Coastguard Worker 
126*2d543d20SAndroid Build Coastguard Worker 	if (optind < argc) {
127*2d543d20SAndroid Build Coastguard Worker 		char *arg = argv[optind];
128*2d543d20SAndroid Build Coastguard Worker 		unsigned int n = strtoul(arg, NULL, 10);
129*2d543d20SAndroid Build Coastguard Worker 
130*2d543d20SAndroid Build Coastguard Worker 		if (errno == ERANGE) {
131*2d543d20SAndroid Build Coastguard Worker 			usage();
132*2d543d20SAndroid Build Coastguard Worker 			die("invalid interval \'%s\'", arg);
133*2d543d20SAndroid Build Coastguard Worker 		}
134*2d543d20SAndroid Build Coastguard Worker 		if (n == 0) {
135*2d543d20SAndroid Build Coastguard Worker 			usage();
136*2d543d20SAndroid Build Coastguard Worker 			exit(EXIT_SUCCESS);
137*2d543d20SAndroid Build Coastguard Worker 		}
138*2d543d20SAndroid Build Coastguard Worker 		interval = n;
139*2d543d20SAndroid Build Coastguard Worker 	}
140*2d543d20SAndroid Build Coastguard Worker 
141*2d543d20SAndroid Build Coastguard Worker 	sa.sa_handler = sighandler;
142*2d543d20SAndroid Build Coastguard Worker 	sa.sa_flags = SA_RESTART;
143*2d543d20SAndroid Build Coastguard Worker 	sigemptyset(&sa.sa_mask);
144*2d543d20SAndroid Build Coastguard Worker 
145*2d543d20SAndroid Build Coastguard Worker 	i = sigaction(SIGWINCH, &sa, NULL);
146*2d543d20SAndroid Build Coastguard Worker 	if (i < 0)
147*2d543d20SAndroid Build Coastguard Worker 		die("sigaction");
148*2d543d20SAndroid Build Coastguard Worker 
149*2d543d20SAndroid Build Coastguard Worker 	set_window_rows();
150*2d543d20SAndroid Build Coastguard Worker 	fd = open(avcstatfile, O_RDONLY);
151*2d543d20SAndroid Build Coastguard Worker 	if (fd < 0)
152*2d543d20SAndroid Build Coastguard Worker 		die("open: \'%s\'", avcstatfile);
153*2d543d20SAndroid Build Coastguard Worker 
154*2d543d20SAndroid Build Coastguard Worker 	for (i = 0;; i++) {
155*2d543d20SAndroid Build Coastguard Worker 		char *line;
156*2d543d20SAndroid Build Coastguard Worker 		ssize_t ret, parsed = 0;
157*2d543d20SAndroid Build Coastguard Worker 
158*2d543d20SAndroid Build Coastguard Worker 		memset(buf, 0, DEF_BUF_SIZE);
159*2d543d20SAndroid Build Coastguard Worker 		ret = read(fd, buf, DEF_BUF_SIZE-1);
160*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0)
161*2d543d20SAndroid Build Coastguard Worker 			die("read");
162*2d543d20SAndroid Build Coastguard Worker 
163*2d543d20SAndroid Build Coastguard Worker 		if (ret == 0)
164*2d543d20SAndroid Build Coastguard Worker 			die("read: \'%s\': unexpected end of file",
165*2d543d20SAndroid Build Coastguard Worker 			    avcstatfile);
166*2d543d20SAndroid Build Coastguard Worker 
167*2d543d20SAndroid Build Coastguard Worker 		line = strtok(buf, "\n");
168*2d543d20SAndroid Build Coastguard Worker 		if (!line)
169*2d543d20SAndroid Build Coastguard Worker 			die("unable to parse \'%s\': end of line not found",
170*2d543d20SAndroid Build Coastguard Worker 			    avcstatfile);
171*2d543d20SAndroid Build Coastguard Worker 
172*2d543d20SAndroid Build Coastguard Worker 		if (strcmp(line, HEADERS))
173*2d543d20SAndroid Build Coastguard Worker 			die("unable to parse \'%s\': invalid headers",
174*2d543d20SAndroid Build Coastguard Worker 			    avcstatfile);
175*2d543d20SAndroid Build Coastguard Worker 
176*2d543d20SAndroid Build Coastguard Worker 		if (!i || !(i % (rows - 2)))
177*2d543d20SAndroid Build Coastguard Worker 			printf("%10s %10s %10s %10s %10s %10s\n", "lookups",
178*2d543d20SAndroid Build Coastguard Worker 			       "hits", "misses", "allocs", "reclaims", "frees");
179*2d543d20SAndroid Build Coastguard Worker 
180*2d543d20SAndroid Build Coastguard Worker 		memset(&tot, 0, sizeof(tot));
181*2d543d20SAndroid Build Coastguard Worker 
182*2d543d20SAndroid Build Coastguard Worker 		while ((line = strtok(NULL, "\n"))) {
183*2d543d20SAndroid Build Coastguard Worker 			struct avc_cache_stats tmp;
184*2d543d20SAndroid Build Coastguard Worker 
185*2d543d20SAndroid Build Coastguard Worker 			ret = sscanf(line, "%llu %llu %llu %llu %llu %llu",
186*2d543d20SAndroid Build Coastguard Worker 				     &tmp.lookups,
187*2d543d20SAndroid Build Coastguard Worker 				     &tmp.hits,
188*2d543d20SAndroid Build Coastguard Worker 				     &tmp.misses,
189*2d543d20SAndroid Build Coastguard Worker 				     &tmp.allocations,
190*2d543d20SAndroid Build Coastguard Worker 				     &tmp.reclaims, &tmp.frees);
191*2d543d20SAndroid Build Coastguard Worker 			if (ret != 6)
192*2d543d20SAndroid Build Coastguard Worker 				die("unable to parse \'%s\': scan error",
193*2d543d20SAndroid Build Coastguard Worker 				    avcstatfile);
194*2d543d20SAndroid Build Coastguard Worker 
195*2d543d20SAndroid Build Coastguard Worker 			tot.lookups += tmp.lookups;
196*2d543d20SAndroid Build Coastguard Worker 			tot.hits += tmp.hits;
197*2d543d20SAndroid Build Coastguard Worker 			tot.misses += tmp.misses;
198*2d543d20SAndroid Build Coastguard Worker 			tot.allocations += tmp.allocations;
199*2d543d20SAndroid Build Coastguard Worker 			tot.reclaims += tmp.reclaims;
200*2d543d20SAndroid Build Coastguard Worker 			tot.frees += tmp.frees;
201*2d543d20SAndroid Build Coastguard Worker 			parsed = 1;
202*2d543d20SAndroid Build Coastguard Worker 		}
203*2d543d20SAndroid Build Coastguard Worker 
204*2d543d20SAndroid Build Coastguard Worker 		if (!parsed)
205*2d543d20SAndroid Build Coastguard Worker 			die("unable to parse \'%s\': no data", avcstatfile);
206*2d543d20SAndroid Build Coastguard Worker 
207*2d543d20SAndroid Build Coastguard Worker 		if (cumulative || !i)
208*2d543d20SAndroid Build Coastguard Worker 			printf("%10llu %10llu %10llu %10llu %10llu %10llu\n",
209*2d543d20SAndroid Build Coastguard Worker 			       tot.lookups, tot.hits, tot.misses,
210*2d543d20SAndroid Build Coastguard Worker 			       tot.allocations, tot.reclaims, tot.frees);
211*2d543d20SAndroid Build Coastguard Worker 		else {
212*2d543d20SAndroid Build Coastguard Worker 			rel.lookups = tot.lookups - last.lookups;
213*2d543d20SAndroid Build Coastguard Worker 			rel.hits = tot.hits - last.hits;
214*2d543d20SAndroid Build Coastguard Worker 			rel.misses = tot.misses - last.misses;
215*2d543d20SAndroid Build Coastguard Worker 			rel.allocations = tot.allocations - last.allocations;
216*2d543d20SAndroid Build Coastguard Worker 			rel.reclaims = tot.reclaims - last.reclaims;
217*2d543d20SAndroid Build Coastguard Worker 			rel.frees = tot.frees - last.frees;
218*2d543d20SAndroid Build Coastguard Worker 			printf("%10llu %10llu %10llu %10llu %10llu %10llu\n",
219*2d543d20SAndroid Build Coastguard Worker 			       rel.lookups, rel.hits, rel.misses,
220*2d543d20SAndroid Build Coastguard Worker 			       rel.allocations, rel.reclaims, rel.frees);
221*2d543d20SAndroid Build Coastguard Worker 		}
222*2d543d20SAndroid Build Coastguard Worker 
223*2d543d20SAndroid Build Coastguard Worker 		if (!interval)
224*2d543d20SAndroid Build Coastguard Worker 			break;
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker 		memcpy(&last, &tot, sizeof(last));
227*2d543d20SAndroid Build Coastguard Worker 		sleep(interval);
228*2d543d20SAndroid Build Coastguard Worker 
229*2d543d20SAndroid Build Coastguard Worker 		ret = lseek(fd, 0, 0);
230*2d543d20SAndroid Build Coastguard Worker 		if (ret < 0)
231*2d543d20SAndroid Build Coastguard Worker 			die("lseek");
232*2d543d20SAndroid Build Coastguard Worker 	}
233*2d543d20SAndroid Build Coastguard Worker 
234*2d543d20SAndroid Build Coastguard Worker 	close(fd);
235*2d543d20SAndroid Build Coastguard Worker 	return 0;
236*2d543d20SAndroid Build Coastguard Worker }
237