So I hacked this together because I got annoyed by the fact that for 
every pid I want to investigate I had to rerun fstat.

Diff below alleviates the searched pid from kvm_getfiles(3) to fstat(1).
I left atomicity (is there any in kvm_getfiles?) in place, by retrieving
everything in one go and filtering it before printing instead of doing
multiple calls to kvm_getfiles.

Would something like this be interesting for inclusion? If not, I reckon
we should add a check that -p and -u are mutually exclusive, because now
the last argument wins, which is not what might be expected.

martijn@

Index: fstat.c
===================================================================
RCS file: /cvs/src/usr.bin/fstat/fstat.c,v
retrieving revision 1.95
diff -u -p -r1.95 fstat.c
--- fstat.c     16 Sep 2018 02:44:06 -0000      1.95
+++ fstat.c     19 Nov 2018 17:28:04 -0000
@@ -87,10 +87,14 @@
 
 #define MAXIMUM(a, b)  (((a) > (b)) ? (a) : (b))
 
+struct fstat_filter {
+       int what;
+       int arg;
+};
+
 struct fileargs fileargs = SLIST_HEAD_INITIALIZER(fileargs);
 
 int    fsflg;  /* show files on same filesystem as file(s) argument */
-int    pflg;   /* show files open by a particular pid */
 int    uflg;   /* show files open by a particular (effective) user */
 int    checkfile; /* true if restricting to particular files or filesystems */
 int    nflg;   /* (numerical) display f.s. and rdev as dev_t */
@@ -102,6 +106,9 @@ int cflg;   /* fuser only */
 int    fuser;  /* 1 if we are fuser, 0 if we are fstat */
 int    signo;  /* signal to send (fuser only) */
 
+int    nfilter = 0;    /* How many uid/pid filters are in place */
+struct fstat_filter *filter = NULL; /* An array of uid/pid filters */
+
 kvm_t *kd;
 uid_t uid;
 
@@ -137,7 +144,7 @@ main(int argc, char *argv[])
 {
        struct passwd *passwd;
        struct kinfo_file *kf, *kflast;
-       int arg, ch, what;
+       int ch;
        char *memf, *nlistf, *optstr;
        char buf[_POSIX2_LINE_MAX];
        const char *errstr;
@@ -145,8 +152,6 @@ main(int argc, char *argv[])
 
        hideroot = getuid();
 
-       arg = -1;
-       what = KERN_FILE_BYPID;
        nlistf = memf = NULL;
        oflg = 0;
 
@@ -196,15 +201,18 @@ main(int argc, char *argv[])
                        oflg = 1;
                        break;
                case 'p':
-                       if (pflg++)
-                               usage();
-                       arg = strtonum(optarg, 0, INT_MAX, &errstr);
+                       if ((filter = recallocarray(filter, nfilter, nfilter + 
1,
+                           sizeof(*filter))) == NULL)
+                               err(1, NULL);
+                       filter[nfilter].arg = strtonum(optarg, 0, INT_MAX,
+                           &errstr);
                        if (errstr != NULL) {
                                warnx("-p requires a process id, %s: %s",
                                        errstr, optarg);
                                usage();
                        }
-                       what = KERN_FILE_BYPID;
+                       filter[nfilter].what = KERN_FILE_BYPID;
+                       nfilter++;
                        break;
                case 's':
                        sflg = 1;
@@ -217,8 +225,7 @@ main(int argc, char *argv[])
                        }
                        break;
                case 'u':
-                       if (uflg++)
-                               usage();
+                       uflg = 1;
                        if (!fuser) {
                                uid_t uid;
 
@@ -230,8 +237,12 @@ main(int argc, char *argv[])
                                                    optarg);
                                        }
                                }
-                               arg = uid;
-                               what = KERN_FILE_BYUID;
+                               if ((filter = recallocarray(filter, nfilter,
+                                   nfilter + 1, sizeof(*filter))) == NULL)
+                                       err(1, NULL);
+                               filter[nfilter].arg = uid;
+                               filter[nfilter].what = KERN_FILE_BYUID;
+                               nfilter++;
                        }
                        break;
                case 'v':
@@ -275,8 +286,15 @@ main(int argc, char *argv[])
                checkfile = 1;
        }
 
-       if ((kf = kvm_getfiles(kd, what, arg, sizeof(*kf), &cnt)) == NULL)
-               errx(1, "%s", kvm_geterr(kd));
+       if (nfilter == 1) {
+               if ((kf = kvm_getfiles(kd, filter[0].what, filter[0].arg,
+                   sizeof(*kf), &cnt)) == NULL)
+                       errx(1, "%s", kvm_geterr(kd));
+       } else {
+               if ((kf = kvm_getfiles(kd, KERN_FILE_BYPID, -1, sizeof(*kf),
+                   &cnt)) == NULL)
+                       errx(1, "%s", kvm_geterr(kd));
+       }
 
        if (fuser) {
                /*
@@ -367,11 +385,23 @@ pid_t     Pid;
 void
 fstat_dofile(struct kinfo_file *kf)
 {
+       int i;
 
        Uname = user_from_uid(kf->p_uid, 0);
        procuid = &kf->p_uid;
        Pid = kf->p_pid;
        Comm = kf->p_comm;
+
+       for (i = 0; i < nfilter; i++) {
+               if (filter[i].what == KERN_FILE_BYPID) {
+                       if (filter[i].arg == Pid)
+                               break;
+               } else if (filter[i].arg == *procuid) {
+                       break;
+               }
+       }
+       if (i == nfilter && nfilter != 0)
+               return;
 
        switch (kf->f_type) {
        case DTYPE_VNODE:

Reply via email to