xref: /original-bsd/usr.bin/netstat/main.c (revision 8fe8c1c5)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)main.c	5.2 (Berkeley) 08/16/85";
15 #endif not lint
16 
17 #include <sys/param.h>
18 #include <sys/vmmac.h>
19 #include <sys/socket.h>
20 #include <machine/pte.h>
21 #include <ctype.h>
22 #include <errno.h>
23 #include <netdb.h>
24 #include <nlist.h>
25 #include <stdio.h>
26 
27 struct nlist nl[] = {
28 #define	N_MBSTAT	0
29 	{ "_mbstat" },
30 #define	N_IPSTAT	1
31 	{ "_ipstat" },
32 #define	N_TCB		2
33 	{ "_tcb" },
34 #define	N_TCPSTAT	3
35 	{ "_tcpstat" },
36 #define	N_UDB		4
37 	{ "_udb" },
38 #define	N_UDPSTAT	5
39 	{ "_udpstat" },
40 #define	N_RAWCB		6
41 	{ "_rawcb" },
42 #define	N_SYSMAP	7
43 	{ "_Sysmap" },
44 #define	N_SYSSIZE	8
45 	{ "_Syssize" },
46 #define	N_IFNET		9
47 	{ "_ifnet" },
48 #define	N_HOSTS		10
49 	{ "_hosts" },
50 #define	N_RTHOST	11
51 	{ "_rthost" },
52 #define	N_RTNET		12
53 	{ "_rtnet" },
54 #define	N_ICMPSTAT	13
55 	{ "_icmpstat" },
56 #define	N_RTSTAT	14
57 	{ "_rtstat" },
58 #define	N_NFILE		15
59 	{ "_nfile" },
60 #define	N_FILE		16
61 	{ "_file" },
62 #define	N_UNIXSW	17
63 	{ "_unixsw" },
64 #define N_RTHASHSIZE	18
65 	{ "_rthashsize" },
66 #define N_IDP		19
67 	{ "_nspcb"},
68 #define N_IDPSTAT	20
69 	{ "_idpstat"},
70 #define N_SPPSTAT	21
71 	{ "_spp_istat"},
72 #define N_NSERR		22
73 	{ "_ns_errstat"},
74 	"",
75 };
76 
77 /* internet protocols */
78 extern	int protopr();
79 extern	int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
80 extern	int nsprotopr();
81 extern	int spp_stats(), idp_stats(), nserr_stats();
82 
83 struct protox {
84 	u_char	pr_index;		/* index into nlist of cb head */
85 	u_char	pr_sindex;		/* index into nlist of stat block */
86 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
87 	int	(*pr_cblocks)();	/* control blocks printing routine */
88 	int	(*pr_stats)();		/* statistics printing routine */
89 	char	*pr_name;		/* well-known name */
90 } protox[] = {
91 	{ N_TCB,	N_TCPSTAT,	1,	protopr,
92 	  tcp_stats,	"tcp" },
93 	{ N_UDB,	N_UDPSTAT,	1,	protopr,
94 	  udp_stats,	"udp" },
95 	{ -1,		N_IPSTAT,	1,	0,
96 	  ip_stats,	"ip" },
97 	{ -1,		N_ICMPSTAT,	1,	0,
98 	  icmp_stats,	"icmp" },
99 	{ -1,		-1,		0,	0,
100 	  0,		0 }
101 };
102 
103 struct protox nsprotox[] = {
104 	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
105 	  idp_stats,	"idp" },
106 	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
107 	  spp_stats,	"spp" },
108 	{ -1,		N_NSERR,	1,	0,
109 	  nserr_stats,	"ns_err" },
110 	{ -1,		-1,		0,	0,
111 	  0,		0 }
112 };
113 
114 struct	pte *Sysmap;
115 
116 char	*system = "/vmunix";
117 char	*kmemf = "/dev/kmem";
118 int	kmem;
119 int	kflag;
120 int	Aflag;
121 int	aflag;
122 int	hflag;
123 int	iflag;
124 int	mflag;
125 int	nflag;
126 int	rflag;
127 int	sflag;
128 int	tflag;
129 int	uflag;
130 int	fflag;
131 int	interval;
132 char	*interface;
133 int	unit;
134 char	usage[] = "[ -Aaihmnrstu ] [-f address_family] [-I interface] [ interval ] [ system ] [ core ]";
135 
136 int	af = AF_UNSPEC;
137 main(argc, argv)
138 	int argc;
139 	char *argv[];
140 {
141 	int i;
142 	char *cp, *name;
143 	register struct protoent *p;
144 	register struct protox *tp;
145 
146 	name = argv[0];
147 	argc--, argv++;
148   	while (argc > 0 && **argv == '-') {
149 		for (cp = &argv[0][1]; *cp; cp++)
150 		switch(*cp) {
151 
152 		case 'A':
153 			Aflag++;
154 			break;
155 
156 		case 'a':
157 			aflag++;
158 			break;
159 
160 		case 'h':
161 			hflag++;
162 			break;
163 
164 		case 'i':
165 			iflag++;
166 			break;
167 
168 		case 'm':
169 			mflag++;
170 			break;
171 
172 		case 'n':
173 			nflag++;
174 			break;
175 
176 		case 'r':
177 			rflag++;
178 			break;
179 
180 		case 's':
181 			sflag++;
182 			break;
183 
184 		case 't':
185 			tflag++;
186 			break;
187 
188 		case 'u':
189 			uflag++;
190 			break;
191 
192 		case 'f':
193 			argv++;
194 			argc--;
195 			if (strcmp(*argv,"ns")==0) {
196 				af = AF_NS;
197 			} else if (strcmp(*argv,"inet")==0) {
198 				af = AF_INET;
199 			}
200 			break;
201 
202 		case 'I':
203 			iflag++;
204 			if (*(interface = cp + 1) == 0) {
205 				if ((interface = argv[1]) == 0)
206 					break;
207 				argv++;
208 				argc--;
209 			}
210 			for (cp = interface; isalpha(*cp); cp++)
211 				;
212 			unit = atoi(cp);
213 			*cp-- = 0;
214 			break;
215 
216 		default:
217 use:
218 			printf("usage: %s %s\n", name, usage);
219 			exit(1);
220 		}
221 		argv++, argc--;
222 	}
223 	if (argc > 0 && isdigit(argv[0][0])) {
224 		interval = atoi(argv[0]);
225 		if (interval <= 0)
226 			goto use;
227 		argv++, argc--;
228 		iflag++;
229 	}
230 	if (argc > 0) {
231 		system = *argv;
232 		argv++, argc--;
233 	}
234 	nlist(system, nl);
235 	if (nl[0].n_type == 0) {
236 		fprintf(stderr, "%s: no namelist\n", system);
237 		exit(1);
238 	}
239 	if (argc > 0) {
240 		kmemf = *argv;
241 		kflag++;
242 	}
243 	kmem = open(kmemf, 0);
244 	if (kmem < 0) {
245 		fprintf(stderr, "cannot open ");
246 		perror(kmemf);
247 		exit(1);
248 	}
249 	if (kflag) {
250 		off_t off;
251 
252 		off = nl[N_SYSMAP].n_value & 0x7fffffff;
253 		lseek(kmem, off, 0);
254 		nl[N_SYSSIZE].n_value *= 4;
255 		Sysmap = (struct pte *)malloc(nl[N_SYSSIZE].n_value);
256 		if (Sysmap == 0) {
257 			perror("Sysmap");
258 			exit(1);
259 		}
260 		read(kmem, Sysmap, nl[N_SYSSIZE].n_value);
261 	}
262 	if (mflag) {
263 		mbpr(nl[N_MBSTAT].n_value);
264 		exit(0);
265 	}
266 	if (uflag) {
267 		unixpr(nl[N_NFILE].n_value, nl[N_FILE].n_value,
268 		    nl[N_UNIXSW].n_value);
269 		exit(0);
270 	}
271 	/*
272 	 * Keep file descriptors open to avoid overhead
273 	 * of open/close on each call to get* routines.
274 	 */
275 	sethostent(1);
276 	setnetent(1);
277 	if (iflag) {
278 		intpr(interval, nl[N_IFNET].n_value);
279 		exit(0);
280 	}
281 	if (hflag) {
282 		hostpr(nl[N_HOSTS].n_value);
283 		exit(0);
284 	}
285 	if (rflag) {
286 		if (sflag)
287 			rt_stats(nl[N_RTSTAT].n_value);
288 		else
289 			routepr(nl[N_RTHOST].n_value, nl[N_RTNET].n_value,
290 				nl[N_RTHASHSIZE].n_value);
291 		exit(0);
292 	}
293     if (af == AF_INET || af == AF_UNSPEC) {
294 	setprotoent(1);
295 	setservent(1);
296 	while (p = getprotoent()) {
297 
298 		for (tp = protox; tp->pr_name; tp++)
299 			if (strcmp(tp->pr_name, p->p_name) == 0)
300 				break;
301 		if (tp->pr_name == 0 || tp->pr_wanted == 0)
302 			continue;
303 		if (sflag && tp->pr_stats) {
304 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value, p->p_name);
305 			continue;
306 		}
307 		if (tp->pr_cblocks)
308 			(*tp->pr_cblocks)(nl[tp->pr_index].n_value, p->p_name);
309 	}
310 	endprotoent();
311     }
312     if (af == AF_NS || af == AF_UNSPEC) {
313 	for (tp = nsprotox; tp->pr_name; tp++) {
314 		if (sflag && tp->pr_stats) {
315 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value, tp->pr_name);
316 			continue;
317 		}
318 		if (tp->pr_cblocks)
319 			(*tp->pr_cblocks)(nl[tp->pr_index].n_value, tp->pr_name);
320 	}
321     }
322 }
323 
324 /*
325  * Seek into the kernel for a value.
326  */
327 klseek(fd, base, off)
328 	int fd, base, off;
329 {
330 
331 	if (kflag) {
332 		/* get kernel pte */
333 #ifdef vax
334 		base &= 0x7fffffff;
335 #endif
336 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
337 	}
338 	lseek(fd, base, off);
339 }
340 
341 char *
342 plural(n)
343 	int n;
344 {
345 
346 	return (n != 1 ? "s" : "");
347 }
348