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