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