diff options
-rw-r--r-- | Makefile | 16 | ||||
-rw-r--r-- | common.c | 14 | ||||
-rw-r--r-- | common.h | 7 | ||||
-rw-r--r-- | cpu.c | 157 | ||||
-rw-r--r-- | entropy.c | 35 | ||||
-rw-r--r-- | forks.c | 44 | ||||
-rw-r--r-- | fw_packets.c | 60 | ||||
-rw-r--r-- | interrupts.c | 47 | ||||
-rw-r--r-- | load.c | 47 | ||||
-rw-r--r-- | main.c | 64 | ||||
-rw-r--r-- | open_files.c | 52 | ||||
-rw-r--r-- | open_inodes.c | 42 | ||||
-rw-r--r-- | processes.c | 42 | ||||
-rw-r--r-- | swap.c | 78 | ||||
-rw-r--r-- | uptime.c | 32 |
15 files changed, 737 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..56a56f6 --- /dev/null +++ b/Makefile @@ -0,0 +1,16 @@ +CC=gcc +CFLAGS=-W -Wall -pedantic -Wextra -g -O2 +OBJS=main.o common.o cpu.o entropy.o forks.o fw_packets.o interrupts.o load.o \ + open_files.o open_inodes.o processes.o swap.o uptime.o +LINKS=cpu entropy forks fw_packets interrupts load open_files open_inodes \ + processes swap uptime + +%.o:%.c + ${CC} ${CFLAGS} -c $< -o $@ +all:main + for l in ${LINKS}; do test -f $$l || ln -s main $$l; done +main:${OBJS} + ${CC} ${CFLAGS} $^ -o $@ +clean: + rm -f main ${OBJS} ${LINKS} +.PHONY:all clean diff --git a/common.c b/common.c new file mode 100644 index 0000000..3d78e51 --- /dev/null +++ b/common.c @@ -0,0 +1,14 @@ +#include <stdio.h> + +int writeyes(void) { + puts("yes"); + return 0; +} + +int writeno(const char *s) { + if(s) + printf("no (%s)\n", s); + else + puts("no"); + return 1; +} diff --git a/common.h b/common.h new file mode 100644 index 0000000..67a5beb --- /dev/null +++ b/common.h @@ -0,0 +1,7 @@ +#ifndef COMMON_H +#define COMMON_H + +int writeyes(void); +int writeno(const char *); + +#endif @@ -0,0 +1,157 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <ctype.h> +#include <stdlib.h> +#include "common.h" + +#define SYSWARNING 30 +#define SYSCRITICAL 50 +#define USRWARNING 80 + +int cpu(int argc, char **argv) { + FILE *f; + char buff[256], *s; + int ncpu=0, extinfo=0, scaleto100=0; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + s = getenv("scaleto100"); + if(s && !strcmp(s, "yes")) + scaleto100=1; + + if(!(f=fopen("/proc/stat", "r"))) { + fputs("cannot open /proc/stat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "cpu", 3)) { + if(isdigit(buff[3])) + ncpu++; + if(buff[3] == ' ') { + s = strtok(buff+4, " \t"); + for(extinfo=0;strtok(NULL, " \t");extinfo++) + ; + } + } + } + fclose(f); + + if(ncpu < 1 || extinfo < 4) { + fputs("cannot parse /proc/stat\n", stderr); + return 1; + } + + puts("graph_title CPU usage"); + if(extinfo == 7) + puts("graph_order system user nice idle iowait irq softirq"); + else + puts("graph_order system user nice idle"); + if(scaleto100) + puts("graph_args --base 1000 -r --lower-limit 0 --upper-limit 100"); + else + printf("graph_args --base 1000 -r --lower-limit 0 --upper-limit %d\n", 100 * ncpu); + puts("graph_vlabel %\n" + "graph_scale no\n" + "graph_info This graph shows how CPU time is spent.\n" + "graph_category system\n" + "graph_period second\n" + "system.label system\n" + "system.draw AREA"); + printf("system.max %d\n", 100 * ncpu); + puts("system.min 0\n" + "system.type DERIVE"); + printf("system.warning %d\n", SYSWARNING * ncpu); + printf("system.critical %d\n", SYSCRITICAL * ncpu); + puts("system.info CPU time spent by the kernel in system activities\n" + "user.label user\n" + "user.draw STACK\n" + "user.min 0"); + printf("user.max %d\n", 100 * ncpu); + printf("user.warning %d\n", USRWARNING * ncpu); + puts("user.type DERIVE\n" + "user.info CPU time spent by normal programs and daemons\n" + "nice.label nice\n" + "nice.draw STACK\n" + "nice.min 0"); + printf("nice.max %d\n", 100 * ncpu); + puts("nice.type DERIVE\n" + "nice.info CPU time spent by nice(1)d programs\n" + "idle.label idle\n" + "idle.draw STACK\n" + "idle.min 0"); + printf("idle.max %d\n", 100 * ncpu); + puts("idle.type DERIVE\n" + "idle.info Idle CPU time"); + if(scaleto100) + printf("system.cdef system,%d,/\n" + "user.cdef user,%d,/\n" + "nice.cdef nice,%d,/\n" + "idle.cdef idle,%d,/\n", ncpu, ncpu, ncpu, ncpu); + if(extinfo == 7) { + puts("iowait.label iowait\n" + "iowait.draw STACK\n" + "iowait.min 0"); + printf("iowait.max %d\n", 100 * ncpu); + puts("iowait.type DERIVE\n" + "iowait.info CPU time spent waiting for I/O operations to finish\n" + "irq.label irq\n" + "irq.draw STACK\n" + "irq.min 0"); + printf("irq.max %d\n", 100 * ncpu); + puts("irq.type DERIVE\n" + "irq.info CPU time spent handling interrupts\n" + "softirq.label softirq\n" + "softirq.draw STACK\n" + "softirq.min 0"); + printf("softirq.max %d\n", 100 * ncpu); + puts("softirq.type DERIVE\n" + "softirq.info CPU time spent handling \"batched\" interrupts"); + if(scaleto100) + printf("iowait.cdef iowait,%d,/\n" + "irq.cdef irq,%d,/\n" + "softirq.cdef softirq,%d,/\n", ncpu, ncpu, ncpu); + } + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/stat", R_OK)) + return writeyes(); + else + return writeno("/proc/stat not readable"); + } + } + if(!(f=fopen("/proc/stat", "r"))) { + fputs("cannot open /proc/stat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "cpu ", 4)) { + fclose(f); + if(!(s = strtok(buff+4, " \t"))) + break; + printf("user.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + break; + printf("nice.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + break; + printf("system.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + break; + printf("idle.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + return 0; + printf("iowait.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + return 0; + printf("irq.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + return 0; + printf("softirq.value %s\n", s); + return 0; + } + } + fclose(f); + fputs("no cpu line found in /proc/stat\n", stderr); + return 1; +} diff --git a/entropy.c b/entropy.c new file mode 100644 index 0000000..4a5d846 --- /dev/null +++ b/entropy.c @@ -0,0 +1,35 @@ +#include <string.h> +#include <stdio.h> +#include "common.h" + +int entropy(int argc, char **argv) { + FILE *f; + int entropy; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Available entropy\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel entropy (bytes)\n" + "graph_scale no\n" + "graph_category system\n" + "graph_info This graph shows the amount of entropy available in the system.\n" + "entropy.label entropy\n" + "entropy.info The number of random bytes available. This is typically used by cryptographic applications."); + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + if(!(f=fopen("/proc/sys/kernel/random/entropy_avail", "r"))) { + fputs("cannot open /proc/sys/kernel/random/entropy_avail\n", stderr); + return 1; + } + if(1 != fscanf(f, "%d", &entropy)) { + fputs("cannot read from /proc/sys/kernel/random/entropy_avail\n", stderr); + fclose(f); + return 1; + } + fclose(f); + printf("entropy.value %d\n", entropy); + return 0; +} @@ -0,0 +1,44 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "common.h" + +int forks(int argc, char **argv) { + FILE *f; + char buff[256]; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Fork rate\n" + "graph_args --base 1000 -l 0 \n" + "graph_vlabel forks / ${graph_period}\n" + "graph_category processes\n" + "graph_info This graph shows the forking rate (new processes started).\n" + "forks.label forks\n" + "forks.type DERIVE\n" + "forks.min 0\n" + "forks.max 100000\n" + "forks.info The number of forks per second."); + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/stat", R_OK)) + return writeyes(); + else + return writeno("/proc/stat not readable"); + } + } + if(!(f=fopen("/proc/stat", "r"))) { + fputs("cannot open /proc/stat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "processes ", 10)) { + fclose(f); + printf("forks.value %s", buff+10); + return 0; + } + } + fclose(f); + fputs("no processes line found in /proc/stat\n", stderr); + return 1; +} diff --git a/fw_packets.c b/fw_packets.c new file mode 100644 index 0000000..06367dd --- /dev/null +++ b/fw_packets.c @@ -0,0 +1,60 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <ctype.h> +#include "common.h" + +int fw_packets(int argc, char **argv) { + FILE *f; + char buff[1024], *s; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Firewall Throughput\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel Packets/${graph_period}\n" + "graph_category network\n" + "received.label Received\n" + "received.draw AREA\n" + "received.type DERIVE\n" + "received.min 0\n" + "forwarded.label Forwarded\n" + "forwarded.draw LINE2\n" + "forwarded.type DERIVE\n" + "forwarded.min 0"); + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/net/snmp", R_OK)) + return writeyes(); + else + return writeno("/proc/net/snmp not readable"); + } + } + if(!(f=fopen("/proc/net/snmp", "r"))) { + fputs("cannot open /proc/net/snmp\n", stderr); + return 1; + } + while(fgets(buff, 1024, f)) { + if(!strncmp(buff, "Ip: ", 4) && isdigit(buff[4])) { + fclose(f); + if(!(s = strtok(buff+4, " \t"))) + break; + if(!(s = strtok(NULL, " \t"))) + break; + if(!(s = strtok(NULL, " \t"))) + break; + printf("received.value %s\n", s); + if(!(s = strtok(NULL, " \t"))) + break; + if(!(s = strtok(NULL, " \t"))) + break; + if(!(s = strtok(NULL, " \t"))) + break; + printf("forwarded.value %s\n", s); + return 0; + } + } + fclose(f); + fputs("no ip line found in /proc/net/snmp\n", stderr); + return 1; +} diff --git a/interrupts.c b/interrupts.c new file mode 100644 index 0000000..2755ccf --- /dev/null +++ b/interrupts.c @@ -0,0 +1,47 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "common.h" + +int interrupts(int argc, char **argv) { + FILE *f; + char buff[256]; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Interrupts & context switches\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel interrupts & ctx switches / ${graph_period}\n" + "graph_category system\n" + "graph_info This graph shows the number of interrupts and context switches on the system. These are typically high on a busy system.\n" + "intr.info Interrupts are events that alter sequence of instructions executed by a processor. They can come from either hardware (exceptions, NMI, IRQ) or software."); + puts("ctx.info A context switch occurs when a multitasking operatings system suspends the currently running process, and starts executing another.\n" + "intr.label interrupts\n" + "ctx.label context switches\n" + "intr.type DERIVE\n" + "ctx.type DERIVE\n" + "intr.max 100000\n" + "ctx.max 100000\n" + "intr.min 0\n" + "ctx.min 0"); + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/stat", R_OK)) + return writeyes(); + else + return writeno("/proc/stat not readable"); + } + } + if(!(f=fopen("/proc/stat", "r"))) { + fputs("cannot open /proc/stat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "intr ", 5)) + printf("intr.value %s", buff+5); + else if(!strncmp(buff, "ctxt ", 5)) + printf("ctx.value %s", buff+5); + } + fclose(f); + return 0; +} @@ -0,0 +1,47 @@ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "common.h" + +int load(int argc, char **argv) { + FILE *f; + int warn, crit; + float val; + char *s; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + s = getenv("load_warn"); + if(s) + warn = atoi(s); + else + warn = 10; + s = getenv("load_crit"); + if(s) + crit = atoi(s); + else + crit = 120; + puts("graph_title Load average\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel load\n" + "graph_scale no\n" + "graph_category system\n" + "load.label load"); + printf("load.warning %d\nload.critical %d\n", warn, crit); + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + if(!(f=fopen("/proc/loadavg", "r"))) { + fputs("cannot open /proc/loadavg\n", stderr); + return 1; + } + if(1 != fscanf(f, "%*f %f", &val)) { + fputs("cannot read from /proc/loadavg\n", stderr); + fclose(f); + return 1; + } + fclose(f); + printf("load.value %.2f\n", val); + return 0; +} @@ -0,0 +1,64 @@ +#include <libgen.h> +#include <string.h> +#include <stdio.h> + +int cpu(int argc, char **argv); +int entropy(int argc, char **argv); +int forks(int argc, char **argv); +int fw_packets(int argc, char **argv); +int interrupts(int argc, char **argv); +int load(int argc, char **argv); +int open_files(int argc, char **argv); +int open_inodes(int argc, char **argv); +int processes(int argc, char **argv); +int swap(int argc, char **argv); +int uptime(int argc, char **argv); + +int main(int argc, char **argv) { + char *progname; + progname = basename(argv[0]); + switch(*progname) { + case 'c': + if(!strcmp(progname+1, "pu")) + return cpu(argc, argv); + break; + case 'e': + if(!strcmp(progname+1, "ntropy")) + return entropy(argc, argv); + break; + case 'f': + if(!strcmp(progname+1, "orks")) + return forks(argc, argv); + if(!strcmp(progname+1, "w_packets")) + return fw_packets(argc, argv); + break; + case 'i': + if(!strcmp(progname+1, "nterrupts")) + return interrupts(argc, argv); + break; + case 'l': + if(!strcmp(progname+1, "oad")) + return load(argc, argv); + break; + case 'o': + if(!strcmp(progname+1, "pen_files")) + return open_files(argc, argv); + if(!strcmp(progname+1, "pen_inodes")) + return open_inodes(argc, argv); + break; + case 'p': + if(!strcmp(progname+1, "rocesses")) + return processes(argc, argv); + break; + case 's': + if(!strcmp(progname+1, "wap")) + return swap(argc, argv); + break; + case 'u': + if(!strcmp(progname+1, "ptime")) + return uptime(argc, argv); + break; + } + fprintf(stderr, "function not specified\n"); + return 1; +} diff --git a/open_files.c b/open_files.c new file mode 100644 index 0000000..3f82c8b --- /dev/null +++ b/open_files.c @@ -0,0 +1,52 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "common.h" + +int open_files(int argc, char **argv) { + FILE *f; + int alloc, freeh, avail; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + if(!(f=fopen("/proc/sys/fs/file-nr", "r"))) { + fprintf(stderr, "cannot open /proc/sys/fs/file-nr\n"); + return 1; + } + if(1 != fscanf(f, "%*d %*d %d", &avail)) { + fclose(f); + fprintf(stderr, "cannot read from /proc/sys/fs/file-nr\n"); + return 1; + } + fclose(f); + puts("graph_title File table usage\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel number of open files\n" + "graph_category system\n" + "graph_info This graph monitors the Linux open files table.\n" + "used.label open files\n" + "used.info The number of currently open files.\n" + "max.label max open files\n" + "max.info The maximum supported number of open files. Tune by modifying /proc/sys/fs/file-max."); + printf("used.warning %d\nused.critical %d\n", (int)(avail*0.92), (int)(avail*0.98)); + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/sys/fs/file-nr", R_OK)) + return writeyes(); + else + return writeno("/proc/sys/fs/file-nr not readable"); + } + } + if(!(f=fopen("/proc/sys/fs/file-nr", "r"))) { + fputs("cannot open /proc/sys/fs/file-nr\n", stderr); + return 1; + } + if(3 != fscanf(f, "%d %d %d", &alloc, &freeh, &avail)) { + fclose(f); + fputs("cannot read from /proc/sys/fs/file-nr\n", stderr); + return 1; + } + fclose(f); + printf("used.value %d\nmax.value %d\n", alloc-freeh, avail); + return 0; +} diff --git a/open_inodes.c b/open_inodes.c new file mode 100644 index 0000000..bc20cc6 --- /dev/null +++ b/open_inodes.c @@ -0,0 +1,42 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "common.h" + +int open_inodes(int argc, char **argv) { + FILE *f; + int nr, freen; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Inode table usage\n" + "graph_args --base 1000 -l 0\n" + "graph_vlabel number of open inodes\n" + "graph_category system\n" + "graph_info This graph monitors the Linux open inode table.\n" + "used.label open inodes\n" + "used.info The number of currently open inodes.\n" + "max.label inode table size\n" + "max.info The size of the system inode table. This is dynamically adjusted by the kernel."); + + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/sys/fs/inode-nr", R_OK)) + return writeyes(); + else + return writeno("/proc/sys/fs/inode-nr not readable"); + } + } + if(!(f=fopen("/proc/sys/fs/inode-nr", "r"))) { + fputs("cannot open /proc/sys/fs/inode-nr\n", stderr); + return 1; + } + if(2 != fscanf(f, "%d %d", &nr, &freen)) { + fclose(f); + fputs("cannot read from /proc/sys/fs/inode-nr\n", stderr); + return 1; + } + fclose(f); + printf("used.value %d\nmax.value %d\n", nr-freen, nr); + return 0; +} diff --git a/processes.c b/processes.c new file mode 100644 index 0000000..b522768 --- /dev/null +++ b/processes.c @@ -0,0 +1,42 @@ +#include <string.h> +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <ctype.h> +#include "common.h" + +int processes(int argc, char **argv) { + DIR *d; + struct dirent *e; + char *s; + int n=0; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Number of Processes\n" + "graph_args --base 1000 -l 0 \n" + "graph_vlabel number of processes\n" + "graph_category processes\n" + "graph_info This graph shows the number of processes in the system.\n" + "processes.label processes\n" + "processes.draw LINE2\n" + "processes.info The current number of processes."); + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + if(!(d = opendir("/proc"))) { + fputs("cannot open /proc\n", stderr); + return 1; + } + while((e = readdir(d))) { + for(s=e->d_name;*s;++s) + if(!isdigit(*s)) + break; + if(!*s) + ++n; + } + closedir(d); + printf("processes.value %d\n", n); + return 0; +} @@ -0,0 +1,78 @@ +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include "common.h" + +int swap(int argc, char **argv) { + FILE *f; + char buff[256]; + int in, out; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Swap in/out\n" + "graph_args -l 0 --base 1000\n" + "graph_vlabel pages per ${graph_period} in (-) / out (+)\n" + "graph_category system\n" + "swap_in.label swap\n" + "swap_in.type DERIVE\n" + "swap_in.max 100000\n" + "swap_in.min 0\n" + "swap_in.graph no\n" + "swap_out.label swap\n" + "swap_out.type DERIVE\n" + "swap_out.max 100000\n" + "swap_out.min 0\n" + "swap_out.negative swap_in"); + + return 0; + } + if(!strcmp(argv[1], "autoconf")) { + if(0 == access("/proc/stat", R_OK)) + return writeyes(); + else + return writeno("/proc/stat not readable"); + } + } + if(!access("/proc/vmstat", F_OK)) { + in=out=0; + if(!(f=fopen("/proc/vmstat", "r"))) { + fputs("cannot open /proc/vmstat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!in && !strncmp(buff, "pswpin ", 7)) { + ++in; + printf("swap_in.value %s", buff+7); + } + else if(!out && !strncmp(buff, "pswpout ", 8)) { + ++out; + printf("swap_out.value %s", buff+8); + } + } + fclose(f); + if(!in*out) { + fputs("no usable data on /proc/vmstat\n", stderr); + return 1; + } + return 0; + } else { + if(!(f=fopen("/proc/stat", "r"))) { + fputs("cannot open /proc/stat\n", stderr); + return 1; + } + while(fgets(buff, 256, f)) { + if(!strncmp(buff, "swap ", 5)) { + fclose(f); + if(2 != sscanf(buff+5, "%d %d", &in, &out)) { + fputs("bad data on /proc/stat\n", stderr); + return 1; + } + printf("swap_in.value %d\nswap_out.value %d\n", in, out); + return 0; + } + } + fclose(f); + fputs("no swap line found in /proc/stat\n", stderr); + return 1; + } +} diff --git a/uptime.c b/uptime.c new file mode 100644 index 0000000..ce6093f --- /dev/null +++ b/uptime.c @@ -0,0 +1,32 @@ +#include <stdio.h> +#include <string.h> +#include "common.h" + +int uptime(int argc, char **argv) { + FILE *f; + float uptime; + if(argc > 1) { + if(!strcmp(argv[1], "config")) { + puts("graph_title Uptime\n" + "graph_args --base 1000 -l 0 \n" + "graph_vlabel uptime in days\n" + "uptime.label uptime\n" + "uptime.draw AREA"); + return 0; + } + if(!strcmp(argv[1], "autoconf")) + return writeyes(); + } + if(!(f=fopen("/proc/uptime", "r"))) { + fputs("cannot open /proc/uptime\n", stderr); + return 1; + } + if(1 != fscanf(f, "%f", &uptime)) { + fputs("cannot read from /proc/uptime\n", stderr); + fclose(f); + return 1; + } + fclose(f); + printf("uptime.value %.2f\n", uptime/86400); + return 0; +} |