remove BSD ifdefs
[unix-history] / usr / src / usr.bin / fstat / fstat.c
CommitLineData
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
19char 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 25static 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 66typedef struct devs {
4575617f
KB
67 struct devs *next;
68 dev_t dev;
69 int inum;
70 char *name;
f255214c 71} DEVS;
4575617f 72DEVS *devs;
5e369078 73
f255214c 74static 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
90struct proc *mproc;
91struct pte *Usrptma, *usrpt;
f255214c 92
055eee28 93union {
4575617f
KB
94 struct user user;
95 char upages[UPAGES][NBPG];
055eee28 96} user;
055eee28 97
4575617f
KB
98extern int errno;
99static int fflg, vflg;
100static int kmem, mem, nproc, swap;
101static char *uname;
1a585c5c 102
4575617f 103off_t lseek();
055eee28
KB
104
105main(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 199static
055eee28
KB
200getu()
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 247static
055eee28
KB
248dotext()
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 261static
3dae3806 262vtrans(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 358static char *
3dae3806
KM
359vtype(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 383static
055eee28 384socktrans(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 */
514static
055eee28 515getinetproto(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
546static
547readf()
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 566static
d81abd9a 567devmatch(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 582static
055eee28 583getfname(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
615static
616openfiles()
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
635static
5ebc207c 636rerr1(what, fromwhat)
f255214c
KB
637 char *what, *fromwhat;
638{
cf2c7bf9 639 VP("error reading %s from %s", what, fromwhat);
5ebc207c
KB
640}
641
642static
cf2c7bf9
KB
643rerr2(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
651static long
652lgetw(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
663static
664usage()
665{
cf2c7bf9
KB
666 (void)fprintf(stderr,
667 "usage: fstat [-u user] [-p pid] [filename ...]\n");
f255214c 668 exit(1);
055eee28 669}