blob: c2cb056466505ccc09540c8cc08a07097dd47eff [file] [log] [blame]
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +00001/*
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>
Stephen Hemminger404582c2013-09-24 11:54:45 -070029#include <getopt.h>
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000030
31#include <SNAPSHOT.h>
32
33int dump_zeros = 0;
34int reset_history = 0;
35int ignore_history = 0;
36int no_output = 0;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -070037int json_output = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000038int no_update = 0;
39int scan_interval = 0;
40int time_constant = 0;
41double W;
42char **patterns;
43int npatterns;
44
45char info_source[128];
46int source_mismatch;
47
Yu Zhiguo4ffc44c2008-06-20 09:50:16 +080048static int generic_proc_open(const char *env, char *name)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000049{
50 char store[128];
51 char *p = getenv(env);
52 if (!p) {
53 p = getenv("PROC_ROOT") ? : "/proc";
54 snprintf(store, sizeof(store)-1, "%s/%s", p, name);
55 p = store;
56 }
Yu Zhiguo4ffc44c2008-06-20 09:50:16 +080057 return open(p, O_RDONLY);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000058}
59
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080060static int net_netstat_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000061{
62 return generic_proc_open("PROC_NET_NETSTAT", "net/netstat");
63}
64
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080065static int net_snmp_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000066{
67 return generic_proc_open("PROC_NET_SNMP", "net/snmp");
68}
69
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080070static int net_snmp6_open(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000071{
72 return generic_proc_open("PROC_NET_SNMP6", "net/snmp6");
73}
74
75struct nstat_ent
76{
77 struct nstat_ent *next;
78 char *id;
79 unsigned long long val;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000080 double rate;
81};
82
83struct nstat_ent *kern_db;
84struct nstat_ent *hist_db;
85
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080086static const char *useless_numbers[] = {
87 "IpForwarding", "IpDefaultTTL",
88 "TcpRtoAlgorithm", "TcpRtoMin", "TcpRtoMax",
89 "TcpMaxConn", "TcpCurrEstab"
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000090};
91
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -080092static int useless_number(const char *id)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +000093{
94 int i;
95 for (i=0; i<sizeof(useless_numbers)/sizeof(*useless_numbers); i++)
96 if (strcmp(id, useless_numbers[i]) == 0)
97 return 1;
98 return 0;
99}
100
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800101static int match(const char *id)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000102{
103 int i;
104
105 if (npatterns == 0)
106 return 1;
107
108 for (i=0; i<npatterns; i++) {
109 if (!fnmatch(patterns[i], id, 0))
110 return 1;
111 }
112 return 0;
113}
114
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800115static void load_good_table(FILE *fp)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000116{
117 char buf[4096];
118 struct nstat_ent *db = NULL;
119 struct nstat_ent *n;
120
121 while (fgets(buf, sizeof(buf), fp) != NULL) {
122 int nr;
123 unsigned long long val;
124 double rate;
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000125 char idbuf[sizeof(buf)];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000126 if (buf[0] == '#') {
127 buf[strlen(buf)-1] = 0;
128 if (info_source[0] && strcmp(info_source, buf+1))
129 source_mismatch = 1;
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000130 info_source[0] = 0;
131 strncat(info_source, buf+1, sizeof(info_source)-1);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000132 continue;
133 }
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000134 /* idbuf is as big as buf, so this is safe */
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000135 nr = sscanf(buf, "%s%llu%lg", idbuf, &val, &rate);
136 if (nr < 2)
137 abort();
138 if (nr < 3)
139 rate = 0;
140 if (useless_number(idbuf))
141 continue;
142 if ((n = malloc(sizeof(*n))) == NULL)
143 abort();
144 n->id = strdup(idbuf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000145 n->val = val;
146 n->rate = rate;
147 n->next = db;
148 db = n;
149 }
150
151 while (db) {
152 n = db;
153 db = db->next;
154 n->next = kern_db;
155 kern_db = n;
156 }
157}
158
Eric Dumazetd4717912014-12-05 18:10:08 -0800159static int count_spaces(const char *line)
160{
161 int count = 0;
162 char c;
163
164 while ((c = *line++) != 0)
165 count += c == ' ' || c == '\n';
166 return count;
167}
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000168
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800169static void load_ugly_table(FILE *fp)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000170{
171 char buf[4096];
172 struct nstat_ent *db = NULL;
173 struct nstat_ent *n;
174
175 while (fgets(buf, sizeof(buf), fp) != NULL) {
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000176 char idbuf[sizeof(buf)];
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000177 int off;
178 char *p;
Eric Dumazetd4717912014-12-05 18:10:08 -0800179 int count1, count2, skip = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000180
181 p = strchr(buf, ':');
182 if (!p)
183 abort();
Eric Dumazetd4717912014-12-05 18:10:08 -0800184 count1 = count_spaces(buf);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000185 *p = 0;
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000186 idbuf[0] = 0;
187 strncat(idbuf, buf, sizeof(idbuf) - 1);
188 off = p - buf;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000189 p += 2;
190
191 while (*p) {
192 char *next;
193 if ((next = strchr(p, ' ')) != NULL)
194 *next++ = 0;
195 else if ((next = strchr(p, '\n')) != NULL)
196 *next++ = 0;
net[shemminger]!shemmingerb482ffa2004-10-19 20:02:59 +0000197 if (off < sizeof(idbuf)) {
198 idbuf[off] = 0;
199 strncat(idbuf, p, sizeof(idbuf) - off - 1);
200 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000201 n = malloc(sizeof(*n));
202 if (!n)
203 abort();
204 n->id = strdup(idbuf);
205 n->rate = 0;
206 n->next = db;
207 db = n;
208 p = next;
209 }
210 n = db;
211 if (fgets(buf, sizeof(buf), fp) == NULL)
212 abort();
Eric Dumazetd4717912014-12-05 18:10:08 -0800213 count2 = count_spaces(buf);
214 if (count2 > count1)
215 skip = count2 - count1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000216 do {
217 p = strrchr(buf, ' ');
218 if (!p)
219 abort();
220 *p = 0;
Eric Dumazetcdb22272014-08-25 07:27:54 -0700221 if (sscanf(p+1, "%llu", &n->val) != 1)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000222 abort();
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000223 /* Trick to skip "dummy" trailing ICMP MIB in 2.4 */
Eric Dumazetd4717912014-12-05 18:10:08 -0800224 if (skip)
225 skip--;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000226 else
227 n = n->next;
228 } while (p > buf + off + 2);
229 }
230
231 while (db) {
232 n = db;
233 db = db->next;
234 if (useless_number(n->id)) {
235 free(n->id);
236 free(n);
237 } else {
238 n->next = kern_db;
239 kern_db = n;
240 }
241 }
242}
243
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800244static void load_snmp(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000245{
246 FILE *fp = fdopen(net_snmp_open(), "r");
247 if (fp) {
248 load_ugly_table(fp);
249 fclose(fp);
250 }
251}
252
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800253static void load_snmp6(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000254{
255 FILE *fp = fdopen(net_snmp6_open(), "r");
256 if (fp) {
257 load_good_table(fp);
258 fclose(fp);
259 }
260}
261
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800262static void load_netstat(void)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000263{
264 FILE *fp = fdopen(net_netstat_open(), "r");
265 if (fp) {
266 load_ugly_table(fp);
267 fclose(fp);
268 }
269}
270
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700271
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800272static void dump_kern_db(FILE *fp, int to_hist)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000273{
274 struct nstat_ent *n, *h;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700275 const char *eol = "\n";
276
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000277 h = hist_db;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700278 if (json_output)
Stephen Hemminger404582c2013-09-24 11:54:45 -0700279 fprintf(fp, "{ \"%s\":{", info_source);
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700280 else
281 fprintf(fp, "#%s\n", info_source);
Stephen Hemminger404582c2013-09-24 11:54:45 -0700282
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000283 for (n=kern_db; n; n=n->next) {
284 unsigned long long val = n->val;
285 if (!dump_zeros && !val && !n->rate)
286 continue;
287 if (!match(n->id)) {
288 struct nstat_ent *h1;
289 if (!to_hist)
290 continue;
291 for (h1 = h; h1; h1 = h1->next) {
292 if (strcmp(h1->id, n->id) == 0) {
293 val = h1->val;
294 h = h1->next;
295 break;
296 }
297 }
298 }
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700299
300 if (json_output) {
Stephen Hemminger404582c2013-09-24 11:54:45 -0700301 fprintf(fp, "%s \"%s\":%llu",
302 eol, n->id, val);
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700303 eol = ",\n";
304 } else
305 fprintf(fp, "%-32s%-16llu%6.1f\n", n->id, val, n->rate);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000306 }
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700307 if (json_output)
Stephen Hemminger404582c2013-09-24 11:54:45 -0700308 fprintf(fp, "\n} }\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000309}
310
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800311static void dump_incr_db(FILE *fp)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000312{
313 struct nstat_ent *n, *h;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700314 const char *eol = "\n";
315
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000316 h = hist_db;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700317 if (json_output)
Stephen Hemminger404582c2013-09-24 11:54:45 -0700318 fprintf(fp, "{ \"%s\":{", info_source);
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700319 else
320 fprintf(fp, "#%s\n", info_source);
321
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000322 for (n=kern_db; n; n=n->next) {
323 int ovfl = 0;
324 unsigned long long val = n->val;
325 struct nstat_ent *h1;
326 for (h1 = h; h1; h1 = h1->next) {
327 if (strcmp(h1->id, n->id) == 0) {
328 if (val < h1->val) {
329 ovfl = 1;
330 val = h1->val;
331 }
332 val -= h1->val;
333 h = h1->next;
334 break;
335 }
336 }
337 if (!dump_zeros && !val && !n->rate)
338 continue;
339 if (!match(n->id))
340 continue;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700341
342 if (json_output) {
Stephen Hemminger404582c2013-09-24 11:54:45 -0700343 fprintf(fp, "%s \"%s\":%llu",
344 eol, n->id, val);
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700345 eol = ",\n";
346 } else
347 fprintf(fp, "%-32s%-16llu%6.1f%s\n", n->id, val,
348 n->rate, ovfl?" (overflow)":"");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000349 }
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700350 if (json_output)
Stephen Hemminger404582c2013-09-24 11:54:45 -0700351 fprintf(fp, "\n} }\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000352}
353
354static int children;
355
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800356static void sigchild(int signo)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000357{
358}
359
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800360static void update_db(int interval)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000361{
362 struct nstat_ent *n, *h;
363
364 n = kern_db;
365 kern_db = NULL;
366
367 load_netstat();
368 load_snmp6();
369 load_snmp();
370
371 h = kern_db;
372 kern_db = n;
373
374 for (n = kern_db; n; n = n->next) {
375 struct nstat_ent *h1;
376 for (h1 = h; h1; h1 = h1->next) {
377 if (strcmp(h1->id, n->id) == 0) {
378 double sample;
Eric Dumazetcdb22272014-08-25 07:27:54 -0700379 unsigned long long incr = h1->val - n->val;
380
381 n->val = h1->val;
382 sample = (double)incr * 1000.0 / interval;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000383 if (interval >= scan_interval) {
384 n->rate += W*(sample-n->rate);
385 } else if (interval >= 1000) {
386 if (interval >= time_constant) {
387 n->rate = sample;
388 } else {
389 double w = W*(double)interval/scan_interval;
390 n->rate += w*(sample-n->rate);
391 }
392 }
393
394 while (h != h1) {
395 struct nstat_ent *tmp = h;
396 h = h->next;
397 free(tmp->id);
398 free(tmp);
399 };
400 h = h1->next;
401 free(h1->id);
402 free(h1);
403 break;
404 }
405 }
406 }
407}
408
409#define T_DIFF(a,b) (((a).tv_sec-(b).tv_sec)*1000 + ((a).tv_usec-(b).tv_usec)/1000)
410
411
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800412static void server_loop(int fd)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000413{
shemminger737f15f2005-07-08 22:08:47 +0000414 struct timeval snaptime = { 0 };
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000415 struct pollfd p;
416 p.fd = fd;
417 p.events = p.revents = POLLIN;
Stephen Hemmingerae665a52006-12-05 10:10:22 -0800418
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000419 sprintf(info_source, "%d.%lu sampling_interval=%d time_const=%d",
420 getpid(), (unsigned long)random(), scan_interval/1000, time_constant/1000);
421
422 load_netstat();
423 load_snmp6();
424 load_snmp();
425
426 for (;;) {
427 int status;
428 int tdiff;
429 struct timeval now;
430 gettimeofday(&now, NULL);
431 tdiff = T_DIFF(now, snaptime);
432 if (tdiff >= scan_interval) {
433 update_db(tdiff);
434 snaptime = now;
435 tdiff = 0;
436 }
437 if (poll(&p, 1, tdiff + scan_interval) > 0
438 && (p.revents&POLLIN)) {
439 int clnt = accept(fd, NULL, NULL);
440 if (clnt >= 0) {
441 pid_t pid;
442 if (children >= 5) {
443 close(clnt);
444 } else if ((pid = fork()) != 0) {
445 if (pid>0)
446 children++;
447 close(clnt);
448 } else {
449 FILE *fp = fdopen(clnt, "w");
450 if (fp) {
451 if (tdiff > 0)
452 update_db(tdiff);
453 dump_kern_db(fp, 0);
454 }
455 exit(0);
456 }
457 }
458 }
459 while (children && waitpid(-1, &status, WNOHANG) > 0)
460 children--;
461 }
462}
463
Stephen Hemmingerd1f28cf2013-02-12 11:09:03 -0800464static int verify_forging(int fd)
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000465{
466 struct ucred cred;
shemminger737f15f2005-07-08 22:08:47 +0000467 socklen_t olen = sizeof(cred);
468
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000469 if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, (void*)&cred, &olen) ||
470 olen < sizeof(cred))
471 return -1;
472 if (cred.uid == getuid() || cred.uid == 0)
473 return 0;
474 return -1;
475}
476
477static void usage(void) __attribute__((noreturn));
478
479static void usage(void)
480{
481 fprintf(stderr,
Stephen Hemminger404582c2013-09-24 11:54:45 -0700482"Usage: nstat [OPTION] [ PATTERN [ PATTERN ] ]\n"
483" -h, --help this message\n"
484" -a, --ignore ignore history\n"
485" -d, --scan=SECS sample every statistics every SECS\n"
486" -j, --json format output in JSON\n"
487" -n, --nooutput do history only\n"
488" -r, --reset reset history\n"
489" -s, --noupdate don\'t update history\n"
490" -t, --interval=SECS report average over the last SECS\n"
491" -V, --version output version information\n"
492" -z, --zeros show entries with zero activity\n");
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000493 exit(-1);
494}
495
Stephen Hemminger404582c2013-09-24 11:54:45 -0700496static const struct option longopts[] = {
497 { "help", 0, 0, 'h' },
498 { "ignore", 0, 0, 'a' },
499 { "scan", 1, 0, 'd'},
500 { "nooutput", 0, 0, 'n' },
501 { "json", 0, 0, 'j' },
502 { "reset", 0, 0, 'r' },
503 { "noupdate", 0, 0, 's' },
504 { "interval", 1, 0, 't' },
505 { "version", 0, 0, 'V' },
506 { "zeros", 0, 0, 'z' },
507 { 0 }
508};
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000509
510int main(int argc, char *argv[])
511{
Stephen Hemminger896ebd62009-12-26 10:21:13 -0800512 char *hist_name;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000513 struct sockaddr_un sun;
514 FILE *hist_fp = NULL;
515 int ch;
516 int fd;
517
Stephen Hemminger404582c2013-09-24 11:54:45 -0700518 while ((ch = getopt_long(argc, argv, "h?vVzrnasd:t:j",
519 longopts, NULL)) != EOF) {
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000520 switch(ch) {
521 case 'z':
522 dump_zeros = 1;
523 break;
524 case 'r':
525 reset_history = 1;
526 break;
527 case 'a':
528 ignore_history = 1;
529 break;
530 case 's':
531 no_update = 1;
532 break;
533 case 'n':
534 no_output = 1;
535 break;
536 case 'd':
537 scan_interval = 1000*atoi(optarg);
538 break;
539 case 't':
540 if (sscanf(optarg, "%d", &time_constant) != 1 ||
541 time_constant <= 0) {
542 fprintf(stderr, "nstat: invalid time constant divisor\n");
543 exit(-1);
544 }
545 break;
Stephen Hemmingerd48ed3f2013-09-13 10:31:41 -0700546 case 'j':
547 json_output = 1;
548 break;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000549 case 'v':
550 case 'V':
551 printf("nstat utility, iproute2-ss%s\n", SNAPSHOT);
552 exit(0);
553 case 'h':
554 case '?':
555 default:
556 usage();
557 }
558 }
559
560 argc -= optind;
561 argv += optind;
562
563 sun.sun_family = AF_UNIX;
564 sun.sun_path[0] = 0;
565 sprintf(sun.sun_path+1, "nstat%d", getuid());
566
567 if (scan_interval > 0) {
568 if (time_constant == 0)
569 time_constant = 60;
570 time_constant *= 1000;
571 W = 1 - 1/exp(log(10)*(double)scan_interval/time_constant);
572 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
573 perror("nstat: socket");
574 exit(-1);
575 }
576 if (bind(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) < 0) {
577 perror("nstat: bind");
578 exit(-1);
579 }
580 if (listen(fd, 5) < 0) {
581 perror("nstat: listen");
582 exit(-1);
583 }
Mike Frysingera7a9ddb2009-11-06 06:04:39 -0500584 if (daemon(0, 0)) {
585 perror("nstat: daemon");
586 exit(-1);
587 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000588 signal(SIGPIPE, SIG_IGN);
589 signal(SIGCHLD, sigchild);
590 server_loop(fd);
591 exit(0);
592 }
593
594 patterns = argv;
595 npatterns = argc;
596
Stephen Hemminger896ebd62009-12-26 10:21:13 -0800597 if ((hist_name = getenv("NSTAT_HISTORY")) == NULL) {
598 hist_name = malloc(128);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000599 sprintf(hist_name, "/tmp/.nstat.u%d", getuid());
Stephen Hemminger896ebd62009-12-26 10:21:13 -0800600 }
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000601
602 if (reset_history)
603 unlink(hist_name);
604
605 if (!ignore_history || !no_update) {
606 struct stat stb;
607
608 fd = open(hist_name, O_RDWR|O_CREAT|O_NOFOLLOW, 0600);
609 if (fd < 0) {
610 perror("nstat: open history file");
611 exit(-1);
612 }
613 if ((hist_fp = fdopen(fd, "r+")) == NULL) {
614 perror("nstat: fdopen history file");
615 exit(-1);
616 }
617 if (flock(fileno(hist_fp), LOCK_EX)) {
618 perror("nstat: flock history file");
619 exit(-1);
620 }
621 if (fstat(fileno(hist_fp), &stb) != 0) {
622 perror("nstat: fstat history file");
623 exit(-1);
624 }
625 if (stb.st_nlink != 1 || stb.st_uid != getuid()) {
626 fprintf(stderr, "nstat: something is so wrong with history file, that I prefer not to proceed.\n");
627 exit(-1);
628 }
629 if (!ignore_history) {
630 FILE *tfp;
Dan McGee9a230772011-08-31 12:16:36 -0700631 long uptime = -1;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000632 if ((tfp = fopen("/proc/uptime", "r")) != NULL) {
633 if (fscanf(tfp, "%ld", &uptime) != 1)
634 uptime = -1;
635 fclose(tfp);
636 }
637 if (uptime >= 0 && time(NULL) >= stb.st_mtime+uptime) {
638 fprintf(stderr, "nstat: history is aged out, resetting\n");
639 ftruncate(fileno(hist_fp), 0);
640 }
641 }
642
643 load_good_table(hist_fp);
644
645 hist_db = kern_db;
646 kern_db = NULL;
647 }
648
649 if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) >= 0 &&
650 (connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0
651 || (strcpy(sun.sun_path+1, "nstat0"),
652 connect(fd, (struct sockaddr*)&sun, 2+1+strlen(sun.sun_path+1)) == 0))
653 && verify_forging(fd) == 0) {
654 FILE *sfp = fdopen(fd, "r");
655 load_good_table(sfp);
656 if (hist_db && source_mismatch) {
657 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
658 hist_db = NULL;
659 }
660 fclose(sfp);
661 } else {
662 if (fd >= 0)
663 close(fd);
664 if (hist_db && info_source[0] && strcmp(info_source, "kernel")) {
665 fprintf(stderr, "nstat: history is stale, ignoring it.\n");
666 hist_db = NULL;
667 info_source[0] = 0;
668 }
669 load_netstat();
670 load_snmp6();
671 load_snmp();
672 if (info_source[0] == 0)
673 strcpy(info_source, "kernel");
674 }
675
676 if (!no_output) {
677 if (ignore_history || hist_db == NULL)
678 dump_kern_db(stdout, 0);
679 else
680 dump_incr_db(stdout);
681 }
682 if (!no_update) {
683 ftruncate(fileno(hist_fp), 0);
684 rewind(hist_fp);
Stephen Hemminger404582c2013-09-24 11:54:45 -0700685
686 json_output = 0;
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000687 dump_kern_db(hist_fp, 1);
Stephen Hemminger404582c2013-09-24 11:54:45 -0700688 fclose(hist_fp);
osdl.org!shemmingeraba5acd2004-04-15 20:56:59 +0000689 }
690 exit(0);
691}