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