113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle/* 213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * avcstat - Display SELinux avc statistics. 313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * 413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com> 513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * 613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * This program is free software; you can redistribute it and/or modify 713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * it under the terms of the GNU General Public License version 2, 813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * as published by the Free Software Foundation. 913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle * 1013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle */ 1113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <stdio.h> 1213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <stdlib.h> 1313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <libgen.h> 1413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <stdarg.h> 1513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <errno.h> 1613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <string.h> 1713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <fcntl.h> 1813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <unistd.h> 1913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <signal.h> 2013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <sys/types.h> 2113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <sys/stat.h> 2213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <sys/ioctl.h> 2313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#include <linux/limits.h> 2413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 2513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#define DEF_STAT_FILE "/avc/cache_stats" 2613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#define DEF_BUF_SIZE 8192 2713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle#define HEADERS "lookups hits misses allocations reclaims frees" 2813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 2913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestruct avc_cache_stats { 3013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long lookups; 3113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long hits; 3213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long misses; 3313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long allocations; 3413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long reclaims; 3513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned long long frees; 3613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle}; 3713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 3813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic int interval; 3913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic int rows; 4013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic char *progname; 4113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic char buf[DEF_BUF_SIZE]; 4213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 4313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle/* selinuxfs mount point */ 4413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindleextern char *selinux_mnt; 4513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 4691d9fe8af05a9a9ded5d02bcd8c1c5a1e1ef670eDaniel P. Berrangestatic __attribute__((__format__(printf,1,2))) void die(const char *msg, ...) 4713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle{ 4813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle va_list args; 4913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 5013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle fputs("ERROR: ", stderr); 5113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 5213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle va_start(args, msg); 5313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle vfprintf(stderr, msg, args); 5413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle va_end(args); 5513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 5613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (errno) 5713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle fprintf(stderr, ": %s", strerror(errno)); 5813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 5913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle fputc('\n', stderr); 6013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle exit(1); 6113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle} 6213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 6313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic void usage(void) 6413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle{ 6513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf("\nUsage: %s [-c] [-f status_file] [interval]\n\n", progname); 6613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf 6713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ("Display SELinux AVC statistics. If the interval parameter is specified, the\n"); 6813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf 6913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ("program will loop, displaying updated statistics every \'interval\' seconds.\n"); 7013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf 7113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ("Relative values are displayed by default. Use the -c option to specify the\n"); 7213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf 7313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ("display of cumulative values. The -f option specifies the location of the\n"); 7413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf("AVC statistics file, defaulting to \'%s%s\'.\n\n", selinux_mnt, 7513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle DEF_STAT_FILE); 7613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle} 7713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 7813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic void set_window_rows(void) 7913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle{ 8013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle int ret; 8113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle struct winsize ws; 8213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 8313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ret = ioctl(fileno(stdout), TIOCGWINSZ, &ws); 8413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (ret < 0 || ws.ws_row < 3) 8513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ws.ws_row = 24; 8613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rows = ws.ws_row; 8713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle} 8813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 8913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindlestatic void sighandler(int num) 9013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle{ 9113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (num == SIGWINCH) 9213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle set_window_rows(); 9313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle} 9413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 9513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindleint main(int argc, char **argv) 9613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle{ 9713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle struct avc_cache_stats tot, rel, last; 9813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle int fd, i, cumulative = 0; 9913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle struct sigaction sa; 10013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle char avcstatfile[PATH_MAX]; 10113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle snprintf(avcstatfile, sizeof avcstatfile, "%s%s", selinux_mnt, 10213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle DEF_STAT_FILE); 10313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle progname = basename(argv[0]); 10413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 10513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle memset(&last, 0, sizeof(last)); 10613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 10713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle while ((i = getopt(argc, argv, "cf:h?-")) != -1) { 10813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle switch (i) { 10913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle case 'c': 11013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle cumulative = 1; 11113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle break; 11213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle case 'f': 11313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle strncpy(avcstatfile, optarg, sizeof avcstatfile); 11413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle break; 11513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle case 'h': 11613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle case '-': 11713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle usage(); 11813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle exit(0); 11913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle default: 12013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle usage(); 12191d9fe8af05a9a9ded5d02bcd8c1c5a1e1ef670eDaniel P. Berrange die("unrecognized parameter '%c'", i); 12213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 12313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 12413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 12513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (optind < argc) { 12613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle char *arg = argv[optind]; 12713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle unsigned int n = strtoul(arg, NULL, 10); 12813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 12913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (errno == ERANGE) { 13013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle usage(); 13113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("invalid interval \'%s\'", arg); 13213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 13313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (n == 0) { 13413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle usage(); 13513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle exit(0); 13613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 13713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle interval = n; 13813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 13913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 14013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle sa.sa_handler = sighandler; 14113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle sa.sa_flags = SA_RESTART; 142fa7a9a604ee9f12dbfa63950adc0122880c092b0Dan Walsh sigemptyset(&sa.sa_mask); 14313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 14413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle i = sigaction(SIGWINCH, &sa, NULL); 14513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (i < 0) 14613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("sigaction"); 14713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 14813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle set_window_rows(); 14913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle fd = open(avcstatfile, O_RDONLY); 15013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (fd < 0) 15113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("open: \'%s\'", avcstatfile); 15213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 15313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle for (i = 0;; i++) { 15413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle char *line; 15513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ssize_t ret, parsed = 0; 15613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 15713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle memset(buf, 0, DEF_BUF_SIZE); 158aa62cd60f7192123b509c2518e7a2083e34a65a2Eric Paris ret = read(fd, buf, DEF_BUF_SIZE-1); 15913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (ret < 0) 16013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("read"); 16113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 16213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (ret == 0) 16313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("read: \'%s\': unexpected end of file", 16413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle avcstatfile); 16513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 16613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle line = strtok(buf, "\n"); 16713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (!line) 16813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("unable to parse \'%s\': end of line not found", 16913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle avcstatfile); 17013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 17113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (strcmp(line, HEADERS)) 17213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("unable to parse \'%s\': invalid headers", 17313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle avcstatfile); 17413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 17513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (!i || !(i % (rows - 2))) 17613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf("%10s %10s %10s %10s %10s %10s\n", "lookups", 17713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle "hits", "misses", "allocs", "reclaims", "frees"); 17813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 17913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle memset(&tot, 0, sizeof(tot)); 18013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 18113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle while ((line = strtok(NULL, "\n"))) { 18213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle struct avc_cache_stats tmp; 18313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 18413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ret = sscanf(line, "%llu %llu %llu %llu %llu %llu", 18513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle &tmp.lookups, 18613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle &tmp.hits, 18713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle &tmp.misses, 18813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle &tmp.allocations, 18913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle &tmp.reclaims, &tmp.frees); 19013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (ret != 6) 19113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("unable to parse \'%s\': scan error", 19213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle avcstatfile); 19313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 19413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.lookups += tmp.lookups; 19513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.hits += tmp.hits; 19613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.misses += tmp.misses; 19713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.allocations += tmp.allocations; 19813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.reclaims += tmp.reclaims; 19913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.frees += tmp.frees; 20013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle parsed = 1; 20113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 20213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 20313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (!parsed) 20413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("unable to parse \'%s\': no data", avcstatfile); 20513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 20613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (cumulative || (!cumulative && !i)) 20713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", 20813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.lookups, tot.hits, tot.misses, 20913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle tot.allocations, tot.reclaims, tot.frees); 21013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle else { 21113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.lookups = tot.lookups - last.lookups; 21213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.hits = tot.hits - last.hits; 21313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.misses = tot.misses - last.misses; 21413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.allocations = tot.allocations - last.allocations; 21513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.reclaims = tot.reclaims - last.reclaims; 21613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.frees = tot.frees - last.frees; 21713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle printf("%10Lu %10Lu %10Lu %10Lu %10Lu %10Lu\n", 21813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.lookups, rel.hits, rel.misses, 21913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle rel.allocations, rel.reclaims, rel.frees); 22013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 22113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 22213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (!interval) 22313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle break; 22413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 22513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle memcpy(&last, &tot, sizeof(last)); 22613cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle sleep(interval); 22713cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 22813cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle ret = lseek(fd, 0, 0); 22913cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle if (ret < 0) 23013cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle die("lseek"); 23113cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle } 23213cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle 23313cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle close(fd); 23413cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle return 0; 23513cd4c8960688af11ad23b4c946149015c80d54Joshua Brindle} 236