|
Chris PeBenito |
473ea7 |
/*
|
|
Chris PeBenito |
473ea7 |
* avcstat - Display SELinux avc statistics.
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* Copyright (C) 2004 Red Hat, Inc., James Morris <jmorris@redhat.com>
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
* This program is free software; you can redistribute it and/or modify
|
|
Chris PeBenito |
473ea7 |
* it under the terms of the GNU General Public License version 2,
|
|
Chris PeBenito |
473ea7 |
* as published by the Free Software Foundation.
|
|
Chris PeBenito |
473ea7 |
*
|
|
Chris PeBenito |
473ea7 |
*/
|
|
Chris PeBenito |
473ea7 |
#include <stdio.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdlib.h>
|
|
Chris PeBenito |
473ea7 |
#include <libgen.h>
|
|
Chris PeBenito |
473ea7 |
#include <stdarg.h>
|
|
Chris PeBenito |
473ea7 |
#include <errno.h>
|
|
Chris PeBenito |
473ea7 |
#include <string.h>
|
|
Chris PeBenito |
473ea7 |
#include <fcntl.h>
|
|
Chris PeBenito |
473ea7 |
#include <unistd.h>
|
|
Chris PeBenito |
473ea7 |
#include <signal.h>
|
|
Chris PeBenito |
473ea7 |
#include <sys/types.h>
|
|
Chris PeBenito |
473ea7 |
#include <sys/stat.h>
|
|
Chris PeBenito |
473ea7 |
#include <sys/ioctl.h>
|
|
Chris PeBenito |
473ea7 |
#include <linux/limits.h>
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
#define DEF_STAT_FILE "/avc/cache_stats"
|
|
Chris PeBenito |
473ea7 |
#define DEF_BUF_SIZE 8192
|
|
Chris PeBenito |
473ea7 |
#define HEADERS "lookups hits misses allocations reclaims frees"
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
struct avc_cache_stats {
|
|
Chris PeBenito |
473ea7 |
unsigned int lookups;
|
|
Chris PeBenito |
473ea7 |
unsigned int hits;
|
|
Chris PeBenito |
473ea7 |
unsigned int misses;
|
|
Chris PeBenito |
473ea7 |
unsigned int allocations;
|
|
Chris PeBenito |
473ea7 |
unsigned int reclaims;
|
|
Chris PeBenito |
473ea7 |
unsigned int frees;
|
|
Chris PeBenito |
473ea7 |
};
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static int interval;
|
|
Chris PeBenito |
473ea7 |
static int rows;
|
|
Chris PeBenito |
473ea7 |
static char *progname;
|
|
Chris PeBenito |
473ea7 |
static char buf[DEF_BUF_SIZE];
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
/* selinuxfs mount point */
|
|
Chris PeBenito |
473ea7 |
extern char *selinux_mnt;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void die(const char *msg, ...)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
va_list args;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
fputs("ERROR: ", stderr);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
va_start(args, msg);
|
|
Chris PeBenito |
473ea7 |
vfprintf(stderr, msg, args);
|
|
Chris PeBenito |
473ea7 |
va_end(args);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (errno)
|
|
Chris PeBenito |
473ea7 |
fprintf(stderr, ": %s", strerror(errno));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
fputc('\n', stderr);
|
|
Chris PeBenito |
473ea7 |
exit(1);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void usage(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
printf("\nUsage: %s [-c] [-f status_file] [interval]\n\n", progname);
|
|
Chris PeBenito |
473ea7 |
printf("Display SELinux AVC statistics. If the interval parameter is specified, the\n");
|
|
Chris PeBenito |
473ea7 |
printf("program will loop, displaying updated statistics every \'interval\' seconds.\n");
|
|
Chris PeBenito |
473ea7 |
printf("Relative values are displayed by default. Use the -c option to specify the\n");
|
|
Chris PeBenito |
473ea7 |
printf("display of cumulative values. The -f option specifies the location of the\n");
|
|
Chris PeBenito |
473ea7 |
printf("AVC statistics file, defaulting to \'%s%s\'.\n\n", selinux_mnt, DEF_STAT_FILE);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void set_window_rows(void)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
int ret;
|
|
Chris PeBenito |
473ea7 |
struct winsize ws;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
ret = ioctl(fileno(stdout), TIOCGWINSZ, &ws);
|
|
Chris PeBenito |
473ea7 |
if (ret < 0 || ws.ws_row < 3)
|
|
Chris PeBenito |
473ea7 |
ws.ws_row = 24;
|
|
Chris PeBenito |
473ea7 |
rows = ws.ws_row;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
static void sighandler(int num)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
if (num == SIGWINCH)
|
|
Chris PeBenito |
473ea7 |
set_window_rows();
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
int main(int argc, char **argv)
|
|
Chris PeBenito |
473ea7 |
{
|
|
Chris PeBenito |
473ea7 |
struct avc_cache_stats tot, rel, last;
|
|
Chris PeBenito |
473ea7 |
int fd, i, cumulative = 0;
|
|
Chris PeBenito |
473ea7 |
struct sigaction sa;
|
|
Chris PeBenito |
473ea7 |
char avcstatfile[PATH_MAX];
|
|
Chris PeBenito |
473ea7 |
snprintf(avcstatfile, sizeof avcstatfile, "%s%s", selinux_mnt, DEF_STAT_FILE);
|
|
Chris PeBenito |
473ea7 |
progname = basename(argv[0]);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memset(&last, 0, sizeof(last));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while((i = getopt(argc, argv, "cf:h?-")) != -1) {
|
|
Chris PeBenito |
473ea7 |
switch (i) {
|
|
Chris PeBenito |
473ea7 |
case 'c':
|
|
Chris PeBenito |
473ea7 |
cumulative = 1;
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'f':
|
|
Chris PeBenito |
473ea7 |
strncpy(avcstatfile, optarg, sizeof avcstatfile);
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
case 'h':
|
|
Chris PeBenito |
473ea7 |
case '-':
|
|
Chris PeBenito |
473ea7 |
usage();
|
|
Chris PeBenito |
473ea7 |
exit(0);
|
|
Chris PeBenito |
473ea7 |
default:
|
|
Chris PeBenito |
473ea7 |
usage();
|
|
Chris PeBenito |
473ea7 |
die("unrecognized parameter", i);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (optind < argc) {
|
|
Chris PeBenito |
473ea7 |
char *arg = argv[optind];
|
|
Chris PeBenito |
473ea7 |
unsigned int n = strtoul(arg, NULL, 10);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (errno == ERANGE) {
|
|
Chris PeBenito |
473ea7 |
usage();
|
|
Chris PeBenito |
473ea7 |
die("invalid interval \'%s\'", arg);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
if (n == 0) {
|
|
Chris PeBenito |
473ea7 |
usage();
|
|
Chris PeBenito |
473ea7 |
exit (0);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
interval = n;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
sa.sa_handler = sighandler;
|
|
Chris PeBenito |
473ea7 |
sa.sa_flags = SA_RESTART;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
i = sigaction(SIGWINCH, &sa, NULL);
|
|
Chris PeBenito |
473ea7 |
if (i < 0)
|
|
Chris PeBenito |
473ea7 |
die("sigaction");
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
set_window_rows();
|
|
Chris PeBenito |
473ea7 |
fd = open(avcstatfile, O_RDONLY);
|
|
Chris PeBenito |
473ea7 |
if (fd < 0)
|
|
Chris PeBenito |
473ea7 |
die("open: \'%s\'", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
for (i = 0;; i++) {
|
|
Chris PeBenito |
473ea7 |
char *line;
|
|
Chris PeBenito |
473ea7 |
ssize_t ret, parsed = 0;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memset(buf, 0, DEF_BUF_SIZE);
|
|
Chris PeBenito |
473ea7 |
ret = read(fd, buf, DEF_BUF_SIZE);
|
|
Chris PeBenito |
473ea7 |
if (ret < 0)
|
|
Chris PeBenito |
473ea7 |
die("read");
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (ret == 0)
|
|
Chris PeBenito |
473ea7 |
die("read: \'%s\': unexpected end of file", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
line = strtok(buf, "\n");
|
|
Chris PeBenito |
473ea7 |
if (!line)
|
|
Chris PeBenito |
473ea7 |
die("unable to parse \'%s\': end of line not found", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (strcmp(line, HEADERS))
|
|
Chris PeBenito |
473ea7 |
die("unable to parse \'%s\': invalid headers", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!i || !(i % (rows - 2)))
|
|
Chris PeBenito |
473ea7 |
printf("%10s %10s %10s %10s %10s %10s\n", "lookups",
|
|
Chris PeBenito |
473ea7 |
"hits", "misses", "allocs", "reclaims", "frees");
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memset(&tot, 0, sizeof(tot));
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
while ((line = strtok(NULL, "\n"))) {
|
|
Chris PeBenito |
473ea7 |
struct avc_cache_stats tmp;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
ret = sscanf(line, "%u %u %u %u %u %u",
|
|
Chris PeBenito |
473ea7 |
&tmp.lookups,
|
|
Chris PeBenito |
473ea7 |
&tmp.hits,
|
|
Chris PeBenito |
473ea7 |
&tmp.misses,
|
|
Chris PeBenito |
473ea7 |
&tmp.allocations,
|
|
Chris PeBenito |
473ea7 |
&tmp.reclaims,
|
|
Chris PeBenito |
473ea7 |
&tmp.frees);
|
|
Chris PeBenito |
473ea7 |
if (ret != 6)
|
|
Chris PeBenito |
473ea7 |
die("unable to parse \'%s\': scan error", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
tot.lookups += tmp.lookups;
|
|
Chris PeBenito |
473ea7 |
tot.hits += tmp.hits;
|
|
Chris PeBenito |
473ea7 |
tot.misses += tmp.misses;
|
|
Chris PeBenito |
473ea7 |
tot.allocations += tmp.allocations;
|
|
Chris PeBenito |
473ea7 |
tot.reclaims += tmp.reclaims;
|
|
Chris PeBenito |
473ea7 |
tot.frees += tmp.frees;
|
|
Chris PeBenito |
473ea7 |
parsed = 1;
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!parsed)
|
|
Chris PeBenito |
473ea7 |
die("unable to parse \'%s\': no data", avcstatfile);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (cumulative || (!cumulative && !i))
|
|
Chris PeBenito |
473ea7 |
printf("%10u %10u %10u %10u %10u %10u\n",
|
|
Chris PeBenito |
473ea7 |
tot.lookups, tot.hits, tot.misses,
|
|
Chris PeBenito |
473ea7 |
tot.allocations, tot.reclaims, tot.frees);
|
|
Chris PeBenito |
473ea7 |
else {
|
|
Chris PeBenito |
473ea7 |
rel.lookups = tot.lookups - last.lookups;
|
|
Chris PeBenito |
473ea7 |
rel.hits = tot.hits - last.hits;
|
|
Chris PeBenito |
473ea7 |
rel.misses = tot.misses - last.misses;
|
|
Chris PeBenito |
473ea7 |
rel.allocations = tot.allocations - last.allocations;
|
|
Chris PeBenito |
473ea7 |
rel.reclaims = tot.reclaims - last.reclaims;
|
|
Chris PeBenito |
473ea7 |
rel.frees = tot.frees - last.frees;
|
|
Chris PeBenito |
473ea7 |
printf("%10u %10u %10u %10u %10u %10u\n",
|
|
Chris PeBenito |
473ea7 |
rel.lookups, rel.hits, rel.misses,
|
|
Chris PeBenito |
473ea7 |
rel.allocations, rel.reclaims, rel.frees);
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
if (!interval)
|
|
Chris PeBenito |
473ea7 |
break;
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
memcpy(&last, &tot, sizeof(last));
|
|
Chris PeBenito |
473ea7 |
sleep(interval);
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
ret = lseek(fd, 0, 0);
|
|
Chris PeBenito |
473ea7 |
if (ret < 0)
|
|
Chris PeBenito |
473ea7 |
die("lseek");
|
|
Chris PeBenito |
473ea7 |
}
|
|
Chris PeBenito |
473ea7 |
|
|
Chris PeBenito |
473ea7 |
close(fd);
|
|
Chris PeBenito |
473ea7 |
return 0;
|
|
Chris PeBenito |
473ea7 |
}
|