[BACK]Return to fstat.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / fstat

Annotation of src/usr.bin/fstat/fstat.c, Revision 1.103

1.103   ! visa        1: /*     $OpenBSD: fstat.c,v 1.102 2021/07/17 20:46:02 kn Exp $  */
1.65      millert     2:
                      3: /*
1.97      millert     4:  * Copyright (c) 2009 Todd C. Miller <millert@openbsd.org>
1.65      millert     5:  *
                      6:  * Permission to use, copy, modify, and distribute this software for any
                      7:  * purpose with or without fee is hereby granted, provided that the above
                      8:  * copyright notice and this permission notice appear in all copies.
                      9:  *
                     10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     17:  */
1.2       niklas     18:
1.1       deraadt    19: /*-
                     20:  * Copyright (c) 1988, 1993
                     21:  *     The Regents of the University of California.  All rights reserved.
                     22:  *
                     23:  * Redistribution and use in source and binary forms, with or without
                     24:  * modification, are permitted provided that the following conditions
                     25:  * are met:
                     26:  * 1. Redistributions of source code must retain the above copyright
                     27:  *    notice, this list of conditions and the following disclaimer.
                     28:  * 2. Redistributions in binary form must reproduce the above copyright
                     29:  *    notice, this list of conditions and the following disclaimer in the
                     30:  *    documentation and/or other materials provided with the distribution.
1.43      millert    31:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    32:  *    may be used to endorse or promote products derived from this software
                     33:  *    without specific prior written permission.
                     34:  *
                     35:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     36:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     37:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     38:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     39:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     40:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     41:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     42:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     43:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     44:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     45:  * SUCH DAMAGE.
                     46:  */
                     47:
1.80      deraadt    48: #include <sys/types.h>
1.68      millert    49: #include <sys/queue.h>
                     50: #include <sys/mount.h>
1.1       deraadt    51: #include <sys/stat.h>
                     52: #include <sys/vnode.h>
                     53: #include <sys/socket.h>
                     54: #include <sys/socketvar.h>
1.37      deraadt    55: #include <sys/eventvar.h>
1.1       deraadt    56: #include <sys/sysctl.h>
1.90      deraadt    57: #include <sys/filedesc.h>
1.65      millert    58: #define _KERNEL /* for DTYPE_* */
1.1       deraadt    59: #include <sys/file.h>
                     60: #undef _KERNEL
1.61      thib       61:
1.1       deraadt    62: #include <net/route.h>
                     63: #include <netinet/in.h>
1.26      itojun     64:
                     65: #include <netdb.h>
1.5       deraadt    66: #include <arpa/inet.h>
                     67:
1.22      art        68: #include <sys/pipe.h>
                     69:
1.1       deraadt    70: #include <ctype.h>
                     71: #include <errno.h>
1.65      millert    72: #include <fcntl.h>
1.1       deraadt    73: #include <kvm.h>
1.2       niklas     74: #include <limits.h>
1.1       deraadt    75: #include <nlist.h>
                     76: #include <pwd.h>
1.72      guenther   77: #include <search.h>
1.68      millert    78: #include <signal.h>
1.1       deraadt    79: #include <stdio.h>
1.65      millert    80: #include <stdint.h>
1.1       deraadt    81: #include <stdlib.h>
                     82: #include <string.h>
1.11      millert    83: #include <unistd.h>
1.17      mickey     84: #include <err.h>
1.1       deraadt    85:
1.68      millert    86: #include "fstat.h"
                     87:
1.80      deraadt    88: #define MAXIMUM(a, b)  (((a) > (b)) ? (a) : (b))
                     89:
1.98      martijn    90: struct fstat_filter {
                     91:        int what;
                     92:        int arg;
                     93: };
                     94:
1.68      millert    95: struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs);
1.1       deraadt    96:
1.46      deraadt    97: int    fsflg;  /* show files on same filesystem as file(s) argument */
                     98: int    uflg;   /* show files open by a particular (effective) user */
1.38      deraadt    99: int    checkfile; /* true if restricting to particular files or filesystems */
1.1       deraadt   100: int    nflg;   /* (numerical) display f.s. and rdev as dev_t */
1.28      hugh      101: int    oflg;   /* display file offset */
1.56      mickey    102: int    sflg;   /* display file xfer/bytes counters */
1.1       deraadt   103: int    vflg;   /* display errors in locating kernel data objects etc... */
1.85      mestre    104: int    cflg;   /* fuser only */
1.68      millert   105:
1.85      mestre    106: int    fuser;  /* 1 if we are fuser, 0 if we are fstat */
                    107: int    signo;  /* signal to send (fuser only) */
1.1       deraadt   108:
1.98      martijn   109: int    nfilter = 0;    /* How many uid/pid filters are in place */
                    110: struct fstat_filter *filter = NULL; /* An array of uid/pid filters */
                    111:
1.1       deraadt   112: kvm_t *kd;
1.62      deraadt   113: uid_t uid;
1.1       deraadt   114:
1.76      guenther  115: void fstat_dofile(struct kinfo_file *);
1.68      millert   116: void fstat_header(void);
1.35      millert   117: void getinetproto(int);
1.85      mestre    118: __dead void usage(void);
1.35      millert   119: int getfname(char *);
1.76      guenther  120: void kqueuetrans(struct kinfo_file *);
                    121: void pipetrans(struct kinfo_file *);
                    122: struct kinfo_file *splice_find(char, u_int64_t);
                    123: void splice_insert(char, u_int64_t, struct kinfo_file *);
                    124: void find_splices(struct kinfo_file *, int);
                    125: void print_inet_details(struct kinfo_file *);
                    126: void print_inet6_details(struct kinfo_file *);
                    127: void print_sock_details(struct kinfo_file *);
                    128: void socktrans(struct kinfo_file *);
                    129: void vtrans(struct kinfo_file *);
1.47      deraadt   130: const char *inet6_addrstr(struct in6_addr *);
1.68      millert   131: int signame_to_signum(char *);
1.74      deraadt   132: void hide(void *p);
                    133:
                    134: int hideroot;
                    135:
                    136: void
                    137: hide(void *p)
                    138: {
                    139:        printf("%p", hideroot ? NULL : p);
                    140: }
1.1       deraadt   141:
1.11      millert   142: int
1.40      deraadt   143: main(int argc, char *argv[])
1.1       deraadt   144: {
1.76      guenther  145:        struct kinfo_file *kf, *kflast;
1.98      martijn   146:        int ch;
1.68      millert   147:        char *memf, *nlistf, *optstr;
1.2       niklas    148:        char buf[_POSIX2_LINE_MAX];
1.58      tedu      149:        const char *errstr;
1.65      millert   150:        int cnt, flags;
1.1       deraadt   151:
1.74      deraadt   152:        hideroot = getuid();
                    153:
1.1       deraadt   154:        nlistf = memf = NULL;
1.28      hugh      155:        oflg = 0;
1.68      millert   156:
                    157:        /* are we fstat(1) or fuser(1)? */
                    158:        if (strcmp(__progname, "fuser") == 0) {
                    159:                fuser = 1;
                    160:                optstr = "cfks:uM:N:";
                    161:        } else {
                    162:                fuser = 0;
                    163:                optstr = "fnop:su:vN:M:";
                    164:        }
1.95      millert   165:
1.68      millert   166:        /*
                    167:         * fuser and fstat share three flags: -f, -s and -u.  In both cases
                    168:         * -f is a boolean, but for -u fstat wants an argument while fuser
                    169:         * does not and for -s fuser wants an argument whereas fstat does not.
                    170:         */
                    171:        while ((ch = getopt(argc, argv, optstr)) != -1)
1.60      sobrado   172:                switch ((char)ch) {
1.68      millert   173:                case 'c':
                    174:                        if (fsflg)
                    175:                                usage();
                    176:                        cflg = 1;
                    177:                        break;
1.1       deraadt   178:                case 'f':
1.68      millert   179:                        if (cflg)
                    180:                                usage();
1.1       deraadt   181:                        fsflg = 1;
                    182:                        break;
1.68      millert   183:                case 'k':
                    184:                        sflg = 1;
                    185:                        signo = SIGKILL;
                    186:                        break;
1.1       deraadt   187:                case 'M':
                    188:                        memf = optarg;
                    189:                        break;
                    190:                case 'N':
                    191:                        nlistf = optarg;
                    192:                        break;
                    193:                case 'n':
                    194:                        nflg = 1;
                    195:                        break;
1.28      hugh      196:                case 'o':
                    197:                        oflg = 1;
                    198:                        break;
1.1       deraadt   199:                case 'p':
1.98      martijn   200:                        if ((filter = recallocarray(filter, nfilter, nfilter + 1,
                    201:                            sizeof(*filter))) == NULL)
                    202:                                err(1, NULL);
                    203:                        filter[nfilter].arg = strtonum(optarg, 0, INT_MAX,
                    204:                            &errstr);
1.58      tedu      205:                        if (errstr != NULL) {
1.74      deraadt   206:                                warnx("-p requires a process id, %s: %s",
1.58      tedu      207:                                        errstr, optarg);
1.1       deraadt   208:                                usage();
                    209:                        }
1.98      martijn   210:                        filter[nfilter].what = KERN_FILE_BYPID;
                    211:                        nfilter++;
1.1       deraadt   212:                        break;
1.56      mickey    213:                case 's':
                    214:                        sflg = 1;
1.68      millert   215:                        if (fuser) {
                    216:                                signo = signame_to_signum(optarg);
                    217:                                if (signo == -1) {
                    218:                                        warnx("invalid signal %s", optarg);
                    219:                                        usage();
                    220:                                }
                    221:                        }
1.56      mickey    222:                        break;
1.1       deraadt   223:                case 'u':
1.98      martijn   224:                        uflg = 1;
1.68      millert   225:                        if (!fuser) {
1.95      millert   226:                                uid_t uid;
                    227:
                    228:                                if (uid_from_user(optarg, &uid) == -1) {
                    229:                                        uid = strtonum(optarg, 0, UID_MAX,
1.69      nicm      230:                                            &errstr);
                    231:                                        if (errstr != NULL) {
                    232:                                                errx(1, "%s: unknown uid",
                    233:                                                    optarg);
                    234:                                        }
1.95      millert   235:                                }
1.98      martijn   236:                                if ((filter = recallocarray(filter, nfilter,
                    237:                                    nfilter + 1, sizeof(*filter))) == NULL)
                    238:                                        err(1, NULL);
                    239:                                filter[nfilter].arg = uid;
                    240:                                filter[nfilter].what = KERN_FILE_BYUID;
                    241:                                nfilter++;
1.68      millert   242:                        }
1.1       deraadt   243:                        break;
                    244:                case 'v':
                    245:                        vflg = 1;
                    246:                        break;
                    247:                default:
                    248:                        usage();
                    249:                }
                    250:
1.41      deraadt   251:        /*
1.62      deraadt   252:         * get the uid, for oflg and sflg
                    253:         */
                    254:        uid = getuid();
                    255:
                    256:        /*
1.65      millert   257:         * Use sysctl unless inspecting an alternate kernel.
1.41      deraadt   258:         */
1.65      millert   259:        if (nlistf == NULL || memf == NULL)
                    260:                flags = KVM_NO_FILES;
                    261:        else
                    262:                flags = O_RDONLY;
1.41      deraadt   263:
1.65      millert   264:        if ((kd = kvm_openfiles(nlistf, memf, NULL, flags, buf)) == NULL)
1.41      deraadt   265:                errx(1, "%s", buf);
                    266:
1.1       deraadt   267:        if (*(argv += optind)) {
                    268:                for (; *argv; ++argv) {
                    269:                        if (getfname(*argv))
                    270:                                checkfile = 1;
                    271:                }
1.68      millert   272:                /* file(s) specified, but none accessible */
                    273:                if (!checkfile)
1.1       deraadt   274:                        exit(1);
1.68      millert   275:        } else if (fuser)
                    276:                usage();
1.1       deraadt   277:
1.68      millert   278:        if (!fuser && fsflg && !checkfile) {
                    279:                /* fstat -f with no files means use wd */
1.1       deraadt   280:                if (getfname(".") == 0)
                    281:                        exit(1);
                    282:                checkfile = 1;
                    283:        }
1.16      deraadt   284:
1.98      martijn   285:        if (nfilter == 1) {
                    286:                if ((kf = kvm_getfiles(kd, filter[0].what, filter[0].arg,
                    287:                    sizeof(*kf), &cnt)) == NULL)
                    288:                        errx(1, "%s", kvm_geterr(kd));
                    289:        } else {
                    290:                if ((kf = kvm_getfiles(kd, KERN_FILE_BYPID, -1, sizeof(*kf),
                    291:                    &cnt)) == NULL)
                    292:                        errx(1, "%s", kvm_geterr(kd));
                    293:        }
1.81      deraadt   294:
1.82      deraadt   295:        if (fuser) {
1.86      semarie   296:                /*
                    297:                 * fuser
                    298:                 *  uflg: need "getpw"
                    299:                 *  sflg: need "proc" (might call kill(2))
                    300:                 */
                    301:                if (uflg && sflg) {
                    302:                        if (pledge("stdio rpath getpw proc", NULL) == -1)
                    303:                                err(1, "pledge");
                    304:                } else if (uflg) {
                    305:                        if (pledge("stdio rpath getpw", NULL) == -1)
                    306:                                err(1, "pledge");
                    307:                } else if (sflg) {
1.82      deraadt   308:                        if (pledge("stdio rpath proc", NULL) == -1)
                    309:                                err(1, "pledge");
                    310:                } else {
                    311:                        if (pledge("stdio rpath", NULL) == -1)
                    312:                                err(1, "pledge");
                    313:                }
                    314:        } else {
1.86      semarie   315:                /* fstat */
1.84      deraadt   316:                if (pledge("stdio rpath getpw", NULL) == -1)
1.82      deraadt   317:                        err(1, "pledge");
                    318:        }
1.68      millert   319:
1.72      guenther  320:        find_splices(kf, cnt);
1.68      millert   321:        if (!fuser)
                    322:                fstat_header();
                    323:        for (kflast = &kf[cnt]; kf < kflast; ++kf) {
                    324:                if (fuser)
                    325:                        fuser_check(kf);
                    326:                else
                    327:                        fstat_dofile(kf);
                    328:        }
                    329:        if (fuser)
                    330:                fuser_run();
                    331:
                    332:        exit(0);
                    333: }
                    334:
                    335: void
                    336: fstat_header(void)
                    337: {
1.1       deraadt   338:        if (nflg)
                    339:                printf("%s",
1.91      deraadt   340: "USER     CMD          PID   FD  DEV      INUM        MODE   R/W    SZ|DV");
1.1       deraadt   341:        else
                    342:                printf("%s",
1.91      deraadt   343: "USER     CMD          PID   FD MOUNT        INUM  MODE         R/W    SZ|DV");
1.28      hugh      344:        if (oflg)
                    345:                printf("%s", ":OFFSET  ");
1.1       deraadt   346:        if (checkfile && fsflg == 0)
1.56      mickey    347:                printf(" NAME");
                    348:        if (sflg)
                    349:                printf("    XFERS   KBYTES");
                    350:        putchar('\n');
1.1       deraadt   351: }
                    352:
1.94      millert   353: const char *Uname, *Comm;
1.62      deraadt   354: uid_t  *procuid;
1.14      deraadt   355: pid_t  Pid;
1.1       deraadt   356:
1.34      deraadt   357: #define PREFIX(i) do { \
1.39      mpech     358:        printf("%-8.8s %-10s %5ld", Uname, Comm, (long)Pid); \
1.60      sobrado   359:        switch (i) { \
1.65      millert   360:        case KERN_FILE_TEXT: \
1.1       deraadt   361:                printf(" text"); \
                    362:                break; \
1.65      millert   363:        case KERN_FILE_CDIR: \
1.1       deraadt   364:                printf("   wd"); \
                    365:                break; \
1.65      millert   366:        case KERN_FILE_RDIR: \
1.1       deraadt   367:                printf(" root"); \
                    368:                break; \
1.65      millert   369:        case KERN_FILE_TRACE: \
1.1       deraadt   370:                printf("   tr"); \
                    371:                break; \
                    372:        default: \
                    373:                printf(" %4d", i); \
                    374:                break; \
1.34      deraadt   375:        } \
                    376: } while (0)
1.1       deraadt   377:
                    378: /*
                    379:  * print open files attributed to this process
                    380:  */
                    381: void
1.76      guenther  382: fstat_dofile(struct kinfo_file *kf)
1.1       deraadt   383: {
1.98      martijn   384:        int i;
1.1       deraadt   385:
1.65      millert   386:        Uname = user_from_uid(kf->p_uid, 0);
                    387:        procuid = &kf->p_uid;
                    388:        Pid = kf->p_pid;
                    389:        Comm = kf->p_comm;
1.98      martijn   390:
                    391:        for (i = 0; i < nfilter; i++) {
                    392:                if (filter[i].what == KERN_FILE_BYPID) {
                    393:                        if (filter[i].arg == Pid)
                    394:                                break;
                    395:                } else if (filter[i].arg == *procuid) {
                    396:                        break;
                    397:                }
                    398:        }
                    399:        if (i == nfilter && nfilter != 0)
                    400:                return;
1.56      mickey    401:
1.65      millert   402:        switch (kf->f_type) {
                    403:        case DTYPE_VNODE:
                    404:                vtrans(kf);
                    405:                break;
                    406:        case DTYPE_SOCKET:
1.101     millert   407:                socktrans(kf);
1.65      millert   408:                break;
                    409:        case DTYPE_PIPE:
1.67      miod      410:                if (checkfile == 0)
                    411:                        pipetrans(kf);
1.65      millert   412:                break;
                    413:        case DTYPE_KQUEUE:
1.67      miod      414:                if (checkfile == 0)
                    415:                        kqueuetrans(kf);
1.65      millert   416:                break;
                    417:        default:
                    418:                if (vflg) {
                    419:                        warnx("unknown file type %d for file %d of pid %ld",
                    420:                            kf->f_type, kf->fd_fd, (long)Pid);
1.1       deraadt   421:                }
1.65      millert   422:                break;
1.1       deraadt   423:        }
                    424: }
                    425:
                    426: void
1.76      guenther  427: vtrans(struct kinfo_file *kf)
1.1       deraadt   428: {
1.65      millert   429:        const char *badtype = NULL;
1.90      deraadt   430:        char rwep[5], mode[12];
1.65      millert   431:        char *filename = NULL;
                    432:
                    433:        if (kf->v_type == VNON)
1.1       deraadt   434:                badtype = "none";
1.65      millert   435:        else if (kf->v_type == VBAD)
1.1       deraadt   436:                badtype = "bad";
1.65      millert   437:        else if (kf->v_tag == VT_NON && !(kf->v_flag & VCLONE))
                    438:                badtype = "none";       /* not a clone */
                    439:
1.1       deraadt   440:        if (checkfile) {
                    441:                int fsmatch = 0;
1.68      millert   442:                struct filearg *fa;
1.1       deraadt   443:
                    444:                if (badtype)
                    445:                        return;
1.68      millert   446:                SLIST_FOREACH(fa, &fileargs, next) {
                    447:                        if (fa->dev == kf->va_fsid) {
1.1       deraadt   448:                                fsmatch = 1;
1.68      millert   449:                                if (fa->ino == kf->va_fileid) {
                    450:                                        filename = fa->name;
1.1       deraadt   451:                                        break;
                    452:                                }
                    453:                        }
1.65      millert   454:                }
1.1       deraadt   455:                if (fsmatch == 0 || (filename == NULL && fsflg == 0))
                    456:                        return;
                    457:        }
1.65      millert   458:        PREFIX(kf->fd_fd);
1.1       deraadt   459:        if (badtype) {
1.53      mickey    460:                (void)printf(" -           -  %10s    -\n", badtype);
1.1       deraadt   461:                return;
                    462:        }
1.61      thib      463:
1.1       deraadt   464:        if (nflg)
1.99      deraadt   465:                (void)printf(" %2lu,%-2lu", (long)major(kf->va_fsid),
1.65      millert   466:                    (long)minor(kf->va_fsid));
                    467:        else if (!(kf->v_flag & VCLONE))
                    468:                (void)printf(" %-8s", kf->f_mntonname);
1.1       deraadt   469:        else
1.73      mikeb     470:                (void)printf(" clone   ");
1.1       deraadt   471:        if (nflg)
1.65      millert   472:                (void)snprintf(mode, sizeof(mode), "%o", kf->va_mode);
1.1       deraadt   473:        else
1.65      millert   474:                strmode(kf->va_mode, mode);
1.89      guenther  475:        printf(" %8llu%s %11s", kf->va_fileid,
                    476:            kf->va_nlink == 0 ? "*" : " ",
                    477:            mode);
1.90      deraadt   478:        rwep[0] = '\0';
1.65      millert   479:        if (kf->f_flag & FREAD)
1.90      deraadt   480:                strlcat(rwep, "r", sizeof rwep);
1.65      millert   481:        if (kf->f_flag & FWRITE)
1.90      deraadt   482:                strlcat(rwep, "w", sizeof rwep);
                    483:        if (kf->fd_ofileflags & UF_EXCLOSE)
                    484:                strlcat(rwep, "e", sizeof rwep);
1.92      bluhm     485:        if (kf->fd_ofileflags & UF_PLEDGED)
                    486:                strlcat(rwep, "p", sizeof rwep);
1.90      deraadt   487:        printf(" %4s", rwep);
1.65      millert   488:        switch (kf->v_type) {
1.1       deraadt   489:        case VBLK:
                    490:        case VCHR: {
                    491:                char *name;
                    492:
1.65      millert   493:                if (nflg || ((name = devname(kf->va_rdev,
                    494:                    kf->v_type == VCHR ?  S_IFCHR : S_IFBLK)) == NULL))
1.99      deraadt   495:                        printf("   %2u,%-3u", major(kf->va_rdev), minor(kf->va_rdev));
1.1       deraadt   496:                else
1.28      hugh      497:                        printf("  %7s", name);
                    498:                if (oflg)
                    499:                        printf("         ");
1.1       deraadt   500:                break;
                    501:        }
                    502:        default:
1.65      millert   503:                printf(" %8llu", kf->va_size);
1.62      deraadt   504:                if (oflg) {
                    505:                        if (uid == 0 || uid == *procuid)
1.65      millert   506:                                printf(":%-8llu", kf->f_offset);
1.74      deraadt   507:                        else
1.62      deraadt   508:                                printf(":%-8s", "*");
                    509:                }
                    510:        }
                    511:        if (sflg) {
                    512:                if (uid == 0 || uid == *procuid) {
1.65      millert   513:                        printf(" %8llu %8llu",
1.74      deraadt   514:                            (kf->f_rxfer + kf->f_rwfer),
                    515:                            (kf->f_rbytes + kf->f_wbytes) / 1024);
1.62      deraadt   516:                } else {
                    517:                        printf(" %8s %8s", "*", "*");
                    518:                }
1.1       deraadt   519:        }
                    520:        if (filename && !fsflg)
1.28      hugh      521:                printf(" %s", filename);
1.1       deraadt   522:        putchar('\n');
                    523: }
                    524:
1.22      art       525: void
1.76      guenther  526: pipetrans(struct kinfo_file *kf)
1.22      art       527: {
                    528:        void *maxaddr;
                    529:
1.65      millert   530:        PREFIX(kf->fd_fd);
1.22      art       531:
                    532:        printf(" ");
                    533:
                    534:        /*
                    535:         * We don't have enough space to fit both peer and own address, so
                    536:         * we select the higher address so both ends of the pipe have the
                    537:         * same visible addr. (it's the higher address because when the other
                    538:         * end closes, it becomes 0)
                    539:         */
1.80      deraadt   540:        maxaddr = (void *)(uintptr_t)MAXIMUM(kf->f_data, kf->pipe_peer);
1.22      art       541:
1.74      deraadt   542:        printf("pipe ");
                    543:        hide(maxaddr);
1.75      bluhm     544:        printf(" state: %s%s%s",
1.65      millert   545:            (kf->pipe_state & PIPE_WANTR) ? "R" : "",
                    546:            (kf->pipe_state & PIPE_WANTW) ? "W" : "",
                    547:            (kf->pipe_state & PIPE_EOF) ? "E" : "");
1.56      mickey    548:        if (sflg)
1.65      millert   549:                printf("\t%8llu %8llu",
                    550:                    (kf->f_rxfer + kf->f_rwfer),
                    551:                    (kf->f_rbytes + kf->f_wbytes) / 1024);
1.56      mickey    552:        printf("\n");
1.37      deraadt   553:        return;
                    554: }
                    555:
                    556: void
1.76      guenther  557: kqueuetrans(struct kinfo_file *kf)
1.37      deraadt   558: {
1.65      millert   559:        PREFIX(kf->fd_fd);
1.37      deraadt   560:
                    561:        printf(" ");
                    562:
1.74      deraadt   563:        printf("kqueue ");
                    564:        hide((void *)(uintptr_t)kf->f_data);
1.103   ! visa      565:        printf(" %d state: %s\n",
1.65      millert   566:            kf->kq_count,
                    567:            (kf->kq_state & KQ_SLEEP) ? "W" : "");
1.22      art       568:        return;
1.1       deraadt   569: }
                    570:
1.26      itojun    571: const char *
1.40      deraadt   572: inet6_addrstr(struct in6_addr *p)
1.26      itojun    573: {
                    574:        struct sockaddr_in6 sin6;
                    575:        static char hbuf[NI_MAXHOST];
1.50      itojun    576:        const int niflags = NI_NUMERICHOST;
1.26      itojun    577:
                    578:        memset(&sin6, 0, sizeof(sin6));
                    579:        sin6.sin6_family = AF_INET6;
                    580:        sin6.sin6_len = sizeof(struct sockaddr_in6);
                    581:        sin6.sin6_addr = *p;
                    582:        if (IN6_IS_ADDR_LINKLOCAL(p) &&
                    583:            *(u_int16_t *)&sin6.sin6_addr.s6_addr[2] != 0) {
                    584:                sin6.sin6_scope_id =
1.38      deraadt   585:                    ntohs(*(u_int16_t *)&sin6.sin6_addr.s6_addr[2]);
1.26      itojun    586:                sin6.sin6_addr.s6_addr[2] = sin6.sin6_addr.s6_addr[3] = 0;
                    587:        }
                    588:
                    589:        if (getnameinfo((struct sockaddr *)&sin6, sin6.sin6_len,
1.38      deraadt   590:            hbuf, sizeof(hbuf), NULL, 0, niflags))
1.26      itojun    591:                return "invalid";
                    592:
                    593:        return hbuf;
                    594: }
                    595:
1.1       deraadt   596: void
1.76      guenther  597: splice_insert(char type, u_int64_t ptr, struct kinfo_file *data)
1.72      guenther  598: {
                    599:        ENTRY entry, *found;
                    600:
1.74      deraadt   601:        if (asprintf(&entry.key, "%c%llx", type, hideroot ? 0 : ptr) == -1)
1.72      guenther  602:                err(1, NULL);
                    603:        entry.data = data;
                    604:        if ((found = hsearch(entry, ENTER)) == NULL)
                    605:                err(1, "hsearch");
                    606:        /* if it's ambiguous, set the data to NULL */
                    607:        if (found->data != data)
                    608:                found->data = NULL;
                    609: }
                    610:
1.76      guenther  611: struct kinfo_file *
1.72      guenther  612: splice_find(char type, u_int64_t ptr)
                    613: {
                    614:        ENTRY entry, *found;
                    615:        char buf[20];
                    616:
1.74      deraadt   617:        snprintf(buf, sizeof(buf), "%c%llx", type, hideroot ? 0 : ptr);
1.72      guenther  618:        entry.key = buf;
                    619:        found = hsearch(entry, FIND);
                    620:        return (found != NULL ? found->data : NULL);
                    621: }
                    622:
                    623: void
1.76      guenther  624: find_splices(struct kinfo_file *kf, int cnt)
1.72      guenther  625: {
                    626:        int i, created;
                    627:
                    628:        created = 0;
                    629:        for (i = 0; i < cnt; i++) {
                    630:                if (kf[i].f_type != DTYPE_SOCKET ||
                    631:                    (kf[i].so_splice == 0 && kf[i].so_splicelen != -1))
                    632:                        continue;
                    633:                if (created++ == 0) {
                    634:                        if (hcreate(1000) == 0)
                    635:                                err(1, "hcreate");
                    636:                }
                    637:                splice_insert('>', kf[i].f_data, &kf[i]);
                    638:                if (kf[i].so_splice != 0)
                    639:                        splice_insert('<', kf[i].so_splice, &kf[i]);
                    640:        }
                    641: }
                    642:
                    643: void
1.76      guenther  644: print_inet_details(struct kinfo_file *kf)
1.72      guenther  645: {
                    646:        struct in_addr laddr, faddr;
                    647:
                    648:        memcpy(&laddr, kf->inp_laddru, sizeof(laddr));
                    649:        memcpy(&faddr, kf->inp_faddru, sizeof(faddr));
                    650:        if (kf->so_protocol == IPPROTO_TCP) {
1.74      deraadt   651:                printf(" ");
                    652:                hide((void *)(uintptr_t)kf->inp_ppcb);
1.72      guenther  653:                printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
                    654:                    inet_ntoa(laddr), ntohs(kf->inp_lport));
                    655:                if (kf->inp_fport) {
                    656:                        if (kf->so_state & SS_CONNECTOUT)
                    657:                                printf(" --> ");
                    658:                        else
                    659:                                printf(" <-- ");
                    660:                        printf("%s:%d",
                    661:                            faddr.s_addr == INADDR_ANY ? "*" :
                    662:                            inet_ntoa(faddr), ntohs(kf->inp_fport));
                    663:                }
                    664:        } else if (kf->so_protocol == IPPROTO_UDP) {
                    665:                printf(" %s:%d", laddr.s_addr == INADDR_ANY ? "*" :
                    666:                    inet_ntoa(laddr), ntohs(kf->inp_lport));
                    667:                if (kf->inp_fport) {
                    668:                        printf(" <-> %s:%d",
                    669:                            faddr.s_addr == INADDR_ANY ? "*" :
                    670:                            inet_ntoa(faddr), ntohs(kf->inp_fport));
                    671:                }
1.74      deraadt   672:        } else if (kf->so_pcb) {
                    673:                printf(" ");
                    674:                hide((void *)(uintptr_t)kf->so_pcb);
                    675:        }
1.72      guenther  676: }
                    677:
                    678: void
1.76      guenther  679: print_inet6_details(struct kinfo_file *kf)
1.72      guenther  680: {
                    681:        char xaddrbuf[NI_MAXHOST + 2];
                    682:        struct in6_addr laddr6, faddr6;
                    683:
                    684:        memcpy(&laddr6, kf->inp_laddru, sizeof(laddr6));
                    685:        memcpy(&faddr6, kf->inp_faddru, sizeof(faddr6));
                    686:        if (kf->so_protocol == IPPROTO_TCP) {
1.74      deraadt   687:                printf(" ");
                    688:                hide((void *)(uintptr_t)kf->inp_ppcb);
1.72      guenther  689:                snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
                    690:                    inet6_addrstr(&laddr6));
                    691:                printf(" %s:%d",
                    692:                    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
                    693:                    xaddrbuf, ntohs(kf->inp_lport));
                    694:                if (kf->inp_fport) {
                    695:                        if (kf->so_state & SS_CONNECTOUT)
                    696:                                printf(" --> ");
                    697:                        else
                    698:                                printf(" <-- ");
                    699:                        snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
                    700:                            inet6_addrstr(&faddr6));
                    701:                        printf("%s:%d",
                    702:                            IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
                    703:                            xaddrbuf, ntohs(kf->inp_fport));
                    704:                }
                    705:        } else if (kf->so_protocol == IPPROTO_UDP) {
                    706:                snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
                    707:                    inet6_addrstr(&laddr6));
                    708:                printf(" %s:%d",
                    709:                    IN6_IS_ADDR_UNSPECIFIED(&laddr6) ? "*" :
                    710:                    xaddrbuf, ntohs(kf->inp_lport));
                    711:                if (kf->inp_fport) {
                    712:                        snprintf(xaddrbuf, sizeof(xaddrbuf), "[%s]",
                    713:                            inet6_addrstr(&faddr6));
                    714:                        printf(" <-> %s:%d",
                    715:                            IN6_IS_ADDR_UNSPECIFIED(&faddr6) ? "*" :
                    716:                            xaddrbuf, ntohs(kf->inp_fport));
                    717:                }
1.74      deraadt   718:        } else if (kf->so_pcb) {
                    719:                printf(" ");
                    720:                hide((void *)(uintptr_t)kf->so_pcb);
                    721:        }
1.72      guenther  722: }
                    723:
                    724: void
1.76      guenther  725: print_sock_details(struct kinfo_file *kf)
1.72      guenther  726: {
                    727:        if (kf->so_family == AF_INET)
                    728:                print_inet_details(kf);
                    729:        else if (kf->so_family == AF_INET6)
                    730:                print_inet6_details(kf);
                    731: }
                    732:
                    733: void
1.76      guenther  734: socktrans(struct kinfo_file *kf)
1.1       deraadt   735: {
                    736:        static char *stypename[] = {
                    737:                "unused",       /* 0 */
1.38      deraadt   738:                "stream",       /* 1 */
1.1       deraadt   739:                "dgram",        /* 2 */
                    740:                "raw",          /* 3 */
                    741:                "rdm",          /* 4 */
                    742:                "seqpak"        /* 5 */
                    743:        };
                    744: #define        STYPEMAX 5
1.66      chl       745:        char *stype, stypebuf[24];
1.1       deraadt   746:
1.101     millert   747:        if (checkfile) {
                    748:                struct filearg *fa;
                    749:
                    750:                if (kf->so_type != AF_UNIX)
                    751:                        return;
                    752:                SLIST_FOREACH(fa, &fileargs, next) {
                    753:                        if (fa->dev != 0)
                    754:                                continue;
                    755:                        if (strcmp(kf->unp_path, fa->name) == 0)
                    756:                                break;
                    757:                }
                    758:                if (fa == NULL)
                    759:                        return;
                    760:        }
                    761:
1.65      millert   762:        PREFIX(kf->fd_fd);
1.1       deraadt   763:
1.65      millert   764:        if (kf->so_type > STYPEMAX) {
                    765:                snprintf(stypebuf, sizeof(stypebuf), "?%d", kf->so_type);
                    766:                stype = stypebuf;
                    767:        } else {
                    768:                stype = stypename[kf->so_type];
1.1       deraadt   769:        }
                    770:
1.34      deraadt   771:        /*
1.1       deraadt   772:         * protocol specific formatting
                    773:         *
                    774:         * Try to find interesting things to print.  For tcp, the interesting
                    775:         * thing is the address of the tcpcb, for udp and others, just the
                    776:         * inpcb (socket pcb).  For unix domain, its the address of the socket
                    777:         * pcb and the address of the connected pcb (if connected).  Otherwise
                    778:         * just print the protocol number and address of the socket itself.
                    779:         * The idea is not to duplicate netstat, but to make available enough
                    780:         * information for further analysis.
                    781:         */
1.65      millert   782:        switch (kf->so_family) {
1.1       deraadt   783:        case AF_INET:
1.65      millert   784:                printf("* internet %s", stype);
                    785:                getinetproto(kf->so_protocol);
1.72      guenther  786:                print_inet_details(kf);
1.93      sthen     787:                if (kf->inp_rtableid)
                    788:                        printf(" rtable %u", kf->inp_rtableid);
1.1       deraadt   789:                break;
1.26      itojun    790:        case AF_INET6:
1.65      millert   791:                printf("* internet6 %s", stype);
                    792:                getinetproto(kf->so_protocol);
1.72      guenther  793:                print_inet6_details(kf);
1.93      sthen     794:                if (kf->inp_rtableid)
                    795:                        printf(" rtable %u", kf->inp_rtableid);
1.26      itojun    796:                break;
1.1       deraadt   797:        case AF_UNIX:
                    798:                /* print address of pcb and connected pcb */
1.65      millert   799:                printf("* unix %s", stype);
                    800:                if (kf->so_pcb) {
1.74      deraadt   801:                        printf(" ");
                    802:                        hide((void *)(uintptr_t)kf->so_pcb);
1.65      millert   803:                        if (kf->unp_conn) {
1.1       deraadt   804:                                char shoconn[4], *cp;
                    805:
                    806:                                cp = shoconn;
1.65      millert   807:                                if (!(kf->so_state & SS_CANTRCVMORE))
1.1       deraadt   808:                                        *cp++ = '<';
                    809:                                *cp++ = '-';
1.65      millert   810:                                if (!(kf->so_state & SS_CANTSENDMORE))
1.1       deraadt   811:                                        *cp++ = '>';
                    812:                                *cp = '\0';
1.74      deraadt   813:                                printf(" %s ", shoconn);
                    814:                                hide((void *)(uintptr_t)kf->unp_conn);
1.1       deraadt   815:                        }
                    816:                }
1.100     millert   817:                if (kf->unp_path[0] != '\0')
                    818:                        printf(" %s", kf->unp_path);
1.1       deraadt   819:                break;
1.65      millert   820:        case AF_MPLS:
                    821:                /* print protocol number and socket address */
                    822:                printf("* mpls %s", stype);
1.74      deraadt   823:                printf(" %d ", kf->so_protocol);
                    824:                hide((void *)(uintptr_t)kf->f_data);
1.65      millert   825:                break;
                    826:        case AF_ROUTE:
                    827:                /* print protocol number and socket address */
                    828:                printf("* route %s", stype);
1.96      dlg       829:                printf(" %d ", kf->so_protocol);
                    830:                hide((void *)(uintptr_t)kf->f_data);
                    831:                break;
                    832:        case AF_KEY:
                    833:                printf("* pfkey %s", stype);
1.74      deraadt   834:                printf(" %d ", kf->so_protocol);
                    835:                hide((void *)(uintptr_t)kf->f_data);
1.65      millert   836:                break;
1.1       deraadt   837:        default:
                    838:                /* print protocol number and socket address */
1.65      millert   839:                printf("* %d %s", kf->so_family, stype);
1.74      deraadt   840:                printf(" %d ", kf->so_protocol);
                    841:                hide((void *)(uintptr_t)kf->f_data);
1.72      guenther  842:        }
                    843:        if (kf->so_splice != 0 || kf->so_splicelen == -1) {
1.76      guenther  844:                struct kinfo_file *from, *to;
1.72      guenther  845:
                    846:                from = splice_find('<', kf->f_data);
                    847:                to = NULL;
                    848:                if (kf->so_splice != 0)
                    849:                        to = splice_find('>', kf->so_splice);
                    850:
                    851:                if (to != NULL && from == to) {
                    852:                        printf(" <==>");
                    853:                        print_sock_details(to);
                    854:                } else if (kf->so_splice != 0) {
                    855:                        printf(" ==>");
                    856:                        if (to != NULL)
                    857:                                print_sock_details(to);
                    858:                } else if (kf->so_splicelen == -1) {
                    859:                        printf(" <==");
                    860:                        if (from != NULL)
                    861:                                print_sock_details(from);
                    862:                }
1.1       deraadt   863:        }
1.56      mickey    864:        if (sflg)
1.65      millert   865:                printf("\t%8llu %8llu",
                    866:                    (kf->f_rxfer + kf->f_rwfer),
                    867:                    (kf->f_rbytes + kf->f_wbytes) / 1024);
1.1       deraadt   868:        printf("\n");
                    869: }
                    870:
                    871: /*
                    872:  * getinetproto --
                    873:  *     print name of protocol number
                    874:  */
                    875: void
1.85      mestre    876: getinetproto(int number)
1.1       deraadt   877: {
1.24      deraadt   878:        static int isopen;
1.32      mpech     879:        struct protoent *pe;
1.1       deraadt   880:
1.24      deraadt   881:        if (!isopen)
                    882:                setprotoent(++isopen);
                    883:        if ((pe = getprotobynumber(number)) != NULL)
                    884:                printf(" %s", pe->p_name);
                    885:        else
1.1       deraadt   886:                printf(" %d", number);
                    887: }
                    888:
1.11      millert   889: int
1.40      deraadt   890: getfname(char *filename)
1.1       deraadt   891: {
1.68      millert   892:        static struct statfs *mntbuf;
                    893:        static int nmounts;
                    894:        int i;
                    895:        struct stat sb;
                    896:        struct filearg *cur;
1.1       deraadt   897:
1.68      millert   898:        if (stat(filename, &sb)) {
1.27      millert   899:                warn("%s", filename);
1.68      millert   900:                return (0);
1.1       deraadt   901:        }
                    902:
1.68      millert   903:        /*
                    904:         * POSIX specifies "For block special devices, all processes using any
                    905:         * file on that device are listed".  However the -f flag description
                    906:         * states "The report shall be only for the named files", so we only
                    907:         * look up a block device if the -f flag has not be specified.
                    908:         */
                    909:        if (fuser && !fsflg && S_ISBLK(sb.st_mode)) {
                    910:                if (mntbuf == NULL) {
                    911:                        nmounts = getmntinfo(&mntbuf, MNT_NOWAIT);
                    912:                        if (nmounts == -1)
                    913:                                err(1, "getmntinfo");
                    914:                }
                    915:                for (i = 0; i < nmounts; i++) {
                    916:                        if (!strcmp(mntbuf[i].f_mntfromname, filename)) {
                    917:                                if (stat(mntbuf[i].f_mntonname, &sb) == -1) {
                    918:                                        warn("%s", filename);
                    919:                                        return (0);
                    920:                                }
                    921:                                cflg = 1;
                    922:                                break;
                    923:                        }
                    924:                }
                    925:        }
1.101     millert   926:        if (!fuser && S_ISSOCK(sb.st_mode)) {
                    927:                char *newname = realpath(filename, NULL);
                    928:                if (newname != NULL)
                    929:                        filename = newname;
                    930:        }
1.68      millert   931:
1.101     millert   932:        if ((cur = calloc(1, sizeof(*cur))) == NULL)
1.68      millert   933:                err(1, NULL);
                    934:
1.101     millert   935:        if (!S_ISSOCK(sb.st_mode)) {
                    936:                cur->ino = sb.st_ino;
                    937:                cur->dev = sb.st_dev & 0xffff;
                    938:        }
1.1       deraadt   939:        cur->name = filename;
1.68      millert   940:        TAILQ_INIT(&cur->fusers);
                    941:        SLIST_INSERT_HEAD(&fileargs, cur, next);
                    942:        return (1);
                    943: }
                    944:
                    945: int
                    946: signame_to_signum(char *sig)
                    947: {
                    948:        int n;
                    949:        const char *errstr = NULL;
                    950:
                    951:        if (isdigit((unsigned char)*sig)) {
                    952:                n = strtonum(sig, 0, NSIG - 1, &errstr);
                    953:                return (errstr ? -1 : n);
                    954:        }
                    955:        if (!strncasecmp(sig, "sig", 3))
                    956:                sig += 3;
                    957:        for (n = 1; n < NSIG; n++) {
                    958:                if (!strcasecmp(sys_signame[n], sig))
                    959:                        return (n);
                    960:        }
                    961:        return (-1);
1.1       deraadt   962: }
                    963:
                    964: void
1.40      deraadt   965: usage(void)
1.1       deraadt   966: {
1.68      millert   967:        if (fuser) {
                    968:                fprintf(stderr, "usage: fuser [-cfku] [-M core] "
                    969:                    "[-N system] [-s signal] file ...\n");
                    970:        } else {
                    971:                fprintf(stderr, "usage: fstat [-fnosv] [-M core] [-N system] "
                    972:                    "[-p pid] [-u user] [file ...]\n");
                    973:        }
1.1       deraadt   974:        exit(1);
                    975: }