Commit | Line | Data |
---|---|---|
055eee28 KB |
1 | /* |
2 | * Copyright (c) 1987 Regents of the University of California. | |
5ebc207c KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
b8c620d6 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. | |
055eee28 KB |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
20 | "@(#) Copyright (c) 1987 Regents of the University of California.\n\ | |
21 | All rights reserved.\n"; | |
5ebc207c | 22 | #endif /* not lint */ |
055eee28 KB |
23 | |
24 | #ifndef lint | |
11f68bc1 | 25 | static char sccsid[] = "@(#)fstat.c 5.20 (Berkeley) %G%"; |
5ebc207c | 26 | #endif /* not lint */ |
055eee28 KB |
27 | |
28 | /* | |
29 | * fstat | |
30 | */ | |
f255214c | 31 | #include <machine/pte.h> |
1a585c5c | 32 | |
055eee28 | 33 | #include <sys/param.h> |
055eee28 KB |
34 | #include <sys/dir.h> |
35 | #include <sys/user.h> | |
36 | #include <sys/proc.h> | |
055eee28 KB |
37 | #include <sys/text.h> |
38 | #include <sys/stat.h> | |
3dae3806 KM |
39 | #include <sys/time.h> |
40 | #include <sys/vnode.h> | |
055eee28 KB |
41 | #include <sys/socket.h> |
42 | #include <sys/socketvar.h> | |
43 | #include <sys/domain.h> | |
44 | #include <sys/protosw.h> | |
055eee28 | 45 | #include <sys/unpcb.h> |
f255214c KB |
46 | #include <sys/vmmac.h> |
47 | #define KERNEL | |
055eee28 | 48 | #include <sys/file.h> |
f255214c | 49 | #undef KERNEL |
3dae3806 | 50 | #include <ufs/inode.h> |
1a585c5c KB |
51 | #include <net/route.h> |
52 | #include <netinet/in.h> | |
53 | #include <netinet/in_pcb.h> | |
54 | #include <stdio.h> | |
7168b138 | 55 | #include <ctype.h> |
1a585c5c KB |
56 | #include <nlist.h> |
57 | #include <pwd.h> | |
cf2c7bf9 | 58 | #include <strings.h> |
435e8dff | 59 | #include <paths.h> |
055eee28 | 60 | |
1a585c5c KB |
61 | #define TEXT -2 |
62 | #define WD -1 | |
f255214c | 63 | |
cf2c7bf9 KB |
64 | #define VP if (vflg) (void)printf |
65 | ||
f255214c | 66 | typedef struct devs { |
4575617f KB |
67 | struct devs *next; |
68 | dev_t dev; | |
69 | int inum; | |
70 | char *name; | |
f255214c | 71 | } DEVS; |
4575617f | 72 | DEVS *devs; |
5e369078 | 73 | |
f255214c | 74 | static struct nlist nl[] = { |
055eee28 KB |
75 | { "_proc" }, |
76 | #define X_PROC 0 | |
77 | { "_Usrptmap" }, | |
78 | #define X_USRPTMA 1 | |
055eee28 | 79 | { "_nproc" }, |
f255214c KB |
80 | #define X_NPROC 2 |
81 | { "_usrpt" }, | |
82 | #define X_USRPT 3 | |
3dae3806 KM |
83 | { "_ufs_vnodeops" }, |
84 | #define X_UFSOPS 4 | |
85 | { "_blk_vnodeops" }, | |
86 | #define X_BLKOPS 5 | |
055eee28 KB |
87 | { "" }, |
88 | }; | |
89 | ||
4575617f KB |
90 | struct proc *mproc; |
91 | struct pte *Usrptma, *usrpt; | |
f255214c | 92 | |
055eee28 | 93 | union { |
4575617f KB |
94 | struct user user; |
95 | char upages[UPAGES][NBPG]; | |
055eee28 | 96 | } user; |
055eee28 | 97 | |
4575617f KB |
98 | extern int errno; |
99 | static int fflg, vflg; | |
100 | static int kmem, mem, nproc, swap; | |
101 | static char *uname; | |
1a585c5c | 102 | |
4575617f | 103 | off_t lseek(); |
055eee28 KB |
104 | |
105 | main(argc, argv) | |
4575617f KB |
106 | int argc; |
107 | char **argv; | |
055eee28 | 108 | { |
f255214c KB |
109 | extern char *optarg; |
110 | extern int optind; | |
111 | register struct passwd *passwd; | |
112 | register int pflg, pid, uflg, uid; | |
113 | int ch, size; | |
114 | struct passwd *getpwnam(), *getpwuid(); | |
115 | long lgetw(); | |
116 | char *malloc(); | |
117 | ||
118 | pflg = uflg = 0; | |
1a585c5c KB |
119 | while ((ch = getopt(argc, argv, "p:u:v")) != EOF) |
120 | switch((char)ch) { | |
121 | case 'p': | |
7168b138 MT |
122 | if (pflg++) |
123 | usage(); | |
124 | if (!isdigit(*optarg)) { | |
125 | fputs("fstat: -p option requires a process id.\n", stderr); | |
055eee28 | 126 | usage(); |
055eee28 | 127 | } |
f255214c | 128 | pid = atoi(optarg); |
1a585c5c KB |
129 | break; |
130 | case 'u': | |
131 | if (uflg++) | |
055eee28 | 132 | usage(); |
f255214c | 133 | if (!(passwd = getpwnam(optarg))) { |
cf2c7bf9 KB |
134 | (void)fprintf(stderr, "%s: unknown uid\n", |
135 | optarg); | |
055eee28 KB |
136 | exit(1); |
137 | } | |
f255214c KB |
138 | uid = passwd->pw_uid; |
139 | uname = passwd->pw_name; | |
1a585c5c | 140 | break; |
5ebc207c | 141 | case 'v': /* undocumented: print read error messages */ |
1a585c5c KB |
142 | vflg++; |
143 | break; | |
144 | case '?': | |
145 | default: | |
146 | usage(); | |
055eee28 | 147 | } |
055eee28 | 148 | |
5ebc207c | 149 | if (*(argv += optind)) { |
193d3a86 | 150 | for (; *argv; ++argv) { |
5ebc207c KB |
151 | if (getfname(*argv)) |
152 | fflg = 1; | |
153 | } | |
154 | if (!fflg) /* file(s) specified, but none accessable */ | |
155 | exit(1); | |
055eee28 | 156 | } |
d81abd9a | 157 | |
055eee28 | 158 | openfiles(); |
055eee28 | 159 | |
0ea8b445 | 160 | if (nlist(_PATH_UNIX, nl) == -1 || !nl[0].n_type) { |
cf2c7bf9 | 161 | (void)fprintf(stderr, "%s: no namelist\n", _PATH_UNIX); |
055eee28 KB |
162 | exit(1); |
163 | } | |
1a585c5c | 164 | Usrptma = (struct pte *)nl[X_USRPTMA].n_value; |
f255214c | 165 | usrpt = (struct pte *) nl[X_USRPT].n_value; |
f255214c KB |
166 | nproc = (int)lgetw((off_t)nl[X_NPROC].n_value); |
167 | ||
5ebc207c | 168 | (void)lseek(kmem, lgetw((off_t)nl[X_PROC].n_value), L_SET); |
f255214c KB |
169 | size = nproc * sizeof(struct proc); |
170 | if ((mproc = (struct proc *)malloc((u_int)size)) == NULL) { | |
cf2c7bf9 | 171 | (void)fprintf(stderr, "fstat: out of space.\n"); |
055eee28 KB |
172 | exit(1); |
173 | } | |
f255214c | 174 | if (read(kmem, (char *)mproc, size) != size) |
0ea8b445 | 175 | rerr1("proc table", _PATH_KMEM); |
5ebc207c | 176 | |
cf2c7bf9 | 177 | (void)printf("USER\t CMD\t PID FD\tDEVICE\tINODE\t SIZE TYPE%s\n", |
5ebc207c | 178 | fflg ? " NAME" : ""); |
f255214c KB |
179 | for (; nproc--; ++mproc) { |
180 | if (mproc->p_stat == 0) | |
181 | continue; | |
182 | if (pflg && mproc->p_pid != pid) | |
183 | continue; | |
184 | if (uflg) { | |
185 | if (mproc->p_uid != uid) | |
186 | continue; | |
187 | } | |
188 | else | |
189 | uname = (passwd = getpwuid(mproc->p_uid)) ? | |
190 | passwd->pw_name : "unknown"; | |
191 | if (mproc->p_stat != SZOMB && getu() == 0) | |
192 | continue; | |
193 | dotext(); | |
194 | readf(); | |
195 | } | |
196 | exit(0); | |
055eee28 KB |
197 | } |
198 | ||
1a585c5c | 199 | static |
055eee28 KB |
200 | getu() |
201 | { | |
202 | struct pte *pteaddr, apte; | |
203 | struct pte arguutl[UPAGES+CLSIZE]; | |
204 | register int i; | |
f255214c | 205 | int ncl; |
055eee28 | 206 | |
055eee28 KB |
207 | if ((mproc->p_flag & SLOAD) == 0) { |
208 | if (swap < 0) | |
f255214c | 209 | return(0); |
1a585c5c | 210 | (void)lseek(swap, (off_t)dtob(mproc->p_swaddr), L_SET); |
f255214c KB |
211 | if (read(swap, (char *)&user.user, sizeof(struct user)) |
212 | != sizeof(struct user)) { | |
cf2c7bf9 | 213 | VP("fstat: can't read u for pid %d from %s\n", |
435e8dff | 214 | mproc->p_pid, _PATH_DRUM); |
1a585c5c | 215 | return(0); |
055eee28 | 216 | } |
1a585c5c | 217 | return(1); |
055eee28 KB |
218 | } |
219 | pteaddr = &Usrptma[btokmx(mproc->p_p0br) + mproc->p_szpt - 1]; | |
1a585c5c | 220 | (void)lseek(kmem, (off_t)pteaddr, L_SET); |
055eee28 | 221 | if (read(kmem, (char *)&apte, sizeof(apte)) != sizeof(apte)) { |
cf2c7bf9 | 222 | VP("fstat: can't read indir pte to get u for pid %d from %s\n", |
435e8dff | 223 | mproc->p_pid, _PATH_DRUM); |
1a585c5c | 224 | return(0); |
055eee28 | 225 | } |
1a585c5c KB |
226 | (void)lseek(mem, (off_t)ctob(apte.pg_pfnum+1) - (UPAGES+CLSIZE) |
227 | * sizeof(struct pte), L_SET); | |
055eee28 | 228 | if (read(mem, (char *)arguutl, sizeof(arguutl)) != sizeof(arguutl)) { |
cf2c7bf9 KB |
229 | VP("fstat: can't read page table for u of pid %d from %s\n", |
230 | mproc->p_pid, _PATH_KMEM); | |
1a585c5c | 231 | return(0); |
055eee28 | 232 | } |
f255214c | 233 | ncl = (sizeof(struct user) + NBPG*CLSIZE - 1) / (NBPG*CLSIZE); |
055eee28 KB |
234 | while (--ncl >= 0) { |
235 | i = ncl * CLSIZE; | |
1a585c5c | 236 | (void)lseek(mem, (off_t)ctob(arguutl[CLSIZE+i].pg_pfnum), L_SET); |
055eee28 | 237 | if (read(mem, user.upages[i], CLSIZE*NBPG) != CLSIZE*NBPG) { |
cf2c7bf9 KB |
238 | VP("fstat: can't read page %u of u of pid %d from %s\n", |
239 | arguutl[CLSIZE+i].pg_pfnum, mproc->p_pid, | |
240 | _PATH_MEM); | |
055eee28 KB |
241 | return(0); |
242 | } | |
243 | } | |
1a585c5c | 244 | return(1); |
055eee28 KB |
245 | } |
246 | ||
1a585c5c | 247 | static |
055eee28 KB |
248 | dotext() |
249 | { | |
4575617f | 250 | struct text text; |
055eee28 | 251 | |
1a585c5c | 252 | (void)lseek(kmem, (off_t)mproc->p_textp, L_SET); |
055eee28 | 253 | if (read(kmem, (char *) &text, sizeof(text)) != sizeof(text)) { |
0ea8b445 | 254 | rerr1("text table", _PATH_KMEM); |
055eee28 KB |
255 | return; |
256 | } | |
f255214c | 257 | if (text.x_flag) |
3dae3806 | 258 | vtrans(DTYPE_VNODE, text.x_vptr, TEXT); |
055eee28 KB |
259 | } |
260 | ||
1a585c5c | 261 | static |
3dae3806 | 262 | vtrans(ftype, g, fno) |
1a585c5c | 263 | int ftype, fno; |
3dae3806 | 264 | struct vnode *g; /* if ftype is vnode */ |
055eee28 | 265 | { |
3dae3806 | 266 | struct vnode vnode; |
f255214c KB |
267 | struct inode inode; |
268 | dev_t idev; | |
3dae3806 | 269 | char *comm, *vtype(); |
d81abd9a | 270 | char *name = (char *)NULL; /* set by devmatch() on a match */ |
1a585c5c | 271 | |
11f68bc1 | 272 | if (ftype == DTYPE_VNODE && (g || fflg)) { |
1a585c5c | 273 | (void)lseek(kmem, (off_t)g, L_SET); |
3dae3806 KM |
274 | if (read(kmem, (char *)&vnode, sizeof(vnode)) != sizeof(vnode)) { |
275 | rerr2((int)g, "vnode"); | |
1a585c5c KB |
276 | return; |
277 | } | |
3dae3806 KM |
278 | if (vnode.v_op != (struct vnodeops *)nl[X_UFSOPS].n_value && |
279 | (vnode.v_op != (struct vnodeops *)nl[X_BLKOPS].n_value || | |
280 | vnode.v_data == (qaddr_t)0)) { | |
281 | if (fflg) | |
282 | return; | |
283 | ftype = -1; | |
284 | } else { | |
285 | (void)lseek(kmem, (off_t)vnode.v_data, L_SET); | |
286 | if (read(kmem, (char *)&inode, sizeof(inode)) | |
287 | != sizeof(inode)) { | |
288 | rerr2((int)vnode.v_data, "inode"); | |
289 | return; | |
290 | } | |
291 | idev = inode.i_dev; | |
292 | if (fflg && !devmatch(idev, inode.i_number, &name)) | |
293 | return; | |
294 | } | |
055eee28 | 295 | } |
055eee28 KB |
296 | if (mproc->p_pid == 0) |
297 | comm = "swapper"; | |
298 | else if (mproc->p_pid == 2) | |
299 | comm = "pagedaemon"; | |
300 | else | |
1a585c5c | 301 | comm = user.user.u_comm; |
cf2c7bf9 | 302 | (void)printf("%-8.8s %-10.10s %5d ", uname, comm, mproc->p_pid); |
f255214c KB |
303 | |
304 | switch(fno) { | |
305 | case WD: | |
cf2c7bf9 | 306 | (void)printf(" wd"); break; |
f255214c | 307 | case TEXT: |
cf2c7bf9 | 308 | (void)printf("text"); break; |
f255214c | 309 | default: |
cf2c7bf9 | 310 | (void)printf("%4d", fno); |
f255214c | 311 | } |
055eee28 KB |
312 | |
313 | if (g == 0) { | |
cf2c7bf9 | 314 | (void)printf("* (deallocated)\n"); |
055eee28 KB |
315 | return; |
316 | } | |
317 | ||
1a585c5c | 318 | switch(ftype) { |
3dae3806 KM |
319 | |
320 | case DTYPE_VNODE: | |
cf2c7bf9 KB |
321 | (void)printf("\t%2d, %2d\t%5lu\t", major(inode.i_dev), |
322 | minor(inode.i_dev), inode.i_number); | |
56af3334 | 323 | switch(inode.i_mode & IFMT) { |
cf2c7bf9 KB |
324 | case IFSOCK: |
325 | (void)printf(" 0\t"); | |
56af3334 | 326 | break; |
3dae3806 | 327 | case IFBLK: |
cf2c7bf9 KB |
328 | case IFCHR: |
329 | (void)printf("%2d, %2d\t", major(inode.i_rdev), | |
330 | minor(inode.i_rdev)); | |
56af3334 KF |
331 | break; |
332 | default: | |
cf2c7bf9 | 333 | (void)printf("%6ld\t", inode.i_size); |
56af3334 | 334 | } |
3dae3806 KM |
335 | (void)printf("%3s %s\n", vtype(vnode.v_type), name ? name : ""); |
336 | break; | |
337 | ||
338 | case -1: /* DTYPE_VNODE for a remote filesystem */ | |
339 | (void)printf(" from remote filesystem\t"); | |
340 | (void)printf("%3s %s\n", vtype(vnode.v_type), name ? name : ""); | |
1a585c5c | 341 | break; |
3dae3806 | 342 | |
1a585c5c | 343 | case DTYPE_SOCKET: |
055eee28 | 344 | socktrans((struct socket *)g); |
1a585c5c | 345 | break; |
3dae3806 | 346 | |
055eee28 | 347 | #ifdef DTYPE_PORT |
1a585c5c | 348 | case DTYPE_PORT: |
cf2c7bf9 | 349 | (void)printf("* (fifo / named pipe)\n"); |
1a585c5c KB |
350 | break; |
351 | #endif | |
3dae3806 | 352 | |
1a585c5c | 353 | default: |
cf2c7bf9 | 354 | (void)printf("* (unknown file type)\n"); |
055eee28 KB |
355 | } |
356 | } | |
1a585c5c | 357 | |
f255214c | 358 | static char * |
3dae3806 KM |
359 | vtype(type) |
360 | enum vtype type; | |
5e369078 | 361 | { |
3dae3806 KM |
362 | switch(type) { |
363 | case VCHR: | |
f255214c | 364 | return("chr"); |
3dae3806 | 365 | case VDIR: |
f255214c | 366 | return("dir"); |
3dae3806 | 367 | case VBLK: |
f255214c | 368 | return("blk"); |
3dae3806 | 369 | case VREG: |
f255214c | 370 | return("reg"); |
3dae3806 | 371 | case VLNK: |
f255214c | 372 | return("lnk"); |
3dae3806 | 373 | case VSOCK: |
f255214c | 374 | return("soc"); |
3dae3806 KM |
375 | case VBAD: |
376 | return("bad"); | |
f255214c KB |
377 | default: |
378 | return("unk"); | |
379 | } | |
380 | /*NOTREACHED*/ | |
5e369078 | 381 | } |
055eee28 | 382 | |
1a585c5c | 383 | static |
055eee28 | 384 | socktrans(sock) |
1a585c5c | 385 | struct socket *sock; |
055eee28 | 386 | { |
f255214c | 387 | static char *stypename[] = { |
1a585c5c KB |
388 | "unused", /* 0 */ |
389 | "stream", /* 1 */ | |
390 | "dgram", /* 2 */ | |
391 | "raw", /* 3 */ | |
392 | "rdm", /* 4 */ | |
393 | "seqpak" /* 5 */ | |
394 | }; | |
395 | #define STYPEMAX 5 | |
396 | struct socket so; | |
397 | struct protosw proto; | |
398 | struct domain dom; | |
399 | struct inpcb inpcb; | |
400 | struct unpcb unpcb; | |
f255214c KB |
401 | int len; |
402 | char dname[32], *strcpy(); | |
055eee28 KB |
403 | |
404 | /* fill in socket */ | |
1a585c5c KB |
405 | (void)lseek(kmem, (off_t)sock, L_SET); |
406 | if (read(kmem, (char *)&so, sizeof(struct socket)) | |
407 | != sizeof(struct socket)) { | |
cf2c7bf9 | 408 | rerr2((int)sock, "socket"); |
055eee28 KB |
409 | return; |
410 | } | |
411 | ||
412 | /* fill in protosw entry */ | |
1a585c5c KB |
413 | (void)lseek(kmem, (off_t)so.so_proto, L_SET); |
414 | if (read(kmem, (char *)&proto, sizeof(struct protosw)) | |
415 | != sizeof(struct protosw)) { | |
cf2c7bf9 | 416 | rerr2((int)so.so_proto, "protosw"); |
055eee28 KB |
417 | return; |
418 | } | |
419 | ||
420 | /* fill in domain */ | |
1a585c5c KB |
421 | (void)lseek(kmem, (off_t)proto.pr_domain, L_SET); |
422 | if (read(kmem, (char *)&dom, sizeof(struct domain)) | |
423 | != sizeof(struct domain)) { | |
cf2c7bf9 | 424 | rerr2((int)proto.pr_domain, "domain"); |
055eee28 KB |
425 | return; |
426 | } | |
427 | ||
f255214c KB |
428 | /* |
429 | * grab domain name | |
430 | * kludge "internet" --> "inet" for brevity | |
431 | */ | |
1a585c5c KB |
432 | if (dom.dom_family == AF_INET) |
433 | (void)strcpy(dname, "inet"); | |
f255214c KB |
434 | else { |
435 | (void)lseek(kmem, (off_t)dom.dom_name, L_SET); | |
436 | if ((len = read(kmem, dname, sizeof(dname) - 1)) < 0) { | |
cf2c7bf9 | 437 | rerr2((int)dom.dom_name, "char"); |
f255214c KB |
438 | dname[0] = '\0'; |
439 | } | |
440 | else | |
441 | dname[len] = '\0'; | |
1a585c5c | 442 | } |
055eee28 | 443 | |
f255214c | 444 | if ((u_short)so.so_type > STYPEMAX) |
cf2c7bf9 | 445 | (void)printf("* (%s unk%d %x", dname, so.so_type, so.so_state); |
f255214c | 446 | else |
cf2c7bf9 | 447 | (void)printf("* (%s %s %x", dname, stypename[so.so_type], |
f255214c | 448 | so.so_state); |
055eee28 KB |
449 | |
450 | /* | |
5ebc207c | 451 | * protocol specific formatting |
055eee28 | 452 | * |
f255214c KB |
453 | * Try to find interesting things to print. For tcp, the interesting |
454 | * thing is the address of the tcpcb, for udp and others, just the | |
455 | * inpcb (socket pcb). For unix domain, its the address of the socket | |
456 | * pcb and the address of the connected pcb (if connected). Otherwise | |
457 | * just print the protocol number and address of the socket itself. | |
458 | * The idea is not to duplicate netstat, but to make available enough | |
459 | * information for further analysis. | |
055eee28 | 460 | */ |
f255214c KB |
461 | switch(dom.dom_family) { |
462 | case AF_INET: | |
463 | getinetproto(proto.pr_protocol); | |
055eee28 KB |
464 | if (proto.pr_protocol == IPPROTO_TCP ) { |
465 | if (so.so_pcb) { | |
1a585c5c KB |
466 | (void)lseek(kmem, (off_t)so.so_pcb, L_SET); |
467 | if (read(kmem, (char *)&inpcb, sizeof(struct inpcb)) | |
055eee28 | 468 | != sizeof(struct inpcb)){ |
cf2c7bf9 | 469 | rerr2((int)so.so_pcb, "inpcb"); |
055eee28 KB |
470 | return; |
471 | } | |
cf2c7bf9 | 472 | (void)printf(" %x", (int)inpcb.inp_ppcb); |
055eee28 | 473 | } |
055eee28 | 474 | } |
1a585c5c | 475 | else if (so.so_pcb) |
cf2c7bf9 | 476 | (void)printf(" %x", (int)so.so_pcb); |
f255214c KB |
477 | break; |
478 | case AF_UNIX: | |
055eee28 KB |
479 | /* print address of pcb and connected pcb */ |
480 | if (so.so_pcb) { | |
cf2c7bf9 | 481 | (void)printf(" %x", (int)so.so_pcb); |
1a585c5c KB |
482 | (void)lseek(kmem, (off_t)so.so_pcb, L_SET); |
483 | if (read(kmem, (char *)&unpcb, sizeof(struct unpcb)) | |
055eee28 | 484 | != sizeof(struct unpcb)){ |
cf2c7bf9 | 485 | rerr2((int)so.so_pcb, "unpcb"); |
055eee28 KB |
486 | return; |
487 | } | |
5e369078 | 488 | if (unpcb.unp_conn) { |
f255214c | 489 | char shoconn[4], *cp; |
1a585c5c | 490 | |
f255214c | 491 | cp = shoconn; |
5e369078 | 492 | if (!(so.so_state & SS_CANTRCVMORE)) |
f255214c KB |
493 | *cp++ = '<'; |
494 | *cp++ = '-'; | |
5e369078 | 495 | if (!(so.so_state & SS_CANTSENDMORE)) |
f255214c KB |
496 | *cp++ = '>'; |
497 | *cp = '\0'; | |
cf2c7bf9 KB |
498 | (void)printf(" %s %x", shoconn, |
499 | (int)unpcb.unp_conn); | |
5e369078 | 500 | } |
055eee28 | 501 | } |
f255214c KB |
502 | break; |
503 | default: | |
504 | /* print protocol number and socket address */ | |
cf2c7bf9 | 505 | (void)printf(" %d %x", proto.pr_protocol, (int)sock); |
f255214c | 506 | } |
cf2c7bf9 | 507 | (void)printf(")\n"); |
055eee28 KB |
508 | } |
509 | ||
f255214c KB |
510 | /* |
511 | * getinetproto -- | |
512 | * print name of protocol number | |
513 | */ | |
514 | static | |
055eee28 | 515 | getinetproto(number) |
1a585c5c | 516 | int number; |
055eee28 | 517 | { |
1a585c5c | 518 | char *cp; |
9bd38ba8 | 519 | |
055eee28 | 520 | switch(number) { |
f255214c KB |
521 | case IPPROTO_IP: |
522 | cp = "ip"; break; | |
523 | case IPPROTO_ICMP: | |
524 | cp ="icmp"; break; | |
525 | case IPPROTO_GGP: | |
526 | cp ="ggp"; break; | |
527 | case IPPROTO_TCP: | |
528 | cp ="tcp"; break; | |
529 | case IPPROTO_EGP: | |
530 | cp ="egp"; break; | |
531 | case IPPROTO_PUP: | |
532 | cp ="pup"; break; | |
533 | case IPPROTO_UDP: | |
534 | cp ="udp"; break; | |
535 | case IPPROTO_IDP: | |
536 | cp ="idp"; break; | |
537 | case IPPROTO_RAW: | |
538 | cp ="raw"; break; | |
9bd38ba8 | 539 | default: |
cf2c7bf9 | 540 | (void)printf(" %d", number); |
f255214c | 541 | return; |
055eee28 | 542 | } |
cf2c7bf9 | 543 | (void)printf(" %s", cp); |
055eee28 KB |
544 | } |
545 | ||
f255214c KB |
546 | static |
547 | readf() | |
055eee28 | 548 | { |
1a585c5c | 549 | struct file lfile; |
f255214c | 550 | int i; |
055eee28 | 551 | |
3dae3806 | 552 | vtrans(DTYPE_VNODE, user.user.u_cdir, WD); |
055eee28 | 553 | for (i = 0; i < NOFILE; i++) { |
1a585c5c | 554 | if (user.user.u_ofile[i] == 0) |
055eee28 | 555 | continue; |
1a585c5c KB |
556 | (void)lseek(kmem, (off_t)user.user.u_ofile[i], L_SET); |
557 | if (read(kmem, (char *)&lfile, sizeof(lfile)) | |
558 | != sizeof(lfile)) { | |
0ea8b445 | 559 | rerr1("file", _PATH_KMEM); |
055eee28 KB |
560 | continue; |
561 | } | |
3dae3806 | 562 | vtrans(lfile.f_type, (struct vnode *)lfile.f_data, i); |
055eee28 KB |
563 | } |
564 | } | |
565 | ||
1a585c5c | 566 | static |
d81abd9a | 567 | devmatch(idev, inum, name) |
f255214c KB |
568 | dev_t idev; |
569 | ino_t inum; | |
d81abd9a | 570 | char **name; |
055eee28 | 571 | { |
f255214c | 572 | register DEVS *d; |
1a585c5c | 573 | |
f255214c | 574 | for (d = devs; d; d = d->next) |
d81abd9a MT |
575 | if (d->dev == idev && (d->inum == 0 || d->inum == inum)) { |
576 | *name = d->name; | |
f255214c | 577 | return(1); |
d81abd9a | 578 | } |
f255214c | 579 | return(0); |
055eee28 KB |
580 | } |
581 | ||
1a585c5c | 582 | static |
055eee28 | 583 | getfname(filename) |
1a585c5c | 584 | char *filename; |
055eee28 | 585 | { |
f255214c KB |
586 | struct stat statbuf; |
587 | DEVS *cur; | |
588 | char *malloc(); | |
055eee28 | 589 | |
1a585c5c | 590 | if (stat(filename, &statbuf)) { |
cf2c7bf9 KB |
591 | (void)fprintf(stderr, "fstat: %s: %s\n", strerror(errno), |
592 | filename); | |
6270ab99 | 593 | return(0); |
1a585c5c | 594 | } |
f255214c | 595 | if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) { |
cf2c7bf9 | 596 | (void)fprintf(stderr, "fstat: out of space.\n"); |
f255214c KB |
597 | exit(1); |
598 | } | |
599 | cur->next = devs; | |
600 | devs = cur; | |
055eee28 | 601 | |
f255214c | 602 | /* if file is block special, look for open files on it */ |
055eee28 | 603 | if ((statbuf.st_mode & S_IFMT) != S_IFBLK) { |
f255214c KB |
604 | cur->inum = statbuf.st_ino; |
605 | cur->dev = statbuf.st_dev; | |
1a585c5c KB |
606 | } |
607 | else { | |
f255214c KB |
608 | cur->inum = 0; |
609 | cur->dev = statbuf.st_rdev; | |
055eee28 | 610 | } |
d81abd9a | 611 | cur->name = filename; |
6270ab99 | 612 | return(1); |
f255214c KB |
613 | } |
614 | ||
615 | static | |
616 | openfiles() | |
617 | { | |
0ea8b445 KB |
618 | if ((kmem = open(_PATH_KMEM, O_RDONLY, 0)) < 0) { |
619 | (void)fprintf(stderr, "fstat: %s: %s\n", | |
620 | strerror(errno), _PATH_KMEM); | |
f255214c KB |
621 | exit(1); |
622 | } | |
0ea8b445 KB |
623 | if ((mem = open(_PATH_MEM, O_RDONLY, 0)) < 0) { |
624 | (void)fprintf(stderr, "fstat: %s: %s\n", | |
625 | strerror(errno), _PATH_MEM); | |
f255214c KB |
626 | exit(1); |
627 | } | |
435e8dff | 628 | if ((swap = open(_PATH_DRUM, O_RDONLY, 0)) < 0) { |
0ea8b445 | 629 | (void)fprintf(stderr, "fstat: %s: %s\n", |
435e8dff | 630 | strerror(errno), _PATH_DRUM); |
f255214c KB |
631 | exit(1); |
632 | } | |
633 | } | |
634 | ||
635 | static | |
5ebc207c | 636 | rerr1(what, fromwhat) |
f255214c KB |
637 | char *what, *fromwhat; |
638 | { | |
cf2c7bf9 | 639 | VP("error reading %s from %s", what, fromwhat); |
5ebc207c KB |
640 | } |
641 | ||
642 | static | |
cf2c7bf9 KB |
643 | rerr2(address, what) |
644 | int address; | |
5ebc207c KB |
645 | char *what; |
646 | { | |
cf2c7bf9 KB |
647 | VP("error %d reading %s at %x from %s\n", errno, what, address, |
648 | _PATH_KMEM); | |
f255214c KB |
649 | } |
650 | ||
651 | static long | |
652 | lgetw(loc) | |
653 | off_t loc; | |
654 | { | |
655 | long word; | |
656 | ||
657 | (void)lseek(kmem, (off_t)loc, L_SET); | |
5ebc207c | 658 | if (read(kmem, (char *)&word, sizeof(word)) != sizeof(word)) |
cf2c7bf9 | 659 | rerr2((int)loc, "word"); |
f255214c KB |
660 | return(word); |
661 | } | |
662 | ||
663 | static | |
664 | usage() | |
665 | { | |
cf2c7bf9 KB |
666 | (void)fprintf(stderr, |
667 | "usage: fstat [-u user] [-p pid] [filename ...]\n"); | |
f255214c | 668 | exit(1); |
055eee28 | 669 | } |