]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/netstat/main.c
Reflect the fact that we actually have NetBSD revision 1.3.
[FreeBSD/FreeBSD.git] / usr.bin / netstat / main.c
1 /*-
2  * Copyright (c) 1983, 1988, 1993
3  *      Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33
34 #ifndef lint
35 char const copyright[] =
36 "@(#) Copyright (c) 1983, 1988, 1993\n\
37         Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #if 0
41 #ifndef lint
42 static char sccsid[] = "@(#)main.c      8.4 (Berkeley) 3/1/94";
43 #endif /* not lint */
44 #endif
45
46 #include <sys/cdefs.h>
47 __FBSDID("$FreeBSD$");
48
49 #include <sys/param.h>
50 #include <sys/file.h>
51 #include <sys/protosw.h>
52 #include <sys/socket.h>
53 #include <sys/socketvar.h>
54
55 #include <netinet/in.h>
56
57 #include <netgraph/ng_socket.h>
58
59 #include <ctype.h>
60 #include <err.h>
61 #include <errno.h>
62 #include <kvm.h>
63 #include <limits.h>
64 #include <netdb.h>
65 #include <nlist.h>
66 #include <paths.h>
67 #include <stdint.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include "netstat.h"
73
74 static struct nlist nl[] = {
75 #define N_IFNET         0
76         { .n_name = "_ifnet" },
77 #define N_RTSTAT        1
78         { .n_name = "_rtstat" },
79 #define N_RTREE         2
80         { .n_name = "_rt_tables"},
81 #define N_MRTSTAT       3
82         { .n_name = "_mrtstat" },
83 #define N_MFCTABLE      4
84         { .n_name = "_mfctable" },
85 #define N_VIFTABLE      5
86         { .n_name = "_viftable" },
87 #define N_IPX           6
88         { .n_name = "_ipxpcb_list"},
89 #define N_IPXSTAT       7
90         { .n_name = "_ipxstat"},
91 #define N_SPXSTAT       8
92         { .n_name = "_spx_istat"},
93 #define N_DDPSTAT       9
94         { .n_name = "_ddpstat"},
95 #define N_DDPCB         10
96         { .n_name = "_ddpcb"},
97 #define N_NGSOCKS       11
98         { .n_name = "_ngsocklist"},
99 #define N_IP6STAT       12
100         { .n_name = "_ip6stat" },
101 #define N_ICMP6STAT     13
102         { .n_name = "_icmp6stat" },
103 #define N_IPSECSTAT     14
104         { .n_name = "_ipsec4stat" },
105 #define N_IPSEC6STAT    15
106         { .n_name = "_ipsec6stat" },
107 #define N_PIM6STAT      16
108         { .n_name = "_pim6stat" },
109 #define N_MRT6STAT      17
110         { .n_name = "_mrt6stat" },
111 #define N_MF6CTABLE     18
112         { .n_name = "_mf6ctable" },
113 #define N_MIF6TABLE     19
114         { .n_name = "_mif6table" },
115 #define N_PFKEYSTAT     20
116         { .n_name = "_pfkeystat" },
117 #define N_MBSTAT        21
118         { .n_name = "_mbstat" },
119 #define N_MBTYPES       22
120         { .n_name = "_mbtypes" },
121 #define N_NMBCLUSTERS   23
122         { .n_name = "_nmbclusters" },
123 #define N_NMBUFS        24
124         { .n_name = "_nmbufs" },
125 #define N_MBHI          25
126         { .n_name = "_mbuf_hiwm" },
127 #define N_CLHI          26
128         { .n_name = "_clust_hiwm" },
129 #define N_NCPUS         27
130         { .n_name = "_smp_cpus" },
131 #define N_PAGESZ        28
132         { .n_name = "_pagesize" },
133 #define N_MBPSTAT       29
134         { .n_name = "_mb_statpcpu" },
135 #define N_RTTRASH       30
136         { .n_name = "_rttrash" },
137 #define N_MBLO          31
138         { .n_name = "_mbuf_lowm" },
139 #define N_CLLO          32
140         { .n_name = "_clust_lowm" },
141 #define N_CARPSTAT      33
142         { .n_name = "_carpstats" },
143 #define N_PFSYNCSTAT    34
144         { .n_name = "_pfsyncstats" },
145 #define N_AHSTAT        35
146         { .n_name = "_ahstat" },
147 #define N_ESPSTAT       36
148         { .n_name = "_espstat" },
149 #define N_IPCOMPSTAT    37
150         { .n_name = "_ipcompstat" },
151 #define N_TCPSTAT       38
152         { .n_name = "_tcpstat" },
153 #define N_UDPSTAT       39
154         { .n_name = "_udpstat" },
155 #define N_IPSTAT        40
156         { .n_name = "_ipstat" },
157 #define N_ICMPSTAT      41
158         { .n_name = "_icmpstat" },
159 #define N_IGMPSTAT      42
160         { .n_name = "_igmpstat" },
161 #define N_PIMSTAT       43
162         { .n_name = "_pimstat" },
163 #define N_TCBINFO       44
164         { .n_name = "_tcbinfo" },
165 #define N_UDBINFO       45
166         { .n_name = "_udbinfo" },
167 #define N_DIVCBINFO     46
168         { .n_name = "_divcbinfo" },
169 #define N_RIPCBINFO     47
170         { .n_name = "_ripcbinfo" },
171 #define N_UNP_COUNT     48
172         { .n_name = "_unp_count" },
173 #define N_UNP_GENCNT    49
174         { .n_name = "_unp_gencnt" },
175 #define N_UNP_DHEAD     50
176         { .n_name = "_unp_dhead" },
177 #define N_UNP_SHEAD     51
178         { .n_name = "_unp_shead" },
179 #define N_RIP6STAT      52
180         { .n_name = "_rip6stat" },
181 #define N_SCTPSTAT      53
182         { .n_name = "_sctpstat" },
183         { .n_name = NULL },
184 };
185
186 struct protox {
187         int     pr_index;               /* index into nlist of cb head */
188         int     pr_sindex;              /* index into nlist of stat block */
189         u_char  pr_wanted;              /* 1 if wanted, 0 otherwise */
190         void    (*pr_cblocks)(u_long, const char *, int, int);
191                                         /* control blocks printing routine */
192         void    (*pr_stats)(u_long, const char *, int, int);
193                                         /* statistics printing routine */
194         void    (*pr_istats)(char *);   /* per/if statistics printing routine */
195         const char      *pr_name;               /* well-known name */
196         int     pr_usesysctl;           /* non-zero if we use sysctl, not kvm */
197         int     pr_protocol;
198 } protox[] = {
199         { N_TCBINFO,    N_TCPSTAT,      1,      protopr,
200           tcp_stats,    NULL,           "tcp",  1,      IPPROTO_TCP },
201         { N_UDBINFO,    N_UDPSTAT,      1,      protopr,
202           udp_stats,    NULL,           "udp",  1,      IPPROTO_UDP },
203 #ifdef SCTP
204         { -1,           N_SCTPSTAT,     1,      sctp_protopr,
205           sctp_stats,   NULL,           "sctp", 1,      IPPROTO_SCTP },
206 #endif
207         { N_DIVCBINFO,  -1,             1,      protopr,
208           NULL,         NULL,           "divert", 1,    IPPROTO_DIVERT },
209         { N_RIPCBINFO,  N_IPSTAT,       1,      protopr,
210           ip_stats,     NULL,           "ip",   1,      IPPROTO_RAW },
211         { N_RIPCBINFO,  N_ICMPSTAT,     1,      protopr,
212           icmp_stats,   NULL,           "icmp", 1,      IPPROTO_ICMP },
213         { N_RIPCBINFO,  N_IGMPSTAT,     1,      protopr,
214           igmp_stats,   NULL,           "igmp", 1,      IPPROTO_IGMP },
215 #ifdef IPSEC
216         { -1,           N_IPSECSTAT,    1,      NULL,   /* keep as compat */
217           ipsec_stats,  NULL,           "ipsec", 0,     0},
218         { -1,           N_AHSTAT,       1,      NULL,
219           ah_stats,     NULL,           "ah",   0,      0},
220         { -1,           N_ESPSTAT,      1,      NULL,
221           esp_stats,    NULL,           "esp",  0,      0},
222         { -1,           N_IPCOMPSTAT,   1,      NULL,
223           ipcomp_stats, NULL,           "ipcomp", 0,    0},
224 #endif
225         { N_RIPCBINFO,  N_PIMSTAT,      1,      protopr,
226           pim_stats,    NULL,           "pim",  1,      IPPROTO_PIM },
227         { -1,           N_CARPSTAT,     1,      NULL,
228           carp_stats,   NULL,           "carp", 1,      0 },
229         { -1,           N_PFSYNCSTAT,   1,      NULL,
230           pfsync_stats, NULL,           "pfsync", 1,    0 },
231         { -1,           -1,             0,      NULL,
232           NULL,         NULL,           NULL,   0,      0 }
233 };
234
235 #ifdef INET6
236 struct protox ip6protox[] = {
237         { N_TCBINFO,    N_TCPSTAT,      1,      protopr,
238           tcp_stats,    NULL,           "tcp",  1,      IPPROTO_TCP },
239         { N_UDBINFO,    N_UDPSTAT,      1,      protopr,
240           udp_stats,    NULL,           "udp",  1,      IPPROTO_UDP },
241         { N_RIPCBINFO,  N_IP6STAT,      1,      protopr,
242           ip6_stats,    ip6_ifstats,    "ip6",  1,      IPPROTO_RAW },
243         { N_RIPCBINFO,  N_ICMP6STAT,    1,      protopr,
244           icmp6_stats,  icmp6_ifstats,  "icmp6", 1,     IPPROTO_ICMPV6 },
245 #ifdef IPSEC
246         { -1,           N_IPSEC6STAT,   1,      NULL,
247           ipsec_stats,  NULL,           "ipsec6", 0,    0 },
248 #endif
249 #ifdef notyet
250         { -1,           N_PIM6STAT,     1,      NULL,
251           pim6_stats,   NULL,           "pim6", 1,      0 },
252 #endif
253         { -1,           N_RIP6STAT,     1,      NULL,
254           rip6_stats,   NULL,           "rip6", 1,      0 },
255         { -1,           -1,             0,      NULL,
256           NULL,         NULL,           NULL,   0,      0 }
257 };
258 #endif /*INET6*/
259
260 #ifdef IPSEC
261 struct protox pfkeyprotox[] = {
262         { -1,           N_PFKEYSTAT,    1,      NULL,
263           pfkey_stats,  NULL,           "pfkey", 0,     0 },
264         { -1,           -1,             0,      NULL,
265           NULL,         NULL,           NULL,   0,      0 }
266 };
267 #endif
268
269 struct protox atalkprotox[] = {
270         { N_DDPCB,      N_DDPSTAT,      1,      atalkprotopr,
271           ddp_stats,    NULL,           "ddp",  0,      0 },
272         { -1,           -1,             0,      NULL,
273           NULL,         NULL,           NULL,   0,      0 }
274 };
275
276 struct protox netgraphprotox[] = {
277         { N_NGSOCKS,    -1,             1,      netgraphprotopr,
278           NULL,         NULL,           "ctrl", 0,      0 },
279         { N_NGSOCKS,    -1,             1,      netgraphprotopr,
280           NULL,         NULL,           "data", 0,      0 },
281         { -1,           -1,             0,      NULL,
282           NULL,         NULL,           NULL,   0,      0 }
283 };
284
285 #ifdef IPX
286 struct protox ipxprotox[] = {
287         { N_IPX,        N_IPXSTAT,      1,      ipxprotopr,
288           ipx_stats,    NULL,           "ipx",  0,      0 },
289         { N_IPX,        N_SPXSTAT,      1,      ipxprotopr,
290           spx_stats,    NULL,           "spx",  0,      0 },
291         { -1,           -1,             0,      NULL,
292           NULL,         NULL,           0,      0,      0 }
293 };
294 #endif
295
296 struct protox *protoprotox[] = {
297                                          protox,
298 #ifdef INET6
299                                          ip6protox,
300 #endif
301 #ifdef IPSEC
302                                          pfkeyprotox,
303 #endif
304 #ifdef IPX
305                                          ipxprotox,
306 #endif
307                                          atalkprotox, NULL };
308
309 static void printproto(struct protox *, const char *);
310 static void usage(void);
311 static struct protox *name2protox(const char *);
312 static struct protox *knownname(const char *);
313
314 static kvm_t *kvmd;
315 static char *nlistf = NULL, *memf = NULL;
316
317 int     Aflag;          /* show addresses of protocol control block */
318 int     aflag;          /* show all sockets (including servers) */
319 int     Bflag;          /* show information about bpf consumers */
320 int     bflag;          /* show i/f total bytes in/out */
321 int     dflag;          /* show i/f dropped packets */
322 int     gflag;          /* show group (multicast) routing or stats */
323 int     hflag;          /* show counters in human readable format */
324 int     iflag;          /* show interfaces */
325 int     Lflag;          /* show size of listen queues */
326 int     mflag;          /* show memory stats */
327 int     numeric_addr;   /* show addresses numerically */
328 int     numeric_port;   /* show ports numerically */
329 static int pflag;       /* show given protocol */
330 int     rflag;          /* show routing tables (or routing stats) */
331 int     sflag;          /* show protocol statistics */
332 int     tflag;          /* show i/f watchdog timers */
333 int     Wflag;          /* wide display */
334 int     xflag;          /* extra information, includes all socket buffer info */
335 int     zflag;          /* zero stats */
336
337 int     interval;       /* repeat interval for i/f stats */
338
339 char    *interface;     /* desired i/f for stats, or NULL for all i/fs */
340 int     unit;           /* unit number for above */
341
342 int     af;             /* address family */
343 int     live;           /* true if we are examining a live system */
344
345 int
346 main(int argc, char *argv[])
347 {
348         struct protox *tp = NULL;  /* for printing cblocks & stats */
349         int ch;
350
351         af = AF_UNSPEC;
352
353         while ((ch = getopt(argc, argv, "AaBbdf:ghI:iLlM:mN:np:rSstuWw:xz")) != -1)
354                 switch(ch) {
355                 case 'A':
356                         Aflag = 1;
357                         break;
358                 case 'a':
359                         aflag = 1;
360                         break;
361                 case 'B':
362                         Bflag = 1;
363                         break;
364                 case 'b':
365                         bflag = 1;
366                         break;
367                 case 'd':
368                         dflag = 1;
369                         break;
370                 case 'f':
371                         if (strcmp(optarg, "ipx") == 0)
372                                 af = AF_IPX;
373                         else if (strcmp(optarg, "inet") == 0)
374                                 af = AF_INET;
375 #ifdef INET6
376                         else if (strcmp(optarg, "inet6") == 0)
377                                 af = AF_INET6;
378 #endif
379 #ifdef IPSEC
380                         else if (strcmp(optarg, "pfkey") == 0)
381                                 af = PF_KEY;
382 #endif
383                         else if (strcmp(optarg, "unix") == 0)
384                                 af = AF_UNIX;
385                         else if (strcmp(optarg, "atalk") == 0)
386                                 af = AF_APPLETALK;
387                         else if (strcmp(optarg, "ng") == 0
388                             || strcmp(optarg, "netgraph") == 0)
389                                 af = AF_NETGRAPH;
390                         else if (strcmp(optarg, "link") == 0)
391                                 af = AF_LINK;
392                         else {
393                                 errx(1, "%s: unknown address family", optarg);
394                         }
395                         break;
396                 case 'g':
397                         gflag = 1;
398                         break;
399                 case 'h':
400                         hflag = 1;
401                         break;
402                 case 'I': {
403                         char *cp;
404
405                         iflag = 1;
406                         for (cp = interface = optarg; isalpha(*cp); cp++)
407                                 continue;
408                         unit = atoi(cp);
409                         break;
410                 }
411                 case 'i':
412                         iflag = 1;
413                         break;
414                 case 'L':
415                         Lflag = 1;
416                         break;
417                 case 'M':
418                         memf = optarg;
419                         break;
420                 case 'm':
421                         mflag = 1;
422                         break;
423                 case 'N':
424                         nlistf = optarg;
425                         break;
426                 case 'n':
427                         numeric_addr = numeric_port = 1;
428                         break;
429                 case 'p':
430                         if ((tp = name2protox(optarg)) == NULL) {
431                                 errx(1,
432                                      "%s: unknown or uninstrumented protocol",
433                                      optarg);
434                         }
435                         pflag = 1;
436                         break;
437                 case 'r':
438                         rflag = 1;
439                         break;
440                 case 's':
441                         ++sflag;
442                         break;
443                 case 'S':
444                         numeric_addr = 1;
445                         break;
446                 case 't':
447                         tflag = 1;
448                         break;
449                 case 'u':
450                         af = AF_UNIX;
451                         break;
452                 case 'W':
453                 case 'l':
454                         Wflag = 1;
455                         break;
456                 case 'w':
457                         interval = atoi(optarg);
458                         iflag = 1;
459                         break;
460                 case 'x':
461                         xflag = 1;
462                         break;
463                 case 'z':
464                         zflag = 1;
465                         break;
466                 case '?':
467                 default:
468                         usage();
469                 }
470         argv += optind;
471         argc -= optind;
472
473 #define BACKWARD_COMPATIBILITY
474 #ifdef  BACKWARD_COMPATIBILITY
475         if (*argv) {
476                 if (isdigit(**argv)) {
477                         interval = atoi(*argv);
478                         if (interval <= 0)
479                                 usage();
480                         ++argv;
481                         iflag = 1;
482                 }
483                 if (*argv) {
484                         nlistf = *argv;
485                         if (*++argv)
486                                 memf = *argv;
487                 }
488         }
489 #endif
490
491         /*
492          * Discard setgid privileges if not the running kernel so that bad
493          * guys can't print interesting stuff from kernel memory.
494          */
495         live = (nlistf == NULL && memf == NULL);
496         if (!live)
497                 setgid(getgid());
498
499         if (Bflag) {
500                 if (!live)
501                         usage();
502                 bpf_stats(interface);
503                 exit(0);
504         }
505         if (mflag) {
506                 if (memf != NULL) {
507                         if (kread(0, NULL, 0) == 0)
508                                 mbpr(kvmd, nl[N_MBSTAT].n_value);
509                 } else
510                         mbpr(NULL, 0);
511                 exit(0);
512         }
513 #if 0
514         /*
515          * Keep file descriptors open to avoid overhead
516          * of open/close on each call to get* routines.
517          */
518         sethostent(1);
519         setnetent(1);
520 #else
521         /*
522          * This does not make sense any more with DNS being default over
523          * the files.  Doing a setXXXXent(1) causes a tcp connection to be
524          * used for the queries, which is slower.
525          */
526 #endif
527         kread(0, NULL, 0);
528         if (iflag && !sflag) {
529                 intpr(interval, nl[N_IFNET].n_value, NULL);
530                 exit(0);
531         }
532         if (rflag) {
533                 if (sflag)
534                         rt_stats(nl[N_RTSTAT].n_value, nl[N_RTTRASH].n_value);
535                 else
536                         routepr(nl[N_RTREE].n_value);
537                 exit(0);
538         }
539         if (gflag) {
540                 if (sflag) {
541                         if (af == AF_INET || af == AF_UNSPEC)
542                                 mrt_stats(nl[N_MRTSTAT].n_value);
543 #ifdef INET6
544                         if (af == AF_INET6 || af == AF_UNSPEC)
545                                 mrt6_stats(nl[N_MRT6STAT].n_value);
546 #endif
547                 } else {
548                         if (af == AF_INET || af == AF_UNSPEC)
549                                 mroutepr(nl[N_MFCTABLE].n_value,
550                                          nl[N_VIFTABLE].n_value);
551 #ifdef INET6
552                         if (af == AF_INET6 || af == AF_UNSPEC)
553                                 mroute6pr(nl[N_MF6CTABLE].n_value,
554                                           nl[N_MIF6TABLE].n_value);
555 #endif
556                 }
557                 ifmalist_dump();
558                 exit(0);
559         }
560
561         if (tp) {
562                 printproto(tp, tp->pr_name);
563                 exit(0);
564         }
565         if (af == AF_INET || af == AF_UNSPEC)
566                 for (tp = protox; tp->pr_name; tp++)
567                         printproto(tp, tp->pr_name);
568 #ifdef INET6
569         if (af == AF_INET6 || af == AF_UNSPEC)
570                 for (tp = ip6protox; tp->pr_name; tp++)
571                         printproto(tp, tp->pr_name);
572 #endif /*INET6*/
573 #ifdef IPSEC
574         if (af == PF_KEY || af == AF_UNSPEC)
575                 for (tp = pfkeyprotox; tp->pr_name; tp++)
576                         printproto(tp, tp->pr_name);
577 #endif /*IPSEC*/
578 #ifdef IPX
579         if (af == AF_IPX || af == AF_UNSPEC) {
580                 for (tp = ipxprotox; tp->pr_name; tp++)
581                         printproto(tp, tp->pr_name);
582         }
583 #endif /* IPX */
584         if (af == AF_APPLETALK || af == AF_UNSPEC)
585                 for (tp = atalkprotox; tp->pr_name; tp++)
586                         printproto(tp, tp->pr_name);
587         if (af == AF_NETGRAPH || af == AF_UNSPEC)
588                 for (tp = netgraphprotox; tp->pr_name; tp++)
589                         printproto(tp, tp->pr_name);
590         if ((af == AF_UNIX || af == AF_UNSPEC) && !Lflag && !sflag)
591                 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
592                     nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value);
593         exit(0);
594 }
595
596 /*
597  * Print out protocol statistics or control blocks (per sflag).
598  * If the interface was not specifically requested, and the symbol
599  * is not in the namelist, ignore this one.
600  */
601 static void
602 printproto(tp, name)
603         struct protox *tp;
604         const char *name;
605 {
606         void (*pr)(u_long, const char *, int, int);
607         u_long off;
608
609         if (sflag) {
610                 if (iflag) {
611                         if (tp->pr_istats)
612                                 intpr(interval, nl[N_IFNET].n_value,
613                                       tp->pr_istats);
614                         else if (pflag)
615                                 printf("%s: no per-interface stats routine\n",
616                                     tp->pr_name);
617                         return;
618                 } else {
619                         pr = tp->pr_stats;
620                         if (!pr) {
621                                 if (pflag)
622                                         printf("%s: no stats routine\n",
623                                             tp->pr_name);
624                                 return;
625                         }
626                         if (tp->pr_usesysctl && live)
627                                 off = 0;
628                         else if (tp->pr_sindex < 0) {
629                                 if (pflag)
630                                         printf(
631                                     "%s: stats routine doesn't work on cores\n",
632                                             tp->pr_name);
633                                 return;
634                         } else
635                                 off = nl[tp->pr_sindex].n_value;
636                 }
637         } else {
638                 pr = tp->pr_cblocks;
639                 if (!pr) {
640                         if (pflag)
641                                 printf("%s: no PCB routine\n", tp->pr_name);
642                         return;
643                 }
644                 if (tp->pr_usesysctl && live)
645                         off = 0;
646                 else if (tp->pr_index < 0) {
647                         if (pflag)
648                                 printf(
649                                     "%s: PCB routine doesn't work on cores\n",
650                                     tp->pr_name);
651                         return;
652                 } else
653                         off = nl[tp->pr_index].n_value;
654         }
655         if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
656             af != AF_UNSPEC))
657                 (*pr)(off, name, af, tp->pr_protocol);
658 }
659
660 /*
661  * Read kernel memory, return 0 on success.
662  */
663 int
664 kread(u_long addr, void *buf, size_t size)
665 {
666         char errbuf[_POSIX2_LINE_MAX];
667
668         if (kvmd == NULL) {
669                 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
670                 setgid(getgid());
671                 if (kvmd != NULL) {
672                         if (kvm_nlist(kvmd, nl) < 0) {
673                                 if (nlistf)
674                                         errx(1, "%s: kvm_nlist: %s", nlistf,
675                                              kvm_geterr(kvmd));
676                                 else
677                                         errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
678                         }
679
680                         if (nl[0].n_type == 0) {
681                                 if (nlistf)
682                                         errx(1, "%s: no namelist", nlistf);
683                                 else
684                                         errx(1, "no namelist");
685                         }
686                 } else {
687                         warnx("kvm not available: %s", errbuf);
688                         return(-1);
689                 }
690         }
691         if (!buf)
692                 return (0);
693         if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
694                 warnx("%s", kvm_geterr(kvmd));
695                 return (-1);
696         }
697         return (0);
698 }
699
700 const char *
701 plural(uintmax_t n)
702 {
703         return (n != 1 ? "s" : "");
704 }
705
706 const char *
707 plurales(uintmax_t n)
708 {
709         return (n != 1 ? "es" : "");
710 }
711
712 const char *
713 pluralies(uintmax_t n)
714 {
715         return (n != 1 ? "ies" : "y");
716 }
717
718 /*
719  * Find the protox for the given "well-known" name.
720  */
721 static struct protox *
722 knownname(const char *name)
723 {
724         struct protox **tpp, *tp;
725
726         for (tpp = protoprotox; *tpp; tpp++)
727                 for (tp = *tpp; tp->pr_name; tp++)
728                         if (strcmp(tp->pr_name, name) == 0)
729                                 return (tp);
730         return (NULL);
731 }
732
733 /*
734  * Find the protox corresponding to name.
735  */
736 static struct protox *
737 name2protox(const char *name)
738 {
739         struct protox *tp;
740         char **alias;                   /* alias from p->aliases */
741         struct protoent *p;
742
743         /*
744          * Try to find the name in the list of "well-known" names. If that
745          * fails, check if name is an alias for an Internet protocol.
746          */
747         if ((tp = knownname(name)) != NULL)
748                 return (tp);
749
750         setprotoent(1);                 /* make protocol lookup cheaper */
751         while ((p = getprotoent()) != NULL) {
752                 /* assert: name not same as p->name */
753                 for (alias = p->p_aliases; *alias; alias++)
754                         if (strcmp(name, *alias) == 0) {
755                                 endprotoent();
756                                 return (knownname(p->p_name));
757                         }
758         }
759         endprotoent();
760         return (NULL);
761 }
762
763 static void
764 usage(void)
765 {
766         (void)fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
767 "usage: netstat [-AaLnSW] [-f protocol_family | -p protocol]\n"
768 "               [-M core] [-N system]",
769 "       netstat -i | -I interface [-abdhnt] [-f address_family]\n"
770 "               [-M core] [-N system]",
771 "       netstat -w wait [-I interface] [-d] [-M core] [-N system]",
772 "       netstat -s [-s] [-z] [-f protocol_family | -p protocol] [-M core]",
773 "       netstat -i | -I interface -s [-f protocol_family | -p protocol]\n"
774 "               [-M core] [-N system]",
775 "       netstat -m [-M core] [-N system]",
776 "       netstat -B [ -I interface]",
777 "       netstat -r [-AenW] [-f address_family] [-M core] [-N system]",
778 "       netstat -rs [-s] [-M core] [-N system]",
779 "       netstat -g [-W] [-f address_family] [-M core] [-N system]",
780 "       netstat -gs [-s] [-f address_family] [-M core] [-N system]");
781         exit(1);
782 }