]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/nstat.c
Merge branch 'iproute2-master' into iproute2-next
[mirror_iproute2.git] / misc / nstat.c
CommitLineData
aba5acdf
SH
1/*
2 * nstat.c handy utility to read counters /proc/net/netstat and snmp
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8 *
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 */
11
12#include <stdio.h>
13#include <stdlib.h>
14#include <unistd.h>
15#include <fcntl.h>
16#include <string.h>
17#include <errno.h>
18#include <time.h>
19#include <sys/time.h>
20#include <fnmatch.h>
21#include <sys/file.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <sys/poll.h>
25#include <sys/wait.h>
26#include <sys/stat.h>
27#include <signal.h>
28#include <math.h>
404582c8 29#include <getopt.h>
aba5acdf 30
fcc16c22 31#include <json_writer.h>
aba5acdf 32#include <SNAPSHOT.h>
62000e51 33#include "utils.h"
aba5acdf 34
acd1e437
SH
35int dump_zeros;
36int reset_history;
37int ignore_history;
38int no_output;
39int json_output;
acd1e437
SH
40int no_update;
41int scan_interval;
42int time_constant;
aba5acdf
SH
43double W;
44char **patterns;
45int npatterns;
46
47char info_source[128];
48int source_mismatch;
49
4ffc44ca 50static int generic_proc_open(const char *env, char *name)
aba5acdf
SH
51{
52 char store[128];
53 char *p = getenv(env);
acd1e437 54
aba5acdf
SH
55 if (!p) {
56 p = getenv("PROC_ROOT") ? : "/proc";
57 snprintf(store, sizeof(store)-1, "%s/%s", p, name);
58 p = store;
59 }
4ffc44ca 60 return open(p, O_RDONLY);
aba5acdf
SH
61}
62
d1f28cf1 63static int net_netstat_open(void)
aba5acdf
SH
64{
65 return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
66}
67
d1f28cf1 68static int net_snmp_open(void)
aba5acdf
SH
69{
70 return generic_proc_open("PROC_NET_SNMP", "net/snmp");
71}
72
d1f28cf1 73static int net_snmp6_open(void)
aba5acdf
SH
74{
75 return generic_proc_open("PROC_NET_SNMP6", "net/snmp6");
76}
77
45a0dc16
HL
78static int net_sctp_snmp_open(void)
79{
80 return generic_proc_open("PROC_NET_SCTP_SNMP", "net/sctp/snmp");
81}
82
acd1e437 83struct nstat_ent {
aba5acdf
SH
84 struct nstat_ent *next;
85 char *id;
86 unsigned long long val;
aba5acdf
SH
87 double rate;
88};
89
90struct nstat_ent *kern_db;
91struct nstat_ent *hist_db;
92
d1f28cf1
SH
93static const char *useless_numbers[] = {
94 "IpForwarding", "IpDefaultTTL",
95 "TcpRtoAlgorithm", "TcpRtoMin", "TcpRtoMax",
96 "TcpMaxConn", "TcpCurrEstab"
aba5acdf
SH
97};
98
d1f28cf1 99static int useless_number(const char *id)
aba5acdf
SH
100{
101 int i;
acd1e437 102
62000e51 103 for (i = 0; i < ARRAY_SIZE(useless_numbers); i++)
aba5acdf
SH
104 if (strcmp(id, useless_numbers[i]) == 0)
105 return 1;
106 return 0;
107}
108
d1f28cf1 109static int match(const char *id)
aba5acdf
SH
110{
111 int i;
112
113 if (npatterns == 0)
114 return 1;
115
acd1e437 116 for (i = 0; i < npatterns; i++) {
aba5acdf
SH
117 if (!fnmatch(patterns[i], id, 0))
118 return 1;
119 }
120 return 0;
121}
122
d1f28cf1 123static void load_good_table(FILE *fp)
aba5acdf
SH
124{
125 char buf[4096];
126 struct nstat_ent *db = NULL;
127 struct nstat_ent *n;
128
129 while (fgets(buf, sizeof(buf), fp) != NULL) {
130 int nr;
131 unsigned long long val;
132 double rate;
b482ffa6 133 char idbuf[sizeof(buf)];
acd1e437 134
aba5acdf
SH
135 if (buf[0] == '#') {
136 buf[strlen(buf)-1] = 0;
137 if (info_source[0] && strcmp(info_source, buf+1))
138 source_mismatch = 1;
b482ffa6 139 info_source[0] = 0;
140 strncat(info_source, buf+1, sizeof(info_source)-1);
aba5acdf
SH
141 continue;
142 }
b482ffa6 143 /* idbuf is as big as buf, so this is safe */
aba5acdf
SH
144 nr = sscanf(buf, "%s%llu%lg", idbuf, &val, &rate);
145 if (nr < 2)
146 abort();
147 if (nr < 3)
148 rate = 0;
149 if (useless_number(idbuf))
150 continue;
151 if ((n = malloc(sizeof(*n))) == NULL)
152 abort();
153 n->id = strdup(idbuf);
aba5acdf
SH
154 n->val = val;
155 n->rate = rate;
156 n->next = db;
157 db = n;
158 }
159
160 while (db) {
161 n = db;
162 db = db->next;
163 n->next = kern_db;
164 kern_db = n;
165 }
166}
167
d4717914
ED
168static int count_spaces(const char *line)
169{
170 int count = 0;
171 char c;
172
173 while ((c = *line++) != 0)
174 count += c == ' ' || c == '\n';
175 return count;
176}
aba5acdf 177
d1f28cf1 178static void load_ugly_table(FILE *fp)
aba5acdf 179{
da8034a0 180 char buf[2048];
aba5acdf
SH
181 struct nstat_ent *db = NULL;
182 struct nstat_ent *n;
183
184 while (fgets(buf, sizeof(buf), fp) != NULL) {
da8034a0 185 char idbuf[4096];
aba5acdf
SH
186 int off;
187 char *p;
d4717914 188 int count1, count2, skip = 0;
aba5acdf
SH
189
190 p = strchr(buf, ':');
191 if (!p)
192 abort();
d4717914 193 count1 = count_spaces(buf);
aba5acdf 194 *p = 0;
b482ffa6 195 idbuf[0] = 0;
196 strncat(idbuf, buf, sizeof(idbuf) - 1);
197 off = p - buf;
aba5acdf
SH
198 p += 2;
199
200 while (*p) {
201 char *next;
acd1e437 202
aba5acdf
SH
203 if ((next = strchr(p, ' ')) != NULL)
204 *next++ = 0;
205 else if ((next = strchr(p, '\n')) != NULL)
206 *next++ = 0;
b482ffa6 207 if (off < sizeof(idbuf)) {
208 idbuf[off] = 0;
209 strncat(idbuf, p, sizeof(idbuf) - off - 1);
210 }
aba5acdf
SH
211 n = malloc(sizeof(*n));
212 if (!n)
213 abort();
214 n->id = strdup(idbuf);
215 n->rate = 0;
216 n->next = db;
217 db = n;
218 p = next;
219 }
220 n = db;
221 if (fgets(buf, sizeof(buf), fp) == NULL)
222 abort();
d4717914
ED
223 count2 = count_spaces(buf);
224 if (count2 > count1)
225 skip = count2 - count1;
aba5acdf
SH
226 do {
227 p = strrchr(buf, ' ');
228 if (!p)
229 abort();
230 *p = 0;
cdb2227e 231 if (sscanf(p+1, "%llu", &n->val) != 1)
aba5acdf 232 abort();
aba5acdf 233 /* Trick to skip "dummy" trailing ICMP MIB in 2.4 */
d4717914
ED
234 if (skip)
235 skip--;
aba5acdf
SH
236 else
237 n = n->next;
238 } while (p > buf + off + 2);
239 }
240
241 while (db) {
242 n = db;
243 db = db->next;
244 if (useless_number(n->id)) {
245 free(n->id);
246 free(n);
247 } else {
248 n->next = kern_db;
249 kern_db = n;
250 }
251 }
252}
253
45a0dc16
HL
254static void load_sctp_snmp(void)
255{
256 FILE *fp = fdopen(net_sctp_snmp_open(), "r");
257
258 if (fp) {
259 load_good_table(fp);
260 fclose(fp);
261 }
262}
263
d1f28cf1 264static void load_snmp(void)
aba5acdf
SH
265{
266 FILE *fp = fdopen(net_snmp_open(), "r");
acd1e437 267
aba5acdf
SH
268 if (fp) {
269 load_ugly_table(fp);
270 fclose(fp);
271 }
272}
273
d1f28cf1 274static void load_snmp6(void)
aba5acdf
SH
275{
276 FILE *fp = fdopen(net_snmp6_open(), "r");
acd1e437 277
aba5acdf
SH
278 if (fp) {
279 load_good_table(fp);
280 fclose(fp);
281 }
282}
283
d1f28cf1 284static void load_netstat(void)
aba5acdf
SH
285{
286 FILE *fp = fdopen(net_netstat_open(), "r");
acd1e437 287
aba5acdf
SH
288 if (fp) {
289 load_ugly_table(fp);
290 fclose(fp);
291 }
292}
293
d48ed3f4 294
d1f28cf1 295static void dump_kern_db(FILE *fp, int to_hist)
aba5acdf 296{
fcc16c22 297 json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
aba5acdf 298 struct nstat_ent *n, *h;
d48ed3f4 299
aba5acdf 300 h = hist_db;
fcc16c22 301 if (jw) {
d721a145 302 jsonw_start_object(jw);
fcc16c22
SH
303 jsonw_pretty(jw, pretty);
304 jsonw_name(jw, info_source);
305 jsonw_start_object(jw);
306 } else
d48ed3f4 307 fprintf(fp, "#%s\n", info_source);
404582c8 308
acd1e437 309 for (n = kern_db; n; n = n->next) {
aba5acdf 310 unsigned long long val = n->val;
acd1e437 311
aba5acdf
SH
312 if (!dump_zeros && !val && !n->rate)
313 continue;
314 if (!match(n->id)) {
315 struct nstat_ent *h1;
acd1e437 316
aba5acdf
SH
317 if (!to_hist)
318 continue;
319 for (h1 = h; h1; h1 = h1->next) {
320 if (strcmp(h1->id, n->id) == 0) {
321 val = h1->val;
322 h = h1->next;
323 break;
324 }
325 }
326 }
d48ed3f4 327
fcc16c22
SH
328 if (jw)
329 jsonw_uint_field(jw, n->id, val);
330 else
d48ed3f4 331 fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate);
aba5acdf 332 }
fcc16c22
SH
333
334 if (jw) {
d721a145
AK
335 jsonw_end_object(jw);
336
fcc16c22
SH
337 jsonw_end_object(jw);
338 jsonw_destroy(&jw);
339 }
aba5acdf
SH
340}
341
d1f28cf1 342static void dump_incr_db(FILE *fp)
aba5acdf 343{
fcc16c22 344 json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
aba5acdf 345 struct nstat_ent *n, *h;
d48ed3f4 346
aba5acdf 347 h = hist_db;
fcc16c22 348 if (jw) {
d721a145 349 jsonw_start_object(jw);
fcc16c22
SH
350 jsonw_pretty(jw, pretty);
351 jsonw_name(jw, info_source);
352 jsonw_start_object(jw);
353 } else
d48ed3f4
SH
354 fprintf(fp, "#%s\n", info_source);
355
acd1e437 356 for (n = kern_db; n; n = n->next) {
aba5acdf
SH
357 int ovfl = 0;
358 unsigned long long val = n->val;
359 struct nstat_ent *h1;
acd1e437 360
aba5acdf
SH
361 for (h1 = h; h1; h1 = h1->next) {
362 if (strcmp(h1->id, n->id) == 0) {
363 if (val < h1->val) {
364 ovfl = 1;
365 val = h1->val;
366 }
367 val -= h1->val;
368 h = h1->next;
369 break;
370 }
371 }
372 if (!dump_zeros && !val && !n->rate)
373 continue;
374 if (!match(n->id))
375 continue;
d48ed3f4 376
fcc16c22
SH
377 if (jw)
378 jsonw_uint_field(jw, n->id, val);
379 else
d48ed3f4
SH
380 fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val,
381 n->rate, ovfl?" (overflow)":"");
aba5acdf 382 }
fcc16c22
SH
383
384 if (jw) {
d721a145
AK
385 jsonw_end_object(jw);
386
fcc16c22
SH
387 jsonw_end_object(jw);
388 jsonw_destroy(&jw);
389 }
aba5acdf
SH
390}
391
392static int children;
393
d1f28cf1 394static void sigchild(int signo)
aba5acdf
SH
395{
396}
397
d1f28cf1 398static void update_db(int interval)
aba5acdf
SH
399{
400 struct nstat_ent *n, *h;
401
402 n = kern_db;
403 kern_db = NULL;
404
405 load_netstat();
406 load_snmp6();
407 load_snmp();
45a0dc16 408 load_sctp_snmp();
aba5acdf
SH
409
410 h = kern_db;
411 kern_db = n;
412
413 for (n = kern_db; n; n = n->next) {
414 struct nstat_ent *h1;
acd1e437 415
aba5acdf
SH
416 for (h1 = h; h1; h1 = h1->next) {
417 if (strcmp(h1->id, n->id) == 0) {
418 double sample;
cdb2227e
ED
419 unsigned long long incr = h1->val - n->val;
420
421 n->val = h1->val;
422 sample = (double)incr * 1000.0 / interval;
aba5acdf
SH
423 if (interval >= scan_interval) {
424 n->rate += W*(sample-n->rate);
425 } else if (interval >= 1000) {
426 if (interval >= time_constant) {
427 n->rate = sample;
428 } else {
429 double w = W*(double)interval/scan_interval;
acd1e437 430
aba5acdf
SH
431 n->rate += w*(sample-n->rate);
432 }
433 }
434
435 while (h != h1) {
436 struct nstat_ent *tmp = h;
acd1e437 437
aba5acdf
SH
438 h = h->next;
439 free(tmp->id);
440 free(tmp);
441 };
442 h = h1->next;
443 free(h1->id);
444 free(h1);
445 break;
446 }
447 }
448 }
449}
450
acd1e437 451#define T_DIFF(a, b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000)
aba5acdf
SH
452
453
d1f28cf1 454static void server_loop(int fd)
aba5acdf 455{
737f15f6 456 struct timeval snaptime = { 0 };
aba5acdf 457 struct pollfd p;
acd1e437 458
aba5acdf
SH
459 p.fd = fd;
460 p.events = p.revents = POLLIN;
ae665a52 461
aba5acdf
SH
462 sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
463 getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);
464
465 load_netstat();
466 load_snmp6();
467 load_snmp();
45a0dc16 468 load_sctp_snmp();
aba5acdf
SH
469
470 for (;;) {
471 int status;
dd81ee04 472 time_t tdiff;
aba5acdf 473 struct timeval now;
acd1e437 474
aba5acdf
SH
475 gettimeofday(&now, NULL);
476 tdiff = T_DIFF(now, snaptime);
477 if (tdiff >= scan_interval) {
478 update_db(tdiff);
479 snaptime = now;
480 tdiff = 0;
481 }
dd81ee04 482 if (poll(&p, 1, scan_interval - tdiff) > 0
aba5acdf
SH
483 && (p.revents&POLLIN)) {
484 int clnt = accept(fd, NULL, NULL);
acd1e437 485
aba5acdf
SH
486 if (clnt >= 0) {
487 pid_t pid;
acd1e437 488
aba5acdf
SH
489 if (children >= 5) {
490 close(clnt);
491 } else if ((pid = fork()) != 0) {
acd1e437 492 if (pid > 0)
aba5acdf
SH
493 children++;
494 close(clnt);
495 } else {
496 FILE *fp = fdopen(clnt, "w");
acd1e437 497
dd81ee04 498 if (fp)
aba5acdf 499 dump_kern_db(fp, 0);
aba5acdf
SH
500 exit(0);
501 }
502 }
503 }
504 while (children && waitpid(-1, &status, WNOHANG) > 0)
505 children--;
506 }
507}
508
d1f28cf1 509static int verify_forging(int fd)
aba5acdf
SH
510{
511 struct ucred cred;
737f15f6
SH
512 socklen_t olen = sizeof(cred);
513
acd1e437 514 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &olen) ||
aba5acdf
SH
515 olen < sizeof(cred))
516 return -1;
517 if (cred.uid == getuid() || cred.uid == 0)
518 return 0;
519 return -1;
520}
521
522static void usage(void) __attribute__((noreturn));
523
524static void usage(void)
525{
526 fprintf(stderr,
404582c8 527"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
eca7a742
MF
528" -h, --help this message\n"
529" -a, --ignore ignore history\n"
530" -d, --scan=SECS sample every statistics every SECS\n"
531" -j, --json format output in JSON\n"
532" -n, --nooutput do history only\n"
533" -p, --pretty pretty print\n"
534" -r, --reset reset history\n"
535" -s, --noupdate don't update history\n"
536" -t, --interval=SECS report average over the last SECS\n"
537" -V, --version output version information\n"
538" -z, --zeros show entries with zero activity\n");
aba5acdf
SH
539 exit(-1);
540}
541
404582c8
SH
542static const struct option longopts[] = {
543 { "help", 0, 0, 'h' },
544 { "ignore", 0, 0, 'a' },
545 { "scan", 1, 0, 'd'},
546 { "nooutput", 0, 0, 'n' },
547 { "json", 0, 0, 'j' },
548 { "reset", 0, 0, 'r' },
549 { "noupdate", 0, 0, 's' },
fcc16c22 550 { "pretty", 0, 0, 'p' },
404582c8
SH
551 { "interval", 1, 0, 't' },
552 { "version", 0, 0, 'V' },
553 { "zeros", 0, 0, 'z' },
554 { 0 }
555};
aba5acdf
SH
556
557int main(int argc, char *argv[])
558{
896ebd6c 559 char *hist_name;
aba5acdf
SH
560 struct sockaddr_un sun;
561 FILE *hist_fp = NULL;
562 int ch;
563 int fd;
564
fcc16c22 565 while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:jp",
404582c8 566 longopts, NULL)) != EOF) {
acd1e437 567 switch (ch) {
aba5acdf
SH
568 case 'z':
569 dump_zeros = 1;
570 break;
571 case 'r':
572 reset_history = 1;
573 break;
574 case 'a':
575 ignore_history = 1;
576 break;
577 case 's':
578 no_update = 1;
579 break;
580 case 'n':
581 no_output = 1;
582 break;
583 case 'd':
584 scan_interval = 1000*atoi(optarg);
585 break;
586 case 't':
587 if (sscanf(optarg, "%d", &time_constant) != 1 ||
588 time_constant <= 0) {
589 fprintf(stderr, "nstat: invalid time constant divisor\n");
590 exit(-1);
591 }
592 break;
d48ed3f4
SH
593 case 'j':
594 json_output = 1;
595 break;
fcc16c22
SH
596 case 'p':
597 pretty = 1;
598 break;
aba5acdf
SH
599 case 'v':
600 case 'V':
601 printf("nstat utility, iproute2-ss%s\n", SNAPSHOT);
602 exit(0);
603 case 'h':
604 case '?':
605 default:
606 usage();
607 }
608 }
609
610 argc -= optind;
611 argv += optind;
612
613 sun.sun_family = AF_UNIX;
614 sun.sun_path[0] = 0;
615 sprintf(sun.sun_path+1, "nstat%d", getuid());
616
617 if (scan_interval > 0) {
618 if (time_constant == 0)
619 time_constant = 60;
620 time_constant *= 1000;
621 W = 1 - 1/exp(log(10)*(double)scan_interval/time_constant);
622 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
623 perror("nstat: socket");
624 exit(-1);
625 }
acd1e437 626 if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) {
aba5acdf
SH
627 perror("nstat: bind");
628 exit(-1);
629 }
630 if (listen(fd, 5) < 0) {
631 perror("nstat: listen");
632 exit(-1);
633 }
a7a9ddbb
MF
634 if (daemon(0, 0)) {
635 perror("nstat: daemon");
636 exit(-1);
637 }
aba5acdf
SH
638 signal(SIGPIPE, SIG_IGN);
639 signal(SIGCHLD, sigchild);
640 server_loop(fd);
641 exit(0);
642 }
643
644 patterns = argv;
645 npatterns = argc;
646
896ebd6c
SH
647 if ((hist_name = getenv("NSTAT_HISTORY")) == NULL) {
648 hist_name = malloc(128);
aba5acdf 649 sprintf(hist_name, "/tmp/.nstat.u%d", getuid());
896ebd6c 650 }
aba5acdf
SH
651
652 if (reset_history)
653 unlink(hist_name);
654
655 if (!ignore_history || !no_update) {
656 struct stat stb;
657
658 fd = open(hist_name, O_RDWR|O_CREAT|O_NOFOLLOW, 0600);
659 if (fd < 0) {
660 perror("nstat: open history file");
661 exit(-1);
662 }
663 if ((hist_fp = fdopen(fd, "r+")) == NULL) {
664 perror("nstat: fdopen history file");
665 exit(-1);
666 }
667 if (flock(fileno(hist_fp), LOCK_EX)) {
668 perror("nstat: flock history file");
669 exit(-1);
670 }
671 if (fstat(fileno(hist_fp), &stb) != 0) {
672 perror("nstat: fstat history file");
673 exit(-1);
674 }
675 if (stb.st_nlink != 1 || stb.st_uid != getuid()) {
676 fprintf(stderr, "nstat: something is so wrong with history file, that I prefer not to proceed.\n");
677 exit(-1);
678 }
679 if (!ignore_history) {
680 FILE *tfp;
9a230771 681 long uptime = -1;
acd1e437 682
aba5acdf
SH
683 if ((tfp = fopen("/proc/uptime", "r")) != NULL) {
684 if (fscanf(tfp, "%ld", &uptime) != 1)
685 uptime = -1;
686 fclose(tfp);
687 }
688 if (uptime >= 0 && time(NULL) >= stb.st_mtime+uptime) {
689 fprintf(stderr, "nstat: history is aged out, resetting\n");
d572ed4d
PS
690 if (ftruncate(fileno(hist_fp), 0) < 0)
691 perror("nstat: ftruncate");
aba5acdf
SH
692 }
693 }
694
695 load_good_table(hist_fp);
696
697 hist_db = kern_db;
698 kern_db = NULL;
699 }
700
701 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 &&
acd1e437 702 (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0
aba5acdf 703 || (strcpy(sun.sun_path+1, "nstat0"),
acd1e437 704 connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0))
aba5acdf
SH
705 && verify_forging(fd) == 0) {
706 FILE *sfp = fdopen(fd, "r");
acd1e437 707
6d02518f
PS
708 if (!sfp) {
709 fprintf(stderr, "nstat: fdopen failed: %s\n",
710 strerror(errno));
711 close(fd);
712 } else {
713 load_good_table(sfp);
714 if (hist_db && source_mismatch) {
715 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
716 hist_db = NULL;
717 }
718 fclose(sfp);
aba5acdf 719 }
aba5acdf
SH
720 } else {
721 if (fd >= 0)
722 close(fd);
723 if (hist_db && info_source[0] && strcmp(info_source, "kernel")) {
724 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
725 hist_db = NULL;
726 info_source[0] = 0;
727 }
728 load_netstat();
729 load_snmp6();
730 load_snmp();
45a0dc16 731 load_sctp_snmp();
aba5acdf
SH
732 if (info_source[0] == 0)
733 strcpy(info_source, "kernel");
734 }
735
736 if (!no_output) {
737 if (ignore_history || hist_db == NULL)
738 dump_kern_db(stdout, 0);
739 else
740 dump_incr_db(stdout);
741 }
742 if (!no_update) {
d572ed4d
PS
743 if (ftruncate(fileno(hist_fp), 0) < 0)
744 perror("nstat: ftruncate");
aba5acdf 745 rewind(hist_fp);
404582c8
SH
746
747 json_output = 0;
aba5acdf 748 dump_kern_db(hist_fp, 1);
404582c8 749 fclose(hist_fp);
aba5acdf
SH
750 }
751 exit(0);
752}