Commit | Line | Data |
---|---|---|
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 | |
19 | char 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 | 25 | static 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 | ||
39 | struct 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 | 103 | extern int protopr(), bbnprotopr(); |
7333c75b | 104 | extern int tcp_stats(), udp_stats(), ip_stats(), icmp_stats(); |
6538ea31 | 105 | /* ns protocols */ |
a5545777 | 106 | extern int tcpstats(), udpstats(), ipstats(), icmpstats(), rdpstats(); |
0be88646 KS |
107 | extern int nsprotopr(); |
108 | extern int spp_stats(), idp_stats(), nserr_stats(); | |
6df0a927 | 109 | |
6538ea31 | 110 | #define NULLPROTOX ((struct protox *) 0) |
ed85a06f | 111 | struct 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 | ||
120 | struct 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 |
133 | struct 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 |
150 | struct 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 |
161 | struct pte *Sysmap; |
162 | ||
163 | char *system = "/vmunix"; | |
164 | char *kmemf = "/dev/kmem"; | |
165 | int kmem; | |
166 | int kflag; | |
167 | int Aflag; | |
168 | int aflag; | |
169 | int hflag; | |
170 | int iflag; | |
171 | int mflag; | |
172 | int nflag; | |
6538ea31 | 173 | int pflag; |
ed85a06f SL |
174 | int rflag; |
175 | int sflag; | |
176 | int tflag; | |
2ebaad6c | 177 | int dflag; |
ed85a06f | 178 | int interval; |
79ddba48 EW |
179 | char *interface; |
180 | int unit; | |
ed85a06f | 181 | |
0be88646 | 182 | int af = AF_UNSPEC; |
2a893f10 | 183 | |
6538ea31 MK |
184 | extern char *malloc(); |
185 | extern off_t lseek(); | |
186 | ||
ed85a06f SL |
187 | main(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 | 385 | off_t |
ed85a06f | 386 | klseek(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 | |
398 | char * | |
399 | plural(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 | */ | |
409 | struct protox * | |
410 | knownname(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 | */ | |
427 | struct protox * | |
428 | name2protox(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 | |
455 | usage() | |
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 | } |