Add forest (-f) mode
authorjob <job@openbsd.org>
Thu, 1 Sep 2022 21:15:54 +0000 (21:15 +0000)
committerjob <job@openbsd.org>
Thu, 1 Sep 2022 21:15:54 +0000 (21:15 +0000)
In -f mode group & display parent/child process relationships using ASCII art.

Borrows heavily from Brian Somers' work on FreeBSD ps(1).

With input from deraadt@ and tb@

OK benno@ claudio@

bin/ps/extern.h
bin/ps/print.c
bin/ps/ps.1
bin/ps/ps.c
bin/ps/ps.h

index 385229f..6464902 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: extern.h,v 1.23 2022/01/05 04:10:36 guenther Exp $    */
+/*     $OpenBSD: extern.h,v 1.24 2022/09/01 21:15:54 job Exp $ */
 /*     $NetBSD: extern.h,v 1.10 1995/05/21 13:38:27 mycroft Exp $      */
 
 /*-
@@ -44,44 +44,44 @@ extern VAR var[];
 extern VARENT *vhead;
 
 __BEGIN_DECLS
-void    command(const struct kinfo_proc *, VARENT *);
-void    cputime(const struct kinfo_proc *, VARENT *);
+void    command(const struct pinfo *, VARENT *);
+void    cputime(const struct pinfo *, VARENT *);
 int     donlist(void);
-void    elapsed(const struct kinfo_proc *, VARENT *);
+void    elapsed(const struct pinfo *, VARENT *);
 double  getpcpu(const struct kinfo_proc *);
 double  getpmem(const struct kinfo_proc *);
-void    gname(const struct kinfo_proc *, VARENT *);
-void    supgid(const struct kinfo_proc *, VARENT *);
-void    supgrp(const struct kinfo_proc *, VARENT *);
-void    logname(const struct kinfo_proc *, VARENT *);
-void    longtname(const struct kinfo_proc *, VARENT *);
-void    lstarted(const struct kinfo_proc *, VARENT *);
-void    maxrss(const struct kinfo_proc *, VARENT *);
+void    gname(const struct pinfo *, VARENT *);
+void    supgid(const struct pinfo *, VARENT *);
+void    supgrp(const struct pinfo *, VARENT *);
+void    logname(const struct pinfo *, VARENT *);
+void    longtname(const struct pinfo *, VARENT *);
+void    lstarted(const struct pinfo *, VARENT *);
+void    maxrss(const struct pinfo *, VARENT *);
 void    nlisterr(struct nlist *);
-void    p_rssize(const struct kinfo_proc *, VARENT *);
-void    pagein(const struct kinfo_proc *, VARENT *);
+void    p_rssize(const struct pinfo *, VARENT *);
+void    pagein(const struct pinfo *, VARENT *);
 void    parsefmt(char *);
-void    pcpu(const struct kinfo_proc *, VARENT *);
-void    pmem(const struct kinfo_proc *, VARENT *);
-void    pri(const struct kinfo_proc *, VARENT *);
+void    pcpu(const struct pinfo *, VARENT *);
+void    pmem(const struct pinfo *, VARENT *);
+void    pri(const struct pinfo *, VARENT *);
 void    printheader(void);
-void    pvar(const struct kinfo_proc *kp, VARENT *);
-void    pnice(const struct kinfo_proc *kp, VARENT *);
-void    rgname(const struct kinfo_proc *, VARENT *);
-void    rssize(const struct kinfo_proc *, VARENT *);
-void    runame(const struct kinfo_proc *, VARENT *);
+void    pvar(const struct pinfo *, VARENT *);
+void    pnice(const struct pinfo *, VARENT *);
+void    rgname(const struct pinfo *, VARENT *);
+void    rssize(const struct pinfo *, VARENT *);
+void    runame(const struct pinfo *, VARENT *);
 void    showkey(void);
-void    started(const struct kinfo_proc *, VARENT *);
-void    printstate(const struct kinfo_proc *, VARENT *);
-void    printpledge(const struct kinfo_proc *, VARENT *);
-void    tdev(const struct kinfo_proc *, VARENT *);
-void    tname(const struct kinfo_proc *, VARENT *);
-void    tsize(const struct kinfo_proc *, VARENT *);
-void    dsize(const struct kinfo_proc *, VARENT *);
-void    ssize(const struct kinfo_proc *, VARENT *);
-void    ucomm(const struct kinfo_proc *, VARENT *);
-void    curwd(const struct kinfo_proc *, VARENT *);
-void    euname(const struct kinfo_proc *, VARENT *);
-void    vsize(const struct kinfo_proc *, VARENT *);
-void    wchan(const struct kinfo_proc *, VARENT *);
+void    started(const struct pinfo *, VARENT *);
+void    printstate(const struct pinfo *, VARENT *);
+void    printpledge(const struct pinfo *, VARENT *);
+void    tdev(const struct pinfo *, VARENT *);
+void    tname(const struct pinfo *, VARENT *);
+void    tsize(const struct pinfo *, VARENT *);
+void    dsize(const struct pinfo *, VARENT *);
+void    ssize(const struct pinfo *, VARENT *);
+void    ucomm(const struct pinfo *, VARENT *);
+void    curwd(const struct pinfo *, VARENT *);
+void    euname(const struct pinfo *, VARENT *);
+void    vsize(const struct pinfo *, VARENT *);
+void    wchan(const struct pinfo *, VARENT *);
 __END_DECLS
index 4afa30f..de3f477 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: print.c,v 1.82 2022/02/15 23:16:00 rob Exp $  */
+/*     $OpenBSD: print.c,v 1.83 2022/09/01 21:15:54 job Exp $  */
 /*     $NetBSD: print.c,v 1.27 1995/09/29 21:58:12 cgd Exp $   */
 
 /*-
@@ -96,8 +96,9 @@ printheader(void)
 }
 
 void
-command(const struct kinfo_proc *kp, VARENT *ve)
+command(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        int left, wantspace = 0;
        char **p;
@@ -138,6 +139,8 @@ command(const struct kinfo_proc *kp, VARENT *ve)
        }
 
        if (needcomm) {
+               if (pi->prefix)
+                       mbswprint(pi->prefix, left, 0);
                if (!commandonly) {
                        char **argv = NULL;
 
@@ -186,14 +189,16 @@ command(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-ucomm(const struct kinfo_proc *kp, VARENT *ve)
+ucomm(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        mbswprint(kp->p_comm, ve->var->width, ve->next != NULL);
 }
 
 void
-curwd(const struct kinfo_proc *kp, VARENT *ve)
+curwd(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        int name[] = { CTL_KERN, KERN_PROC_CWD, kp->p_pid };
        char path[PATH_MAX];
        size_t pathlen = sizeof path;
@@ -205,8 +210,9 @@ curwd(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-logname(const struct kinfo_proc *kp, VARENT *ve)
+logname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -223,8 +229,9 @@ logname(const struct kinfo_proc *kp, VARENT *ve)
 #define pgtok(a)       (((unsigned long long)(a)*getpagesize())/1024)
 
 void
-printstate(const struct kinfo_proc *kp, VARENT *ve)
+printstate(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        int flag;
        char *cp, state = '\0';
        VAR *v;
@@ -306,8 +313,9 @@ printstate(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-printpledge(const struct kinfo_proc *kp, VARENT *ve)
+printpledge(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        int i;
        VAR *v;
        char buf[1024];
@@ -327,8 +335,9 @@ printpledge(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-pri(const struct kinfo_proc *kp, VARENT *ve)
+pri(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -336,44 +345,55 @@ pri(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-pnice(const struct kinfo_proc *kp, VARENT *ve)
+pnice(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
+
        v = ve->var;
        (void)printf("%*d", v->width, kp->p_nice - NZERO);
 }
 
 void
-euname(const struct kinfo_proc *kp, VARENT *ve)
+euname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
+
        mbswprint(user_from_uid(kp->p_uid, 0), ve->var->width,
            ve->next != NULL);
 }
 
 void
-runame(const struct kinfo_proc *kp, VARENT *ve)
+runame(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
+
        mbswprint(user_from_uid(kp->p_ruid, 0), ve->var->width,
            ve->next != NULL);
 }
 
 void
-gname(const struct kinfo_proc *kp, VARENT *ve)
+gname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
+
        mbswprint(group_from_gid(kp->p_gid, 0), ve->var->width,
            ve->next != NULL);
 }
 
 void
-rgname(const struct kinfo_proc *kp, VARENT *ve)
+rgname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
+
        mbswprint(group_from_gid(kp->p_rgid, 0), ve->var->width,
            ve->next != NULL);
 }
 
 void
-supgid(const struct kinfo_proc *kp, VARENT *ve)
+supgid(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        char buf[1024];
        char *p = buf;
        ssize_t size = sizeof(buf);
@@ -393,8 +413,9 @@ supgid(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-supgrp(const struct kinfo_proc *kp, VARENT *ve)
+supgrp(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        char buf[1024];
        char *p = buf;
        ssize_t size = sizeof(buf);
@@ -414,8 +435,9 @@ supgrp(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-tdev(const struct kinfo_proc *kp, VARENT *ve)
+tdev(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        dev_t dev;
 
@@ -433,8 +455,9 @@ tdev(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-tname(const struct kinfo_proc *kp, VARENT *ve)
+tname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        dev_t dev;
        char *ttname;
@@ -452,8 +475,9 @@ tname(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-longtname(const struct kinfo_proc *kp, VARENT *ve)
+longtname(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        dev_t dev;
        char *ttname;
@@ -467,8 +491,9 @@ longtname(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-started(const struct kinfo_proc *kp, VARENT *ve)
+started(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        static time_t now;
        time_t startt;
@@ -498,8 +523,9 @@ started(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-lstarted(const struct kinfo_proc *kp, VARENT *ve)
+lstarted(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        time_t startt;
        char buf[100];
@@ -515,8 +541,9 @@ lstarted(const struct kinfo_proc *kp, VARENT *ve)
        (void)printf("%-*s", v->width, buf);
 }
 
-void elapsed(const struct kinfo_proc *kp, VARENT *ve)
+void elapsed(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        static time_t now;
        time_t secs;
@@ -560,8 +587,9 @@ void elapsed(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-wchan(const struct kinfo_proc *kp, VARENT *ve)
+wchan(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -572,8 +600,9 @@ wchan(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-vsize(const struct kinfo_proc *kp, VARENT *ve)
+vsize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -582,8 +611,9 @@ vsize(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-rssize(const struct kinfo_proc *kp, VARENT *ve)
+rssize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -593,8 +623,9 @@ rssize(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-p_rssize(const struct kinfo_proc *kp, VARENT *ve)
+p_rssize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -603,8 +634,9 @@ p_rssize(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-cputime(const struct kinfo_proc *kp, VARENT *ve)
+cputime(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
        long secs;
        long psecs;     /* "parts" of a second. first micro, then centi */
@@ -648,12 +680,12 @@ getpcpu(const struct kinfo_proc *kp)
 }
 
 void
-pcpu(const struct kinfo_proc *kp, VARENT *ve)
+pcpu(const struct pinfo *pi, VARENT *ve)
 {
        VAR *v;
 
        v = ve->var;
-       (void)printf("%*.1f", v->width, getpcpu(kp));
+       (void)printf("%*.1f", v->width, getpcpu(pi->ki));
 }
 
 double
@@ -672,17 +704,18 @@ getpmem(const struct kinfo_proc *kp)
 }
 
 void
-pmem(const struct kinfo_proc *kp, VARENT *ve)
+pmem(const struct pinfo *pi, VARENT *ve)
 {
        VAR *v;
 
        v = ve->var;
-       (void)printf("%*.1f", v->width, getpmem(kp));
+       (void)printf("%*.1f", v->width, getpmem(pi->ki));
 }
 
 void
-pagein(const struct kinfo_proc *kp, VARENT *ve)
+pagein(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -691,8 +724,9 @@ pagein(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-maxrss(const struct kinfo_proc *kp, VARENT *ve)
+maxrss(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -700,8 +734,9 @@ maxrss(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-tsize(const struct kinfo_proc *kp, VARENT *ve)
+tsize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -709,8 +744,9 @@ tsize(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-dsize(const struct kinfo_proc *kp, VARENT *ve)
+dsize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -718,8 +754,9 @@ dsize(const struct kinfo_proc *kp, VARENT *ve)
 }
 
 void
-ssize(const struct kinfo_proc *kp, VARENT *ve)
+ssize(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
@@ -778,8 +815,9 @@ printval(char *bp, VAR *v)
 }
 
 void
-pvar(const struct kinfo_proc *kp, VARENT *ve)
+pvar(const struct pinfo *pi, VARENT *ve)
 {
+       const struct kinfo_proc *kp = pi->ki;
        VAR *v;
 
        v = ve->var;
index d70cb4d..33cced3 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: ps.1,v 1.126 2022/07/05 15:06:16 visa Exp $
+.\"    $OpenBSD: ps.1,v 1.127 2022/09/01 21:15:54 job Exp $
 .\"    $NetBSD: ps.1,v 1.16 1996/03/21 01:36:28 jtc Exp $
 .\"
 .\" Copyright (c) 1980, 1990, 1991, 1993, 1994
@@ -30,7 +30,7 @@
 .\"
 .\"     @(#)ps.1       8.3 (Berkeley) 4/18/94
 .\"
-.Dd $Mdocdate: July 5 2022 $
+.Dd $Mdocdate: September 1 2022 $
 .Dt PS 1
 .Os
 .Sh NAME
@@ -39,7 +39,7 @@
 .Sh SYNOPSIS
 .Nm ps
 .Sm off
-.Op Oo Fl Oc Cm AaceHhjkLlmrSTuvwx
+.Op Oo Fl Oc Cm AacefHhjkLlmrSTuvwx
 .Sm on
 .Op Fl M Ar core
 .Op Fl N Ar system
@@ -85,6 +85,15 @@ scripts will show as
 .Dq sh .
 .It Fl e
 Display the environment as well.
+.It Fl f
+Arrange processes into a tree, order and prefix each command with
+indentation text showing sibling and parent/child relationships.
+If either of the
+.Fl m
+and
+.Fl r
+options are also used, they control how sibling processes are sorted relative
+to each other.
 .It Fl H
 Also display information about kernel visible threads.
 .It Fl h
@@ -652,7 +661,7 @@ X/Open System Interfaces option of
 .St -p1003.1-2008 .
 .Pp
 The flags
-.Op Fl cHhjkLMmNOrSTvWwx
+.Op Fl cfHhjkLMmNOrSTvWwx
 are extensions to
 .St -p1003.1-2008 .
 .Pp
index 6c7c68b..4cf9bfd 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ps.c,v 1.78 2021/12/01 18:21:23 deraadt Exp $ */
+/*     $OpenBSD: ps.c,v 1.79 2022/09/01 21:15:54 job Exp $     */
 /*     $NetBSD: ps.c,v 1.15 1995/05/18 20:33:25 mycroft Exp $  */
 
 /*-
@@ -73,6 +73,7 @@ enum sort { DEFAULT, SORTMEM, SORTCPU } sortby = DEFAULT;
 static char    *kludge_oldps_options(char *);
 static int      pscomp(const void *, const void *);
 static void     scanvars(void);
+static void     forest_sort(struct pinfo *, int);
 static void     usage(void);
 
 char dfmt[] = "pid tt state time command";
@@ -90,7 +91,8 @@ int kvm_sysctl_only;
 int
 main(int argc, char *argv[])
 {
-       struct kinfo_proc *kp, **kinfo;
+       struct kinfo_proc *kp;
+       struct pinfo *pinfo;
        struct varent *vent;
        struct winsize ws;
        dev_t ttydev;
@@ -98,6 +100,7 @@ main(int argc, char *argv[])
        uid_t uid;
        int all, ch, flag, i, fmt, lineno, nentries;
        int prtheader, showthreads, wflag, kflag, what, Uflag, xflg;
+       int forest;
        char *nlistf, *memf, *swapf, *cols, errbuf[_POSIX2_LINE_MAX];
 
        setlocale(LC_CTYPE, "");
@@ -120,10 +123,11 @@ main(int argc, char *argv[])
        all = fmt = prtheader = showthreads = wflag = kflag = Uflag = xflg = 0;
        pid = -1;
        uid = 0;
+       forest = 0;
        ttydev = NODEV;
        memf = nlistf = swapf = NULL;
        while ((ch = getopt(argc, argv,
-           "AaCcegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
+           "AaCcefgHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
                switch (ch) {
                case 'A':
                        all = 1;
@@ -140,6 +144,9 @@ main(int argc, char *argv[])
                case 'e':                       /* XXX set ufmt */
                        needenv = 1;
                        break;
+               case 'f':
+                       forest = 1;
+                       break;
                case 'g':
                        break;                  /* no-op */
                case 'H':
@@ -349,26 +356,27 @@ main(int argc, char *argv[])
        printheader();
        if (nentries == 0)
                exit(1);
-       /*
-        * sort proc list, we convert from an array of structs to an array
-        * of pointers to make the sort cheaper.
-        */
-       if ((kinfo = reallocarray(NULL, nentries, sizeof(*kinfo))) == NULL)
-               err(1, "failed to allocate memory for proc pointers");
+
+       if ((pinfo = calloc(nentries, sizeof(struct pinfo))) == NULL)
+               err(1, NULL);
        for (i = 0; i < nentries; i++)
-               kinfo[i] = &kp[i];
-       qsort(kinfo, nentries, sizeof(*kinfo), pscomp);
+               pinfo[i].ki = &kp[i];
+       qsort(pinfo, nentries, sizeof(struct pinfo), pscomp);
+
+       if (forest)
+               forest_sort(pinfo, nentries);
+
        /*
         * for each proc, call each variable output function.
         */
        for (i = lineno = 0; i < nentries; i++) {
-               if (xflg == 0 && ((int)kinfo[i]->p_tdev == NODEV ||
-                   (kinfo[i]->p_psflags & PS_CONTROLT ) == 0))
+               if (xflg == 0 && ((int)pinfo[i].ki->p_tdev == NODEV ||
+                   (pinfo[i].ki->p_psflags & PS_CONTROLT ) == 0))
                        continue;
-               if (showthreads && kinfo[i]->p_tid == -1)
+               if (showthreads && pinfo[i].ki->p_tid == -1)
                        continue;
                for (vent = vhead; vent; vent = vent->next) {
-                       (vent->var->oproc)(kinfo[i], vent);
+                       (vent->var->oproc)(&pinfo[i], vent);
                        if (vent->next != NULL)
                                (void)putchar(' ');
                }
@@ -406,8 +414,10 @@ scanvars(void)
 static int
 pscomp(const void *v1, const void *v2)
 {
-       const struct kinfo_proc *kp1 = *(const struct kinfo_proc **)v1;
-       const struct kinfo_proc *kp2 = *(const struct kinfo_proc **)v2;
+       const struct pinfo *p1 = (const struct pinfo *)v1;
+       const struct pinfo *p2 = (const struct pinfo *)v2;
+       const struct kinfo_proc *kp1 = p1->ki;
+       const struct kinfo_proc *kp2 = p2->ki;
        int i;
 #define VSIZE(k) ((k)->p_vm_dsize + (k)->p_vm_ssize + (k)->p_vm_tsize)
 
@@ -483,13 +493,125 @@ kludge_oldps_options(char *s)
        return (newopts);
 }
 
+static void
+forest_sort(struct pinfo *ki, int items)
+{
+       int dst, lvl, maxlvl, n, ndst, nsrc, siblings, src;
+       unsigned char *path;
+       struct pinfo kn;
+
+       /*
+        * First, sort the entries by forest, tracking the forest
+        * depth in the level field.
+        */
+       src = 0;
+       maxlvl = 0;
+       while (src < items) {
+               if (ki[src].level) {
+                       src++;
+                       continue;
+               }
+               for (nsrc = 1; src + nsrc < items; nsrc++)
+                       if (!ki[src + nsrc].level)
+                               break;
+
+               for (dst = 0; dst < items; dst++) {
+                       if (ki[dst].ki->p_pid == ki[src].ki->p_pid)
+                               continue;
+                       if (ki[dst].ki->p_pid == ki[src].ki->p_ppid)
+                               break;
+               }
+
+               if (dst == items) {
+                       src += nsrc;
+                       continue;
+               }
+
+               for (ndst = 1; dst + ndst < items; ndst++)
+                       if (ki[dst + ndst].level <= ki[dst].level)
+                               break;
+
+               for (n = src; n < src + nsrc; n++) {
+                       ki[n].level += ki[dst].level + 1;
+                       if (maxlvl < ki[n].level)
+                               maxlvl = ki[n].level;
+               }
+
+               while (nsrc) {
+                       if (src < dst) {
+                               kn = ki[src];
+                               memmove(ki + src, ki + src + 1,
+                                   (dst - src + ndst - 1) * sizeof *ki);
+                               ki[dst + ndst - 1] = kn;
+                               nsrc--;
+                               dst--;
+                               ndst++;
+                       } else if (src != dst + ndst) {
+                               kn = ki[src];
+                               memmove(ki + dst + ndst + 1, ki + dst + ndst,
+                                   (src - dst - ndst) * sizeof *ki);
+                               ki[dst + ndst] = kn;
+                               ndst++;
+                               nsrc--;
+                               src++;
+                       } else {
+                               ndst += nsrc;
+                               src += nsrc;
+                               nsrc = 0;
+                       }
+               }
+       }
+       /*
+        * Now populate prefix (instead of level) with the command
+        * prefix used to show descendancies.
+        */
+       path = calloc(1, (maxlvl + 7) / 8);
+       if (path == NULL)
+               err(1, NULL);
+
+       for (src = 0; src < items; src++) {
+               if ((lvl = ki[src].level) == 0) {
+                       ki[src].prefix = NULL;
+                       continue;
+               }
+
+               if ((ki[src].prefix = malloc(lvl * 2 + 1)) == NULL)
+                       err(1, NULL);
+
+               for (n = 0; n < lvl - 2; n++) {
+                       ki[src].prefix[n * 2] =
+                           path[n / 8] & 1 << (n % 8) ? '|' : ' ';
+                       ki[src].prefix[n * 2 + 1] = ' ';
+
+               }
+               if (n == lvl - 2) {
+                       /* Have I any more siblings? */
+                       for (siblings = 0, dst = src + 1; dst < items; dst++) {
+                               if (ki[dst].level > lvl)
+                                       continue;
+                               if (ki[dst].level == lvl)
+                                       siblings = 1;
+                               break;
+                       }
+                       if (siblings)
+                               path[n / 8] |= 1 << (n % 8);
+                       else
+                               path[n / 8] &= ~(1 << (n % 8));
+                       ki[src].prefix[n * 2] = siblings ? '|' : '`';
+                       ki[src].prefix[n * 2 + 1] = '-';
+                       n++;
+               }
+               strlcpy(ki[src].prefix + n * 2, "- ", (lvl - n) * 2 + 1);
+       }
+       free(path);
+}
+
 static void
 usage(void)
 {
-       (void)fprintf(stderr,
-           "usage: %s [-AaceHhjkLlmrSTuvwx] [-M core] [-N system] [-O fmt] [-o fmt] [-p pid]\n",
-           __progname);
-       (void)fprintf(stderr,
-           "%-*s[-t tty] [-U username] [-W swap]\n", (int)strlen(__progname) + 8, "");
+       fprintf(stderr, "usage: %s [-AacefHhjkLlmrSTuvwx] [-M core] [-N system]"
+           " [-O fmt] [-o fmt] [-p pid]\n", __progname);
+       fprintf(stderr, "%-*s[-t tty] [-U username] [-W swap]\n",
+           (int)strlen(__progname) + 8, "");
        exit(1);
 }
index 689b128..65df509 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: ps.h,v 1.10 2015/05/03 06:23:28 guenther Exp $        */
+/*     $OpenBSD: ps.h,v 1.11 2022/09/01 21:15:54 job Exp $     */
 /*     $NetBSD: ps.h,v 1.11 1995/09/29 21:57:03 cgd Exp $      */
 
 /*-
@@ -44,6 +44,11 @@ typedef struct varent {
 } VARENT;
 
 struct kinfo_proc;
+struct pinfo {
+       struct kinfo_proc *ki;
+       char *prefix;
+       int level;
+};
 typedef struct var {
        char    *name;          /* name(s) of variable */
        char    *header;        /* default header */
@@ -55,7 +60,7 @@ typedef struct var {
 #define        NLIST   0x10            /* needs nlist info from kernel */
        u_int   flag;
                                /* output routine */
-       void    (*oproc)(const struct kinfo_proc *, struct varent *);
+       void    (*oproc)(const struct pinfo *, struct varent *);
        short   width;          /* printing width */
        char    parsed;         /* have we been parsed yet? (avoid dupes) */
        /*