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