add man page, cleanup
[unix-history] / usr / src / usr.bin / netstat / main.c
CommitLineData
5ff67f98 1/*
b36fc510 2 * Copyright (c) 1983, 1988 Regents of the University of California.
ee3f90a5
MK
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
b36fc510
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5ff67f98
DF
16 */
17
18#ifndef lint
19char copyright[] =
b36fc510 20"@(#) Copyright (c) 1983, 1988 Regents of the University of California.\n\
5ff67f98 21 All rights reserved.\n";
d2c7d54c 22#endif /* not lint */
5ff67f98 23
ed85a06f 24#ifndef lint
b36fc510 25static char sccsid[] = "@(#)main.c 5.14 (Berkeley) %G%";
d2c7d54c 26#endif /* not lint */
ed85a06f
SL
27
28#include <sys/param.h>
d96df0d1 29#include <sys/vmmac.h>
0be88646 30#include <sys/socket.h>
d2c7d54c 31#include <sys/file.h>
7cd60ad6 32#include <machine/pte.h>
ed85a06f
SL
33#include <ctype.h>
34#include <errno.h>
35#include <netdb.h>
36#include <nlist.h>
37#include <stdio.h>
38
39struct nlist nl[] = {
40#define N_MBSTAT 0
41 { "_mbstat" },
42#define N_IPSTAT 1
43 { "_ipstat" },
44#define N_TCB 2
45 { "_tcb" },
46#define N_TCPSTAT 3
47 { "_tcpstat" },
48#define N_UDB 4
49 { "_udb" },
50#define N_UDPSTAT 5
51 { "_udpstat" },
52#define N_RAWCB 6
53 { "_rawcb" },
54#define N_SYSMAP 7
55 { "_Sysmap" },
56#define N_SYSSIZE 8
57 { "_Syssize" },
58#define N_IFNET 9
59 { "_ifnet" },
0e710523
MK
60#define N_IMP 10
61 { "_imp_softc" },
ed85a06f
SL
62#define N_RTHOST 11
63 { "_rthost" },
64#define N_RTNET 12
65 { "_rtnet" },
7333c75b
SL
66#define N_ICMPSTAT 13
67 { "_icmpstat" },
bbd2d21e
SL
68#define N_RTSTAT 14
69 { "_rtstat" },
404a567d
SL
70#define N_NFILE 15
71 { "_nfile" },
72#define N_FILE 16
73 { "_file" },
74#define N_UNIXSW 17
75 { "_unixsw" },
f508555e
MK
76#define N_RTHASHSIZE 18
77 { "_rthashsize" },
0be88646
KS
78#define N_IDP 19
79 { "_nspcb"},
80#define N_IDPSTAT 20
81 { "_idpstat"},
82#define N_SPPSTAT 21
83 { "_spp_istat"},
84#define N_NSERR 22
85 { "_ns_errstat"},
0e710523
MK
86#define N_NIMP 23
87 { "_nimp"},
a5545777
MK
88
89 /* BBN Internet protocol implementation */
90#define N_TCP 23
91 { "_tcp" },
92#define N_UDP 24
93 { "_udp" },
94#define N_RDP 25
95 { "_rdp" },
96#define N_RDPSTAT 26
97 { "_rdpstat" },
98
7333c75b 99 "",
ed85a06f
SL
100};
101
404a567d 102/* internet protocols */
a5545777 103extern int protopr(), bbnprotopr();
7333c75b 104extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats();
6538ea31 105/* ns protocols */
a5545777 106extern int tcpstats(), udpstats(), ipstats(), icmpstats(), rdpstats();
0be88646
KS
107extern int nsprotopr();
108extern int spp_stats(), idp_stats(), nserr_stats();
6df0a927 109
6538ea31 110#define NULLPROTOX ((struct protox *) 0)
ed85a06f 111struct protox {
6df0a927
SL
112 u_char pr_index; /* index into nlist of cb head */
113 u_char pr_sindex; /* index into nlist of stat block */
114 u_char pr_wanted; /* 1 if wanted, 0 otherwise */
115 int (*pr_cblocks)(); /* control blocks printing routine */
116 int (*pr_stats)(); /* statistics printing routine */
117 char *pr_name; /* well-known name */
a5545777
MK
118};
119
120struct protox berkprotox[] = {
6df0a927
SL
121 { N_TCB, N_TCPSTAT, 1, protopr,
122 tcp_stats, "tcp" },
123 { N_UDB, N_UDPSTAT, 1, protopr,
124 udp_stats, "udp" },
125 { -1, N_IPSTAT, 1, 0,
126 ip_stats, "ip" },
7333c75b
SL
127 { -1, N_ICMPSTAT, 1, 0,
128 icmp_stats, "icmp" },
6df0a927
SL
129 { -1, -1, 0, 0,
130 0, 0 }
ed85a06f
SL
131};
132
a5545777
MK
133struct protox bbnprotox[] = {
134 { N_TCP, N_TCPSTAT, 1, bbnprotopr,
135 tcpstats, "tcp" },
136 { N_UDP, N_UDPSTAT, 1, bbnprotopr,
137 udpstats, "udp" },
138 { N_RDP, N_RDPSTAT, 1, bbnprotopr,
139 rdpstats, "rdp" },
140 { N_RAWCB, 0, 1, bbnprotopr,
141 0, "raw" },
142 { -1, N_IPSTAT, 1, 0,
143 ipstats, "ip" },
144 { -1, N_ICMPSTAT, 1, 0,
145 icmpstats, "icmp" },
146 { -1, -1, 0, 0,
147 0, 0 }
148};
149
0be88646
KS
150struct protox nsprotox[] = {
151 { N_IDP, N_IDPSTAT, 1, nsprotopr,
152 idp_stats, "idp" },
153 { N_IDP, N_SPPSTAT, 1, nsprotopr,
154 spp_stats, "spp" },
155 { -1, N_NSERR, 1, 0,
156 nserr_stats, "ns_err" },
157 { -1, -1, 0, 0,
158 0, 0 }
159};
160
ed85a06f
SL
161struct pte *Sysmap;
162
163char *system = "/vmunix";
164char *kmemf = "/dev/kmem";
165int kmem;
166int kflag;
167int Aflag;
168int aflag;
169int hflag;
170int iflag;
171int mflag;
172int nflag;
6538ea31 173int pflag;
ed85a06f
SL
174int rflag;
175int sflag;
176int tflag;
2ebaad6c 177int dflag;
ed85a06f 178int interval;
79ddba48
EW
179char *interface;
180int unit;
ed85a06f 181
0be88646 182int af = AF_UNSPEC;
2a893f10 183
6538ea31
MK
184extern char *malloc();
185extern off_t lseek();
186
ed85a06f
SL
187main(argc, argv)
188 int argc;
189 char *argv[];
190{
d2c7d54c
KB
191 extern char *optarg;
192 extern int optind;
ed85a06f 193 register struct protoent *p;
6538ea31
MK
194 register struct protox *tp; /* for printing cblocks & stats */
195 struct protox *name2protox(); /* for -p */
d2c7d54c 196 int ch;
ed85a06f 197
2ebaad6c 198 while ((ch = getopt(argc, argv, "AI:af:himnp:drstu")) != EOF)
d2c7d54c 199 switch((char)ch) {
ed85a06f
SL
200 case 'A':
201 Aflag++;
202 break;
d2c7d54c
KB
203 case 'I': {
204 char *cp;
ed85a06f 205
d2c7d54c
KB
206 iflag++;
207 for (cp = interface = optarg; isalpha(*cp); cp++);
208 unit = atoi(cp);
209 *cp = '\0';
210 break;
211 }
ed85a06f
SL
212 case 'a':
213 aflag++;
214 break;
2ebaad6c
MK
215 case 'd':
216 dflag++;
217 break;
d2c7d54c
KB
218 case 'f':
219 if (strcmp(optarg, "ns") == 0)
220 af = AF_NS;
221 else if (strcmp(optarg, "inet") == 0)
222 af = AF_INET;
223 else if (strcmp(optarg, "unix") == 0)
224 af = AF_UNIX;
225 else {
226 fprintf(stderr, "%s: unknown address family\n", optarg);
227 exit(10);
228 }
229 break;
ed85a06f
SL
230 case 'h':
231 hflag++;
232 break;
ed85a06f
SL
233 case 'i':
234 iflag++;
235 break;
ed85a06f
SL
236 case 'm':
237 mflag++;
238 break;
ed85a06f
SL
239 case 'n':
240 nflag++;
241 break;
d2c7d54c
KB
242 case 'p':
243 if ((tp = name2protox(optarg)) == NULLPROTOX) {
244 fprintf(stderr, "%s: unknown or uninstrumented protocol\n", optarg);
245 exit(10);
246 }
247 pflag++;
248 break;
ed85a06f
SL
249 case 'r':
250 rflag++;
251 break;
ed85a06f
SL
252 case 's':
253 sflag++;
254 break;
ed85a06f
SL
255 case 't':
256 tflag++;
257 break;
404a567d 258 case 'u':
2a893f10 259 af = AF_UNIX;
404a567d 260 break;
d2c7d54c
KB
261 case '?':
262 default:
263 usage();
264 }
265 argv += optind;
266 argc -= optind;
404a567d 267
d2c7d54c
KB
268 if (argc > 0) {
269 if (isdigit(argv[0][0])) {
270 interval = atoi(argv[0]);
271 if (interval <= 0)
272 usage();
273 argv++, argc--;
79ddba48 274 iflag++;
d2c7d54c
KB
275 }
276 if (argc > 0) {
277 system = *argv;
278 argv++, argc--;
279 if (argc > 0) {
280 kmemf = *argv;
281 kflag++;
79ddba48 282 }
ed85a06f 283 }
ed85a06f 284 }
d2c7d54c 285 if (nlist(system, nl) < 0 || nl[0].n_type == 0) {
ed85a06f
SL
286 fprintf(stderr, "%s: no namelist\n", system);
287 exit(1);
288 }
d2c7d54c 289 kmem = open(kmemf, O_RDONLY);
ed85a06f 290 if (kmem < 0) {
ed85a06f
SL
291 perror(kmemf);
292 exit(1);
293 }
294 if (kflag) {
295 off_t off;
296
d2c7d54c
KB
297 Sysmap = (struct pte *)
298 malloc((u_int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
299 if (!Sysmap) {
300 fputs("netstat: can't get memory for Sysmap.\n", stderr);
ed85a06f
SL
301 exit(1);
302 }
d2c7d54c
KB
303 off = nl[N_SYSMAP].n_value & ~KERNBASE;
304 (void)lseek(kmem, off, L_SET);
305 (void)read(kmem, (char *)Sysmap,
306 (int)(nl[N_SYSSIZE].n_value * sizeof(struct pte)));
ed85a06f
SL
307 }
308 if (mflag) {
6538ea31
MK
309 mbpr((off_t)nl[N_MBSTAT].n_value);
310 exit(0);
311 }
312 if (pflag) {
313 if (tp->pr_stats)
d2c7d54c 314 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
6538ea31
MK
315 tp->pr_name);
316 else
317 printf("%s: no stats routine\n", tp->pr_name);
ed85a06f
SL
318 exit(0);
319 }
0e710523
MK
320 if (hflag) {
321 hostpr(nl[N_IMP].n_value, nl[N_NIMP].n_value);
322 exit(0);
323 }
ed85a06f
SL
324 /*
325 * Keep file descriptors open to avoid overhead
326 * of open/close on each call to get* routines.
327 */
ed85a06f
SL
328 sethostent(1);
329 setnetent(1);
90cb8200
SL
330 if (iflag) {
331 intpr(interval, nl[N_IFNET].n_value);
332 exit(0);
333 }
ed85a06f 334 if (rflag) {
bbd2d21e 335 if (sflag)
6538ea31 336 rt_stats((off_t)nl[N_RTSTAT].n_value);
bbd2d21e 337 else
6538ea31
MK
338 routepr((off_t)nl[N_RTHOST].n_value,
339 (off_t)nl[N_RTNET].n_value,
340 (off_t)nl[N_RTHASHSIZE].n_value);
ed85a06f
SL
341 exit(0);
342 }
0be88646 343 if (af == AF_INET || af == AF_UNSPEC) {
a5545777
MK
344 struct protox *head;
345
346 head = (nl[N_TCB].n_type == 0) ? bbnprotox : berkprotox;
90cb8200
SL
347 setprotoent(1);
348 setservent(1);
ed85a06f 349
a5545777
MK
350 for (tp = head; tp->pr_name; tp++) {
351 if (tp->pr_wanted == 0)
ed85a06f 352 continue;
a5545777
MK
353
354 if (sflag) {
355 if (tp->pr_stats)
356 (*tp->pr_stats)(nl[tp->pr_sindex].n_value, tp->pr_name);
357 } else if (tp->pr_cblocks)
358 (*tp->pr_cblocks)(nl[tp->pr_index].n_value, tp->pr_name);
ed85a06f
SL
359 }
360 endprotoent();
0be88646
KS
361 }
362 if (af == AF_NS || af == AF_UNSPEC) {
363 for (tp = nsprotox; tp->pr_name; tp++) {
54c165a5
MK
364 if (sflag) {
365 if (tp->pr_stats)
366 (*tp->pr_stats)(nl[tp->pr_sindex].n_value,
367 tp->pr_name);
368 } else
369 if (tp->pr_cblocks)
370 (*tp->pr_cblocks)(nl[tp->pr_index].n_value,
371 tp->pr_name);
0be88646
KS
372 }
373 }
54c165a5 374 if ((af == AF_UNIX || af == AF_UNSPEC) && !sflag)
6538ea31
MK
375 unixpr((off_t)nl[N_NFILE].n_value, (off_t)nl[N_FILE].n_value,
376 (struct protosw *)nl[N_UNIXSW].n_value);
0e710523
MK
377 if (af == AF_UNSPEC && sflag)
378 impstats(nl[N_IMP].n_value, nl[N_NIMP].n_value);
085b521c 379 exit(0);
ed85a06f
SL
380}
381
382/*
383 * Seek into the kernel for a value.
384 */
6538ea31 385off_t
ed85a06f 386klseek(fd, base, off)
6538ea31
MK
387 int fd, off;
388 off_t base;
ed85a06f 389{
ed85a06f
SL
390 if (kflag) {
391 /* get kernel pte */
33e1c186 392 base &= ~KERNBASE;
d96df0d1 393 base = ctob(Sysmap[btop(base)].pg_pfnum) + (base & PGOFSET);
ed85a06f 394 }
6538ea31 395 return (lseek(fd, base, off));
ed85a06f 396}
bbd2d21e
SL
397
398char *
399plural(n)
400 int n;
401{
402
403 return (n != 1 ? "s" : "");
404}
6538ea31
MK
405
406/*
407 * Find the protox for the given "well-known" name.
408 */
409struct protox *
410knownname(name)
411 char *name;
412{
413 struct protox *tp;
d2c7d54c 414
6538ea31
MK
415 for (tp = protox; tp->pr_name; tp++)
416 if (strcmp(tp->pr_name, name) == 0)
417 return(tp);
418 for (tp = nsprotox; tp->pr_name; tp++)
419 if (strcmp(tp->pr_name, name) == 0)
420 return(tp);
421 return(NULLPROTOX);
422}
423
424/*
425 * Find the protox corresponding to name.
426 */
427struct protox *
428name2protox(name)
429 char *name;
430{
431 struct protox *tp;
432 char **alias; /* alias from p->aliases */
433 struct protoent *p;
d2c7d54c 434
6538ea31
MK
435 /*
436 * Try to find the name in the list of "well-known" names. If that
437 * fails, check if name is an alias for an Internet protocol.
438 */
439 if (tp = knownname(name))
440 return(tp);
d2c7d54c 441
6538ea31
MK
442 setprotoent(1); /* make protocol lookup cheaper */
443 while (p = getprotoent()) {
444 /* assert: name not same as p->name */
445 for (alias = p->p_aliases; *alias; alias++)
446 if (strcmp(name, *alias) == 0) {
447 endprotoent();
448 return(knownname(p->p_name));
449 }
450 }
451 endprotoent();
452 return(NULLPROTOX);
453}
d2c7d54c
KB
454
455usage()
456{
457 fputs("usage: netstat [-Aan] [-f address_family] [system] [core]\n [-himnrs] [-f address_family] [system] [core]\n [-n] [-I interface] interval [system] [core]\n", stderr);
458 exit(1);
459}