diff options
author | osdl.net!shemminger <osdl.net!shemminger> | 2004-10-19 20:21:14 +0000 |
---|---|---|
committer | osdl.net!shemminger <osdl.net!shemminger> | 2004-10-19 20:21:14 +0000 |
commit | 056eb9d8dd2329c20394d6b2dd81c151dfeac164 (patch) | |
tree | 7f35e01e8f6a10908f527098dbf4b033e07244d9 /misc/lnstat.c | |
parent | fad7478dc7c74ca19d5548c24692f557b4b88f75 (diff) |
(Logical change 1.98)
Diffstat (limited to 'misc/lnstat.c')
-rw-r--r-- | misc/lnstat.c | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/misc/lnstat.c b/misc/lnstat.c new file mode 100644 index 00000000..2b330e5f --- /dev/null +++ b/misc/lnstat.c @@ -0,0 +1,336 @@ +/* lnstat - Unified linux network statistics + * + * Copyright (C) 2004 by Harald Welte <laforge@gnumonks.org> + * + * Development of this code was funded by Astaro AG, http://www.astaro.com/ + * + * Based on original concept and ideas from predecessor rtstat.c: + * + * Copyright 2001 by Robert Olsson <robert.olsson@its.uu.se> + * Uppsala University, Sweden + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +/* Maximum number of fields that can be displayed */ +#define MAX_FIELDS 64 + +/* Maximum number of header lines */ +#define HDR_LINES 10 + +/* default field width if none specified */ +#define FIELD_WIDTH_DEFAULT 8 +#define FIELD_WIDTH_MAX 20 + +#define DEFAULT_INTERVAL 2 + +#define HDR_LINE_LENGTH (MAX_FIELDS*FIELD_WIDTH_MAX) + +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <getopt.h> + +#include "lnstat.h" + +static struct option opts[] = { + { "version", 0, NULL, 'V' }, + { "count", 1, NULL, 'c' }, + { "dump", 1, NULL, 'd' }, + { "file", 1, NULL, 'f' }, + { "help", 0, NULL, 'h' }, + { "interval", 1, NULL, 'i' }, + { "key", 1, NULL, 'k' }, + { "subject", 1, NULL, 's' }, + { "width", 1, NULL, 'w' }, +}; + +static int usage(char *name, int exit_code) +{ + fprintf(stderr, "%s Version %s\n", name, LNSTAT_VERSION); + fprintf(stderr, "Copyright (C) 2004 by Harald Welte " + "<laforge@gnumonks.org>\n"); + fprintf(stderr, "This program is free software licensed under GNU GPLv2" + "\nwith ABSOLUTELY NO WARRANTY.\n\n"); + fprintf(stderr, "Parameters:\n"); + fprintf(stderr, "\t-V --version\t\tPrint Version of Program\n"); + fprintf(stderr, "\t-c --count <count>\t" + "Print <count> number of intervals\n"); + fprintf(stderr, "\t-d --dumpt\t\t" + "Dump list of available files/keys\n"); + fprintf(stderr, "\t-f --file <file>\tStatistics file to use\n"); + fprintf(stderr, "\t-h --help\t\tThis help message\n"); + fprintf(stderr, "\t-i --interval <intv>\t" + "Set interval to 'intv' seconds\n"); + fprintf(stderr, "\t-k --keys k,k,k,...\tDisplay only keys specified\n"); + fprintf(stderr, "\t-s --subject [0-2]\t?\n"); + fprintf(stderr, "\t-w --width n,n,n,...\tWidth for each field\n"); + fprintf(stderr, "\n"); + + exit(exit_code); +} + +struct field_param { + char *name; + struct lnstat_field *lf; + struct { + unsigned int width; + } print; +}; + +struct field_params { + unsigned int num; + struct field_param params[MAX_FIELDS]; +}; + +static void print_line(FILE *of, struct lnstat_file *lnstat_files, + struct field_params *fp) +{ + int i; + + for (i = 0; i < fp->num; i++) { + struct lnstat_field *lf = fp->params[i].lf; + char formatbuf[255]; + + snprintf(formatbuf, sizeof(formatbuf)-1, "%%%ulu|", + fp->params[i].print.width); + fprintf(of, formatbuf, lf->result); + } + fputc('\n', of); +} + +/* find lnstat_field according to user specification */ +static int map_field_params(struct lnstat_file *lnstat_files, + struct field_params *fps, int interval) +{ + int i, j = 0; + struct lnstat_file *lf; + + /* no field specification on commandline, need to build default */ + if (!fps->num) { + for (lf = lnstat_files; lf; lf = lf->next) { + for (i = 0; i < lf->num_fields; i++) { + fps->params[j].lf = &lf->fields[i]; + fps->params[j].lf->file->interval.tv_sec = + interval; + if (!fps->params[j].print.width) + fps->params[j].print.width = + FIELD_WIDTH_DEFAULT; + j++; + } + } + fps->num = j; + return 1; + } + + for (i = 0; i < fps->num; i++) { + fps->params[i].lf = lnstat_find_field(lnstat_files, + fps->params[i].name); + if (!fps->params[i].lf) { + fprintf(stderr, "Field `%s' unknown\n", + fps->params[i].name); + return 0; + } + fps->params[i].lf->file->interval.tv_sec = interval; + if (!fps->params[i].print.width) + fps->params[i].print.width = FIELD_WIDTH_DEFAULT; + } + return 1; +} + +struct table_hdr { + int num_lines; + char *hdr[HDR_LINES]; +}; + +static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files, + struct field_params *fps, + int linewidth) +{ + int h,i; + static struct table_hdr th; + int ofs = 0; + + for (i = 0; i < HDR_LINES; i++) { + th.hdr[i] = malloc(HDR_LINE_LENGTH); + memset(th.hdr[i], 0, sizeof(th.hdr[i])); + } + + for (i = 0; i < fps->num; i++) { + char *cname, *fname = fps->params[i].lf->name; + char fmt[12]; + unsigned int width = fps->params[i].print.width; + + snprintf(fmt, sizeof(fmt)-1, "%%%u.%us|", width, width); + + snprintf(th.hdr[0]+ofs, width+2, fmt, + fps->params[i].lf->file->basename); + + cname = fname; + for (h = 1; h < HDR_LINES; h++) { + if (cname - fname >= strlen(fname)) + snprintf(th.hdr[h]+ofs, width+2, fmt, ""); + else { + th.num_lines = h+1; + snprintf(th.hdr[h]+ofs, width+2, fmt, cname); + } + cname += width; + } + ofs += width+1; + } + /* fill in spaces */ + for (h = 1; h <= th.num_lines; h++) { + for (i = 0; i < ofs; i++) { + if (th.hdr[h][i] == '\0') + th.hdr[h][i] = ' '; + } + } + + return &th; +} + +static int print_hdr(FILE *of, struct table_hdr *th) +{ + int i; + + for (i = 0; i < th->num_lines; i++) { + fputs(th->hdr[i], of); + fputc('\n', of); + } + return 0; +} + + +int main(int argc, char **argv) +{ + struct lnstat_file *lnstat_files; + char *basename; + int c; + + int interval = DEFAULT_INTERVAL; + int hdr = 2; + + enum { + MODE_DUMP, + MODE_NORMAL, + } mode; + unsigned long count = 0; + struct field_params fp; + int num_req_files = 0; + char *req_files[LNSTAT_MAX_FILES]; + + memset(&fp, 0, sizeof(fp)); + + mode = MODE_NORMAL; + + /* backwards compatibility mode for old tools */ + basename = strrchr(argv[0], '/') + 1; + if (!strcmp(basename, "rtstat")) { + /* rtstat compatibility mode */ + req_files[0] = "rt_cache"; + num_req_files = 1; + } else if (!strcmp(basename, "ctstat")) { + /* ctstat compatibility mode */ + req_files[0] = "ip_conntrack"; + num_req_files = 1; + } + + while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:", + opts, NULL)) != -1) { + switch (c) { + int i, len; + char *tmp, *tok; + case 'c': + count = strtoul(optarg, NULL, 0); + break; + case 'd': + mode = MODE_DUMP; + break; + case 'f': + req_files[num_req_files++] = strdup(optarg); + break; + case '?': + case 'h': + usage(argv[0], 0); + break; + case 'i': + sscanf(optarg, "%u", &interval); + break; + case 'k': + tmp = strdup(optarg); + if (!tmp) + break; + for (tok = strtok(tmp, ","); + tok; + tok = strtok(NULL, ",")) { + if (fp.num >= MAX_FIELDS) + break; + fp.params[fp.num++].name = tok; + } + break; + case 's': + sscanf(optarg, "%u", &hdr); + break; + case 'w': + tmp = strdup(optarg); + if (!tmp) + break; + i = 0; + for (tok = strtok(tmp, ","); + tok; + tok = strtok(NULL, ",")) { + len = strtoul(tok, NULL, 0); + if (len > FIELD_WIDTH_MAX) + len = FIELD_WIDTH_MAX; + fp.params[i].print.width = len; + i++; + } + if (i == 1) { + for (i = 0; i < MAX_FIELDS; i++) + fp.params[i].print.width = len; + } + break; + default: + usage(argv[0], 1); + break; + } + } + + lnstat_files = lnstat_scan_dir(PROC_NET_STAT, num_req_files, + (const char **) req_files); + + switch (mode) { + int i; + struct table_hdr *header; + case MODE_DUMP: + lnstat_dump(stderr, lnstat_files); + break; + case MODE_NORMAL: + + if (!map_field_params(lnstat_files, &fp, interval)) + exit(1); + + header = build_hdr_string(lnstat_files, &fp, 80); + if (!header) + exit(1); + + if (interval < 1 ) + interval=1; + + for (i = 0; i < count; i++) { + if ((hdr > 1 && (! (i % 20))) || (hdr == 1 && i == 0)) + print_hdr(stdout, header); + lnstat_update(lnstat_files); + print_line(stdout, lnstat_files, &fp); + sleep(interval); + } + } + + return 1; +} + |