xref: /original-bsd/usr.bin/netstat/main.c (revision f1324ba5)
1 /*
2  * Copyright (c) 1983, 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)main.c	5.14 (Berkeley) 06/29/88";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/vmmac.h>
30 #include <sys/socket.h>
31 #include <sys/file.h>
32 #include <machine/pte.h>
33 #include <ctype.h>
34 #include <errno.h>
35 #include <netdb.h>
36 #include <nlist.h>
37 #include <stdio.h>
38 
39 struct nlist nl[] = {
40 #define	N_MBSTAT	0
41 	{ "_mbstat" },
42 #define	N_IPSTAT	1
43 	{ "_ipstat" },
44 #define	N_TCB		2
45 	{ "_tcb" },
46 #define	N_TCPSTAT	3
47 	{ "_tcpstat" },
48 #define	N_UDB		4
49 	{ "_udb" },
50 #define	N_UDPSTAT	5
51 	{ "_udpstat" },
52 #define	N_RAWCB		6
53 	{ "_rawcb" },
54 #define	N_SYSMAP	7
55 	{ "_Sysmap" },
56 #define	N_SYSSIZE	8
57 	{ "_Syssize" },
58 #define	N_IFNET		9
59 	{ "_ifnet" },
60 #define	N_IMP		10
61 	{ "_imp_softc" },
62 #define	N_RTHOST	11
63 	{ "_rthost" },
64 #define	N_RTNET		12
65 	{ "_rtnet" },
66 #define	N_ICMPSTAT	13
67 	{ "_icmpstat" },
68 #define	N_RTSTAT	14
69 	{ "_rtstat" },
70 #define	N_NFILE		15
71 	{ "_nfile" },
72 #define	N_FILE		16
73 	{ "_file" },
74 #define	N_UNIXSW	17
75 	{ "_unixsw" },
76 #define N_RTHASHSIZE	18
77 	{ "_rthashsize" },
78 #define N_IDP		19
79 	{ "_nspcb"},
80 #define N_IDPSTAT	20
81 	{ "_idpstat"},
82 #define N_SPPSTAT	21
83 	{ "_spp_istat"},
84 #define N_NSERR		22
85 	{ "_ns_errstat"},
86 #define N_NIMP		23
87 	{ "_nimp"},
88 	"",
89 };
90 
91 /* internet protocols */
92 extern	int protopr();
93 extern	int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
94 /* ns protocols */
95 extern	int nsprotopr();
96 extern	int spp_stats(), idp_stats(), nserr_stats();
97 
98 #define NULLPROTOX	((struct protox *) 0)
99 struct protox {
100 	u_char	pr_index;		/* index into nlist of cb head */
101 	u_char	pr_sindex;		/* index into nlist of stat block */
102 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
103 	int	(*pr_cblocks)();	/* control blocks printing routine */
104 	int	(*pr_stats)();		/* statistics printing routine */
105 	char	*pr_name;		/* well-known name */
106 } protox[] = {
107 	{ N_TCB,	N_TCPSTAT,	1,	protopr,
108 	  tcp_stats,	"tcp" },
109 	{ N_UDB,	N_UDPSTAT,	1,	protopr,
110 	  udp_stats,	"udp" },
111 	{ -1,		N_IPSTAT,	1,	0,
112 	  ip_stats,	"ip" },
113 	{ -1,		N_ICMPSTAT,	1,	0,
114 	  icmp_stats,	"icmp" },
115 	{ -1,		-1,		0,	0,
116 	  0,		0 }
117 };
118 
119 struct protox nsprotox[] = {
120 	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
121 	  idp_stats,	"idp" },
122 	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
123 	  spp_stats,	"spp" },
124 	{ -1,		N_NSERR,	1,	0,
125 	  nserr_stats,	"ns_err" },
126 	{ -1,		-1,		0,	0,
127 	  0,		0 }
128 };
129 
130 struct	pte *Sysmap;
131 
132 char	*system = "/vmunix";
133 char	*kmemf = "/dev/kmem";
134 int	kmem;
135 int	kflag;
136 int	Aflag;
137 int	aflag;
138 int	hflag;
139 int	iflag;
140 int	mflag;
141 int	nflag;
142 int	pflag;
143 int	rflag;
144 int	sflag;
145 int	tflag;
146 int	dflag;
147 int	interval;
148 char	*interface;
149 int	unit;
150 
151 int	af = AF_UNSPEC;
152 
153 extern	char *malloc();
154 extern	off_t lseek();
155 
156 main(argc, argv)
157 	int argc;
158 	char *argv[];
159 {
160 	extern char *optarg;
161 	extern int optind;
162 	register struct protoent *p;
163 	register struct protox *tp;	/* for printing cblocks & stats */
164 	struct protox *name2protox();	/* for -p */
165 	int ch;
166 
167 	while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF)
168 		switch((char)ch) {
169 		case 'A':
170 			Aflag++;
171 			break;
172 		case 'I': {
173 			char *cp;
174 
175 			iflag++;
176 			for (cp = interface = optarg; isalpha(*cp); cp++);
177 			unit = atoi(cp);
178 			*cp = '\0';
179 			break;
180 		}
181 		case 'a':
182 			aflag++;
183 			break;
184 		case 'd':
185 			dflag++;
186 			break;
187 		case 'f':
188 			if (strcmp(optarg, "ns") == 0)
189 				af = AF_NS;
190 			else if (strcmp(optarg, "inet") == 0)
191 				af = AF_INET;
192 			else if (strcmp(optarg, "unix") == 0)
193 				af = AF_UNIX;
194 			else {
195 				fprintf(stderr, "%s: unknown address family\n", optarg);
196 				exit(10);
197 			}
198 			break;
199 		case 'h':
200 			hflag++;
201 			break;
202 		case 'i':
203 			iflag++;
204 			break;
205 		case 'm':
206 			mflag++;
207 			break;
208 		case 'n':
209 			nflag++;
210 			break;
211 		case 'p':
212 			if ((tp = name2protox(optarg)) == NULLPROTOX) {
213 				fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg);
214 				exit(10);
215 			}
216 			pflag++;
217 			break;
218 		case 'r':
219 			rflag++;
220 			break;
221 		case 's':
222 			sflag++;
223 			break;
224 		case 't':
225 			tflag++;
226 			break;
227 		case 'u':
228 			af = AF_UNIX;
229 			break;
230 		case '?':
231 		default:
232 			usage();
233 		}
234 	argv += optind;
235 	argc -= optind;
236 
237 	if (argc > 0) {
238 		if (isdigit(argv[0][0])) {
239 			interval = atoi(argv[0]);
240 			if (interval <= 0)
241 				usage();
242 			argv++, argc--;
243 			iflag++;
244 		}
245 		if (argc > 0) {
246 			system = *argv;
247 			argv++, argc--;
248 			if (argc > 0) {
249 				kmemf = *argv;
250 				kflag++;
251 			}
252 		}
253 	}
254 	if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
255 		fprintf(stderr, "%s: no namelist\n", system);
256 		exit(1);
257 	}
258 	kmem = open(kmemf, O_RDONLY);
259 	if (kmem < 0) {
260 		perror(kmemf);
261 		exit(1);
262 	}
263 	if (kflag) {
264 		off_t off;
265 
266 		Sysmap = (struct pte *)
267 		   malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
268 		if (!Sysmap) {
269 			fputs("netstat: can't get memory for Sysmap.\n", stderr);
270 			exit(1);
271 		}
272 		off = nl[N_SYSMAP].n_value & ~KERNBASE;
273 		(void)lseek(kmem, off, L_SET);
274 		(void)read(kmem, (char *)Sysmap,
275 		    (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
276 	}
277 	if (mflag) {
278 		mbpr((off_t)nl[N_MBSTAT].n_value);
279 		exit(0);
280 	}
281 	if (pflag) {
282 		if (tp->pr_stats)
283 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
284 				tp->pr_name);
285 		else
286 			printf("%s: no stats routine\n", tp->pr_name);
287 		exit(0);
288 	}
289 	if (hflag) {
290 		hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value);
291 		exit(0);
292 	}
293 	/*
294 	 * Keep file descriptors open to avoid overhead
295 	 * of open/close on each call to get* routines.
296 	 */
297 	sethostent(1);
298 	setnetent(1);
299 	if (iflag) {
300 		intpr(interval, nl[N_IFNET].n_value);
301 		exit(0);
302 	}
303 	if (rflag) {
304 		if (sflag)
305 			rt_stats((off_t)nl[N_RTSTAT].n_value);
306 		else
307 			routepr((off_t)nl[N_RTHOST].n_value,
308 				(off_t)nl[N_RTNET].n_value,
309 				(off_t)nl[N_RTHASHSIZE].n_value);
310 		exit(0);
311 	}
312     if (af == AF_INET || af == AF_UNSPEC) {
313 	setprotoent(1);
314 	setservent(1);
315 	while (p = getprotoent()) {
316 
317 		for (tp = protox; tp->pr_name; tp++)
318 			if (strcmp(tp->pr_name, p->p_name) == 0)
319 				break;
320 		if (tp->pr_name == 0 || tp->pr_wanted == 0)
321 			continue;
322 		if (sflag) {
323 			if (tp->pr_stats)
324 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
325 					p->p_name);
326 		} else
327 			if (tp->pr_cblocks)
328 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
329 					p->p_name);
330 	}
331 	endprotoent();
332     }
333     if (af == AF_NS || af == AF_UNSPEC) {
334 	for (tp = nsprotox; tp->pr_name; tp++) {
335 		if (sflag) {
336 			if (tp->pr_stats)
337 				(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
338 					tp->pr_name);
339 		} else
340 			if (tp->pr_cblocks)
341 				(*tp->pr_cblocks)(nl[tp->pr_index].n_value,
342 					tp->pr_name);
343 	}
344     }
345     if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
346 	    unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value,
347 		(struct protosw *)nl[N_UNIXSW].n_value);
348     if (af == AF_UNSPEC && sflag)
349 	impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value);
350     exit(0);
351 }
352 
353 /*
354  * Seek into the kernel for a value.
355  */
356 off_t
357 klseek(fd, base, off)
358 	int fd, off;
359 	off_t base;
360 {
361 	if (kflag) {
362 		/* get kernel pte */
363 		base &= ~KERNBASE;
364 		base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
365 	}
366 	return (lseek(fd, base, off));
367 }
368 
369 char *
370 plural(n)
371 	int n;
372 {
373 
374 	return (n != 1 ? "s" : "");
375 }
376 
377 /*
378  * Find the protox for the given "well-known" name.
379  */
380 struct protox *
381 knownname(name)
382 	char *name;
383 {
384 	struct protox *tp;
385 
386 	for (tp = protox; tp->pr_name; tp++)
387 		if (strcmp(tp->pr_name, name) == 0)
388 			return(tp);
389 	for (tp = nsprotox; tp->pr_name; tp++)
390 		if (strcmp(tp->pr_name, name) == 0)
391 			return(tp);
392 	return(NULLPROTOX);
393 }
394 
395 /*
396  * Find the protox corresponding to name.
397  */
398 struct protox *
399 name2protox(name)
400 	char *name;
401 {
402 	struct protox *tp;
403 	char **alias;			/* alias from p->aliases */
404 	struct protoent *p;
405 
406 	/*
407 	 * Try to find the name in the list of "well-known" names. If that
408 	 * fails, check if name is an alias for an Internet protocol.
409 	 */
410 	if (tp = knownname(name))
411 		return(tp);
412 
413 	setprotoent(1);			/* make protocol lookup cheaper */
414 	while (p = getprotoent()) {
415 		/* assert: name not same as p->name */
416 		for (alias = p->p_aliases; *alias; alias++)
417 			if (strcmp(name, *alias) == 0) {
418 				endprotoent();
419 				return(knownname(p->p_name));
420 			}
421 	}
422 	endprotoent();
423 	return(NULLPROTOX);
424 }
425 
426 usage()
427 {
428 	fputs("usage: netstat [-Aan] [-f address_family] [system] [core]\n               [-himnrs] [-f address_family] [system] [core]\n               [-n] [-I interface] interval [system] [core]\n", stderr);
429 	exit(1);
430 }
431