xref: /minix3/usr.bin/netstat/main.c (revision c3b6f8f269dded933641674db559d1ecea71d5f1)
1 /*	$NetBSD: main.c,v 1.95 2014/11/12 03:34:59 christos Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1988, 1993
5  *	Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 #ifndef lint
34 __COPYRIGHT("@(#) Copyright (c) 1983, 1988, 1993\
35  Regents of the University of California.  All rights reserved.");
36 #endif /* not lint */
37 
38 #ifndef lint
39 #if 0
40 static char sccsid[] = "from: @(#)main.c	8.4 (Berkeley) 3/1/94";
41 #else
42 __RCSID("$NetBSD: main.c,v 1.95 2014/11/12 03:34:59 christos Exp $");
43 #endif
44 #endif /* not lint */
45 
46 #include <sys/param.h>
47 #include <sys/file.h>
48 #include <sys/protosw.h>
49 #include <sys/socket.h>
50 
51 #include <net/if.h>
52 #include <netinet/in.h>
53 
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <kvm.h>
58 #include <limits.h>
59 #include <netdb.h>
60 #include <nlist.h>
61 #include <paths.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <unistd.h>
66 #include "netstat.h"
67 #include "rtutil.h"
68 #include "prog_ops.h"
69 
70 struct nlist nl[] = {
71 #define	N_MBSTAT	0
72 	{ "_mbstat", 0, 0, 0, 0 },
73 #define	N_IPSTAT	1
74 	{ "_ipstat", 0, 0, 0, 0 },	/* not available via kvm */
75 #define	N_TCBTABLE	2
76 	{ "_tcbtable", 0, 0, 0, 0 },
77 #define	N_TCPSTAT	3
78 	{ "_tcpstat", 0, 0, 0, 0 },	/* not available via kvm */
79 #define	N_UDBTABLE	4
80 	{ "_udbtable", 0, 0, 0, 0 },
81 #define	N_UDPSTAT	5
82 	{ "_udpstat", 0, 0, 0, 0 },	/* not available via kvm */
83 #define	N_IFNET_LIST		6
84 	{ "_ifnet_list", 0, 0, 0, 0 },
85 #define	N_ICMPSTAT	7
86 	{ "_icmpstat", 0, 0, 0, 0 },	/* not available via kvm */
87 #define	N_RTSTAT	8
88 	{ "_rtstat", 0, 0, 0, 0 },
89 #define	N_UNIXSW	9
90 	{ "_unixsw", 0, 0, 0, 0 },
91 #define N_RTREE		10
92 	{ "_rt_tables", 0, 0, 0, 0 },
93 #define	N_NFILE		11
94 	{ "_nfile", 0, 0, 0, 0 },
95 #define N_IGMPSTAT	12
96 	{ "_igmpstat", 0, 0, 0, 0 },	/* not available via kvm */
97 #define N_MRTPROTO	13
98 	{ "_ip_mrtproto", 0, 0, 0, 0 },
99 #define N_MRTSTAT	14
100 	{ "_mrtstat", 0, 0, 0, 0 },
101 #define N_MFCHASHTBL	15
102 	{ "_mfchashtbl", 0, 0, 0, 0 },
103 #define	N_MFCHASH	16
104 	{ "_mfchash", 0, 0, 0, 0 },
105 #define N_VIFTABLE	17
106 	{ "_viftable", 0, 0, 0, 0 },
107 #define N_MSIZE		18
108 	{ "_msize", 0, 0, 0, 0 },
109 #define N_MCLBYTES	19
110 	{ "_mclbytes", 0, 0, 0, 0 },
111 #define N_DDPSTAT	20
112 	{ "_ddpstat", 0, 0, 0, 0 },	/* not available via kvm */
113 #define N_DDPCB		21
114 	{ "_ddpcb", 0, 0, 0, 0 },
115 #define N_MBPOOL	22
116 	{ "_mbpool", 0, 0, 0, 0 },
117 #define N_MCLPOOL	23
118 	{ "_mclpool", 0, 0, 0, 0 },
119 #define N_IP6STAT	24
120 	{ "_ip6stat", 0, 0, 0, 0 },	/* not available via kvm */
121 #define N_TCP6STAT	25
122 	{ "_tcp6stat", 0, 0, 0, 0 },	/* not available via kvm */
123 #define N_UDP6STAT	26
124 	{ "_udp6stat", 0, 0, 0, 0 },	/* not available via kvm */
125 #define N_ICMP6STAT	27
126 	{ "_icmp6stat", 0, 0, 0, 0 },	/* not available via kvm */
127 #define N_IPSECSTAT	28
128 	{ "_ipsecstat", 0, 0, 0, 0 },	/* not available via kvm */
129 #define N_IPSEC6STAT	29
130 	{ "_ipsec6stat", 0, 0, 0, 0 },	/* not available via kvm */
131 #define N_PIM6STAT	30
132 	{ "_pim6stat", 0, 0, 0, 0 },	/* not available via kvm */
133 #define N_MRT6PROTO	31
134 	{ "_ip6_mrtproto", 0, 0, 0, 0 },
135 #define N_MRT6STAT	32
136 	{ "_mrt6stat", 0, 0, 0, 0 },
137 #define N_MF6CTABLE	33
138 	{ "_mf6ctable", 0, 0, 0, 0 },
139 #define N_MIF6TABLE	34
140 	{ "_mif6table", 0, 0, 0, 0 },
141 #define N_PFKEYSTAT	35
142 	{ "_pfkeystat", 0, 0, 0, 0 },	/* not available via kvm */
143 #define N_ARPSTAT	36
144 	{ "_arpstat", 0, 0, 0, 0 },	/* not available via kvm */
145 #define N_RIP6STAT	37
146 	{ "_rip6stat", 0, 0, 0, 0 },	/* not available via kvm */
147 #define	N_ARPINTRQ	38
148 	{ "_arpintrq", 0, 0, 0, 0 },
149 #define	N_IPINTRQ	39
150 	{ "_ipintrq", 0, 0, 0, 0 },
151 #define	N_IP6INTRQ	40
152 	{ "_ip6intrq", 0, 0, 0, 0 },
153 #define	N_ATINTRQ1	41
154 	{ "_atintrq1", 0, 0, 0, 0 },
155 #define	N_ATINTRQ2	42
156 	{ "_atintrq2", 0, 0, 0, 0 },
157 #define	N_NSINTRQ	43
158 	{ "_nsintrq", 0, 0, 0, 0 },
159 #define	N_LLCINTRQ	44
160 	{ "_llcintrq", 0, 0, 0, 0 },
161 #define	N_HDINTRQ	45
162 	{ "_hdintrq", 0, 0, 0, 0 },
163 #define	N_NATMINTRQ	46
164 	{ "_natmintrq", 0, 0, 0, 0 },
165 #define	N_PPPOEDISCINQ	47
166 	{ "_ppoediscinq", 0, 0, 0, 0 },
167 #define	N_PPPOEINQ	48
168 	{ "_ppoeinq", 0, 0, 0, 0 },
169 #define	N_PKINTRQ	49
170 	{ "_pkintrq", 0, 0, 0, 0 },
171 #define	N_HARDCLOCK_TICKS 50
172 	{ "_hardclock_ticks", 0, 0, 0, 0 },
173 #define N_PIMSTAT	51
174 	{ "_pimstat", 0, 0, 0, 0 },
175 #define N_CARPSTAT	52
176 	{ "_carpstats", 0, 0, 0, 0 },	/* not available via kvm */
177 #define N_PFSYNCSTAT	53
178 	{ "_pfsyncstats", 0, 0, 0, 0},  /* not available via kvm */
179 	{ "", 0, 0, 0, 0 },
180 };
181 
182 struct protox {
183 	u_char	pr_index;		/* index into nlist of cb head */
184 	u_char	pr_sindex;		/* index into nlist of stat block */
185 	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
186 	void	(*pr_cblocks)		/* control blocks printing routine */
187 			__P((u_long, const char *));
188 	void	(*pr_stats)		/* statistics printing routine */
189 			__P((u_long, const char *));
190 	void	(*pr_istats)
191 			__P((const char *));	/* per/if statistics printing routine */
192 	void	(*pr_dump)		/* PCB state dump routine */
193 			__P((u_long, const char *, u_long));
194 	const char *pr_name;		/* well-known name */
195 } protox[] = {
196 	{ N_TCBTABLE,	N_TCPSTAT,	1,	protopr,
197 	  tcp_stats,	NULL,		tcp_dump,	"tcp" },
198 	{ N_UDBTABLE,	N_UDPSTAT,	1,	protopr,
199 	  udp_stats,	NULL,		0,	"udp" },
200 	{ -1,		N_IPSTAT,	1,	0,
201 	  ip_stats,	NULL,		0,	"ip" },
202 	{ -1,		N_ICMPSTAT,	1,	0,
203 	  icmp_stats,	NULL,		0,	"icmp" },
204 	{ -1,		N_IGMPSTAT,	1,	0,
205 	  igmp_stats,	NULL,		0,	"igmp" },
206 	{ -1,		N_CARPSTAT,	1,	0,
207 	  carp_stats,	NULL,		0,	"carp" },
208 #ifdef IPSEC
209 	{ -1,		N_IPSECSTAT,	1,	0,
210 	  fast_ipsec_stats, NULL,	0,	"ipsec" },
211 #endif
212 	{ -1,		N_PIMSTAT,	1,	0,
213 	  pim_stats,	NULL,		0,	"pim" },
214 	{ -1,		N_PFSYNCSTAT,  1,  0,
215 	  pfsync_stats,  NULL,		0,  "pfsync" },
216 	{ -1,		-1,		0,	0,
217 	  0,		NULL,		0,	0 }
218 };
219 
220 #ifdef INET6
221 struct protox ip6protox[] = {
222 	{ -1,		N_IP6STAT,	1,	0,
223 	  ip6_stats,	ip6_ifstats,	0,	"ip6" },
224 	{ -1,		N_ICMP6STAT,	1,	0,
225 	  icmp6_stats,	icmp6_ifstats,	0,	"icmp6" },
226 #ifdef TCP6
227 	{ N_TCBTABLE,	N_TCP6STAT,	1,	ip6protopr,
228 	  tcp6_stats,	NULL,		tcp6_dump,	"tcp6" },
229 #else
230 	{ N_TCBTABLE,	N_TCP6STAT,	1,	ip6protopr,
231 	  tcp_stats,	NULL,		tcp6_dump,	"tcp6" },
232 #endif
233 	{ N_UDBTABLE,	N_UDP6STAT,	1,	ip6protopr,
234 	  udp6_stats,	NULL,		0,	"udp6" },
235 #ifdef IPSEC
236 	{ -1,		N_IPSEC6STAT,	1,	0,
237 	  fast_ipsec_stats, NULL,	0,	"ipsec6" },
238 #endif
239 	{ -1,		N_PIM6STAT,	1,	0,
240 	  pim6_stats,	NULL,		0,	"pim6" },
241 	{ -1,		N_RIP6STAT,	1,	0,
242 	  rip6_stats,	NULL,		0,	"rip6" },
243 	{ -1,		-1,		0,	0,
244 	  0,		NULL,		0,	0 }
245 };
246 #endif
247 
248 struct protox arpprotox[] = {
249 	{ -1,		N_ARPSTAT,	1,	0,
250 	  arp_stats,	NULL,		0,	"arp" },
251 	{ -1,		-1,		0,	0,
252 	  0,		NULL,		0,	0 }
253 };
254 
255 #ifdef IPSEC
256 struct protox pfkeyprotox[] = {
257 	{ -1,		N_PFKEYSTAT,	1,	0,
258 	  pfkey_stats,	NULL,		0,	"pfkey" },
259 	{ -1,		-1,		0,	0,
260 	  0,		NULL,		0,	0 }
261 };
262 #endif
263 
264 #ifndef SMALL
265 struct protox atalkprotox[] = {
266 	{ N_DDPCB,	N_DDPSTAT,	1,	atalkprotopr,
267 	  ddp_stats,	NULL,		0,	"ddp" },
268 	{ -1,		-1,		0,	0,
269 	  0,		NULL,		0,	NULL }
270 };
271 #endif
272 
273 struct protox *protoprotox[] = { protox,
274 #ifdef INET6
275 				 ip6protox,
276 #endif
277 				 arpprotox,
278 #ifdef IPSEC
279 				 pfkeyprotox,
280 #endif
281 #ifndef SMALL
282 				 atalkprotox,
283 #endif
284 				 NULL };
285 
286 const struct softintrq {
287 	const char *siq_name;
288 	int siq_index;
289 } softintrq[] = {
290 	{ "arpintrq", N_ARPINTRQ },
291 	{ "ipintrq", N_IPINTRQ },
292 	{ "ip6intrq", N_IP6INTRQ },
293 	{ "atintrq1", N_ATINTRQ1 },
294 	{ "atintrq2", N_ATINTRQ2 },
295 	{ "llcintrq", N_LLCINTRQ },
296 	{ "hdintrq", N_HDINTRQ },
297 	{ "natmintrq", N_NATMINTRQ },
298 	{ "ppoediscinq", N_PPPOEDISCINQ },
299 	{ "ppoeinq", N_PPPOEINQ },
300 	{ "pkintrq", N_PKINTRQ },
301 	{ NULL, -1 },
302 };
303 
304 int main __P((int, char *[]));
305 static void printproto __P((struct protox *, const char *));
306 static void print_softintrq __P((void));
307 __dead static void usage(void);
308 static struct protox *name2protox __P((const char *));
309 static struct protox *knownname __P((const char *));
310 static void prepare(const char *, const char *, struct protox *tp);
311 static kvm_t *prepare_kvmd(const char *, const char *, char *);
312 
313 static kvm_t *kvmd = NULL;
314 gid_t egid;
315 int interval;	/* repeat interval for i/f stats */
316 static const char *nlistf = NULL, *memf = NULL;
317 
318 kvm_t *
319 get_kvmd(void)
320 {
321 	char buf[_POSIX2_LINE_MAX];
322 
323 	if (kvmd != NULL)
324 		return kvmd;
325 	if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL)
326 		errx(1, "kvm error: %s", buf);
327 	return kvmd;
328 }
329 
330 static kvm_t *
331 prepare_kvmd(const char *nf, const char *mf, char *errbuf)
332 {
333 	kvm_t *k;
334 
335 	(void)setegid(egid);
336 	k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf);
337 	(void)setgid(getgid());
338 	return k;
339 }
340 
341 void
342 prepare(const char *nf, const char *mf, struct protox *tp)
343 {
344 	char buf[_POSIX2_LINE_MAX];
345 	/*
346 	 * Try to figure out if we can use sysctl or not.
347 	 */
348 	if (nf != NULL || mf != NULL) {
349 		/* Of course, we can't use sysctl with dumps. */
350 		if (force_sysctl)
351 			errx(EXIT_FAILURE, "can't use sysctl with dumps");
352 
353 		/*
354 		 * If we have -M or -N, we're not dealing with live memory
355 		 * or want to use kvm interface explicitly.  It is sometimes
356 		 * useful to dig inside of kernel without extending
357 		 * sysctl interface (i.e., without rebuilding kernel).
358 		 */
359 		use_sysctl = 0;
360 	} else if (qflag ||
361 		   iflag ||
362 #ifndef SMALL
363 		   gflag ||
364 #endif
365 		   (pflag && tp->pr_sindex == N_PIMSTAT) ||
366 		   Pflag) {
367 		/* These flags are not yet supported via sysctl(3). */
368 		use_sysctl = 0;
369 	} else {
370 		/* We can use sysctl(3). */
371 		use_sysctl = 1;
372 	}
373 
374 	if (force_sysctl && !use_sysctl) {
375 		/* Let the user know what's about to happen. */
376 		warnx("forcing sysctl usage even though it might not be "\
377 		    "supported");
378 		use_sysctl = 1;
379 	}
380 
381 #ifdef __minix
382 	use_sysctl = 1;
383 #endif /* __minix */
384 
385 	kvmd = prepare_kvmd(nf, mf, buf);
386 
387 	if (!use_sysctl) {
388 
389 		if (kvmd == NULL)
390 			errx(1, "kvm error: %s", buf);
391 		if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
392 			if (nf)
393 				errx(1, "%s: no namelist", nf);
394 			else
395 				errx(1, "no namelist");
396 		}
397 	} else
398 		(void)setgid(getgid());
399 }
400 
401 int
402 main(int argc, char *argv[])
403 {
404 	struct protoent *p;
405 	struct protox *tp;	/* for printing cblocks & stats */
406 	int ch;
407 	char *cp;
408 	char *afname, *afnames;
409 	u_long pcbaddr;
410 
411 	if (prog_init) {
412 		if (prog_init() == -1)
413 			err(1, "init failed");
414 		force_sysctl = 1; /* cheap trick */
415 	}
416 
417 	egid = getegid();
418 	(void)setegid(getgid());
419 	tp = NULL;
420 	af = AF_UNSPEC;
421 	afnames = NULL;
422 	pcbaddr = 0;
423 
424 	while ((ch = getopt(argc, argv,
425 	    "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
426 		switch (ch) {
427 		case 'A':
428 			Aflag = RT_AFLAG;
429 			break;
430 		case 'a':
431 			aflag = 1;
432 			break;
433 		case 'b':
434 			bflag = 1;
435 			break;
436 		case 'B':
437 			Bflag = 1;
438 			break;
439 		case 'd':
440 			dflag = 1;
441 			break;
442 		case 'f':
443 			afnames = optarg;
444 			break;
445 #ifndef SMALL
446 		case 'g':
447 			gflag = 1;
448 			break;
449 #endif
450 		case 'h':
451 			hflag = 1;
452 			break;
453 		case 'I':
454 			iflag = 1;
455 			interface = optarg;
456 			break;
457 		case 'i':
458 			iflag = 1;
459 			break;
460 		case 'L':
461 			Lflag = RT_LFLAG;
462 			break;
463 		case 'l':
464 			lflag = 1;
465 			break;
466 		case 'M':
467 			memf = optarg;
468 			break;
469 		case 'm':
470 			mflag = 1;
471 			break;
472 		case 'N':
473 			nlistf = optarg;
474 			break;
475 		case 'n':
476 			numeric_addr = numeric_port = nflag = RT_NFLAG;
477 			break;
478 		case 'P':
479 			errno = 0;
480 			pcbaddr = strtoul(optarg, &cp, 16);
481 			if (*cp != '\0' || errno == ERANGE)
482 				errx(1, "invalid PCB address %s",
483 				    optarg);
484 			Pflag = 1;
485 			break;
486 		case 'p':
487 			if ((tp = name2protox(optarg)) == NULL)
488 				errx(1, "%s: unknown or uninstrumented protocol",
489 				    optarg);
490 			pflag = 1;
491 			break;
492 		case 'q':
493 			qflag = 1;
494 			break;
495 		case 'r':
496 			rflag = 1;
497 			break;
498 		case 's':
499 			++sflag;
500 			break;
501 		case 'S':
502 			numeric_addr = 1;
503 			break;
504 		case 't':
505 			tflag = 1;
506 			break;
507 		case 'T':
508 			tagflag = RT_TFLAG;
509 			break;
510 		case 'u':
511 			af = AF_LOCAL;
512 			break;
513 		case 'V':
514 			Vflag++;
515 			break;
516 		case 'v':
517 			vflag = RT_VFLAG;
518 			break;
519 		case 'w':
520 			interval = atoi(optarg);
521 			iflag = 1;
522 			break;
523 		case 'X':
524 			force_sysctl = 1;
525 			break;
526 		case '?':
527 		default:
528 			usage();
529 		}
530 	argv += optind;
531 	argc -= optind;
532 
533 #define	BACKWARD_COMPATIBILITY
534 #ifdef	BACKWARD_COMPATIBILITY
535 	if (*argv) {
536 		if (isdigit((unsigned char)**argv)) {
537 			interval = atoi(*argv);
538 			if (interval <= 0)
539 				usage();
540 			++argv;
541 			iflag = 1;
542 		}
543 		if (*argv) {
544 			nlistf = *argv;
545 			if (*++argv)
546 				memf = *argv;
547 		}
548 	}
549 #endif
550 
551 	prepare(nlistf, memf, tp);
552 
553 #ifndef SMALL
554 	if (Bflag) {
555 		if (sflag)
556 			bpf_stats();
557 		else
558 			bpf_dump(interface);
559 		exit(0);
560 	}
561 #endif
562 
563 	if (mflag) {
564 		mbpr(nl[N_MBSTAT].n_value,  nl[N_MSIZE].n_value,
565 		    nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value,
566 		    nl[N_MCLPOOL].n_value);
567 		exit(0);
568 	}
569 	if (Pflag) {
570 		if (tp == NULL) {
571 			/* Default to TCP. */
572 			tp = name2protox("tcp");
573 		}
574 		if (tp->pr_dump)
575 			(*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name,
576 			    pcbaddr);
577 		else
578 			printf("%s: no PCB dump routine\n", tp->pr_name);
579 		exit(0);
580 	}
581 	if (pflag) {
582 		if (iflag && tp->pr_istats)
583 			intpr(interval, nl[N_IFNET_LIST].n_value, tp->pr_istats);
584 		else if (tp->pr_stats)
585 			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
586 				tp->pr_name);
587 		else
588 			printf("%s: no stats routine\n", tp->pr_name);
589 		exit(0);
590 	}
591 	if (qflag) {
592 		print_softintrq();
593 		exit(0);
594 	}
595 	/*
596 	 * Keep file descriptors open to avoid overhead
597 	 * of open/close on each call to get* routines.
598 	 */
599 	sethostent(1);
600 	setnetent(1);
601 	/*
602 	 * If -f was used afnames != NULL, loop over the address families.
603 	 * Otherwise do this at least once (with af == AF_UNSPEC).
604 	 */
605 	afname = NULL;
606 	do {
607 		if (afnames != NULL) {
608 			afname = strsep(&afnames, ",");
609 			if (afname == NULL)
610 				break;		/* Exit early */
611 			if (strcmp(afname, "inet") == 0)
612 				af = AF_INET;
613 			else if (strcmp(afname, "inet6") == 0)
614 				af = AF_INET6;
615 			else if (strcmp(afname, "arp") == 0)
616 				af = AF_ARP;
617 			else if (strcmp(afname, "pfkey") == 0)
618 				af = PF_KEY;
619 			else if (strcmp(afname, "unix") == 0
620 			    || strcmp(afname, "local") == 0)
621 				af = AF_LOCAL;
622 			else if (strcmp(afname, "atalk") == 0)
623 				af = AF_APPLETALK;
624 			else if (strcmp(afname, "mpls") == 0)
625 				af = AF_MPLS;
626 			else {
627 				warnx("%s: unknown address family",
628 				    afname);
629 				continue;
630 			}
631 		}
632 
633 		if (iflag) {
634 			if (af != AF_UNSPEC)
635 				goto protostat;
636 
637 			intpr(interval, nl[N_IFNET_LIST].n_value, NULL);
638 			break;
639 		}
640 		if (rflag) {
641 			if (sflag)
642 				rt_stats(use_sysctl ? 0 : nl[N_RTSTAT].n_value);
643 			else {
644 				if (use_sysctl)
645 					p_rttables(af,
646 					    nflag|tagflag|vflag|Lflag, 0, ~0);
647 				else
648 					routepr(nl[N_RTREE].n_value);
649 			}
650 			break;
651 		}
652 #ifndef SMALL
653 		if (gflag) {
654 			if (sflag) {
655 				if (af == AF_INET || af == AF_UNSPEC)
656 					mrt_stats(nl[N_MRTPROTO].n_value,
657 						  nl[N_MRTSTAT].n_value);
658 #ifdef INET6
659 				if (af == AF_INET6 || af == AF_UNSPEC)
660 					mrt6_stats(nl[N_MRT6PROTO].n_value,
661 						   nl[N_MRT6STAT].n_value);
662 #endif
663 			}
664 			else {
665 				if (af == AF_INET || af == AF_UNSPEC)
666 					mroutepr(nl[N_MRTPROTO].n_value,
667 						 nl[N_MFCHASHTBL].n_value,
668 						 nl[N_MFCHASH].n_value,
669 						 nl[N_VIFTABLE].n_value);
670 #ifdef INET6
671 				if (af == AF_INET6 || af == AF_UNSPEC)
672 					mroute6pr(nl[N_MRT6PROTO].n_value,
673 						  nl[N_MF6CTABLE].n_value,
674 						  nl[N_MIF6TABLE].n_value);
675 #endif
676 			}
677 			break;
678 		}
679 #endif
680 	  protostat:
681 		if (af == AF_INET || af == AF_UNSPEC) {
682 			setprotoent(1);
683 			setservent(1);
684 			/* ugh, this is O(MN) ... why do we do this? */
685 			while ((p = getprotoent()) != NULL) {
686 				for (tp = protox; tp->pr_name; tp++)
687 					if (strcmp(tp->pr_name, p->p_name) == 0)
688 						break;
689 				if (tp->pr_name == 0 || tp->pr_wanted == 0)
690 					continue;
691 				printproto(tp, p->p_name);
692 				tp->pr_wanted = 0;
693 			}
694 			endprotoent();
695 			for (tp = protox; tp->pr_name; tp++)
696 				if (tp->pr_wanted)
697 					printproto(tp, tp->pr_name);
698 		}
699 #ifdef INET6
700 		if (af == AF_INET6 || af == AF_UNSPEC)
701 			for (tp = ip6protox; tp->pr_name; tp++)
702 				printproto(tp, tp->pr_name);
703 #endif
704 		if (af == AF_ARP || af == AF_UNSPEC)
705 			for (tp = arpprotox; tp->pr_name; tp++)
706 				printproto(tp, tp->pr_name);
707 #ifdef IPSEC
708 		if (af == PF_KEY || af == AF_UNSPEC)
709 			for (tp = pfkeyprotox; tp->pr_name; tp++)
710 				printproto(tp, tp->pr_name);
711 #endif
712 #ifndef SMALL
713 		if (af == AF_APPLETALK || af == AF_UNSPEC)
714 			for (tp = atalkprotox; tp->pr_name; tp++)
715 				printproto(tp, tp->pr_name);
716 		if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag)
717 			unixpr(nl[N_UNIXSW].n_value);
718 #endif
719 	} while (afnames != NULL && afname != NULL);
720 	exit(0);
721 }
722 
723 /*
724  * Print out protocol statistics or control blocks (per sflag).
725  * If the interface was not specifically requested, and the symbol
726  * is not in the namelist, ignore this one.
727  */
728 static void
729 printproto(struct protox *tp, const char *name)
730 {
731 	void (*pr) __P((u_long, const char *));
732 	u_long off;
733 
734 	if (sflag) {
735 		if (iflag) {
736 			if (tp->pr_istats)
737 				intpr(interval, nl[N_IFNET_LIST].n_value,
738 				      tp->pr_istats);
739 			return;
740 		}
741 		else {
742 			pr = tp->pr_stats;
743 			off = nl[tp->pr_sindex].n_value;
744 		}
745 	} else {
746 		pr = tp->pr_cblocks;
747 		off = nl[tp->pr_index].n_value;
748 	}
749 	if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) {
750 		(*pr)(off, name);
751 	}
752 }
753 
754 /*
755  * Print softintrq status.
756  */
757 void
758 print_softintrq(void)
759 {
760 	struct ifqueue intrq, *ifq = &intrq;
761 	const struct softintrq *siq;
762 	u_long off;
763 
764 	for (siq = softintrq; siq->siq_name != NULL; siq++) {
765 		off = nl[siq->siq_index].n_value;
766 		if (off == 0)
767 			continue;
768 
769 		kread(off, (char *)ifq, sizeof(*ifq));
770 		printf("%s:\n", siq->siq_name);
771 		printf("\tqueue length: %d\n", ifq->ifq_len);
772 		printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen);
773 		printf("\tpackets dropped: %d\n", ifq->ifq_drops);
774 	}
775 }
776 
777 /*
778  * Read kernel memory, return 0 on success.
779  */
780 int
781 kread(u_long addr, char *buf, int size)
782 {
783 
784 	if (kvm_read(kvmd, addr, buf, size) != size) {
785 		warnx("%s", kvm_geterr(kvmd));
786 		return (-1);
787 	}
788 	return (0);
789 }
790 
791 const char *
792 plural(int n)
793 {
794 
795 	return (n != 1 ? "s" : "");
796 }
797 
798 const char *
799 plurales(int n)
800 {
801 
802 	return (n != 1 ? "es" : "");
803 }
804 
805 int
806 get_hardticks(void)
807 {
808 	int hardticks;
809 
810 	kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks,
811 	    sizeof(hardticks));
812 	return (hardticks);
813 }
814 
815 /*
816  * Find the protox for the given "well-known" name.
817  */
818 static struct protox *
819 knownname(const char *name)
820 {
821 	struct protox **tpp, *tp;
822 
823 	for (tpp = protoprotox; *tpp; tpp++)
824 		for (tp = *tpp; tp->pr_name; tp++)
825 			if (strcmp(tp->pr_name, name) == 0)
826 				return (tp);
827 	return (NULL);
828 }
829 
830 /*
831  * Find the protox corresponding to name.
832  */
833 static struct protox *
834 name2protox(const char *name)
835 {
836 	struct protox *tp;
837 	char **alias;			/* alias from p->aliases */
838 	struct protoent *p;
839 
840 	/*
841 	 * Try to find the name in the list of "well-known" names. If that
842 	 * fails, check if name is an alias for an Internet protocol.
843 	 */
844 	if ((tp = knownname(name)) != NULL)
845 		return (tp);
846 
847 	setprotoent(1);			/* make protocol lookup cheaper */
848 	while ((p = getprotoent()) != NULL) {
849 		/* assert: name not same as p->name */
850 		for (alias = p->p_aliases; *alias; alias++)
851 			if (strcmp(name, *alias) == 0) {
852 				endprotoent();
853 				return (knownname(p->p_name));
854 			}
855 	}
856 	endprotoent();
857 	return (NULL);
858 }
859 
860 static void
861 usage(void)
862 {
863 	const char *progname = getprogname();
864 
865 	(void)fprintf(stderr,
866 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname);
867 	(void)fprintf(stderr,
868 "       %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
869 	progname);
870 	(void)fprintf(stderr,
871 "       %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname);
872 	(void)fprintf(stderr,
873 "       %s [-p protocol] [-M core] [-N system]\n", progname);
874 	(void)fprintf(stderr,
875 "       %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname);
876 	(void)fprintf(stderr,
877 "       %s [-p protocol] [-i] [-I Interface] \n", progname);
878 	(void)fprintf(stderr,
879 "       %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname);
880 	(void)fprintf(stderr,
881 "       %s [-s] [-B] [-I interface]\n", progname);
882 	exit(1);
883 }
884