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