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