main.c revision 78215
1217309Snwhitehorn/*
2220749Snwhitehorn * Copyright (c) 1983, 1988, 1993
3217309Snwhitehorn *	Regents of the University of California.  All rights reserved.
4220749Snwhitehorn *
5217309Snwhitehorn * Redistribution and use in source and binary forms, with or without
6217309Snwhitehorn * modification, are permitted provided that the following conditions
7217309Snwhitehorn * are met:
8217309Snwhitehorn * 1. Redistributions of source code must retain the above copyright
9217309Snwhitehorn *    notice, this list of conditions and the following disclaimer.
10217309Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright
11217309Snwhitehorn *    notice, this list of conditions and the following disclaimer in the
12217309Snwhitehorn *    documentation and/or other materials provided with the distribution.
13217309Snwhitehorn * 3. All advertising materials mentioning features or use of this software
14217309Snwhitehorn *    must display the following acknowledgement:
15217309Snwhitehorn *	This product includes software developed by the University of
16217309Snwhitehorn *	California, Berkeley and its contributors.
17217309Snwhitehorn * 4. Neither the name of the University nor the names of its contributors
18217309Snwhitehorn *    may be used to endorse or promote products derived from this software
19217309Snwhitehorn *    without specific prior written permission.
20217309Snwhitehorn *
21217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22217309Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23217309Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24217309Snwhitehorn * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25217309Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26217309Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27217309Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28217309Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29217309Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30217309Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31217309Snwhitehorn * SUCH DAMAGE.
32217309Snwhitehorn */
33217309Snwhitehorn
34217309Snwhitehorn#ifndef lint
35217309Snwhitehornchar const copyright[] =
36217309Snwhitehorn"@(#) Copyright (c) 1983, 1988, 1993\n\
37217309Snwhitehorn	Regents of the University of California.  All rights reserved.\n";
38217309Snwhitehorn#endif /* not lint */
39220749Snwhitehorn
40217309Snwhitehorn#ifndef lint
41217309Snwhitehorn#if 0
42217309Snwhitehornstatic char sccsid[] = "@(#)main.c	8.4 (Berkeley) 3/1/94";
43217309Snwhitehorn#endif
44217309Snwhitehornstatic const char rcsid[] =
45217309Snwhitehorn  "$FreeBSD: head/usr.bin/netstat/main.c 78215 2001-06-14 14:15:41Z ru $";
46217309Snwhitehorn#endif /* not lint */
47217309Snwhitehorn
48217309Snwhitehorn#include <sys/param.h>
49217309Snwhitehorn#include <sys/file.h>
50217309Snwhitehorn#include <sys/protosw.h>
51217309Snwhitehorn#include <sys/socket.h>
52217309Snwhitehorn
53217309Snwhitehorn#include <netinet/in.h>
54217309Snwhitehorn
55217309Snwhitehorn#include <netgraph/ng_socket.h>
56217309Snwhitehorn
57217309Snwhitehorn#include <ctype.h>
58217309Snwhitehorn#include <err.h>
59217309Snwhitehorn#include <errno.h>
60217309Snwhitehorn#include <kvm.h>
61217309Snwhitehorn#include <limits.h>
62217309Snwhitehorn#include <netdb.h>
63217309Snwhitehorn#include <nlist.h>
64217309Snwhitehorn#include <paths.h>
65217309Snwhitehorn#include <stdio.h>
66217309Snwhitehorn#include <stdlib.h>
67217309Snwhitehorn#include <string.h>
68217309Snwhitehorn#include <unistd.h>
69217309Snwhitehorn#include "netstat.h"
70217309Snwhitehorn
71217309Snwhitehornstatic struct nlist nl[] = {
72217309Snwhitehorn#define	N_IFNET		0
73217309Snwhitehorn	{ "_ifnet" },
74217309Snwhitehorn#define	N_IMP		1
75217309Snwhitehorn	{ "_imp_softc" },
76217309Snwhitehorn#define	N_RTSTAT	2
77217309Snwhitehorn	{ "_rtstat" },
78217309Snwhitehorn#define	N_UNIXSW	3
79217309Snwhitehorn	{ "_localsw" },
80217309Snwhitehorn#define N_IDP		4
81217309Snwhitehorn	{ "_nspcb"},
82217309Snwhitehorn#define N_IDPSTAT	5
83217309Snwhitehorn	{ "_idpstat"},
84217309Snwhitehorn#define N_SPPSTAT	6
85217309Snwhitehorn	{ "_spp_istat"},
86217309Snwhitehorn#define N_NSERR		7
87217309Snwhitehorn	{ "_ns_errstat"},
88217309Snwhitehorn#define	N_CLNPSTAT	8
89217309Snwhitehorn	{ "_clnp_stat"},
90217309Snwhitehorn#define	IN_NOTUSED	9
91217309Snwhitehorn	{ "_tp_inpcb" },
92217309Snwhitehorn#define	ISO_TP		10
93217309Snwhitehorn	{ "_tp_refinfo" },
94217309Snwhitehorn#define	N_TPSTAT	11
95217309Snwhitehorn	{ "_tp_stat" },
96217309Snwhitehorn#define	N_ESISSTAT	12
97217309Snwhitehorn	{ "_esis_stat"},
98217309Snwhitehorn#define N_NIMP		13
99217309Snwhitehorn	{ "_nimp"},
100217309Snwhitehorn#define N_RTREE		14
101217309Snwhitehorn	{ "_rt_tables"},
102217309Snwhitehorn#define N_CLTP		15
103217309Snwhitehorn	{ "_cltb"},
104217309Snwhitehorn#define N_CLTPSTAT	16
105217309Snwhitehorn	{ "_cltpstat"},
106217309Snwhitehorn#define	N_NFILE		17
107217309Snwhitehorn	{ "_nfile" },
108217309Snwhitehorn#define	N_FILE		18
109217309Snwhitehorn	{ "_file" },
110217309Snwhitehorn#define N_MRTSTAT	19
111217309Snwhitehorn	{ "_mrtstat" },
112217309Snwhitehorn#define N_MFCTABLE	20
113217309Snwhitehorn	{ "_mfctable" },
114217309Snwhitehorn#define N_VIFTABLE	21
115217309Snwhitehorn	{ "_viftable" },
116217309Snwhitehorn#define N_IPX		22
117217309Snwhitehorn	{ "_ipxpcb"},
118217309Snwhitehorn#define N_IPXSTAT	23
119217309Snwhitehorn	{ "_ipxstat"},
120217309Snwhitehorn#define N_SPXSTAT	24
121217309Snwhitehorn	{ "_spx_istat"},
122217309Snwhitehorn#define N_DDPSTAT	25
123217309Snwhitehorn	{ "_ddpstat"},
124217309Snwhitehorn#define N_DDPCB		26
125217309Snwhitehorn	{ "_ddpcb"},
126217309Snwhitehorn#define N_NGSOCKS	27
127217309Snwhitehorn	{ "_ngsocklist"},
128217309Snwhitehorn#define N_IP6STAT	28
129217309Snwhitehorn	{ "_ip6stat" },
130217309Snwhitehorn#define N_ICMP6STAT	29
131217309Snwhitehorn	{ "_icmp6stat" },
132217309Snwhitehorn#define N_IPSECSTAT	30
133217309Snwhitehorn	{ "_ipsecstat" },
134217309Snwhitehorn#define N_IPSEC6STAT	31
135217309Snwhitehorn	{ "_ipsec6stat" },
136#define N_PIM6STAT	32
137	{ "_pim6stat" },
138#define N_MRT6PROTO	33
139	{ "_ip6_mrtproto" },
140#define N_MRT6STAT	34
141	{ "_mrt6stat" },
142#define N_MF6CTABLE	35
143	{ "_mf6ctable" },
144#define N_MIF6TABLE	36
145	{ "_mif6table" },
146#define N_PFKEYSTAT	37
147	{ "_pfkeystat" },
148	{ "" },
149};
150
151struct protox {
152	u_char	pr_index;		/* index into nlist of cb head */
153	u_char	pr_sindex;		/* index into nlist of stat block */
154	u_char	pr_wanted;		/* 1 if wanted, 0 otherwise */
155	void	(*pr_cblocks)();	/* control blocks printing routine */
156	void	(*pr_stats)();		/* statistics printing routine */
157	void	(*pr_istats)();		/* per/if statistics printing routine */
158	char	*pr_name;		/* well-known name */
159	int	pr_usesysctl;		/* true if we use sysctl, not kvm */
160} protox[] = {
161	{ -1,		-1,		1,	protopr,
162	  tcp_stats,	NULL,		"tcp",	IPPROTO_TCP },
163	{ -1,		-1,		1,	protopr,
164	  udp_stats,	NULL,		"udp",	IPPROTO_UDP },
165	{ -1,		-1,		1,	protopr,
166	  NULL,		NULL,		"divert",IPPROTO_DIVERT },
167	{ -1,		-1,		1,	protopr,
168	  ip_stats,	NULL,		"ip",	IPPROTO_RAW },
169	{ -1,		-1,		1,	protopr,
170	  icmp_stats,	NULL,		"icmp",	IPPROTO_ICMP },
171	{ -1,		-1,		1,	protopr,
172	  igmp_stats,	NULL,		"igmp",	IPPROTO_IGMP },
173#ifdef IPSEC
174	{ -1,		N_IPSECSTAT,	1,	0,
175	  ipsec_stats,	NULL,		"ipsec",	0},
176#endif
177	{ -1,		-1,		1,	0,
178	  bdg_stats,	NULL,		"bdg",	1 /* bridging... */ },
179	{ -1,		-1,		0,	0,
180	  0,		NULL,		0 }
181};
182
183#ifdef INET6
184struct protox ip6protox[] = {
185	{ -1,		-1,		1,	protopr,
186	  tcp_stats,	NULL,		"tcp",	IPPROTO_TCP },
187	{ -1,		-1,		1,	protopr,
188	  udp_stats,	NULL,		"udp",	IPPROTO_UDP },
189	{ -1,		N_IP6STAT,	1,	0,
190	  ip6_stats,	ip6_ifstats,	"ip6",	0 },
191	{ -1,		N_ICMP6STAT,	1,	0,
192	  icmp6_stats,	icmp6_ifstats,	"icmp6",0 },
193#ifdef IPSEC
194	{ -1,		N_IPSEC6STAT,	1,	0,
195	  ipsec_stats,	NULL,		"ipsec6",0 },
196#endif
197#ifdef notyet
198	{ -1,		N_PIM6STAT,	1,	0,
199	  pim6_stats,	NULL,		"pim6",	0 },
200#endif
201	{ -1,		-1,		1,	0,
202	  rip6_stats,	NULL,		"rip6",	0 },
203	{ -1,		-1,		1,	0,
204	  bdg_stats,	NULL,		"bdg",	1 /* bridging... */ },
205	{ -1,		-1,		0,	0,
206	  0,		NULL,		0,	0 }
207};
208#endif /*INET6*/
209
210#ifdef IPSEC
211struct protox pfkeyprotox[] = {
212	{ -1,		N_PFKEYSTAT,	1,	0,
213	  pfkey_stats,	NULL,		"pfkey", 0 },
214	{ -1,		-1,		0,	0,
215	  0,		NULL,		0,	0 }
216};
217#endif
218
219struct protox atalkprotox[] = {
220	{ N_DDPCB,	N_DDPSTAT,	1,	atalkprotopr,
221	  ddp_stats,	NULL,		"ddp" },
222	{ -1,		-1,		0,	0,
223	  0,		NULL,		0 }
224};
225
226struct protox netgraphprotox[] = {
227	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
228	  NULL,		NULL,		"ctrl" },
229	{ N_NGSOCKS,	-1,		1,	netgraphprotopr,
230	  NULL,		NULL,		"data" },
231	{ -1,		NULL,		0,	0,
232	  0,		NULL,		0 }
233};
234
235struct protox ipxprotox[] = {
236	{ N_IPX,	N_IPXSTAT,	1,	ipxprotopr,
237	  ipx_stats,	NULL,		"ipx",	0 },
238	{ N_IPX,	N_SPXSTAT,	1,	ipxprotopr,
239	  spx_stats,	NULL,		"spx",	0 },
240	{ -1,		-1,		0,	0,
241	  0,		NULL,		0,	0 }
242};
243
244#ifdef NS
245struct protox nsprotox[] = {
246	{ N_IDP,	N_IDPSTAT,	1,	nsprotopr,
247	  idp_stats,	NULL,		"idp" },
248	{ N_IDP,	N_SPPSTAT,	1,	nsprotopr,
249	  spp_stats,	NULL,		"spp" },
250	{ -1,		N_NSERR,	1,	0,
251	  nserr_stats,	NULL,		"ns_err" },
252	{ -1,		-1,		0,	0,
253	  0,		NULL,		0 }
254};
255#endif
256
257#ifdef ISO
258struct protox isoprotox[] = {
259	{ ISO_TP,	N_TPSTAT,	1,	iso_protopr,
260	  tp_stats,	NULL,		"tp" },
261	{ N_CLTP,	N_CLTPSTAT,	1,	iso_protopr,
262	  cltp_stats,	NULL,		"cltp" },
263	{ -1,		N_CLNPSTAT,	1,	 0,
264	  clnp_stats,	NULL,		"clnp"},
265	{ -1,		N_ESISSTAT,	1,	 0,
266	  esis_stats,	NULL,		"esis"},
267	{ -1,		-1,		0,	0,
268	  0,		NULL,		0 }
269};
270#endif
271
272struct protox *protoprotox[] = {
273					 protox,
274#ifdef INET6
275					 ip6protox,
276#endif
277#ifdef IPSEC
278					 pfkeyprotox,
279#endif
280					 ipxprotox, atalkprotox,
281#ifdef NS
282					 nsprotox,
283#endif
284#ifdef ISO
285					 isoprotox,
286#endif
287					 NULL };
288
289static void printproto __P((struct protox *, char *));
290static void usage __P((void));
291static struct protox *name2protox __P((char *));
292static struct protox *knownname __P((char *));
293
294static kvm_t *kvmd;
295static char *nlistf = NULL, *memf = NULL;
296
297int	Aflag;		/* show addresses of protocol control block */
298int	aflag;		/* show all sockets (including servers) */
299int	bflag;		/* show i/f total bytes in/out */
300int	dflag;		/* show i/f dropped packets */
301int	gflag;		/* show group (multicast) routing or stats */
302int	iflag;		/* show interfaces */
303int	lflag;		/* show routing table with use and ref */
304int	Lflag;		/* show size of listen queues */
305int	mflag;		/* show memory stats */
306int	nflag;		/* show addresses numerically */
307int	pflag;		/* show given protocol */
308int	rflag;		/* show routing tables (or routing stats) */
309int	sflag;		/* show protocol statistics */
310int	tflag;		/* show i/f watchdog timers */
311int	Wflag;		/* wide display */
312
313int	interval;	/* repeat interval for i/f stats */
314
315char	*interface;	/* desired i/f for stats, or NULL for all i/fs */
316int	unit;		/* unit number for above */
317
318int	af;		/* address family */
319
320int
321main(argc, argv)
322	int argc;
323	char *argv[];
324{
325	register struct protox *tp = NULL;  /* for printing cblocks & stats */
326	int ch;
327
328	af = AF_UNSPEC;
329
330	while ((ch = getopt(argc, argv, "Aabdf:gI:iLlM:mN:np:rstuWw:")) != -1)
331		switch(ch) {
332		case 'A':
333			Aflag = 1;
334			break;
335		case 'a':
336			aflag = 1;
337			break;
338		case 'b':
339			bflag = 1;
340			break;
341		case 'd':
342			dflag = 1;
343			break;
344		case 'f':
345#ifdef NS
346			if (strcmp(optarg, "ns") == 0)
347				af = AF_NS;
348			else
349#endif
350			if (strcmp(optarg, "ipx") == 0)
351				af = AF_IPX;
352			else if (strcmp(optarg, "inet") == 0)
353				af = AF_INET;
354#ifdef INET6
355			else if (strcmp(optarg, "inet6") == 0)
356				af = AF_INET6;
357#endif /*INET6*/
358#ifdef INET6
359			else if (strcmp(optarg, "pfkey") == 0)
360				af = PF_KEY;
361#endif /*INET6*/
362			else if (strcmp(optarg, "unix") == 0)
363				af = AF_UNIX;
364			else if (strcmp(optarg, "atalk") == 0)
365				af = AF_APPLETALK;
366			else if (strcmp(optarg, "ng") == 0
367			    || strcmp(optarg, "netgraph") == 0)
368				af = AF_NETGRAPH;
369#ifdef ISO
370			else if (strcmp(optarg, "iso") == 0)
371				af = AF_ISO;
372#endif
373			else {
374				errx(1, "%s: unknown address family", optarg);
375			}
376			break;
377		case 'g':
378			gflag = 1;
379			break;
380		case 'I': {
381			char *cp;
382
383			iflag = 1;
384			for (cp = interface = optarg; isalpha(*cp); cp++)
385				continue;
386			unit = atoi(cp);
387			break;
388		}
389		case 'i':
390			iflag = 1;
391			break;
392		case 'l':
393			lflag = 1;
394			break;
395		case 'L':
396			Lflag = 1;
397			break;
398		case 'M':
399			memf = optarg;
400			break;
401		case 'm':
402			mflag = 1;
403			break;
404		case 'N':
405			nlistf = optarg;
406			break;
407		case 'n':
408			nflag = 1;
409			break;
410		case 'p':
411			if ((tp = name2protox(optarg)) == NULL) {
412				errx(1,
413				     "%s: unknown or uninstrumented protocol",
414				     optarg);
415			}
416			pflag = 1;
417			break;
418		case 'r':
419			rflag = 1;
420			break;
421		case 's':
422			++sflag;
423			break;
424		case 't':
425			tflag = 1;
426			break;
427		case 'u':
428			af = AF_UNIX;
429			break;
430		case 'W':
431			Wflag = 1;
432			break;
433		case 'w':
434			interval = atoi(optarg);
435			iflag = 1;
436			break;
437		case '?':
438		default:
439			usage();
440		}
441	argv += optind;
442	argc -= optind;
443
444#define	BACKWARD_COMPATIBILITY
445#ifdef	BACKWARD_COMPATIBILITY
446	if (*argv) {
447		if (isdigit(**argv)) {
448			interval = atoi(*argv);
449			if (interval <= 0)
450				usage();
451			++argv;
452			iflag = 1;
453		}
454		if (*argv) {
455			nlistf = *argv;
456			if (*++argv)
457				memf = *argv;
458		}
459	}
460#endif
461
462	/*
463	 * Discard setgid privileges if not the running kernel so that bad
464	 * guys can't print interesting stuff from kernel memory.
465	 */
466	if (nlistf != NULL || memf != NULL)
467		setgid(getgid());
468
469	if (mflag) {
470		mbpr();
471		exit(0);
472	}
473	if (pflag) {
474		if (iflag && tp->pr_istats) {
475			kread(0, 0, 0);
476			intpr(interval, nl[N_IFNET].n_value, tp->pr_istats);
477			exit(0);
478		}
479		if (!tp->pr_stats) {
480			printf("%s: no stats routine\n", tp->pr_name);
481			exit(0);
482		}
483		if (tp->pr_usesysctl) {
484			(*tp->pr_stats)(tp->pr_usesysctl, tp->pr_name);
485		} else {
486			kread(0, 0, 0);
487			(*tp->pr_stats)(nl[tp->pr_sindex].n_value,
488					tp->pr_name);
489		}
490		exit(0);
491	}
492#if 0
493	/*
494	 * Keep file descriptors open to avoid overhead
495	 * of open/close on each call to get* routines.
496	 */
497	sethostent(1);
498	setnetent(1);
499#else
500	/*
501	 * This does not make sense any more with DNS being default over
502	 * the files.  Doing a setXXXXent(1) causes a tcp connection to be
503	 * used for the queries, which is slower.
504	 */
505#endif
506	if (iflag) {
507		if (sflag && af != AF_UNSPEC)
508			goto protostat;
509
510		kread(0, 0, 0);
511		intpr(interval, nl[N_IFNET].n_value, NULL);
512		exit(0);
513	}
514	if (rflag) {
515		kread(0, 0, 0);
516		if (sflag)
517			rt_stats(nl[N_RTSTAT].n_value);
518		else
519			routepr(nl[N_RTREE].n_value);
520		exit(0);
521	}
522	if (gflag) {
523		kread(0, 0, 0);
524		if (sflag) {
525			if (af == AF_INET || af == AF_UNSPEC)
526				mrt_stats(nl[N_MRTSTAT].n_value);
527#ifdef INET6
528			if (af == AF_INET6 || af == AF_UNSPEC)
529				mrt6_stats(nl[N_MRT6STAT].n_value);
530#endif
531		} else {
532			if (af == AF_INET || af == AF_UNSPEC)
533				mroutepr(nl[N_MFCTABLE].n_value,
534					 nl[N_VIFTABLE].n_value);
535#ifdef INET6
536			if (af == AF_INET6 || af == AF_UNSPEC)
537				mroute6pr(nl[N_MF6CTABLE].n_value,
538					  nl[N_MIF6TABLE].n_value);
539#endif
540		}
541		exit(0);
542	}
543
544  protostat:
545	kread(0, 0, 0);
546	if (af == AF_INET || af == AF_UNSPEC)
547		for (tp = protox; tp->pr_name; tp++)
548			printproto(tp, tp->pr_name);
549#ifdef INET6
550	if (af == AF_INET6 || af == AF_UNSPEC)
551		for (tp = ip6protox; tp->pr_name; tp++)
552			printproto(tp, tp->pr_name);
553#endif /*INET6*/
554#ifdef IPSEC
555	if (af == PF_KEY || af == AF_UNSPEC)
556		for (tp = pfkeyprotox; tp->pr_name; tp++)
557			printproto(tp, tp->pr_name);
558#endif /*IPSEC*/
559	if (af == AF_IPX || af == AF_UNSPEC) {
560		kread(0, 0, 0);
561		for (tp = ipxprotox; tp->pr_name; tp++)
562			printproto(tp, tp->pr_name);
563	}
564	if (af == AF_APPLETALK || af == AF_UNSPEC)
565		for (tp = atalkprotox; tp->pr_name; tp++)
566			printproto(tp, tp->pr_name);
567	if (af == AF_NETGRAPH || af == AF_UNSPEC)
568		for (tp = netgraphprotox; tp->pr_name; tp++)
569			printproto(tp, tp->pr_name);
570#ifdef NS
571	if (af == AF_NS || af == AF_UNSPEC)
572		for (tp = nsprotox; tp->pr_name; tp++)
573			printproto(tp, tp->pr_name);
574#endif
575#ifdef ISO
576	if (af == AF_ISO || af == AF_UNSPEC)
577		for (tp = isoprotox; tp->pr_name; tp++)
578			printproto(tp, tp->pr_name);
579#endif
580	if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
581		unixpr();
582	exit(0);
583}
584
585/*
586 * Print out protocol statistics or control blocks (per sflag).
587 * If the interface was not specifically requested, and the symbol
588 * is not in the namelist, ignore this one.
589 */
590static void
591printproto(tp, name)
592	register struct protox *tp;
593	char *name;
594{
595	void (*pr)();
596	u_long off;
597
598	if (sflag) {
599		if (iflag) {
600			if (tp->pr_istats)
601				intpr(interval, nl[N_IFNET].n_value,
602				      tp->pr_istats);
603			return;
604		}
605		else {
606			pr = tp->pr_stats;
607			off = tp->pr_usesysctl ? tp->pr_usesysctl
608				: nl[tp->pr_sindex].n_value;
609		}
610	} else {
611		pr = tp->pr_cblocks;
612		off = tp->pr_usesysctl ? tp->pr_usesysctl
613			: nl[tp->pr_index].n_value;
614	}
615	if (pr != NULL && (off || af != AF_UNSPEC))
616		(*pr)(off, name, af);
617}
618
619/*
620 * Read kernel memory, return 0 on success.
621 */
622int
623kread(addr, buf, size)
624	u_long addr;
625	char *buf;
626	int size;
627{
628	if (kvmd == 0) {
629		/*
630		 * XXX.
631		 */
632		kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, buf);
633		if (kvmd != NULL) {
634			if (kvm_nlist(kvmd, nl) < 0) {
635				if(nlistf)
636					errx(1, "%s: kvm_nlist: %s", nlistf,
637					     kvm_geterr(kvmd));
638				else
639					errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
640			}
641
642			if (nl[0].n_type == 0) {
643				if(nlistf)
644					errx(1, "%s: no namelist", nlistf);
645				else
646					errx(1, "no namelist");
647			}
648		} else {
649			warnx("kvm not available");
650			return(-1);
651		}
652	}
653	if (!buf)
654		return (0);
655	if (kvm_read(kvmd, addr, buf, size) != size) {
656		warnx("%s", kvm_geterr(kvmd));
657		return (-1);
658	}
659	return (0);
660}
661
662char *
663plural(n)
664	int n;
665{
666	return (n != 1 ? "s" : "");
667}
668
669char *
670plurales(n)
671	int n;
672{
673	return (n != 1 ? "es" : "");
674}
675
676/*
677 * Find the protox for the given "well-known" name.
678 */
679static struct protox *
680knownname(name)
681	char *name;
682{
683	struct protox **tpp, *tp;
684
685	for (tpp = protoprotox; *tpp; tpp++)
686		for (tp = *tpp; tp->pr_name; tp++)
687			if (strcmp(tp->pr_name, name) == 0)
688				return (tp);
689	return (NULL);
690}
691
692/*
693 * Find the protox corresponding to name.
694 */
695static struct protox *
696name2protox(name)
697	char *name;
698{
699	struct protox *tp;
700	char **alias;			/* alias from p->aliases */
701	struct protoent *p;
702
703	/*
704	 * Try to find the name in the list of "well-known" names. If that
705	 * fails, check if name is an alias for an Internet protocol.
706	 */
707	if ((tp = knownname(name)) != NULL)
708		return (tp);
709
710	setprotoent(1);			/* make protocol lookup cheaper */
711	while ((p = getprotoent()) != NULL) {
712		/* assert: name not same as p->name */
713		for (alias = p->p_aliases; *alias; alias++)
714			if (strcmp(name, *alias) == 0) {
715				endprotoent();
716				return (knownname(p->p_name));
717			}
718	}
719	endprotoent();
720	return (NULL);
721}
722
723static void
724usage()
725{
726	(void)fprintf(stderr, "%s\n%s\n%s\n%s\n",
727"usage: netstat [-AaLlnW] [-f address_family] [-M core] [-N system]",
728"       netstat [-abdgilmnrs] [-f address_family] [-M core] [-N system]",
729"       netstat [-bdn] [-I interface] [-M core] [-N system] [-w wait]",
730"       netstat [-M core] [-N system] [-p protocol]");
731	exit(1);
732}
733