Annotation of 43BSDReno/usr.bin/fstat/fstat.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.