new copyright; att/bsd/shared
[unix-history] / usr / src / usr.bin / fstat / fstat.c
CommitLineData
7f9552fe
MT
1/*-
2 * Copyright (c) 1988 The Regents of the University of California.
5ebc207c
KB
3 * All rights reserved.
4 *
7f9552fe 5 * %sccs.include.redist.c%
055eee28
KB
6 */
7
8#ifndef lint
9char copyright[] =
7f9552fe 10"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
055eee28 11 All rights reserved.\n";
5ebc207c 12#endif /* not lint */
055eee28
KB
13
14#ifndef lint
49acea14 15static char sccsid[] = "@(#)fstat.c 5.27 (Berkeley) %G%";
5ebc207c 16#endif /* not lint */
055eee28
KB
17
18/*
19 * fstat
20 */
f255214c 21#include <machine/pte.h>
1a585c5c 22
055eee28 23#include <sys/param.h>
49acea14 24#include <sys/time.h>
055eee28 25#include <sys/proc.h>
055eee28
KB
26#include <sys/text.h>
27#include <sys/stat.h>
3dae3806 28#include <sys/vnode.h>
055eee28
KB
29#include <sys/socket.h>
30#include <sys/socketvar.h>
31#include <sys/domain.h>
32#include <sys/protosw.h>
055eee28 33#include <sys/unpcb.h>
f255214c 34#include <sys/vmmac.h>
49acea14
MT
35#include <sys/kinfo.h>
36#include <sys/namei.h>
37#include <sys/filedesc.h>
f255214c 38#define KERNEL
e00a6228 39#define NFS
055eee28 40#include <sys/file.h>
e00a6228 41#include <sys/mount.h>
7f9552fe 42#include <ufs/quota.h>
3dae3806 43#include <ufs/inode.h>
e00a6228
MT
44#include <nfs/nfsv2.h>
45#include <nfs/nfs.h>
46#include <nfs/nfsnode.h>
47#undef KERNEL
48
1a585c5c
KB
49#include <net/route.h>
50#include <netinet/in.h>
e00a6228
MT
51#include <netinet/in_systm.h>
52#include <netinet/ip.h>
1a585c5c 53#include <netinet/in_pcb.h>
e00a6228
MT
54
55#include <kvm.h>
56#include <paths.h>
7168b138 57#include <ctype.h>
1a585c5c
KB
58#include <nlist.h>
59#include <pwd.h>
7f9552fe 60#include <string.h>
e00a6228 61#include <stdio.h>
f255214c 62
e00a6228
MT
63#define TEXT -1
64#define CDIR -2
65#define RDIR -3
66#define TRACE -4
cf2c7bf9 67
f255214c 68typedef struct devs {
e00a6228 69 struct devs *next;
7f9552fe 70 long fsid;
e00a6228
MT
71 ino_t ino;
72 char *name;
f255214c 73} DEVS;
4575617f 74DEVS *devs;
5e369078 75
e00a6228
MT
76struct filestat {
77 long fsid;
78 long fileid;
7f9552fe 79 mode_t mode;
e00a6228
MT
80 u_long size;
81 dev_t rdev;
82};
83
7f9552fe 84#ifdef notdef
e00a6228 85struct nlist nl[] = {
055eee28
KB
86 { "" },
87};
7f9552fe 88#endif
055eee28 89
e00a6228
MT
90int fsflg, /* show files on same filesystem as file(s) argument */
91 pflg, /* show files open by a particular pid */
92 uflg; /* show files open by a particular (effective) user */
93int checkfile; /* true if restricting to particular files or filesystems */
94int nflg; /* (numerical) display f.s. and rdev as dev_t */
95int vflg; /* display errors in locating kernel data objects etc... */
f255214c 96
e00a6228 97#define dprintf if (vflg) fprintf
055eee28 98
49acea14
MT
99struct file **ofiles; /* buffer of pointers to file structures */
100int maxfiles;
101#define ALLOC_OFILES(d) \
102 if ((d) > maxfiles) { \
103 free(ofiles); \
104 ofiles = (struct file **)malloc((d) * sizeof(struct file *)); \
105 if (ofiles == NULL) { \
106 fprintf(stderr, "fstat: out of memory\n"); \
107 exit(1); \
108 } \
109 maxfiles = (d); \
110 }
111
112/*
113 * a kvm_read that returns true if everything is read
114 */
115#define KVM_READ(kaddr, paddr, len) (kvm_read((kaddr), (paddr), (len)) == (len))
116
4575617f 117extern int errno;
4575617f 118off_t lseek();
055eee28 119
49acea14 120
055eee28 121main(argc, argv)
4575617f
KB
122 int argc;
123 char **argv;
055eee28 124{
e00a6228
MT
125 register struct passwd *passwd;
126 int what = KINFO_PROC_ALL, arg = 0;
127 struct passwd *getpwnam(), *getpwuid();
128 struct proc *p;
f255214c
KB
129 extern char *optarg;
130 extern int optind;
7f9552fe 131 int ch;
f255214c
KB
132 char *malloc();
133
e00a6228
MT
134
135 while ((ch = getopt(argc, argv, "p:u:fnv")) != EOF)
1a585c5c
KB
136 switch((char)ch) {
137 case 'p':
7168b138
MT
138 if (pflg++)
139 usage();
140 if (!isdigit(*optarg)) {
141 fputs("fstat: -p option requires a process id.\n", stderr);
055eee28 142 usage();
055eee28 143 }
e00a6228
MT
144 what = KINFO_PROC_PID;
145 arg = atoi(optarg);
1a585c5c
KB
146 break;
147 case 'u':
148 if (uflg++)
055eee28 149 usage();
f255214c 150 if (!(passwd = getpwnam(optarg))) {
7f9552fe 151 fprintf(stderr, "%s: unknown uid\n",
cf2c7bf9 152 optarg);
055eee28
KB
153 exit(1);
154 }
e00a6228
MT
155 what = KINFO_PROC_UID;
156 arg = passwd->pw_uid;
1a585c5c 157 break;
e00a6228
MT
158 case 'f':
159 fsflg++;
160 break;
161 case 'n':
162 nflg++;
163 break;
164 case 'v':
1a585c5c
KB
165 vflg++;
166 break;
167 case '?':
168 default:
169 usage();
055eee28 170 }
055eee28 171
5ebc207c 172 if (*(argv += optind)) {
193d3a86 173 for (; *argv; ++argv) {
5ebc207c 174 if (getfname(*argv))
e00a6228 175 checkfile = 1;
5ebc207c 176 }
e00a6228 177 if (!checkfile) /* file(s) specified, but none accessable */
5ebc207c 178 exit(1);
055eee28 179 }
49acea14
MT
180
181 ALLOC_OFILES(256); /* reverse space for file pointers */
182
e00a6228
MT
183 if (fsflg && !checkfile) {
184 /* -f with no files means use wd */
185 if (getfname(".") == 0)
186 exit(1);
187 checkfile = 1;
188 }
d81abd9a 189
d0410028 190 /* modify the following to make work on dead kernels */
e00a6228
MT
191 if (kvm_openfiles(NULL, NULL, NULL) == -1) {
192 fprintf(stderr, "fstat: %s\n", kvm_geterr());
055eee28
KB
193 exit(1);
194 }
7f9552fe 195#ifdef notdef
e00a6228 196 if (kvm_nlist(nl) != 0) {
7f9552fe 197 fprintf(stderr, "fstat: no namelist: %s\n", kvm_geterr());
e00a6228
MT
198 exit(1);
199 }
7f9552fe 200#endif
e00a6228
MT
201 if (kvm_getprocs(what, arg) == -1) {
202 fprintf(stderr, "fstat: %s\n", kvm_geterr());
055eee28
KB
203 exit(1);
204 }
e00a6228 205 if (nflg)
7f9552fe 206fputs("USER CMD PID FD DEV INUM MODE SZ|DV", stdout);
e00a6228 207 else
7f9552fe 208fputs("USER CMD PID FD MOUNT INUM MODE SZ|DV", stdout);
e00a6228
MT
209 if (checkfile && fsflg == 0)
210 fputs(" NAME\n", stdout);
211 else
212 putchar('\n');
5ebc207c 213
e00a6228
MT
214 while ((p = kvm_nextproc()) != NULL) {
215 if (p->p_stat == SZOMB)
f255214c 216 continue;
e00a6228 217 dofiles(p);
f255214c
KB
218 }
219 exit(0);
055eee28
KB
220}
221
e00a6228
MT
222char *Uname, *Comm;
223int Pid;
224
49acea14 225#define PREFIX(i) printf("%-8.8s %-8s %5d", Uname, Comm, Pid); \
e00a6228
MT
226 switch(i) { \
227 case TEXT: \
228 fputs(" text", stdout); \
229 break; \
230 case CDIR: \
231 fputs(" wd", stdout); \
232 break; \
233 case RDIR: \
234 fputs(" root", stdout); \
235 break; \
236 case TRACE: \
237 fputs(" tr", stdout); \
238 break; \
239 default: \
240 printf(" %4d", i); \
241 break; \
055eee28 242 }
e00a6228
MT
243
244/*
245 * print open files attributed to this process
246 */
247dofiles(p)
248 struct proc *p;
249{
49acea14 250 int i, last;
e00a6228 251 struct file file;
49acea14
MT
252 struct filedesc filed;
253
7f9552fe 254 extern char *user_from_uid();
49acea14
MT
255#ifdef notdef
256 struct vnode *xvptr;
257#endif
e00a6228
MT
258
259 Uname = user_from_uid(p->p_uid, 0);
260 Pid = p->p_pid;
261 Comm = p->p_comm;
262
49acea14
MT
263 if (p->p_fd == NULL)
264 return;
265 if (!KVM_READ(p->p_fd, &filed, sizeof (struct filedesc))) {
266 dprintf(stderr, "can't read filedesc at %x for pid %d\n",
267 p->p_fd, Pid);
e00a6228 268 return;
055eee28 269 }
e00a6228
MT
270 /*
271 * root directory vnode, if one
272 */
49acea14
MT
273 if (filed.fd_rdir)
274 vtrans(filed.fd_rdir, RDIR);
275#ifdef notdef
e00a6228
MT
276 /*
277 * text vnode
278 */
279 if (p->p_textp &&
49acea14 280 KVM_READ(&(p->p_textp->x_vptr), &xvptr, sizeof (struct vnode *)) &&
e00a6228
MT
281 xvptr != NULL)
282 vtrans(xvptr, TEXT);
49acea14 283#endif
e00a6228
MT
284 /*
285 * current working directory vnode
286 */
49acea14 287 vtrans(filed.fd_cdir, CDIR);
e00a6228
MT
288 /*
289 * ktrace vnode, if one
290 */
291 if (p->p_tracep)
292 vtrans(p->p_tracep, TRACE);
293 /*
294 * open files
295 */
49acea14
MT
296#define FPSIZE (sizeof (struct file *))
297 ALLOC_OFILES(last=filed.fd_lastfile);
298#ifdef newvm
299 if (!KVM_READ(filed.fd_ofiles, ofiles, filed.fd_lastfile * FPSIZE)) {
300 dprintf(stderr, "can't read file structures at %x for pid %d\n",
301 filed.fd_ofiles, Pid);
302 return;
303 }
304#else
305 bcopy(filed.fd_ofile, ofiles, NDFILE * FPSIZE);
306 if ((last > NDFILE) && !KVM_READ(filed.fd_moreofiles, &ofiles[NDFILE],
307 (last - NDFILE) * FPSIZE)) {
308 dprintf(stderr, "can't read rest of files at %x for pid %d\n",
309 filed.fd_moreofiles, Pid);
310 return;
311 }
312#endif
313 for (i = 0; i <= filed.fd_lastfile; i++) {
314 if (ofiles[i] == NULL)
e00a6228 315 continue;
49acea14
MT
316 if (!KVM_READ(ofiles[i], &file, sizeof (struct file))) {
317 dprintf(stderr, "can't read file %d at %x for pid %d\n",
318 i, ofiles[i], Pid);
e00a6228
MT
319 continue;
320 }
321 if (file.f_type == DTYPE_VNODE)
322 vtrans((struct vnode *)file.f_data, i);
323 else if (file.f_type == DTYPE_SOCKET && checkfile == 0)
324 socktrans((struct socket *)file.f_data, i);
325 else {
326 dprintf(stderr,
327 "unknown file type %d for file %d of pid %d\n",
328 file.f_type, i, Pid);
055eee28
KB
329 }
330 }
055eee28
KB
331}
332
e00a6228
MT
333vtrans(vp, i)
334 struct vnode *vp;
055eee28 335{
e00a6228
MT
336 struct vnode vn;
337 struct filestat fst;
338 char *filename = NULL;
7f9552fe
MT
339 char *badtype = NULL;
340 char *getmnton();
7179a0b6 341 extern char *devname();
7f9552fe 342 char mode[15];
e00a6228 343
49acea14 344 if (!KVM_READ((off_t)vp, &vn, sizeof (struct vnode))) {
e00a6228
MT
345 dprintf(stderr, "can't read vnode at %x for pid %d\n",
346 vp, Pid);
055eee28
KB
347 return;
348 }
7f9552fe
MT
349 if (vn.v_type == VNON || vn.v_tag == VT_NON)
350 badtype = "none";
351 else if (vn.v_type == VBAD)
352 badtype = "bad";
353 else
354 switch (vn.v_tag) {
355 case VT_UFS:
356 ufs_filestat(&vn, &fst);
357 break;
358 case VT_MFS:
359 ufs_filestat(&vn, &fst);
360 break;
361 case VT_NFS:
362 nfs_filestat(&vn, &fst);
363 break;
364 default: {
365 static char unknown[10];
366 sprintf(badtype = unknown, "?(%x)", vn.v_tag);
367 break;;
368 }
e00a6228
MT
369 }
370 if (checkfile) {
371 int fsmatch = 0;
372 register DEVS *d;
055eee28 373
7f9552fe 374 if (badtype)
1a585c5c 375 return;
e00a6228 376 for (d = devs; d != NULL; d = d->next)
7f9552fe 377 if (d->fsid == fst.fsid) {
e00a6228
MT
378 fsmatch = 1;
379 if (d->ino == fst.fileid) {
380 filename = d->name;
381 break;
382 }
3dae3806 383 }
e00a6228
MT
384 if (fsmatch == 0 || (filename == NULL && fsflg == 0))
385 return;
386 }
387 PREFIX(i);
7f9552fe
MT
388 if (badtype) {
389 (void)printf(" - - %10s -\n", badtype);
e00a6228 390 return;
055eee28 391 }
e00a6228 392 if (nflg)
7f9552fe 393 (void)printf(" %2d,%-2d", major(fst.fsid), minor(fst.fsid));
055eee28 394 else
7f9552fe
MT
395 (void)printf(" %-8s", getmnton(vn.v_mount));
396 if (nflg)
397 (void)sprintf(mode, "%o", fst.mode);
398 else
399 strmode(fst.mode, mode);
400 (void)printf(" %6d %10s", fst.fileid, mode);
e00a6228
MT
401 switch (vn.v_type) {
402 case VBLK:
7179a0b6
MT
403 case VCHR: {
404 char *name;
405
406 if (nflg || ((name = devname(fst.rdev, vn.v_type == VCHR ?
407 S_IFCHR : S_IFBLK)) == NULL))
e00a6228
MT
408 printf(" %2d,%-2d", major(fst.rdev), minor(fst.rdev));
409 else
7179a0b6 410 printf(" %6s", name);
e00a6228 411 break;
7179a0b6 412 }
f255214c 413 default:
e00a6228 414 printf(" %6d", fst.size);
055eee28 415 }
e00a6228
MT
416 if (filename && !fsflg)
417 printf(" %s", filename);
418
419 putchar('\n');
420}
055eee28 421
e00a6228
MT
422ufs_filestat(vp, fsp)
423 struct vnode *vp;
424 struct filestat *fsp;
425{
426 struct inode *ip = VTOI(vp);
3dae3806 427
7f9552fe 428 fsp->fsid = ip->i_dev & 0xffff;
e00a6228 429 fsp->fileid = (long)ip->i_number;
7f9552fe 430 fsp->mode = (mode_t)ip->i_mode;
e00a6228
MT
431 fsp->size = (u_long)ip->i_size;
432 fsp->rdev = ip->i_rdev;
433}
3dae3806 434
e00a6228
MT
435nfs_filestat(vp, fsp)
436 struct vnode *vp;
437 struct filestat *fsp;
438{
7f9552fe
MT
439 register struct nfsnode *np = VTONFS(vp);
440 register mode_t mode;
3dae3806 441
e00a6228
MT
442 fsp->fsid = np->n_vattr.va_fsid;
443 fsp->fileid = np->n_vattr.va_fileid;
7179a0b6 444 fsp->size = np->n_size;
e00a6228 445 fsp->rdev = np->n_vattr.va_rdev;
7f9552fe
MT
446 mode = (mode_t)np->n_vattr.va_mode;
447 switch (vp->v_type) {
448 case VREG:
449 mode |= S_IFREG;
450 break;
451 case VDIR:
452 mode |= S_IFDIR;
453 break;
454 case VBLK:
455 mode |= S_IFBLK;
456 break;
457 case VCHR:
458 mode |= S_IFCHR;
459 break;
460 case VLNK:
461 mode |= S_IFLNK;
462 break;
463 case VSOCK:
464 mode |= S_IFSOCK;
465 break;
466 case VFIFO:
467 mode |= S_IFIFO;
468 break;
469 };
470 fsp->mode = mode;
e00a6228 471}
3dae3806 472
3dae3806 473
e00a6228
MT
474char *
475getmnton(m)
476 struct mount *m;
477{
478 static struct mount mount;
479 static struct mtab {
480 struct mtab *next;
481 struct mount *m;
482 char mntonname[MNAMELEN];
483 } *mhead = NULL;
484 register struct mtab *mt;
485
486 for (mt = mhead; mt != NULL; mt = mt->next)
487 if (m == mt->m)
488 return (mt->mntonname);
49acea14 489 if (!KVM_READ((off_t)m, &mount, sizeof(struct mount))) {
e00a6228
MT
490 fprintf(stderr, "can't read mount table at %x\n", m);
491 return (NULL);
055eee28 492 }
e00a6228
MT
493 if ((mt = (struct mtab *)malloc(sizeof (struct mtab))) == NULL) {
494 fprintf(stderr, "out of memory\n");
495 exit(1);
496 }
497 mt->m = m;
7f9552fe 498 bcopy(&mount.mnt_stat.f_mntonname[0], &mt->mntonname[0], MNAMELEN);
e00a6228
MT
499 mt->next = mhead;
500 mhead = mt;
501 return (mt->mntonname);
055eee28 502}
1a585c5c 503
e00a6228 504socktrans(sock, i)
1a585c5c 505 struct socket *sock;
055eee28 506{
f255214c 507 static char *stypename[] = {
1a585c5c
KB
508 "unused", /* 0 */
509 "stream", /* 1 */
510 "dgram", /* 2 */
511 "raw", /* 3 */
512 "rdm", /* 4 */
513 "seqpak" /* 5 */
514 };
515#define STYPEMAX 5
516 struct socket so;
517 struct protosw proto;
518 struct domain dom;
519 struct inpcb inpcb;
520 struct unpcb unpcb;
f255214c
KB
521 int len;
522 char dname[32], *strcpy();
055eee28 523
e00a6228
MT
524 PREFIX(i);
525
055eee28 526 /* fill in socket */
49acea14 527 if (!KVM_READ(sock, &so, sizeof(struct socket))) {
e00a6228 528 dprintf(stderr, "can't read sock at %x\n", sock);
7f9552fe 529 goto bad;
055eee28
KB
530 }
531
532 /* fill in protosw entry */
49acea14 533 if (!KVM_READ(so.so_proto, &proto, sizeof(struct protosw))) {
e00a6228 534 dprintf(stderr, "can't read protosw at %x", so.so_proto);
7f9552fe 535 goto bad;
055eee28
KB
536 }
537
538 /* fill in domain */
49acea14 539 if (!KVM_READ(proto.pr_domain, &dom, sizeof(struct domain))) {
e00a6228 540 dprintf(stderr, "can't read domain at %x\n", proto.pr_domain);
7f9552fe 541 goto bad;
055eee28
KB
542 }
543
49acea14
MT
544 if ((len = kvm_read((off_t)dom.dom_name, dname, sizeof(dname) - 1)) < 0) {
545 dprintf(stderr, "can't read domain name at %x\n",
546 dom.dom_name);
547 dname[0] = '\0';
1a585c5c 548 }
49acea14
MT
549 else
550 dname[len] = '\0';
055eee28 551
f255214c 552 if ((u_short)so.so_type > STYPEMAX)
7f9552fe 553 printf("* %s ?%d", dname, so.so_type);
f255214c 554 else
7f9552fe 555 printf("* %s %s", dname, stypename[so.so_type]);
055eee28
KB
556
557 /*
5ebc207c 558 * protocol specific formatting
055eee28 559 *
f255214c
KB
560 * Try to find interesting things to print. For tcp, the interesting
561 * thing is the address of the tcpcb, for udp and others, just the
562 * inpcb (socket pcb). For unix domain, its the address of the socket
563 * pcb and the address of the connected pcb (if connected). Otherwise
564 * just print the protocol number and address of the socket itself.
565 * The idea is not to duplicate netstat, but to make available enough
566 * information for further analysis.
055eee28 567 */
f255214c
KB
568 switch(dom.dom_family) {
569 case AF_INET:
570 getinetproto(proto.pr_protocol);
055eee28
KB
571 if (proto.pr_protocol == IPPROTO_TCP ) {
572 if (so.so_pcb) {
e00a6228 573 if (kvm_read((off_t)so.so_pcb, (char *)&inpcb, sizeof(struct inpcb))
055eee28 574 != sizeof(struct inpcb)){
e00a6228
MT
575 dprintf(stderr,
576 "can't read inpcb at %x\n", so.so_pcb);
7f9552fe 577 goto bad;
055eee28 578 }
7f9552fe 579 printf(" %x", (int)inpcb.inp_ppcb);
055eee28 580 }
055eee28 581 }
1a585c5c 582 else if (so.so_pcb)
7f9552fe 583 printf(" %x", (int)so.so_pcb);
f255214c
KB
584 break;
585 case AF_UNIX:
055eee28
KB
586 /* print address of pcb and connected pcb */
587 if (so.so_pcb) {
7f9552fe 588 printf(" %x", (int)so.so_pcb);
e00a6228 589 if (kvm_read((off_t)so.so_pcb, (char *)&unpcb, sizeof(struct unpcb))
055eee28 590 != sizeof(struct unpcb)){
e00a6228
MT
591 dprintf(stderr, "can't read unpcb at %x\n",
592 so.so_pcb);
7f9552fe 593 goto bad;
055eee28 594 }
5e369078 595 if (unpcb.unp_conn) {
f255214c 596 char shoconn[4], *cp;
1a585c5c 597
f255214c 598 cp = shoconn;
5e369078 599 if (!(so.so_state & SS_CANTRCVMORE))
f255214c
KB
600 *cp++ = '<';
601 *cp++ = '-';
5e369078 602 if (!(so.so_state & SS_CANTSENDMORE))
f255214c
KB
603 *cp++ = '>';
604 *cp = '\0';
7f9552fe 605 printf(" %s %x", shoconn,
cf2c7bf9 606 (int)unpcb.unp_conn);
5e369078 607 }
055eee28 608 }
f255214c
KB
609 break;
610 default:
611 /* print protocol number and socket address */
7f9552fe 612 printf(" %d %x", proto.pr_protocol, (int)sock);
f255214c 613 }
7f9552fe
MT
614 printf("\n");
615 return;
616bad:
617 printf("* error\n");
055eee28
KB
618}
619
f255214c
KB
620/*
621 * getinetproto --
622 * print name of protocol number
623 */
055eee28 624getinetproto(number)
1a585c5c 625 int number;
055eee28 626{
1a585c5c 627 char *cp;
9bd38ba8 628
055eee28 629 switch(number) {
f255214c
KB
630 case IPPROTO_IP:
631 cp = "ip"; break;
632 case IPPROTO_ICMP:
633 cp ="icmp"; break;
634 case IPPROTO_GGP:
635 cp ="ggp"; break;
636 case IPPROTO_TCP:
637 cp ="tcp"; break;
638 case IPPROTO_EGP:
639 cp ="egp"; break;
640 case IPPROTO_PUP:
641 cp ="pup"; break;
642 case IPPROTO_UDP:
643 cp ="udp"; break;
644 case IPPROTO_IDP:
645 cp ="idp"; break;
646 case IPPROTO_RAW:
647 cp ="raw"; break;
9bd38ba8 648 default:
7f9552fe 649 printf(" %d", number);
f255214c 650 return;
055eee28 651 }
7f9552fe 652 printf(" %s", cp);
055eee28
KB
653}
654
055eee28 655getfname(filename)
1a585c5c 656 char *filename;
055eee28 657{
f255214c
KB
658 struct stat statbuf;
659 DEVS *cur;
660 char *malloc();
055eee28 661
1a585c5c 662 if (stat(filename, &statbuf)) {
7f9552fe 663 fprintf(stderr, "fstat: %s: %s\n", strerror(errno),
cf2c7bf9 664 filename);
6270ab99 665 return(0);
1a585c5c 666 }
f255214c 667 if ((cur = (DEVS *)malloc(sizeof(DEVS))) == NULL) {
7f9552fe 668 fprintf(stderr, "fstat: out of space.\n");
f255214c
KB
669 exit(1);
670 }
671 cur->next = devs;
672 devs = cur;
055eee28 673
e00a6228 674 cur->ino = statbuf.st_ino;
7f9552fe 675 cur->fsid = statbuf.st_dev & 0xffff;
d81abd9a 676 cur->name = filename;
6270ab99 677 return(1);
f255214c
KB
678}
679
f255214c
KB
680usage()
681{
cf2c7bf9 682 (void)fprintf(stderr,
108d5c63 683 "usage: fstat [-fnv] [-p pid] [-u user] [filename ...]\n");
f255214c 684 exit(1);
055eee28 685}