]> git.proxmox.com Git - mirror_iproute2.git/blame - misc/nstat.c
rtacct: drop unused header
[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 144 nr = sscanf(buf, "%s%llu%lg", idbuf, &val, &rate);
2c7056ac
AC
145 if (nr < 2) {
146 fprintf(stderr, "%s:%d: error parsing history file\n",
147 __FILE__, __LINE__);
148 exit(-2);
149 }
aba5acdf
SH
150 if (nr < 3)
151 rate = 0;
152 if (useless_number(idbuf))
153 continue;
2c7056ac
AC
154 if ((n = malloc(sizeof(*n))) == NULL) {
155 perror("nstat: malloc");
156 exit(-1);
157 }
aba5acdf 158 n->id = strdup(idbuf);
aba5acdf
SH
159 n->val = val;
160 n->rate = rate;
161 n->next = db;
162 db = n;
163 }
164
165 while (db) {
166 n = db;
167 db = db->next;
168 n->next = kern_db;
169 kern_db = n;
170 }
171}
172
d4717914
ED
173static int count_spaces(const char *line)
174{
175 int count = 0;
176 char c;
177
178 while ((c = *line++) != 0)
179 count += c == ' ' || c == '\n';
180 return count;
181}
aba5acdf 182
d1f28cf1 183static void load_ugly_table(FILE *fp)
aba5acdf 184{
72cdb77d
ED
185 char *buf = NULL;
186 size_t buflen = 0;
187 ssize_t nread;
aba5acdf
SH
188 struct nstat_ent *db = NULL;
189 struct nstat_ent *n;
190
72cdb77d 191 while ((nread = getline(&buf, &buflen, fp)) != -1) {
da8034a0 192 char idbuf[4096];
aba5acdf
SH
193 int off;
194 char *p;
d4717914 195 int count1, count2, skip = 0;
aba5acdf
SH
196
197 p = strchr(buf, ':');
2c7056ac
AC
198 if (!p) {
199 fprintf(stderr, "%s:%d: error parsing history file\n",
200 __FILE__, __LINE__);
201 exit(-2);
202 }
d4717914 203 count1 = count_spaces(buf);
aba5acdf 204 *p = 0;
b482ffa6 205 idbuf[0] = 0;
206 strncat(idbuf, buf, sizeof(idbuf) - 1);
207 off = p - buf;
aba5acdf
SH
208 p += 2;
209
210 while (*p) {
211 char *next;
acd1e437 212
aba5acdf
SH
213 if ((next = strchr(p, ' ')) != NULL)
214 *next++ = 0;
215 else if ((next = strchr(p, '\n')) != NULL)
216 *next++ = 0;
b482ffa6 217 if (off < sizeof(idbuf)) {
218 idbuf[off] = 0;
219 strncat(idbuf, p, sizeof(idbuf) - off - 1);
220 }
aba5acdf 221 n = malloc(sizeof(*n));
2c7056ac
AC
222 if (!n) {
223 perror("nstat: malloc");
224 exit(-1);
225 }
aba5acdf
SH
226 n->id = strdup(idbuf);
227 n->rate = 0;
228 n->next = db;
229 db = n;
230 p = next;
231 }
232 n = db;
72cdb77d 233 nread = getline(&buf, &buflen, fp);
2c7056ac
AC
234 if (nread == -1) {
235 fprintf(stderr, "%s:%d: error parsing history file\n",
236 __FILE__, __LINE__);
237 exit(-2);
238 }
d4717914
ED
239 count2 = count_spaces(buf);
240 if (count2 > count1)
241 skip = count2 - count1;
aba5acdf
SH
242 do {
243 p = strrchr(buf, ' ');
2c7056ac
AC
244 if (!p) {
245 fprintf(stderr, "%s:%d: error parsing history file\n",
246 __FILE__, __LINE__);
247 exit(-2);
248 }
aba5acdf 249 *p = 0;
2c7056ac
AC
250 if (sscanf(p+1, "%llu", &n->val) != 1) {
251 fprintf(stderr, "%s:%d: error parsing history file\n",
252 __FILE__, __LINE__);
253 exit(-2);
254 }
aba5acdf 255 /* Trick to skip "dummy" trailing ICMP MIB in 2.4 */
d4717914
ED
256 if (skip)
257 skip--;
aba5acdf
SH
258 else
259 n = n->next;
260 } while (p > buf + off + 2);
261 }
72cdb77d 262 free(buf);
aba5acdf
SH
263
264 while (db) {
265 n = db;
266 db = db->next;
267 if (useless_number(n->id)) {
268 free(n->id);
269 free(n);
270 } else {
271 n->next = kern_db;
272 kern_db = n;
273 }
274 }
275}
276
45a0dc16
HL
277static void load_sctp_snmp(void)
278{
279 FILE *fp = fdopen(net_sctp_snmp_open(), "r");
280
281 if (fp) {
282 load_good_table(fp);
283 fclose(fp);
284 }
285}
286
d1f28cf1 287static void load_snmp(void)
aba5acdf
SH
288{
289 FILE *fp = fdopen(net_snmp_open(), "r");
acd1e437 290
aba5acdf
SH
291 if (fp) {
292 load_ugly_table(fp);
293 fclose(fp);
294 }
295}
296
d1f28cf1 297static void load_snmp6(void)
aba5acdf
SH
298{
299 FILE *fp = fdopen(net_snmp6_open(), "r");
acd1e437 300
aba5acdf
SH
301 if (fp) {
302 load_good_table(fp);
303 fclose(fp);
304 }
305}
306
d1f28cf1 307static void load_netstat(void)
aba5acdf
SH
308{
309 FILE *fp = fdopen(net_netstat_open(), "r");
acd1e437 310
aba5acdf
SH
311 if (fp) {
312 load_ugly_table(fp);
313 fclose(fp);
314 }
315}
316
d48ed3f4 317
d1f28cf1 318static void dump_kern_db(FILE *fp, int to_hist)
aba5acdf 319{
fcc16c22 320 json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
aba5acdf 321 struct nstat_ent *n, *h;
d48ed3f4 322
aba5acdf 323 h = hist_db;
fcc16c22 324 if (jw) {
d721a145 325 jsonw_start_object(jw);
fcc16c22
SH
326 jsonw_pretty(jw, pretty);
327 jsonw_name(jw, info_source);
328 jsonw_start_object(jw);
329 } else
d48ed3f4 330 fprintf(fp, "#%s\n", info_source);
404582c8 331
acd1e437 332 for (n = kern_db; n; n = n->next) {
aba5acdf 333 unsigned long long val = n->val;
acd1e437 334
aba5acdf
SH
335 if (!dump_zeros && !val && !n->rate)
336 continue;
337 if (!match(n->id)) {
338 struct nstat_ent *h1;
acd1e437 339
aba5acdf
SH
340 if (!to_hist)
341 continue;
342 for (h1 = h; h1; h1 = h1->next) {
343 if (strcmp(h1->id, n->id) == 0) {
344 val = h1->val;
345 h = h1->next;
346 break;
347 }
348 }
349 }
d48ed3f4 350
fcc16c22
SH
351 if (jw)
352 jsonw_uint_field(jw, n->id, val);
353 else
d48ed3f4 354 fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate);
aba5acdf 355 }
fcc16c22
SH
356
357 if (jw) {
d721a145
AK
358 jsonw_end_object(jw);
359
fcc16c22
SH
360 jsonw_end_object(jw);
361 jsonw_destroy(&jw);
362 }
aba5acdf
SH
363}
364
d1f28cf1 365static void dump_incr_db(FILE *fp)
aba5acdf 366{
fcc16c22 367 json_writer_t *jw = json_output ? jsonw_new(fp) : NULL;
aba5acdf 368 struct nstat_ent *n, *h;
d48ed3f4 369
aba5acdf 370 h = hist_db;
fcc16c22 371 if (jw) {
d721a145 372 jsonw_start_object(jw);
fcc16c22
SH
373 jsonw_pretty(jw, pretty);
374 jsonw_name(jw, info_source);
375 jsonw_start_object(jw);
376 } else
d48ed3f4
SH
377 fprintf(fp, "#%s\n", info_source);
378
acd1e437 379 for (n = kern_db; n; n = n->next) {
aba5acdf
SH
380 int ovfl = 0;
381 unsigned long long val = n->val;
382 struct nstat_ent *h1;
acd1e437 383
aba5acdf
SH
384 for (h1 = h; h1; h1 = h1->next) {
385 if (strcmp(h1->id, n->id) == 0) {
386 if (val < h1->val) {
387 ovfl = 1;
388 val = h1->val;
389 }
390 val -= h1->val;
391 h = h1->next;
392 break;
393 }
394 }
395 if (!dump_zeros && !val && !n->rate)
396 continue;
397 if (!match(n->id))
398 continue;
d48ed3f4 399
fcc16c22
SH
400 if (jw)
401 jsonw_uint_field(jw, n->id, val);
402 else
d48ed3f4
SH
403 fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val,
404 n->rate, ovfl?" (overflow)":"");
aba5acdf 405 }
fcc16c22
SH
406
407 if (jw) {
d721a145
AK
408 jsonw_end_object(jw);
409
fcc16c22
SH
410 jsonw_end_object(jw);
411 jsonw_destroy(&jw);
412 }
aba5acdf
SH
413}
414
415static int children;
416
d1f28cf1 417static void sigchild(int signo)
aba5acdf
SH
418{
419}
420
d1f28cf1 421static void update_db(int interval)
aba5acdf
SH
422{
423 struct nstat_ent *n, *h;
424
425 n = kern_db;
426 kern_db = NULL;
427
428 load_netstat();
429 load_snmp6();
430 load_snmp();
45a0dc16 431 load_sctp_snmp();
aba5acdf
SH
432
433 h = kern_db;
434 kern_db = n;
435
436 for (n = kern_db; n; n = n->next) {
437 struct nstat_ent *h1;
acd1e437 438
aba5acdf
SH
439 for (h1 = h; h1; h1 = h1->next) {
440 if (strcmp(h1->id, n->id) == 0) {
441 double sample;
cdb2227e
ED
442 unsigned long long incr = h1->val - n->val;
443
444 n->val = h1->val;
445 sample = (double)incr * 1000.0 / interval;
aba5acdf
SH
446 if (interval >= scan_interval) {
447 n->rate += W*(sample-n->rate);
448 } else if (interval >= 1000) {
449 if (interval >= time_constant) {
450 n->rate = sample;
451 } else {
452 double w = W*(double)interval/scan_interval;
acd1e437 453
aba5acdf
SH
454 n->rate += w*(sample-n->rate);
455 }
456 }
457
458 while (h != h1) {
459 struct nstat_ent *tmp = h;
acd1e437 460
aba5acdf
SH
461 h = h->next;
462 free(tmp->id);
463 free(tmp);
464 };
465 h = h1->next;
466 free(h1->id);
467 free(h1);
468 break;
469 }
470 }
471 }
472}
473
acd1e437 474#define T_DIFF(a, b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000)
aba5acdf
SH
475
476
d1f28cf1 477static void server_loop(int fd)
aba5acdf 478{
737f15f6 479 struct timeval snaptime = { 0 };
aba5acdf 480 struct pollfd p;
acd1e437 481
aba5acdf
SH
482 p.fd = fd;
483 p.events = p.revents = POLLIN;
ae665a52 484
aba5acdf
SH
485 sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
486 getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);
487
488 load_netstat();
489 load_snmp6();
490 load_snmp();
45a0dc16 491 load_sctp_snmp();
aba5acdf
SH
492
493 for (;;) {
494 int status;
dd81ee04 495 time_t tdiff;
aba5acdf 496 struct timeval now;
acd1e437 497
aba5acdf
SH
498 gettimeofday(&now, NULL);
499 tdiff = T_DIFF(now, snaptime);
500 if (tdiff >= scan_interval) {
501 update_db(tdiff);
502 snaptime = now;
503 tdiff = 0;
504 }
dd81ee04 505 if (poll(&p, 1, scan_interval - tdiff) > 0
aba5acdf
SH
506 && (p.revents&POLLIN)) {
507 int clnt = accept(fd, NULL, NULL);
acd1e437 508
aba5acdf
SH
509 if (clnt >= 0) {
510 pid_t pid;
acd1e437 511
aba5acdf
SH
512 if (children >= 5) {
513 close(clnt);
514 } else if ((pid = fork()) != 0) {
acd1e437 515 if (pid > 0)
aba5acdf
SH
516 children++;
517 close(clnt);
518 } else {
519 FILE *fp = fdopen(clnt, "w");
acd1e437 520
dd81ee04 521 if (fp)
aba5acdf 522 dump_kern_db(fp, 0);
aba5acdf
SH
523 exit(0);
524 }
525 }
526 }
527 while (children && waitpid(-1, &status, WNOHANG) > 0)
528 children--;
529 }
530}
531
d1f28cf1 532static int verify_forging(int fd)
aba5acdf
SH
533{
534 struct ucred cred;
737f15f6
SH
535 socklen_t olen = sizeof(cred);
536
acd1e437 537 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &olen) ||
aba5acdf
SH
538 olen < sizeof(cred))
539 return -1;
540 if (cred.uid == getuid() || cred.uid == 0)
541 return 0;
542 return -1;
543}
544
545static void usage(void) __attribute__((noreturn));
546
547static void usage(void)
548{
549 fprintf(stderr,
8589eb4e
MC
550 "Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
551 " -h, --help this message\n"
552 " -a, --ignore ignore history\n"
553 " -d, --scan=SECS sample every statistics every SECS\n"
554 " -j, --json format output in JSON\n"
555 " -n, --nooutput do history only\n"
556 " -p, --pretty pretty print\n"
557 " -r, --reset reset history\n"
558 " -s, --noupdate don't update history\n"
559 " -t, --interval=SECS report average over the last SECS\n"
560 " -V, --version output version information\n"
561 " -z, --zeros show entries with zero activity\n");
aba5acdf
SH
562 exit(-1);
563}
564
404582c8
SH
565static const struct option longopts[] = {
566 { "help", 0, 0, 'h' },
567 { "ignore", 0, 0, 'a' },
568 { "scan", 1, 0, 'd'},
569 { "nooutput", 0, 0, 'n' },
570 { "json", 0, 0, 'j' },
571 { "reset", 0, 0, 'r' },
572 { "noupdate", 0, 0, 's' },
fcc16c22 573 { "pretty", 0, 0, 'p' },
404582c8
SH
574 { "interval", 1, 0, 't' },
575 { "version", 0, 0, 'V' },
576 { "zeros", 0, 0, 'z' },
577 { 0 }
578};
aba5acdf
SH
579
580int main(int argc, char *argv[])
581{
896ebd6c 582 char *hist_name;
aba5acdf
SH
583 struct sockaddr_un sun;
584 FILE *hist_fp = NULL;
585 int ch;
586 int fd;
587
fcc16c22 588 while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:jp",
404582c8 589 longopts, NULL)) != EOF) {
acd1e437 590 switch (ch) {
aba5acdf
SH
591 case 'z':
592 dump_zeros = 1;
593 break;
594 case 'r':
595 reset_history = 1;
596 break;
597 case 'a':
598 ignore_history = 1;
599 break;
600 case 's':
601 no_update = 1;
602 break;
603 case 'n':
604 no_output = 1;
605 break;
606 case 'd':
607 scan_interval = 1000*atoi(optarg);
608 break;
609 case 't':
610 if (sscanf(optarg, "%d", &time_constant) != 1 ||
611 time_constant <= 0) {
612 fprintf(stderr, "nstat: invalid time constant divisor\n");
613 exit(-1);
614 }
615 break;
d48ed3f4
SH
616 case 'j':
617 json_output = 1;
618 break;
fcc16c22
SH
619 case 'p':
620 pretty = 1;
621 break;
aba5acdf
SH
622 case 'v':
623 case 'V':
624 printf("nstat utility, iproute2-ss%s\n", SNAPSHOT);
625 exit(0);
626 case 'h':
627 case '?':
628 default:
629 usage();
630 }
631 }
632
633 argc -= optind;
634 argv += optind;
635
636 sun.sun_family = AF_UNIX;
637 sun.sun_path[0] = 0;
638 sprintf(sun.sun_path+1, "nstat%d", getuid());
639
640 if (scan_interval > 0) {
641 if (time_constant == 0)
642 time_constant = 60;
643 time_constant *= 1000;
644 W = 1 - 1/exp(log(10)*(double)scan_interval/time_constant);
645 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
646 perror("nstat: socket");
647 exit(-1);
648 }
acd1e437 649 if (bind(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) < 0) {
aba5acdf
SH
650 perror("nstat: bind");
651 exit(-1);
652 }
653 if (listen(fd, 5) < 0) {
654 perror("nstat: listen");
655 exit(-1);
656 }
a7a9ddbb
MF
657 if (daemon(0, 0)) {
658 perror("nstat: daemon");
659 exit(-1);
660 }
aba5acdf
SH
661 signal(SIGPIPE, SIG_IGN);
662 signal(SIGCHLD, sigchild);
663 server_loop(fd);
664 exit(0);
665 }
666
667 patterns = argv;
668 npatterns = argc;
669
896ebd6c
SH
670 if ((hist_name = getenv("NSTAT_HISTORY")) == NULL) {
671 hist_name = malloc(128);
aba5acdf 672 sprintf(hist_name, "/tmp/.nstat.u%d", getuid());
896ebd6c 673 }
aba5acdf
SH
674
675 if (reset_history)
676 unlink(hist_name);
677
678 if (!ignore_history || !no_update) {
679 struct stat stb;
680
681 fd = open(hist_name, O_RDWR|O_CREAT|O_NOFOLLOW, 0600);
682 if (fd < 0) {
683 perror("nstat: open history file");
684 exit(-1);
685 }
686 if ((hist_fp = fdopen(fd, "r+")) == NULL) {
687 perror("nstat: fdopen history file");
688 exit(-1);
689 }
690 if (flock(fileno(hist_fp), LOCK_EX)) {
691 perror("nstat: flock history file");
692 exit(-1);
693 }
694 if (fstat(fileno(hist_fp), &stb) != 0) {
695 perror("nstat: fstat history file");
696 exit(-1);
697 }
698 if (stb.st_nlink != 1 || stb.st_uid != getuid()) {
699 fprintf(stderr, "nstat: something is so wrong with history file, that I prefer not to proceed.\n");
700 exit(-1);
701 }
702 if (!ignore_history) {
703 FILE *tfp;
9a230771 704 long uptime = -1;
acd1e437 705
aba5acdf
SH
706 if ((tfp = fopen("/proc/uptime", "r")) != NULL) {
707 if (fscanf(tfp, "%ld", &uptime) != 1)
708 uptime = -1;
709 fclose(tfp);
710 }
711 if (uptime >= 0 && time(NULL) >= stb.st_mtime+uptime) {
712 fprintf(stderr, "nstat: history is aged out, resetting\n");
d572ed4d
PS
713 if (ftruncate(fileno(hist_fp), 0) < 0)
714 perror("nstat: ftruncate");
aba5acdf
SH
715 }
716 }
717
718 load_good_table(hist_fp);
719
720 hist_db = kern_db;
721 kern_db = NULL;
722 }
723
724 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 &&
acd1e437 725 (connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0
aba5acdf 726 || (strcpy(sun.sun_path+1, "nstat0"),
acd1e437 727 connect(fd, (struct sockaddr *)&sun, 2+1+strlen(sun.sun_path+1)) == 0))
aba5acdf
SH
728 && verify_forging(fd) == 0) {
729 FILE *sfp = fdopen(fd, "r");
acd1e437 730
6d02518f
PS
731 if (!sfp) {
732 fprintf(stderr, "nstat: fdopen failed: %s\n",
733 strerror(errno));
734 close(fd);
735 } else {
736 load_good_table(sfp);
737 if (hist_db && source_mismatch) {
738 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
739 hist_db = NULL;
740 }
741 fclose(sfp);
aba5acdf 742 }
aba5acdf
SH
743 } else {
744 if (fd >= 0)
745 close(fd);
746 if (hist_db && info_source[0] && strcmp(info_source, "kernel")) {
747 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
748 hist_db = NULL;
749 info_source[0] = 0;
750 }
751 load_netstat();
752 load_snmp6();
753 load_snmp();
45a0dc16 754 load_sctp_snmp();
aba5acdf
SH
755 if (info_source[0] == 0)
756 strcpy(info_source, "kernel");
757 }
758
759 if (!no_output) {
760 if (ignore_history || hist_db == NULL)
761 dump_kern_db(stdout, 0);
762 else
763 dump_incr_db(stdout);
764 }
765 if (!no_update) {
d572ed4d
PS
766 if (ftruncate(fileno(hist_fp), 0) < 0)
767 perror("nstat: ftruncate");
aba5acdf 768 rewind(hist_fp);
404582c8
SH
769
770 json_output = 0;
aba5acdf 771 dump_kern_db(hist_fp, 1);
404582c8 772 fclose(hist_fp);
aba5acdf
SH
773 }
774 exit(0);
775}