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