1/* lnstat - Unified linux network statistics 2 * 3 * Copyright (C) 2004 by Harald Welte <laforge@gnumonks.org> 4 * 5 * Development of this code was funded by Astaro AG, http://www.astaro.com/ 6 * 7 * Based on original concept and ideas from predecessor rtstat.c: 8 * 9 * Copyright 2001 by Robert Olsson <robert.olsson@its.uu.se> 10 * Uppsala University, Sweden 11 * 12 * This program is free software; you can redistribute it and/or modify 13 * it under the terms of the GNU General Public License as published by 14 * the Free Software Foundation; either version 2 of the License, or 15 * (at your option) any later version. 16 * 17 */ 18 19/* Maximum number of fields that can be displayed */ 20#define MAX_FIELDS 64 21 22/* Maximum number of header lines */ 23#define HDR_LINES 10 24 25/* default field width if none specified */ 26#define FIELD_WIDTH_DEFAULT 8 27#define FIELD_WIDTH_MAX 20 28 29#define DEFAULT_INTERVAL 2 30 31#define HDR_LINE_LENGTH (MAX_FIELDS*FIELD_WIDTH_MAX) 32 33#include <unistd.h> 34#include <stdio.h> 35#include <stdlib.h> 36#include <string.h> 37#include <getopt.h> 38 39#include "lnstat.h" 40 41static struct option opts[] = { 42 { "version", 0, NULL, 'V' }, 43 { "count", 1, NULL, 'c' }, 44 { "dump", 1, NULL, 'd' }, 45 { "file", 1, NULL, 'f' }, 46 { "help", 0, NULL, 'h' }, 47 { "interval", 1, NULL, 'i' }, 48 { "key", 1, NULL, 'k' }, 49 { "subject", 1, NULL, 's' }, 50 { "width", 1, NULL, 'w' }, 51}; 52 53static int usage(char *name, int exit_code) 54{ 55 fprintf(stderr, "%s Version %s\n", name, LNSTAT_VERSION); 56 fprintf(stderr, "Copyright (C) 2004 by Harald Welte " 57 "<laforge@gnumonks.org>\n"); 58 fprintf(stderr, "This program is free software licensed under GNU GPLv2" 59 "\nwith ABSOLUTELY NO WARRANTY.\n\n"); 60 fprintf(stderr, "Parameters:\n"); 61 fprintf(stderr, "\t-V --version\t\tPrint Version of Program\n"); 62 fprintf(stderr, "\t-c --count <count>\t" 63 "Print <count> number of intervals\n"); 64 fprintf(stderr, "\t-d --dumpt\t\t" 65 "Dump list of available files/keys\n"); 66 fprintf(stderr, "\t-f --file <file>\tStatistics file to use\n"); 67 fprintf(stderr, "\t-h --help\t\tThis help message\n"); 68 fprintf(stderr, "\t-i --interval <intv>\t" 69 "Set interval to 'intv' seconds\n"); 70 fprintf(stderr, "\t-k --keys k,k,k,...\tDisplay only keys specified\n"); 71 fprintf(stderr, "\t-s --subject [0-2]\t?\n"); 72 fprintf(stderr, "\t-w --width n,n,n,...\tWidth for each field\n"); 73 fprintf(stderr, "\n"); 74 75 exit(exit_code); 76} 77 78struct field_param { 79 const char *name; 80 struct lnstat_field *lf; 81 struct { 82 unsigned int width; 83 } print; 84}; 85 86struct field_params { 87 unsigned int num; 88 struct field_param params[MAX_FIELDS]; 89}; 90 91static void print_line(FILE *of, const struct lnstat_file *lnstat_files, 92 const struct field_params *fp) 93{ 94 int i; 95 96 for (i = 0; i < fp->num; i++) { 97 struct lnstat_field *lf = fp->params[i].lf; 98 char formatbuf[255]; 99 100 snprintf(formatbuf, sizeof(formatbuf)-1, "%%%ulu|", 101 fp->params[i].print.width); 102 fprintf(of, formatbuf, lf->result); 103 } 104 fputc('\n', of); 105} 106 107/* find lnstat_field according to user specification */ 108static int map_field_params(struct lnstat_file *lnstat_files, 109 struct field_params *fps, int interval) 110{ 111 int i, j = 0; 112 struct lnstat_file *lf; 113 114 /* no field specification on commandline, need to build default */ 115 if (!fps->num) { 116 for (lf = lnstat_files; lf; lf = lf->next) { 117 for (i = 0; i < lf->num_fields; i++) { 118 fps->params[j].lf = &lf->fields[i]; 119 fps->params[j].lf->file->interval.tv_sec = 120 interval; 121 if (!fps->params[j].print.width) 122 fps->params[j].print.width = 123 FIELD_WIDTH_DEFAULT; 124 j++; 125 } 126 } 127 fps->num = j; 128 return 1; 129 } 130 131 for (i = 0; i < fps->num; i++) { 132 fps->params[i].lf = lnstat_find_field(lnstat_files, 133 fps->params[i].name); 134 if (!fps->params[i].lf) { 135 fprintf(stderr, "Field `%s' unknown\n", 136 fps->params[i].name); 137 return 0; 138 } 139 fps->params[i].lf->file->interval.tv_sec = interval; 140 if (!fps->params[i].print.width) 141 fps->params[i].print.width = FIELD_WIDTH_DEFAULT; 142 } 143 return 1; 144} 145 146struct table_hdr { 147 int num_lines; 148 char *hdr[HDR_LINES]; 149}; 150 151static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files, 152 struct field_params *fps, 153 int linewidth) 154{ 155 int h,i; 156 static struct table_hdr th; 157 int ofs = 0; 158 159 for (i = 0; i < HDR_LINES; i++) { 160 th.hdr[i] = malloc(HDR_LINE_LENGTH); 161 memset(th.hdr[i], 0, sizeof(th.hdr[i])); 162 } 163 164 for (i = 0; i < fps->num; i++) { 165 char *cname, *fname = fps->params[i].lf->name; 166 char fmt[12]; 167 unsigned int width = fps->params[i].print.width; 168 169 snprintf(fmt, sizeof(fmt)-1, "%%%u.%us|", width, width); 170 171 snprintf(th.hdr[0]+ofs, width+2, fmt, 172 fps->params[i].lf->file->basename); 173 174 cname = fname; 175 for (h = 1; h < HDR_LINES; h++) { 176 if (cname - fname >= strlen(fname)) 177 snprintf(th.hdr[h]+ofs, width+2, fmt, ""); 178 else { 179 th.num_lines = h+1; 180 snprintf(th.hdr[h]+ofs, width+2, fmt, cname); 181 } 182 cname += width; 183 } 184 ofs += width+1; 185 } 186 /* fill in spaces */ 187 for (h = 1; h <= th.num_lines; h++) { 188 for (i = 0; i < ofs; i++) { 189 if (th.hdr[h][i] == '\0') 190 th.hdr[h][i] = ' '; 191 } 192 } 193 194 return &th; 195} 196 197static int print_hdr(FILE *of, struct table_hdr *th) 198{ 199 int i; 200 201 for (i = 0; i < th->num_lines; i++) { 202 fputs(th->hdr[i], of); 203 fputc('\n', of); 204 } 205 return 0; 206} 207 208 209int main(int argc, char **argv) 210{ 211 struct lnstat_file *lnstat_files; 212 const char *basename; 213 int c; 214 int interval = DEFAULT_INTERVAL; 215 int hdr = 2; 216 enum { 217 MODE_DUMP, 218 MODE_NORMAL, 219 } mode = MODE_NORMAL; 220 221 unsigned long count = 1; 222 static struct field_params fp; 223 int num_req_files = 0; 224 char *req_files[LNSTAT_MAX_FILES]; 225 226 /* backwards compatibility mode for old tools */ 227 basename = strrchr(argv[0], '/'); 228 if (basename) 229 basename += 1; /* name after slash */ 230 else 231 basename = argv[0]; /* no slash */ 232 233 if (!strcmp(basename, "rtstat")) { 234 /* rtstat compatibility mode */ 235 req_files[0] = "rt_cache"; 236 num_req_files = 1; 237 } else if (!strcmp(basename, "ctstat")) { 238 /* ctstat compatibility mode */ 239 req_files[0] = "ip_conntrack"; 240 num_req_files = 1; 241 } 242 243 while ((c = getopt_long(argc, argv,"Vc:df:h?i:k:s:w:", 244 opts, NULL)) != -1) { 245 int i, len = 0; 246 char *tmp, *tok; 247 248 switch (c) { 249 case 'c': 250 count = strtoul(optarg, NULL, 0); 251 break; 252 case 'd': 253 mode = MODE_DUMP; 254 break; 255 case 'f': 256 req_files[num_req_files++] = strdup(optarg); 257 break; 258 case '?': 259 case 'h': 260 usage(argv[0], 0); 261 break; 262 case 'i': 263 sscanf(optarg, "%u", &interval); 264 break; 265 case 'k': 266 tmp = strdup(optarg); 267 if (!tmp) 268 break; 269 for (tok = strtok(tmp, ","); 270 tok; 271 tok = strtok(NULL, ",")) { 272 if (fp.num >= MAX_FIELDS) 273 break; 274 fp.params[fp.num++].name = tok; 275 } 276 break; 277 case 's': 278 sscanf(optarg, "%u", &hdr); 279 break; 280 case 'w': 281 tmp = strdup(optarg); 282 if (!tmp) 283 break; 284 i = 0; 285 for (tok = strtok(tmp, ","); 286 tok; 287 tok = strtok(NULL, ",")) { 288 len = strtoul(tok, NULL, 0); 289 if (len > FIELD_WIDTH_MAX) 290 len = FIELD_WIDTH_MAX; 291 fp.params[i].print.width = len; 292 i++; 293 } 294 if (i == 1) { 295 for (i = 0; i < MAX_FIELDS; i++) 296 fp.params[i].print.width = len; 297 } 298 break; 299 default: 300 usage(argv[0], 1); 301 break; 302 } 303 } 304 305 lnstat_files = lnstat_scan_dir(PROC_NET_STAT, num_req_files, 306 (const char **) req_files); 307 308 switch (mode) { 309 int i; 310 struct table_hdr *header; 311 case MODE_DUMP: 312 lnstat_dump(stderr, lnstat_files); 313 break; 314 case MODE_NORMAL: 315 316 if (!map_field_params(lnstat_files, &fp, interval)) 317 exit(1); 318 319 header = build_hdr_string(lnstat_files, &fp, 80); 320 if (!header) 321 exit(1); 322 323 if (interval < 1 ) 324 interval=1; 325 326 for (i = 0; i < count; i++) { 327 if ((hdr > 1 && (! (i % 20))) || (hdr == 1 && i == 0)) 328 print_hdr(stdout, header); 329 lnstat_update(lnstat_files); 330 print_line(stdout, lnstat_files, &fp); 331 sleep(interval); 332 } 333 } 334 335 return 1; 336} 337 338