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