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