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