Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / misc / lnstat.c
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              128
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 <json_writer.h>
40 #include "lnstat.h"
41
42 static struct option opts[] = {
43         { "version", 0, NULL, 'V' },
44         { "count", 1, NULL, 'c' },
45         { "dump", 0, NULL, 'd' },
46         { "json", 0, NULL, 'j' },
47         { "file", 1, NULL, 'f' },
48         { "help", 0, NULL, 'h' },
49         { "interval", 1, NULL, 'i' },
50         { "keys", 1, NULL, 'k' },
51         { "subject", 1, NULL, 's' },
52         { "width", 1, NULL, 'w' },
53         { "oneline", 0, NULL, 0 },
54 };
55
56 static int usage(char *name, int exit_code)
57 {
58         fprintf(stderr,
59                 "%s Version %s\n"
60                 "Copyright (C) 2004 by Harald Welte <laforge@gnumonks.org>\n"
61                 "This program is free software licensed under GNU GPLv2\nwith ABSOLUTELY NO WARRANTY.\n"
62                 "\n"
63                 "Parameters:\n"
64                 "       -V --version            Print Version of Program\n"
65                 "       -c --count <count>      "
66                 "Print <count> number of intervals\n"
67                 "       -d --dump               "
68                 "Dump list of available files/keys\n"
69                 "       -j --json               "
70                 "Display in JSON format\n"
71                 "       -f --file <file>        Statistics file to use\n"
72                 "       -h --help               This help message\n"
73                 "       -i --interval <intv>    "
74                 "Set interval to 'intv' seconds\n"
75                 "       -k --keys k,k,k,...     Display only keys specified\n"
76                 "       -s --subject [0-2]      Control header printing:\n"
77                 "                               0 = never\n"
78                 "                               1 = once\n"
79                 "                               2 = every 20 lines (default))\n"
80                 "       -w --width n,n,n,...    Width for each field\n"
81                 "\n",
82                 name, LNSTAT_VERSION);
83
84         exit(exit_code);
85 }
86
87 struct field_param {
88         const char *name;
89         struct lnstat_field *lf;
90         struct {
91                 unsigned int width;
92         } print;
93 };
94
95 struct field_params {
96         unsigned int num;
97         struct field_param params[MAX_FIELDS];
98 };
99
100 static void print_line(FILE *of, const struct lnstat_file *lnstat_files,
101                        const struct field_params *fp)
102 {
103         int i;
104
105         for (i = 0; i < fp->num; i++) {
106                 const struct lnstat_field *lf = fp->params[i].lf;
107
108                 fprintf(of, "%*lu|", fp->params[i].print.width, lf->result);
109         }
110         fputc('\n', of);
111 }
112
113 static void print_json(FILE *of, const struct lnstat_file *lnstat_files,
114                        const struct field_params *fp)
115 {
116         json_writer_t *jw = jsonw_new(of);
117         int i;
118
119         jsonw_start_object(jw);
120         for (i = 0; i < fp->num; i++) {
121                 const struct lnstat_field *lf = fp->params[i].lf;
122
123                 jsonw_uint_field(jw, lf->name, lf->result);
124         }
125         jsonw_end_object(jw);
126         jsonw_destroy(&jw);
127 }
128
129 /* find lnstat_field according to user specification */
130 static int map_field_params(struct lnstat_file *lnstat_files,
131                             struct field_params *fps, int interval)
132 {
133         int i, j = 0;
134         struct lnstat_file *lf;
135
136         /* no field specification on commandline, need to build default */
137         if (!fps->num) {
138                 for (lf = lnstat_files; lf; lf = lf->next) {
139                         for (i = 0; i < lf->num_fields; i++) {
140                                 fps->params[j].lf = &lf->fields[i];
141                                 fps->params[j].lf->file->interval.tv_sec =
142                                                                 interval;
143                                 if (!fps->params[j].print.width)
144                                         fps->params[j].print.width =
145                                                         FIELD_WIDTH_DEFAULT;
146
147                                 if (++j >= MAX_FIELDS - 1) {
148                                         fprintf(stderr,
149                                                 "WARN: MAX_FIELDS (%d) reached, truncating number of keys\n",
150                                                 MAX_FIELDS);
151                                         goto full;
152                                 }
153                         }
154                 }
155 full:
156                 fps->num = j;
157                 return 1;
158         }
159
160         for (i = 0; i < fps->num; i++) {
161                 fps->params[i].lf = lnstat_find_field(lnstat_files,
162                                                       fps->params[i].name);
163                 if (!fps->params[i].lf) {
164                         fprintf(stderr, "Field `%s' unknown\n",
165                                 fps->params[i].name);
166                         return 0;
167                 }
168                 fps->params[i].lf->file->interval.tv_sec = interval;
169                 if (!fps->params[i].print.width)
170                         fps->params[i].print.width = FIELD_WIDTH_DEFAULT;
171         }
172         return 1;
173 }
174
175 struct table_hdr {
176         int num_lines;
177         char *hdr[HDR_LINES];
178 };
179
180 static struct table_hdr *build_hdr_string(struct lnstat_file *lnstat_files,
181                                           struct field_params *fps,
182                                           int linewidth)
183 {
184         int h, i;
185         static struct table_hdr th;
186         int ofs = 0;
187
188         for (i = 0; i < HDR_LINES; i++)
189                 th.hdr[i] = calloc(1, HDR_LINE_LENGTH);
190
191         for (i = 0; i < fps->num; i++) {
192                 char *cname, *fname = fps->params[i].lf->name;
193                 unsigned int width = fps->params[i].print.width;
194
195                 snprintf(th.hdr[0]+ofs, width+2, "%*.*s|", width, width,
196                          fps->params[i].lf->file->basename);
197
198                 cname = fname;
199                 for (h = 1; h < HDR_LINES; h++) {
200                         if (cname - fname >= strlen(fname))
201                                 snprintf(th.hdr[h]+ofs, width+2,
202                                          "%*.*s|", width, width, "");
203                         else {
204                                 th.num_lines = h+1;
205                                 snprintf(th.hdr[h]+ofs, width+2,
206                                          "%*.*s|", width, width, cname);
207                         }
208                         cname += width;
209                 }
210                 ofs += width+1;
211         }
212         /* fill in spaces */
213         for (h = 1; h <= th.num_lines; h++) {
214                 for (i = 0; i < ofs; i++) {
215                         if (th.hdr[h][i] == '\0')
216                                 th.hdr[h][i] = ' ';
217                 }
218         }
219
220         return &th;
221 }
222
223 static int print_hdr(FILE *of, struct table_hdr *th)
224 {
225         int i;
226
227         for (i = 0; i < th->num_lines; i++) {
228                 fputs(th->hdr[i], of);
229                 fputc('\n', of);
230         }
231         return 0;
232 }
233
234
235 int main(int argc, char **argv)
236 {
237         struct lnstat_file *lnstat_files;
238         const char *basename;
239         int i, c;
240         int interval = DEFAULT_INTERVAL;
241         int hdr = 2;
242         enum {
243                 MODE_DUMP,
244                 MODE_JSON,
245                 MODE_NORMAL,
246         } mode = MODE_NORMAL;
247         unsigned long count = 0;
248         struct table_hdr *header;
249         static struct field_params fp;
250         int num_req_files = 0;
251         char *req_files[LNSTAT_MAX_FILES];
252
253         /* backwards compatibility mode for old tools */
254         basename = strrchr(argv[0], '/');
255         if (basename)
256                 basename += 1;    /* name after slash */
257         else
258                 basename = argv[0]; /* no slash */
259
260         if (!strcmp(basename, "rtstat")) {
261                 /* rtstat compatibility mode */
262                 req_files[0] = "rt_cache";
263                 num_req_files = 1;
264         } else if (!strcmp(basename, "ctstat")) {
265                 /* ctstat compatibility mode */
266                 req_files[0] = "ip_conntrack";
267                 num_req_files = 1;
268         }
269
270         while ((c = getopt_long(argc, argv, "Vc:djpf:h?i:k:s:w:",
271                                 opts, NULL)) != -1) {
272                 int len = 0;
273                 char *tmp, *tok;
274
275                 switch (c) {
276                 case 'c':
277                         count = strtoul(optarg, NULL, 0);
278                         break;
279                 case 'd':
280                         mode = MODE_DUMP;
281                         break;
282                 case 'j':
283                         mode = MODE_JSON;
284                         break;
285                 case 'f':
286                         req_files[num_req_files++] = strdup(optarg);
287                         break;
288                 case '?':
289                 case 'h':
290                         usage(argv[0], 0);
291                         break;
292                 case 'i':
293                         sscanf(optarg, "%u", &interval);
294                         break;
295                 case 'k':
296                         tmp = strdup(optarg);
297                         if (!tmp)
298                                 break;
299                         for (tok = strtok(tmp, ",");
300                              tok;
301                              tok = strtok(NULL, ",")) {
302                                 if (fp.num >= MAX_FIELDS) {
303                                         fprintf(stderr,
304                                                 "WARN: too many keys requested: (%d max)\n",
305                                                 MAX_FIELDS);
306                                         break;
307                                 }
308                                 fp.params[fp.num++].name = tok;
309                         }
310                         break;
311                 case 's':
312                         sscanf(optarg, "%u", &hdr);
313                         break;
314                 case 'w':
315                         tmp = strdup(optarg);
316                         if (!tmp)
317                                 break;
318                         i = 0;
319                         for (tok = strtok(tmp, ",");
320                              tok;
321                              tok = strtok(NULL, ",")) {
322                                 len  = strtoul(tok, NULL, 0);
323                                 if (len > FIELD_WIDTH_MAX)
324                                         len = FIELD_WIDTH_MAX;
325                                 fp.params[i].print.width = len;
326                                 i++;
327                         }
328                         if (i == 1) {
329                                 for (i = 0; i < MAX_FIELDS; i++)
330                                         fp.params[i].print.width = len;
331                         }
332                         break;
333                 default:
334                         usage(argv[0], 1);
335                         break;
336                 }
337         }
338
339         lnstat_files = lnstat_scan_dir(PROC_NET_STAT, num_req_files,
340                                        (const char **) req_files);
341
342         switch (mode) {
343         case MODE_DUMP:
344                 lnstat_dump(stdout, lnstat_files);
345                 break;
346
347         case MODE_NORMAL:
348         case MODE_JSON:
349                 if (!map_field_params(lnstat_files, &fp, interval))
350                         exit(1);
351
352                 header = build_hdr_string(lnstat_files, &fp, 80);
353                 if (!header)
354                         exit(1);
355
356                 if (interval < 1)
357                         interval = 1;
358
359                 for (i = 0; i < count || !count; i++) {
360                         lnstat_update(lnstat_files);
361                         if (mode == MODE_JSON)
362                                 print_json(stdout, lnstat_files, &fp);
363                         else {
364                                 if  ((hdr > 1 && !(i % 20)) ||
365                                      (hdr == 1 && i == 0))
366                                         print_hdr(stdout, header);
367                                 print_line(stdout, lnstat_files, &fp);
368                         }
369                         fflush(stdout);
370                         if (i < count - 1 || !count)
371                                 sleep(interval);
372                 }
373                 break;
374         }
375
376         return 1;
377 }