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 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #ifndef lint
31 static char const copyright[] =
32 "@(#) Copyright (c) 1983, 1988, 1993\n\
33 Regents of the University of California. All rights reserved.\n";
34 #endif /* not lint */
35
36 #if 0
37 #ifndef lint
38 static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 3/1/94";
39 #endif /* not lint */
40 #endif
41
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44
45 #include <sys/param.h>
46 #include <sys/file.h>
47 #include <sys/protosw.h>
48 #include <sys/socket.h>
49 #include <sys/socketvar.h>
50 #include <sys/sysctl.h>
51
52 #include <netinet/in.h>
53
54 #ifdef NETGRAPH
55 #include <netgraph/ng_socket.h>
56 #endif
57
58 #include <ctype.h>
59 #include <err.h>
60 #include <errno.h>
61 #include <kvm.h>
62 #include <limits.h>
63 #include <netdb.h>
64 #include <nlist.h>
65 #include <paths.h>
66 #include <stdint.h>
67 #include <stdio.h>
68 #include <stdlib.h>
69 #include <stdbool.h>
70 #include <string.h>
71 #include <unistd.h>
72 #include "netstat.h"
73 #include "nl_defs.h"
74 #include <libxo/xo.h>
75
76 static struct protox {
77 int pr_index; /* index into nlist of cb head */
78 int pr_sindex; /* index into nlist of stat block */
79 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
80 void (*pr_cblocks)(u_long, const char *, int, int);
81 /* control blocks printing routine */
82 void (*pr_stats)(u_long, const char *, int, int);
83 /* statistics printing routine */
84 void (*pr_istats)(char *); /* per/if statistics printing routine */
85 const char *pr_name; /* well-known name */
86 int pr_usesysctl; /* non-zero if we use sysctl, not kvm */
87 int pr_protocol;
88 } protox[] = {
89 { N_TCBINFO, N_TCPSTAT, 1, protopr,
90 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
91 { N_UDBINFO, N_UDPSTAT, 1, protopr,
92 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
93 #ifdef SCTP
94 { -1, N_SCTPSTAT, 1, sctp_protopr,
95 sctp_stats, NULL, "sctp", 1, IPPROTO_SCTP },
96 #endif
97 #ifdef SDP
98 { -1, -1, 1, protopr,
99 NULL, NULL, "sdp", 1, IPPROTO_TCP },
100 #endif
101 { N_DIVCBINFO, -1, 1, protopr,
102 NULL, NULL, "divert", 1, IPPROTO_DIVERT },
103 { N_RIPCBINFO, N_IPSTAT, 1, protopr,
104 ip_stats, NULL, "ip", 1, IPPROTO_RAW },
105 { N_RIPCBINFO, N_ICMPSTAT, 1, protopr,
106 icmp_stats, NULL, "icmp", 1, IPPROTO_ICMP },
107 { N_RIPCBINFO, N_IGMPSTAT, 1, protopr,
108 igmp_stats, NULL, "igmp", 1, IPPROTO_IGMP },
109 #ifdef IPSEC
110 { -1, N_IPSEC4STAT, 1, NULL, /* keep as compat */
111 ipsec_stats, NULL, "ipsec", 1, 0},
112 { -1, N_AHSTAT, 1, NULL,
113 ah_stats, NULL, "ah", 1, 0},
114 { -1, N_ESPSTAT, 1, NULL,
115 esp_stats, NULL, "esp", 1, 0},
116 { -1, N_IPCOMPSTAT, 1, NULL,
117 ipcomp_stats, NULL, "ipcomp", 1, 0},
118 #endif
119 { N_RIPCBINFO, N_PIMSTAT, 1, protopr,
120 pim_stats, NULL, "pim", 1, IPPROTO_PIM },
121 { -1, N_CARPSTATS, 1, NULL,
122 carp_stats, NULL, "carp", 1, 0 },
123 #ifdef PF
124 { -1, N_PFSYNCSTATS, 1, NULL,
125 pfsync_stats, NULL, "pfsync", 1, 0 },
126 #endif
127 { -1, N_ARPSTAT, 1, NULL,
128 arp_stats, NULL, "arp", 1, 0 },
129 { -1, -1, 0, NULL,
130 NULL, NULL, NULL, 0, 0 }
131 };
132
133 #ifdef INET6
134 static struct protox ip6protox[] = {
135 { N_TCBINFO, N_TCPSTAT, 1, protopr,
136 tcp_stats, NULL, "tcp", 1, IPPROTO_TCP },
137 { N_UDBINFO, N_UDPSTAT, 1, protopr,
138 udp_stats, NULL, "udp", 1, IPPROTO_UDP },
139 { N_RIPCBINFO, N_IP6STAT, 1, protopr,
140 ip6_stats, ip6_ifstats, "ip6", 1, IPPROTO_RAW },
141 { N_RIPCBINFO, N_ICMP6STAT, 1, protopr,
142 icmp6_stats, icmp6_ifstats, "icmp6", 1, IPPROTO_ICMPV6 },
143 #ifdef SDP
144 { -1, -1, 1, protopr,
145 NULL, NULL, "sdp", 1, IPPROTO_TCP },
146 #endif
147 #ifdef IPSEC
148 { -1, N_IPSEC6STAT, 1, NULL,
149 ipsec_stats, NULL, "ipsec6", 1, 0 },
150 #endif
151 #ifdef notyet
152 { -1, N_PIM6STAT, 1, NULL,
153 pim6_stats, NULL, "pim6", 1, 0 },
154 #endif
155 { -1, N_RIP6STAT, 1, NULL,
156 rip6_stats, NULL, "rip6", 1, 0 },
157 { -1, -1, 0, NULL,
158 NULL, NULL, NULL, 0, 0 }
159 };
160 #endif /*INET6*/
161
162 #ifdef IPSEC
163 static struct protox pfkeyprotox[] = {
164 { -1, N_PFKEYSTAT, 1, NULL,
165 pfkey_stats, NULL, "pfkey", 0, 0 },
166 { -1, -1, 0, NULL,
167 NULL, NULL, NULL, 0, 0 }
168 };
169 #endif
170
171 #ifdef NETGRAPH
172 static struct protox netgraphprotox[] = {
173 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
174 NULL, NULL, "ctrl", 0, 0 },
175 { N_NGSOCKLIST, -1, 1, netgraphprotopr,
176 NULL, NULL, "data", 0, 0 },
177 { -1, -1, 0, NULL,
178 NULL, NULL, NULL, 0, 0 }
179 };
180 #endif
181
182 static struct protox *protoprotox[] = {
183 protox,
184 #ifdef INET6
185 ip6protox,
186 #endif
187 #ifdef IPSEC
188 pfkeyprotox,
189 #endif
190 NULL };
191
192 static void printproto(struct protox *, const char *, bool *);
193 static void usage(void);
194 static struct protox *name2protox(const char *);
195 static struct protox *knownname(const char *);
196
197 static int kresolve_list(struct nlist *_nl);
198
199 static kvm_t *kvmd;
200 static char *nlistf = NULL, *memf = NULL;
201
202 int Aflag; /* show addresses of protocol control block */
203 int aflag; /* show all sockets (including servers) */
204 static int Bflag; /* show information about bpf consumers */
205 int bflag; /* show i/f total bytes in/out */
206 int dflag; /* show i/f dropped packets */
207 int gflag; /* show group (multicast) routing or stats */
208 int hflag; /* show counters in human readable format */
209 int iflag; /* show interfaces */
210 int Lflag; /* show size of listen queues */
211 int mflag; /* show memory stats */
212 int noutputs = 0; /* how much outputs before we exit */
213 int numeric_addr; /* show addresses numerically */
214 int numeric_port; /* show ports numerically */
215 static int pflag; /* show given protocol */
216 static int Qflag; /* show netisr information */
217 int rflag; /* show routing tables (or routing stats) */
218 int Rflag; /* show flow / RSS statistics */
219 int sflag; /* show protocol statistics */
220 int Wflag; /* wide display */
221 int Tflag; /* TCP Information */
222 int xflag; /* extra information, includes all socket buffer info */
223 int zflag; /* zero stats */
224
225 int interval; /* repeat interval for i/f stats */
226
227 char *interface; /* desired i/f for stats, or NULL for all i/fs */
228 int unit; /* unit number for above */
229
230 static int af; /* address family */
231 int live; /* true if we are examining a live system */
232
233 int
main(int argc,char * argv[])234 main(int argc, char *argv[])
235 {
236 struct protox *tp = NULL; /* for printing cblocks & stats */
237 int ch;
238 int fib = -1;
239 char *endptr;
240 bool first = true;
241
242 af = AF_UNSPEC;
243
244 argc = xo_parse_args(argc, argv);
245 if (argc < 0)
246 exit(EXIT_FAILURE);
247
248 while ((ch = getopt(argc, argv, "46AaBbdF:f:ghI:iLlM:mN:np:Qq:RrSTsuWw:xz"))
249 != -1)
250 switch(ch) {
251 case '4':
252 #ifdef INET
253 af = AF_INET;
254 #else
255 errx(1, "IPv4 support is not compiled in");
256 #endif
257 break;
258 case '6':
259 #ifdef INET6
260 af = AF_INET6;
261 #else
262 errx(1, "IPv6 support is not compiled in");
263 #endif
264 break;
265 case 'A':
266 Aflag = 1;
267 break;
268 case 'a':
269 aflag = 1;
270 break;
271 case 'B':
272 Bflag = 1;
273 break;
274 case 'b':
275 bflag = 1;
276 break;
277 case 'd':
278 dflag = 1;
279 break;
280 case 'F':
281 fib = strtol(optarg, &endptr, 0);
282 if (*endptr != '\0' ||
283 (fib == 0 && (errno == EINVAL || errno == ERANGE)))
284 xo_errx(1, "%s: invalid fib", optarg);
285 break;
286 case 'f':
287 if (strcmp(optarg, "inet") == 0)
288 af = AF_INET;
289 #ifdef INET6
290 else if (strcmp(optarg, "inet6") == 0)
291 af = AF_INET6;
292 #endif
293 #ifdef IPSEC
294 else if (strcmp(optarg, "pfkey") == 0)
295 af = PF_KEY;
296 #endif
297 else if (strcmp(optarg, "unix") == 0 ||
298 strcmp(optarg, "local") == 0)
299 af = AF_UNIX;
300 #ifdef NETGRAPH
301 else if (strcmp(optarg, "ng") == 0
302 || strcmp(optarg, "netgraph") == 0)
303 af = AF_NETGRAPH;
304 #endif
305 else if (strcmp(optarg, "link") == 0)
306 af = AF_LINK;
307 else {
308 xo_errx(1, "%s: unknown address family",
309 optarg);
310 }
311 break;
312 case 'g':
313 gflag = 1;
314 break;
315 case 'h':
316 hflag = 1;
317 break;
318 case 'I': {
319 char *cp;
320
321 iflag = 1;
322 for (cp = interface = optarg; isalpha(*cp); cp++)
323 continue;
324 unit = atoi(cp);
325 break;
326 }
327 case 'i':
328 iflag = 1;
329 break;
330 case 'L':
331 Lflag = 1;
332 break;
333 case 'M':
334 memf = optarg;
335 break;
336 case 'm':
337 mflag = 1;
338 break;
339 case 'N':
340 nlistf = optarg;
341 break;
342 case 'n':
343 numeric_addr = numeric_port = 1;
344 break;
345 case 'p':
346 if ((tp = name2protox(optarg)) == NULL) {
347 xo_errx(1, "%s: unknown or uninstrumented "
348 "protocol", optarg);
349 }
350 pflag = 1;
351 break;
352 case 'Q':
353 Qflag = 1;
354 break;
355 case 'q':
356 noutputs = atoi(optarg);
357 if (noutputs != 0)
358 noutputs++;
359 break;
360 case 'r':
361 rflag = 1;
362 break;
363 case 'R':
364 Rflag = 1;
365 break;
366 case 's':
367 ++sflag;
368 break;
369 case 'S':
370 numeric_addr = 1;
371 break;
372 case 'u':
373 af = AF_UNIX;
374 break;
375 case 'W':
376 case 'l':
377 Wflag = 1;
378 break;
379 case 'w':
380 interval = atoi(optarg);
381 iflag = 1;
382 break;
383 case 'T':
384 Tflag = 1;
385 break;
386 case 'x':
387 xflag = 1;
388 break;
389 case 'z':
390 zflag = 1;
391 break;
392 case '?':
393 default:
394 usage();
395 }
396 argv += optind;
397 argc -= optind;
398
399 #define BACKWARD_COMPATIBILITY
400 #ifdef BACKWARD_COMPATIBILITY
401 if (*argv) {
402 if (isdigit(**argv)) {
403 interval = atoi(*argv);
404 if (interval <= 0)
405 usage();
406 ++argv;
407 iflag = 1;
408 }
409 if (*argv) {
410 nlistf = *argv;
411 if (*++argv)
412 memf = *argv;
413 }
414 }
415 #endif
416
417 /*
418 * Discard setgid privileges if not the running kernel so that bad
419 * guys can't print interesting stuff from kernel memory.
420 */
421 live = (nlistf == NULL && memf == NULL);
422 if (!live) {
423 if (setgid(getgid()) != 0)
424 xo_err(-1, "setgid");
425 }
426
427 if (xflag && Tflag)
428 xo_errx(1, "-x and -T are incompatible, pick one.");
429
430 if (Bflag) {
431 if (!live)
432 usage();
433 bpf_stats(interface);
434 xo_finish();
435 exit(0);
436 }
437 if (mflag) {
438 if (!live) {
439 if (kread(0, NULL, 0) == 0)
440 mbpr(kvmd, nl[N_SFSTAT].n_value);
441 } else
442 mbpr(NULL, 0);
443 xo_finish();
444 exit(0);
445 }
446 if (Qflag) {
447 if (!live) {
448 if (kread(0, NULL, 0) == 0)
449 netisr_stats();
450 } else
451 netisr_stats();
452 xo_finish();
453 exit(0);
454 }
455 #if 0
456 /*
457 * Keep file descriptors open to avoid overhead
458 * of open/close on each call to get* routines.
459 */
460 sethostent(1);
461 setnetent(1);
462 #else
463 /*
464 * This does not make sense any more with DNS being default over
465 * the files. Doing a setXXXXent(1) causes a tcp connection to be
466 * used for the queries, which is slower.
467 */
468 #endif
469 if (iflag && !sflag) {
470 xo_open_container("statistics");
471 intpr(NULL, af);
472 xo_close_container("statistics");
473 xo_finish();
474 exit(0);
475 }
476 if (rflag) {
477 xo_open_container("statistics");
478 if (sflag) {
479 rt_stats();
480 flowtable_stats();
481 } else
482 routepr(fib, af);
483 xo_close_container("statistics");
484 xo_finish();
485 exit(0);
486 }
487
488 if (gflag) {
489 xo_open_container("statistics");
490 if (sflag) {
491 if (af == AF_INET || af == AF_UNSPEC)
492 mrt_stats();
493 #ifdef INET6
494 if (af == AF_INET6 || af == AF_UNSPEC)
495 mrt6_stats();
496 #endif
497 } else {
498 if (af == AF_INET || af == AF_UNSPEC)
499 mroutepr();
500 #ifdef INET6
501 if (af == AF_INET6 || af == AF_UNSPEC)
502 mroute6pr();
503 #endif
504 }
505 xo_close_container("statistics");
506 xo_finish();
507 exit(0);
508 }
509
510 /* Load all necessary kvm symbols */
511 kresolve_list(nl);
512
513 if (tp) {
514 xo_open_container("statistics");
515 printproto(tp, tp->pr_name, &first);
516 if (!first)
517 xo_close_list("socket");
518 xo_close_container("statistics");
519 xo_finish();
520 exit(0);
521 }
522
523 xo_open_container("statistics");
524 if (af == AF_INET || af == AF_UNSPEC)
525 for (tp = protox; tp->pr_name; tp++)
526 printproto(tp, tp->pr_name, &first);
527 #ifdef INET6
528 if (af == AF_INET6 || af == AF_UNSPEC)
529 for (tp = ip6protox; tp->pr_name; tp++)
530 printproto(tp, tp->pr_name, &first);
531 #endif /*INET6*/
532 #ifdef IPSEC
533 if (af == PF_KEY || af == AF_UNSPEC)
534 for (tp = pfkeyprotox; tp->pr_name; tp++)
535 printproto(tp, tp->pr_name, &first);
536 #endif /*IPSEC*/
537 #ifdef NETGRAPH
538 if (af == AF_NETGRAPH || af == AF_UNSPEC)
539 for (tp = netgraphprotox; tp->pr_name; tp++)
540 printproto(tp, tp->pr_name, &first);
541 #endif /* NETGRAPH */
542 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
543 unixpr(nl[N_UNP_COUNT].n_value, nl[N_UNP_GENCNT].n_value,
544 nl[N_UNP_DHEAD].n_value, nl[N_UNP_SHEAD].n_value,
545 nl[N_UNP_SPHEAD].n_value, &first);
546
547 if (!first)
548 xo_close_list("socket");
549 xo_close_container("statistics");
550 xo_finish();
551 exit(0);
552 }
553
554 int
fetch_stats(const char * sysctlname,u_long off,void * stats,size_t len,int (* kreadfn)(u_long,void *,size_t))555 fetch_stats(const char *sysctlname, u_long off, void *stats, size_t len,
556 int (*kreadfn)(u_long, void *, size_t))
557 {
558 int error;
559
560 if (live) {
561 memset(stats, 0, len);
562 if (zflag)
563 error = sysctlbyname(sysctlname, NULL, NULL, stats,
564 len);
565 else
566 error = sysctlbyname(sysctlname, stats, &len, NULL, 0);
567 if (error == -1 && errno != ENOENT)
568 xo_warn("sysctl %s", sysctlname);
569 } else {
570 if (off == 0)
571 return (1);
572 error = kreadfn(off, stats, len);
573 }
574 return (error);
575 }
576
577 /*
578 * Print out protocol statistics or control blocks (per sflag).
579 * If the interface was not specifically requested, and the symbol
580 * is not in the namelist, ignore this one.
581 */
582 static void
printproto(struct protox * tp,const char * name,bool * first)583 printproto(struct protox *tp, const char *name, bool *first)
584 {
585 void (*pr)(u_long, const char *, int, int);
586 u_long off;
587 bool doingdblocks = false;
588
589 if (sflag) {
590 if (iflag) {
591 if (tp->pr_istats)
592 intpr(tp->pr_istats, af);
593 else if (pflag)
594 xo_message("%s: no per-interface stats routine",
595 tp->pr_name);
596 return;
597 } else {
598 pr = tp->pr_stats;
599 if (!pr) {
600 if (pflag)
601 xo_message("%s: no stats routine",
602 tp->pr_name);
603 return;
604 }
605 if (tp->pr_usesysctl && live)
606 off = 0;
607 else if (tp->pr_sindex < 0) {
608 if (pflag)
609 xo_message("%s: stats routine doesn't "
610 "work on cores", tp->pr_name);
611 return;
612 } else
613 off = nl[tp->pr_sindex].n_value;
614 }
615 } else {
616 doingdblocks = true;
617 pr = tp->pr_cblocks;
618 if (!pr) {
619 if (pflag)
620 xo_message("%s: no PCB routine", tp->pr_name);
621 return;
622 }
623 if (tp->pr_usesysctl && live)
624 off = 0;
625 else if (tp->pr_index < 0) {
626 if (pflag)
627 xo_message("%s: PCB routine doesn't work on "
628 "cores", tp->pr_name);
629 return;
630 } else
631 off = nl[tp->pr_index].n_value;
632 }
633 if (pr != NULL && (off || (live && tp->pr_usesysctl) ||
634 af != AF_UNSPEC)) {
635 if (doingdblocks && *first) {
636 xo_open_list("socket");
637 *first = false;
638 }
639
640 (*pr)(off, name, af, tp->pr_protocol);
641 }
642 }
643
644 static int
kvmd_init(void)645 kvmd_init(void)
646 {
647 char errbuf[_POSIX2_LINE_MAX];
648
649 if (kvmd != NULL)
650 return (0);
651
652 kvmd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
653 if (setgid(getgid()) != 0)
654 xo_err(-1, "setgid");
655
656 if (kvmd == NULL) {
657 xo_warnx("kvm not available: %s", errbuf);
658 return (-1);
659 }
660
661 return (0);
662 }
663
664 /*
665 * Resolve symbol list, return 0 on success.
666 */
667 static int
kresolve_list(struct nlist * _nl)668 kresolve_list(struct nlist *_nl)
669 {
670
671 if ((kvmd == NULL) && (kvmd_init() != 0))
672 return (-1);
673
674 if (_nl[0].n_type != 0)
675 return (0);
676
677 if (kvm_nlist(kvmd, _nl) < 0) {
678 if (nlistf)
679 xo_errx(1, "%s: kvm_nlist: %s", nlistf,
680 kvm_geterr(kvmd));
681 else
682 xo_errx(1, "kvm_nlist: %s", kvm_geterr(kvmd));
683 }
684
685 return (0);
686 }
687
688 /*
689 * Wrapper of kvm_dpcpu_setcpu().
690 */
691 void
kset_dpcpu(u_int cpuid)692 kset_dpcpu(u_int cpuid)
693 {
694
695 if ((kvmd == NULL) && (kvmd_init() != 0))
696 xo_errx(-1, "%s: kvm is not available", __func__);
697
698 if (kvm_dpcpu_setcpu(kvmd, cpuid) < 0)
699 xo_errx(-1, "%s: kvm_dpcpu_setcpu(%u): %s", __func__,
700 cpuid, kvm_geterr(kvmd));
701 return;
702 }
703
704 /*
705 * Read kernel memory, return 0 on success.
706 */
707 int
kread(u_long addr,void * buf,size_t size)708 kread(u_long addr, void *buf, size_t size)
709 {
710
711 if (kvmd_init() < 0)
712 return (-1);
713
714 if (!buf)
715 return (0);
716 if (kvm_read(kvmd, addr, buf, size) != (ssize_t)size) {
717 xo_warnx("%s", kvm_geterr(kvmd));
718 return (-1);
719 }
720 return (0);
721 }
722
723 /*
724 * Read single counter(9).
725 */
726 uint64_t
kread_counter(u_long addr)727 kread_counter(u_long addr)
728 {
729
730 if (kvmd_init() < 0)
731 return (-1);
732
733 return (kvm_counter_u64_fetch(kvmd, addr));
734 }
735
736 /*
737 * Read an array of N counters in kernel memory into array of N uint64_t's.
738 */
739 int
kread_counters(u_long addr,void * buf,size_t size)740 kread_counters(u_long addr, void *buf, size_t size)
741 {
742 uint64_t *c;
743 u_long *counters;
744 size_t i, n;
745
746 if (kvmd_init() < 0)
747 return (-1);
748
749 if (size % sizeof(uint64_t) != 0) {
750 xo_warnx("kread_counters: invalid counter set size");
751 return (-1);
752 }
753
754 n = size / sizeof(uint64_t);
755 if ((counters = malloc(n * sizeof(u_long))) == NULL)
756 xo_err(-1, "malloc");
757 if (kread(addr, counters, n * sizeof(u_long)) < 0) {
758 free(counters);
759 return (-1);
760 }
761
762 c = buf;
763 for (i = 0; i < n; i++)
764 c[i] = kvm_counter_u64_fetch(kvmd, counters[i]);
765
766 free(counters);
767 return (0);
768 }
769
770 const char *
plural(uintmax_t n)771 plural(uintmax_t n)
772 {
773 return (n != 1 ? "s" : "");
774 }
775
776 const char *
plurales(uintmax_t n)777 plurales(uintmax_t n)
778 {
779 return (n != 1 ? "es" : "");
780 }
781
782 const char *
pluralies(uintmax_t n)783 pluralies(uintmax_t n)
784 {
785 return (n != 1 ? "ies" : "y");
786 }
787
788 /*
789 * Find the protox for the given "well-known" name.
790 */
791 static struct protox *
knownname(const char * name)792 knownname(const char *name)
793 {
794 struct protox **tpp, *tp;
795
796 for (tpp = protoprotox; *tpp; tpp++)
797 for (tp = *tpp; tp->pr_name; tp++)
798 if (strcmp(tp->pr_name, name) == 0)
799 return (tp);
800 return (NULL);
801 }
802
803 /*
804 * Find the protox corresponding to name.
805 */
806 static struct protox *
name2protox(const char * name)807 name2protox(const char *name)
808 {
809 struct protox *tp;
810 char **alias; /* alias from p->aliases */
811 struct protoent *p;
812
813 /*
814 * Try to find the name in the list of "well-known" names. If that
815 * fails, check if name is an alias for an Internet protocol.
816 */
817 if ((tp = knownname(name)) != NULL)
818 return (tp);
819
820 setprotoent(1); /* make protocol lookup cheaper */
821 while ((p = getprotoent()) != NULL) {
822 /* assert: name not same as p->name */
823 for (alias = p->p_aliases; *alias; alias++)
824 if (strcmp(name, *alias) == 0) {
825 endprotoent();
826 return (knownname(p->p_name));
827 }
828 }
829 endprotoent();
830 return (NULL);
831 }
832
833 static void
usage(void)834 usage(void)
835 {
836 (void)xo_error("%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
837 "usage: netstat [-46AaLnRSTWx] [-f protocol_family | -p protocol]\n"
838 " [-M core] [-N system]",
839 " netstat -i | -I interface [-46abdhnW] [-f address_family]\n"
840 " [-M core] [-N system]",
841 " netstat -w wait [-I interface] [-46d] [-M core] [-N system]\n"
842 " [-q howmany]",
843 " netstat -s [-46sz] [-f protocol_family | -p protocol]\n"
844 " [-M core] [-N system]",
845 " netstat -i | -I interface -s [-46s]\n"
846 " [-f protocol_family | -p protocol] [-M core] [-N system]",
847 " netstat -m [-M core] [-N system]",
848 " netstat -B [-z] [-I interface]",
849 " netstat -r [-46AnW] [-F fibnum] [-f address_family]\n"
850 " [-M core] [-N system]",
851 " netstat -rs [-s] [-M core] [-N system]",
852 " netstat -g [-46W] [-f address_family] [-M core] [-N system]",
853 " netstat -gs [-46s] [-f address_family] [-M core] [-N system]",
854 " netstat -Q");
855 xo_finish();
856 exit(1);
857 }
858