xref: /original-bsd/usr.bin/netstat/main.c (revision cd18b70b)
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.9 (Berkeley) 07/27/87";
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 /* ns protocols */
81 extern	int nsprotopr();
82 extern	int spp_stats(), idp_stats(), nserr_stats();
83 
84 #define NULLPROTOX	((struct protox *) 0)
85 struct protox {
86 	u_char	pr_index;		/* index into nlist of cb head */
87 	u_char	pr_sindex;		/* index into nlist of stat block */
88 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
89 	int	(*pr_cblocks)();	/* control blocks printing routine */
90 	int	(*pr_stats)();		/* statistics printing routine */
91 	char	*pr_name;		/* well-known name */
92 } protox[] = {
93 	{ N_TCB,	N_TCPSTAT,	1,	protopr,
94 	  tcp_stats,	"tcp" },
95 	{ N_UDB,	N_UDPSTAT,	1,	protopr,
96 	  udp_stats,	"udp" },
97 	{ -1,		N_IPSTAT,	1,	0,
98 	  ip_stats,	"ip" },
99 	{ -1,		N_ICMPSTAT,	1,	0,
100 	  icmp_stats,	"icmp" },
101 	{ -1,		-1,		0,	0,
102 	  0,		0 }
103 };
104 
105 struct protox nsprotox[] = {
106 	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
107 	  idp_stats,	"idp" },
108 	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
109 	  spp_stats,	"spp" },
110 	{ -1,		N_NSERR,	1,	0,
111 	  nserr_stats,	"ns_err" },
112 	{ -1,		-1,		0,	0,
113 	  0,		0 }
114 };
115 
116 struct	pte *Sysmap;
117 
118 char	*system = "/vmunix";
119 char	*kmemf = "/dev/kmem";
120 int	kmem;
121 int	kflag;
122 int	Aflag;
123 int	aflag;
124 int	hflag;
125 int	iflag;
126 int	mflag;
127 int	nflag;
128 int	pflag;
129 int	rflag;
130 int	sflag;
131 int	tflag;
132 int	interval;
133 char	*interface;
134 int	unit;
135 char	usage[] = "[ -Aaihmnrst ] [-f family] [-p proto] [-I interface] [ interval ] [ system ] [ core ]";
136 
137 int	af = AF_UNSPEC;
138 
139 extern	char *malloc();
140 extern	off_t lseek();
141 
142 main(argc, argv)
143 	int argc;
144 	char *argv[];
145 {
146 	char *cp, *name;
147 	register struct protoent *p;
148 	register struct protox *tp;	/* for printing cblocks & stats */
149 	struct protox *name2protox();	/* for -p */
150 
151 	name = argv[0];
152 	argc--, argv++;
153   	while (argc > 0 && **argv == '-') {
154 		for (cp = &argv[0][1]; *cp; cp++)
155 		switch(*cp) {
156 
157 		case 'A':
158 			Aflag++;
159 			break;
160 
161 		case 'a':
162 			aflag++;
163 			break;
164 
165 		case 'h':
166 			hflag++;
167 			break;
168 
169 		case 'i':
170 			iflag++;
171 			break;
172 
173 		case 'm':
174 			mflag++;
175 			break;
176 
177 		case 'n':
178 			nflag++;
179 			break;
180 
181 		case 'r':
182 			rflag++;
183 			break;
184 
185 		case 's':
186 			sflag++;
187 			break;
188 
189 		case 't':
190 			tflag++;
191 			break;
192 
193 		case 'u':
194 			af = AF_UNIX;
195 			break;
196 
197 		case 'p':
198 			argv++;
199 			argc--;
200 			if (argc == 0)
201 				goto use;
202 			if ((tp = name2protox(*argv)) == NULLPROTOX) {
203 				fprintf(stderr, "%s: unknown or uninstrumented protocol\n",
204 					*argv);
205 				exit(10);
206 			}
207 			pflag++;
208 			break;
209 
210 		case 'f':
211 			argv++;
212 			argc--;
213 			if (strcmp(*argv, "ns") == 0)
214 				af = AF_NS;
215 			else if (strcmp(*argv, "inet") == 0)
216 				af = AF_INET;
217 			else if (strcmp(*argv, "unix") == 0)
218 				af = AF_UNIX;
219 			else {
220 				fprintf(stderr, "%s: unknown address family\n",
221 					*argv);
222 				exit(10);
223 			}
224 			break;
225 
226 		case 'I':
227 			iflag++;
228 			if (*(interface = cp + 1) == 0) {
229 				if ((interface = argv[1]) == 0)
230 					break;
231 				argv++;
232 				argc--;
233 			}
234 			for (cp = interface; isalpha(*cp); cp++)
235 				;
236 			unit = atoi(cp);
237 			*cp-- = 0;
238 			break;
239 
240 		default:
241 use:
242 			printf("usage: %s %s\n", name, usage);
243 			exit(1);
244 		}
245 		argv++, argc--;
246 	}
247 	if (argc > 0 && isdigit(argv[0][0])) {
248 		interval = atoi(argv[0]);
249 		if (interval <= 0)
250 			goto use;
251 		argv++, argc--;
252 		iflag++;
253 	}
254 	if (argc > 0) {
255 		system = *argv;
256 		argv++, argc--;
257 	}
258 	nlist(system, nl);
259 	if (nl[0].n_type == 0) {
260 		fprintf(stderr, "%s: no namelist\n", system);
261 		exit(1);
262 	}
263 	if (argc > 0) {
264 		kmemf = *argv;
265 		kflag++;
266 	}
267 	kmem = open(kmemf, 0);
268 	if (kmem < 0) {
269 		fprintf(stderr, "cannot open ");
270 		perror(kmemf);
271 		exit(1);
272 	}
273 	if (kflag) {
274 		off_t off;
275 
276 		off = nl[N_SYSMAP].n_value & 0x7fffffff;
277 		lseek(kmem, off, 0);
278 		nl[N_SYSSIZE].n_value *= 4;
279 		Sysmap = (struct pte *)malloc((u_int)nl[N_SYSSIZE].n_value);
280 		if (Sysmap == 0) {
281 			perror("Sysmap");
282 			exit(1);
283 		}
284 		read(kmem, (char *)Sysmap, (int)nl[N_SYSSIZE].n_value);
285 	}
286 	if (mflag) {
287 		mbpr((off_t)nl[N_MBSTAT].n_value);
288 		exit(0);
289 	}
290 	if (pflag) {
291 		if (tp->pr_stats)
292 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
293 				tp->pr_name);
294 		else
295 			printf("%s: no stats routine\n", tp->pr_name);
296 		exit(0);
297 	}
298 	/*
299 	 * Keep file descriptors open to avoid overhead
300 	 * of open/close on each call to get* routines.
301 	 */
302 	sethostent(1);
303 	setnetent(1);
304 	if (iflag) {
305 		intpr(interval, nl[N_IFNET].n_value);
306 		exit(0);
307 	}
308 	if (hflag) {
309 		hostpr(nl[N_HOSTS].n_value);
310 		exit(0);
311 	}
312 	if (rflag) {
313 		if (sflag)
314 			rt_stats((off_t)nl[N_RTSTAT].n_value);
315 		else
316 			routepr((off_t)nl[N_RTHOST].n_value,
317 				(off_t)nl[N_RTNET].n_value,
318 				(off_t)nl[N_RTHASHSIZE].n_value);
319 		exit(0);
320 	}
321     if (af == AF_INET || af == AF_UNSPEC) {
322 	setprotoent(1);
323 	setservent(1);
324 	while (p = getprotoent()) {
325 
326 		for (tp = protox; tp->pr_name; tp++)
327 			if (strcmp(tp->pr_name, p->p_name) == 0)
328 				break;
329 		if (tp->pr_name == 0 || tp->pr_wanted == 0)
330 			continue;
331 		if (sflag) {
332 			if (tp->pr_stats)
333 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
334 					p->p_name);
335 		} else
336 			if (tp->pr_cblocks)
337 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
338 					p->p_name);
339 	}
340 	endprotoent();
341     }
342     if (af == AF_NS || af == AF_UNSPEC) {
343 	for (tp = nsprotox; tp->pr_name; tp++) {
344 		if (sflag) {
345 			if (tp->pr_stats)
346 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
347 					tp->pr_name);
348 		} else
349 			if (tp->pr_cblocks)
350 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
351 					tp->pr_name);
352 	}
353     }
354     if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
355 	    unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value,
356 		(struct protosw *)nl[N_UNIXSW].n_value);
357     exit(0);
358 }
359 
360 /*
361  * Seek into the kernel for a value.
362  */
363 off_t
364 klseek(fd, base, off)
365 	int fd, off;
366 	off_t base;
367 {
368 	if (kflag) {
369 		/* get kernel pte */
370 		base &= ~KERNBASE;
371 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
372 	}
373 	return (lseek(fd, base, off));
374 }
375 
376 char *
377 plural(n)
378 	int n;
379 {
380 
381 	return (n != 1 ? "s" : "");
382 }
383 
384 /*
385  * Find the protox for the given "well-known" name.
386  */
387 struct protox *
388 knownname(name)
389 	char *name;
390 {
391 	struct protox *tp;
392 
393 	for (tp = protox; tp->pr_name; tp++)
394 		if (strcmp(tp->pr_name, name) == 0)
395 			return(tp);
396 	for (tp = nsprotox; tp->pr_name; tp++)
397 		if (strcmp(tp->pr_name, name) == 0)
398 			return(tp);
399 	return(NULLPROTOX);
400 }
401 
402 /*
403  * Find the protox corresponding to name.
404  */
405 struct protox *
406 name2protox(name)
407 	char *name;
408 {
409 	struct protox *tp;
410 	char **alias;			/* alias from p->aliases */
411 	struct protoent *p;
412 
413 	/*
414 	 * Try to find the name in the list of "well-known" names. If that
415 	 * fails, check if name is an alias for an Internet protocol.
416 	 */
417 	if (tp = knownname(name))
418 		return(tp);
419 
420 	setprotoent(1);			/* make protocol lookup cheaper */
421 	while (p = getprotoent()) {
422 		/* assert: name not same as p->name */
423 		for (alias = p->p_aliases; *alias; alias++)
424 			if (strcmp(name, *alias) == 0) {
425 				endprotoent();
426 				return(knownname(p->p_name));
427 			}
428 	}
429 	endprotoent();
430 	return(NULLPROTOX);
431 }
432