main.c revision 1.99 1 /* $NetBSD: main.c,v 1.99 2016/07/14 20:13:10 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.99 2016/07/14 20:13:10 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_ATINTRQ1 39
150 { "_atintrq1", 0, 0, 0, 0 },
151 #define N_ATINTRQ2 40
152 { "_atintrq2", 0, 0, 0, 0 },
153 #define N_NATMINTRQ 41
154 { "_natmintrq", 0, 0, 0, 0 },
155 #define N_PPPOEDISCINQ 42
156 { "_ppoediscinq", 0, 0, 0, 0 },
157 #define N_PPPOEINQ 43
158 { "_ppoeinq", 0, 0, 0, 0 },
159 #define N_HARDCLOCK_TICKS 44
160 { "_hardclock_ticks", 0, 0, 0, 0 },
161 #define N_PIMSTAT 45
162 { "_pimstat", 0, 0, 0, 0 },
163 #define N_CARPSTAT 46
164 { "_carpstats", 0, 0, 0, 0 }, /* not available via kvm */
165 #define N_PFSYNCSTAT 47
166 { "_pfsyncstats", 0, 0, 0, 0}, /* not available via kvm */
167 { "", 0, 0, 0, 0 },
168 };
169
170 struct protox {
171 u_char pr_index; /* index into nlist of cb head */
172 u_char pr_sindex; /* index into nlist of stat block */
173 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
174 void (*pr_cblocks) /* control blocks printing routine */
175 (u_long, const char *);
176 void (*pr_stats) /* statistics printing routine */
177 (u_long, const char *);
178 void (*pr_istats)
179 (const char *); /* per/if statistics printing routine */
180 void (*pr_dump) /* PCB state dump routine */
181 (u_long, const char *, u_long);
182 const char *pr_name; /* well-known name */
183 } protox[] = {
184 { N_TCBTABLE, N_TCPSTAT, 1, protopr,
185 tcp_stats, NULL, tcp_dump, "tcp" },
186 { N_UDBTABLE, N_UDPSTAT, 1, protopr,
187 udp_stats, NULL, 0, "udp" },
188 { -1, N_IPSTAT, 1, 0,
189 ip_stats, NULL, 0, "ip" },
190 { -1, N_ICMPSTAT, 1, 0,
191 icmp_stats, NULL, 0, "icmp" },
192 { -1, N_IGMPSTAT, 1, 0,
193 igmp_stats, NULL, 0, "igmp" },
194 { -1, N_CARPSTAT, 1, 0,
195 carp_stats, NULL, 0, "carp" },
196 #ifdef IPSEC
197 { -1, N_IPSECSTAT, 1, 0,
198 fast_ipsec_stats, NULL, 0, "ipsec" },
199 #endif
200 { -1, N_PIMSTAT, 1, 0,
201 pim_stats, NULL, 0, "pim" },
202 { -1, N_PFSYNCSTAT, 1, 0,
203 pfsync_stats, NULL, 0, "pfsync" },
204 { -1, -1, 0, 0,
205 0, NULL, 0, 0 }
206 };
207
208 #ifdef INET6
209 struct protox ip6protox[] = {
210 { -1, N_IP6STAT, 1, 0,
211 ip6_stats, ip6_ifstats, 0, "ip6" },
212 { -1, N_ICMP6STAT, 1, 0,
213 icmp6_stats, icmp6_ifstats, 0, "icmp6" },
214 #ifdef TCP6
215 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
216 tcp6_stats, NULL, tcp6_dump, "tcp6" },
217 #else
218 { N_TCBTABLE, N_TCP6STAT, 1, ip6protopr,
219 tcp_stats, NULL, tcp6_dump, "tcp6" },
220 #endif
221 { N_UDBTABLE, N_UDP6STAT, 1, ip6protopr,
222 udp6_stats, NULL, 0, "udp6" },
223 #ifdef IPSEC
224 { -1, N_IPSEC6STAT, 1, 0,
225 fast_ipsec_stats, NULL, 0, "ipsec6" },
226 #endif
227 { -1, N_PIM6STAT, 1, 0,
228 pim6_stats, NULL, 0, "pim6" },
229 { -1, N_RIP6STAT, 1, 0,
230 rip6_stats, NULL, 0, "rip6" },
231 { -1, -1, 0, 0,
232 0, NULL, 0, 0 }
233 };
234 #endif
235
236 struct protox arpprotox[] = {
237 { -1, N_ARPSTAT, 1, 0,
238 arp_stats, NULL, 0, "arp" },
239 { -1, -1, 0, 0,
240 0, NULL, 0, 0 }
241 };
242
243 #ifdef IPSEC
244 struct protox pfkeyprotox[] = {
245 { -1, N_PFKEYSTAT, 1, 0,
246 pfkey_stats, NULL, 0, "pfkey" },
247 { -1, -1, 0, 0,
248 0, NULL, 0, 0 }
249 };
250 #endif
251
252 #ifndef SMALL
253 struct protox atalkprotox[] = {
254 { N_DDPCB, N_DDPSTAT, 1, atalkprotopr,
255 ddp_stats, NULL, 0, "ddp" },
256 { -1, -1, 0, 0,
257 0, NULL, 0, NULL }
258 };
259 #endif
260
261 struct protox *protoprotox[] = { protox,
262 #ifdef INET6
263 ip6protox,
264 #endif
265 arpprotox,
266 #ifdef IPSEC
267 pfkeyprotox,
268 #endif
269 #ifndef SMALL
270 atalkprotox,
271 #endif
272 NULL };
273
274 const struct softintrq {
275 const char *siq_name;
276 int siq_index;
277 } softintrq[] = {
278 { "arpintrq", N_ARPINTRQ },
279 { "atintrq1", N_ATINTRQ1 },
280 { "atintrq2", N_ATINTRQ2 },
281 { "natmintrq", N_NATMINTRQ },
282 { "ppoediscinq", N_PPPOEDISCINQ },
283 { "ppoeinq", N_PPPOEINQ },
284 { NULL, -1 },
285 };
286
287 static void printproto(struct protox *, const char *);
288 static void print_softintrq(void);
289 __dead static void usage(void);
290 static struct protox *name2protox(const char *);
291 static struct protox *knownname(const char *);
292 static void prepare(const char *, const char *, struct protox *tp);
293 static kvm_t *prepare_kvmd(const char *, const char *, char *);
294
295 static kvm_t *kvmd = NULL;
296 gid_t egid;
297 int interval; /* repeat interval for i/f stats */
298 static const char *nlistf = NULL, *memf = NULL;
299
300 kvm_t *
301 get_kvmd(void)
302 {
303 char buf[_POSIX2_LINE_MAX];
304
305 if (kvmd != NULL)
306 return kvmd;
307 if ((kvmd = prepare_kvmd(nlistf, memf, buf)) == NULL)
308 errx(1, "kvm error: %s", buf);
309 return kvmd;
310 }
311
312 static kvm_t *
313 prepare_kvmd(const char *nf, const char *mf, char *errbuf)
314 {
315 kvm_t *k;
316
317 (void)setegid(egid);
318 k = kvm_openfiles(nf, mf, NULL, O_RDONLY, errbuf);
319 (void)setgid(getgid());
320 return k;
321 }
322
323 void
324 prepare(const char *nf, const char *mf, struct protox *tp)
325 {
326 char buf[_POSIX2_LINE_MAX];
327 /*
328 * Try to figure out if we can use sysctl or not.
329 */
330 if (nf != NULL || mf != NULL) {
331 /* Of course, we can't use sysctl with dumps. */
332 if (force_sysctl)
333 errx(EXIT_FAILURE, "can't use sysctl with dumps");
334
335 /*
336 * If we have -M or -N, we're not dealing with live memory
337 * or want to use kvm interface explicitly. It is sometimes
338 * useful to dig inside of kernel without extending
339 * sysctl interface (i.e., without rebuilding kernel).
340 */
341 use_sysctl = 0;
342 } else if (qflag ||
343 #ifndef SMALL
344 gflag ||
345 #endif
346 (pflag && tp->pr_sindex == N_PIMSTAT) ||
347 Pflag) {
348 /* These flags are not yet supported via sysctl(3). */
349 use_sysctl = 0;
350 } else {
351 /* We can use sysctl(3). */
352 use_sysctl = 1;
353 }
354
355 if (force_sysctl && !use_sysctl) {
356 /* Let the user know what's about to happen. */
357 warnx("forcing sysctl usage even though it might not be "\
358 "supported");
359 use_sysctl = 1;
360 }
361
362 kvmd = prepare_kvmd(nf, mf, buf);
363
364 if (!use_sysctl) {
365
366 if (kvmd == NULL)
367 errx(1, "kvm error: %s", buf);
368 if (kvm_nlist(kvmd, nl) < 0 || nl[0].n_type == 0) {
369 if (nf)
370 errx(1, "%s: no namelist", nf);
371 else
372 errx(1, "no namelist");
373 }
374 } else
375 (void)setgid(getgid());
376 }
377
378 int
379 main(int argc, char *argv[])
380 {
381 struct protoent *p;
382 struct protox *tp; /* for printing cblocks & stats */
383 int ch;
384 char *cp;
385 char *afname, *afnames;
386 u_long pcbaddr;
387
388 if (prog_init) {
389 if (prog_init() == -1)
390 err(1, "init failed");
391 force_sysctl = 1; /* cheap trick */
392 }
393
394 egid = getegid();
395 (void)setegid(getgid());
396 tp = NULL;
397 af = AF_UNSPEC;
398 afnames = NULL;
399 pcbaddr = 0;
400
401 while ((ch = getopt(argc, argv,
402 "AabBdf:ghI:LliM:mN:nP:p:qrsStTuVvw:X")) != -1)
403 switch (ch) {
404 case 'A':
405 Aflag = RT_AFLAG;
406 break;
407 case 'a':
408 aflag = 1;
409 break;
410 case 'b':
411 bflag = 1;
412 break;
413 case 'B':
414 Bflag = 1;
415 break;
416 case 'd':
417 dflag = 1;
418 break;
419 case 'f':
420 afnames = optarg;
421 break;
422 #ifndef SMALL
423 case 'g':
424 gflag = 1;
425 break;
426 #endif
427 case 'h':
428 hflag = 1;
429 break;
430 case 'I':
431 iflag = 1;
432 interface = optarg;
433 break;
434 case 'i':
435 iflag = 1;
436 break;
437 case 'L':
438 Lflag = RT_LFLAG;
439 break;
440 case 'l':
441 lflag = 1;
442 break;
443 case 'M':
444 memf = optarg;
445 break;
446 case 'm':
447 mflag = 1;
448 break;
449 case 'N':
450 nlistf = optarg;
451 break;
452 case 'n':
453 numeric_addr = numeric_port = nflag = RT_NFLAG;
454 break;
455 case 'P':
456 errno = 0;
457 pcbaddr = strtoul(optarg, &cp, 16);
458 if (*cp != '\0' || errno == ERANGE)
459 errx(1, "invalid PCB address %s",
460 optarg);
461 Pflag = 1;
462 break;
463 case 'p':
464 if ((tp = name2protox(optarg)) == NULL)
465 errx(1, "%s: unknown or uninstrumented protocol",
466 optarg);
467 pflag = 1;
468 break;
469 case 'q':
470 qflag = 1;
471 break;
472 case 'r':
473 rflag = 1;
474 break;
475 case 's':
476 ++sflag;
477 break;
478 case 'S':
479 numeric_addr = 1;
480 break;
481 case 't':
482 tflag = 1;
483 break;
484 case 'T':
485 tagflag = RT_TFLAG;
486 break;
487 case 'u':
488 af = AF_LOCAL;
489 break;
490 case 'V':
491 Vflag++;
492 break;
493 case 'v':
494 vflag = RT_VFLAG;
495 break;
496 case 'w':
497 interval = atoi(optarg);
498 iflag = 1;
499 break;
500 case 'X':
501 force_sysctl = 1;
502 break;
503 case '?':
504 default:
505 usage();
506 }
507 argv += optind;
508 argc -= optind;
509
510 #define BACKWARD_COMPATIBILITY
511 #ifdef BACKWARD_COMPATIBILITY
512 if (*argv) {
513 if (isdigit((unsigned char)**argv)) {
514 interval = atoi(*argv);
515 if (interval <= 0)
516 usage();
517 ++argv;
518 iflag = 1;
519 }
520 if (*argv) {
521 nlistf = *argv;
522 if (*++argv)
523 memf = *argv;
524 }
525 }
526 #endif
527
528 prepare(nlistf, memf, tp);
529
530 #ifndef SMALL
531 if (Bflag) {
532 if (sflag)
533 bpf_stats();
534 else
535 bpf_dump(interface);
536 exit(0);
537 }
538 #endif
539
540 if (mflag) {
541 mbpr(nl[N_MBSTAT].n_value, nl[N_MSIZE].n_value,
542 nl[N_MCLBYTES].n_value, nl[N_MBPOOL].n_value,
543 nl[N_MCLPOOL].n_value);
544 exit(0);
545 }
546 if (Pflag) {
547 if (tp == NULL) {
548 /* Default to TCP. */
549 tp = name2protox("tcp");
550 }
551 if (tp->pr_dump)
552 (*tp->pr_dump)(nl[tp->pr_index].n_value, tp->pr_name,
553 pcbaddr);
554 else
555 printf("%s: no PCB dump routine\n", tp->pr_name);
556 exit(0);
557 }
558 if (pflag) {
559 if (iflag && tp->pr_istats)
560 intpr(interval, nl[N_IFNET_LIST].n_value, tp->pr_istats);
561 else if (tp->pr_stats)
562 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
563 tp->pr_name);
564 else
565 printf("%s: no stats routine\n", tp->pr_name);
566 exit(0);
567 }
568 if (qflag) {
569 print_softintrq();
570 exit(0);
571 }
572 /*
573 * Keep file descriptors open to avoid overhead
574 * of open/close on each call to get* routines.
575 */
576 sethostent(1);
577 setnetent(1);
578 /*
579 * If -f was used afnames != NULL, loop over the address families.
580 * Otherwise do this at least once (with af == AF_UNSPEC).
581 */
582 afname = NULL;
583 do {
584 if (afnames != NULL) {
585 afname = strsep(&afnames, ",");
586 if (afname == NULL)
587 break; /* Exit early */
588 if (strcmp(afname, "inet") == 0)
589 af = AF_INET;
590 else if (strcmp(afname, "inet6") == 0)
591 af = AF_INET6;
592 else if (strcmp(afname, "arp") == 0)
593 af = AF_ARP;
594 else if (strcmp(afname, "pfkey") == 0)
595 af = PF_KEY;
596 else if (strcmp(afname, "unix") == 0
597 || strcmp(afname, "local") == 0)
598 af = AF_LOCAL;
599 else if (strcmp(afname, "atalk") == 0)
600 af = AF_APPLETALK;
601 else if (strcmp(afname, "mpls") == 0)
602 af = AF_MPLS;
603 else {
604 warnx("%s: unknown address family",
605 afname);
606 continue;
607 }
608 }
609
610 if (iflag) {
611 if (af != AF_UNSPEC)
612 goto protostat;
613
614 intpr(interval, nl[N_IFNET_LIST].n_value, NULL);
615 break;
616 }
617 if (rflag) {
618 if (sflag)
619 rt_stats(use_sysctl ? 0 : nl[N_RTSTAT].n_value);
620 else {
621 if (use_sysctl)
622 p_rttables(af,
623 nflag|tagflag|vflag|Lflag, 0, ~0);
624 else
625 routepr(nl[N_RTREE].n_value);
626 }
627 break;
628 }
629 #ifndef SMALL
630 if (gflag) {
631 if (sflag) {
632 if (af == AF_INET || af == AF_UNSPEC)
633 mrt_stats(nl[N_MRTPROTO].n_value,
634 nl[N_MRTSTAT].n_value);
635 #ifdef INET6
636 if (af == AF_INET6 || af == AF_UNSPEC)
637 mrt6_stats(nl[N_MRT6PROTO].n_value,
638 nl[N_MRT6STAT].n_value);
639 #endif
640 }
641 else {
642 if (af == AF_INET || af == AF_UNSPEC)
643 mroutepr(nl[N_MRTPROTO].n_value,
644 nl[N_MFCHASHTBL].n_value,
645 nl[N_MFCHASH].n_value,
646 nl[N_VIFTABLE].n_value);
647 #ifdef INET6
648 if (af == AF_INET6 || af == AF_UNSPEC)
649 mroute6pr(nl[N_MRT6PROTO].n_value,
650 nl[N_MF6CTABLE].n_value,
651 nl[N_MIF6TABLE].n_value);
652 #endif
653 }
654 break;
655 }
656 #endif
657 protostat:
658 if (af == AF_INET || af == AF_UNSPEC) {
659 setprotoent(1);
660 setservent(1);
661 /* ugh, this is O(MN) ... why do we do this? */
662 while ((p = getprotoent()) != NULL) {
663 for (tp = protox; tp->pr_name; tp++)
664 if (strcmp(tp->pr_name, p->p_name) == 0)
665 break;
666 if (tp->pr_name == 0 || tp->pr_wanted == 0)
667 continue;
668 printproto(tp, p->p_name);
669 tp->pr_wanted = 0;
670 }
671 endprotoent();
672 for (tp = protox; tp->pr_name; tp++)
673 if (tp->pr_wanted)
674 printproto(tp, tp->pr_name);
675 }
676 #ifdef INET6
677 if (af == AF_INET6 || af == AF_UNSPEC)
678 for (tp = ip6protox; tp->pr_name; tp++)
679 printproto(tp, tp->pr_name);
680 #endif
681 if (af == AF_ARP || af == AF_UNSPEC)
682 for (tp = arpprotox; tp->pr_name; tp++)
683 printproto(tp, tp->pr_name);
684 #ifdef IPSEC
685 if (af == PF_KEY || af == AF_UNSPEC)
686 for (tp = pfkeyprotox; tp->pr_name; tp++)
687 printproto(tp, tp->pr_name);
688 #endif
689 #ifndef SMALL
690 if (af == AF_APPLETALK || af == AF_UNSPEC)
691 for (tp = atalkprotox; tp->pr_name; tp++)
692 printproto(tp, tp->pr_name);
693 if ((af == AF_LOCAL || af == AF_UNSPEC) && !sflag)
694 unixpr(nl[N_UNIXSW].n_value);
695 #endif
696 } while (afnames != NULL && afname != NULL);
697 exit(0);
698 }
699
700 /*
701 * Print out protocol statistics or control blocks (per sflag).
702 * If the interface was not specifically requested, and the symbol
703 * is not in the namelist, ignore this one.
704 */
705 static void
706 printproto(struct protox *tp, const char *name)
707 {
708 void (*pr)(u_long, const char *);
709 u_long off;
710
711 if (sflag) {
712 if (iflag) {
713 if (tp->pr_istats)
714 intpr(interval, nl[N_IFNET_LIST].n_value,
715 tp->pr_istats);
716 return;
717 }
718 else {
719 pr = tp->pr_stats;
720 off = nl[tp->pr_sindex].n_value;
721 }
722 } else {
723 pr = tp->pr_cblocks;
724 off = nl[tp->pr_index].n_value;
725 }
726 if (pr != NULL && ((off || af != AF_UNSPEC) || use_sysctl)) {
727 (*pr)(off, name);
728 }
729 }
730
731 /*
732 * Print softintrq status.
733 */
734 void
735 print_softintrq(void)
736 {
737 struct ifqueue intrq, *ifq = &intrq;
738 const struct softintrq *siq;
739 u_long off;
740
741 for (siq = softintrq; siq->siq_name != NULL; siq++) {
742 off = nl[siq->siq_index].n_value;
743 if (off == 0)
744 continue;
745
746 kread(off, (char *)ifq, sizeof(*ifq));
747 printf("%s:\n", siq->siq_name);
748 printf("\tqueue length: %d\n", ifq->ifq_len);
749 printf("\tmaximum queue length: %d\n", ifq->ifq_maxlen);
750 printf("\tpackets dropped: %d\n", ifq->ifq_drops);
751 }
752 }
753
754 /*
755 * Read kernel memory, return 0 on success.
756 */
757 int
758 kread(u_long addr, char *buf, int size)
759 {
760
761 if (kvm_read(kvmd, addr, buf, size) != size) {
762 warnx("%s", kvm_geterr(kvmd));
763 return (-1);
764 }
765 return (0);
766 }
767
768 const char *
769 plural(int n)
770 {
771
772 return (n != 1 ? "s" : "");
773 }
774
775 const char *
776 plurales(int n)
777 {
778
779 return (n != 1 ? "es" : "");
780 }
781
782 int
783 get_hardticks(void)
784 {
785 int hardticks;
786
787 kread(nl[N_HARDCLOCK_TICKS].n_value, (char *)&hardticks,
788 sizeof(hardticks));
789 return (hardticks);
790 }
791
792 /*
793 * Find the protox for the given "well-known" name.
794 */
795 static struct protox *
796 knownname(const char *name)
797 {
798 struct protox **tpp, *tp;
799
800 for (tpp = protoprotox; *tpp; tpp++)
801 for (tp = *tpp; tp->pr_name; tp++)
802 if (strcmp(tp->pr_name, name) == 0)
803 return (tp);
804 return (NULL);
805 }
806
807 /*
808 * Find the protox corresponding to name.
809 */
810 static struct protox *
811 name2protox(const char *name)
812 {
813 struct protox *tp;
814 char **alias; /* alias from p->aliases */
815 struct protoent *p;
816
817 /*
818 * Try to find the name in the list of "well-known" names. If that
819 * fails, check if name is an alias for an Internet protocol.
820 */
821 if ((tp = knownname(name)) != NULL)
822 return (tp);
823
824 setprotoent(1); /* make protocol lookup cheaper */
825 while ((p = getprotoent()) != NULL) {
826 /* assert: name not same as p->name */
827 for (alias = p->p_aliases; *alias; alias++)
828 if (strcmp(name, *alias) == 0) {
829 endprotoent();
830 return (knownname(p->p_name));
831 }
832 }
833 endprotoent();
834 return (NULL);
835 }
836
837 static void
838 usage(void)
839 {
840 const char *progname = getprogname();
841
842 (void)fprintf(stderr,
843 "usage: %s [-Aan] [-f address_family[,family ...]] [-M core] [-N system]\n", progname);
844 (void)fprintf(stderr,
845 " %s [-bdgiLmnqrsSv] [-f address_family[,family ...]] [-M core] [-N system]\n",
846 progname);
847 (void)fprintf(stderr,
848 " %s [-dn] [-I interface] [-M core] [-N system] [-w wait]\n", progname);
849 (void)fprintf(stderr,
850 " %s [-p protocol] [-M core] [-N system]\n", progname);
851 (void)fprintf(stderr,
852 " %s [-p protocol] [-M core] [-N system] -P pcbaddr\n", progname);
853 (void)fprintf(stderr,
854 " %s [-p protocol] [-i] [-I Interface] \n", progname);
855 (void)fprintf(stderr,
856 " %s [-s] [-f address_family[,family ...]] [-i] [-I Interface]\n", progname);
857 (void)fprintf(stderr,
858 " %s [-s] [-B] [-I interface]\n", progname);
859 exit(1);
860 }
861