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