Dear all,

Some ps(1) implementations have an '-d' ('descendancy') option. Through
ASCII art parent/child process relationships are grouped and displayed.
Here is an example:

    $ ps ad -O ppid,user
      PID  PPID USER     TT  STAT        TIME COMMAND
    18180 12529 job      pb  I+p      0:00.01 `-- -sh (sh)
    26689 56460 job      p3  Ip       0:00.01   `-- -ksh (ksh)
     5153 26689 job      p3  I+p      0:40.18     `-- mutt
    62046 25272 job      p4  Sp       0:00.25   `-- -ksh (ksh)
    61156 62046 job      p4  R+/0     0:00.00     `-- ps -ad -O ppid
    26816  2565 job      p5  Ip       0:00.01   `-- -ksh (ksh)
    79431 26816 root     p5  Ip       0:00.16     `-- /bin/ksh
    43915 79431 _rpki-cl p5  S+pU     0:06.97       `-- rpki-client
    70511 43915 _rpki-cl p5  I+pU     0:01.26         |-- rpki-client: parser 
(rpki-client)
    96992 43915 _rpki-cl p5  I+pU     0:00.00         |-- rpki-client: rsync 
(rpki-client)
    49160 43915 _rpki-cl p5  S+p      0:01.52         |-- rpki-client: http 
(rpki-client)
    99329 43915 _rpki-cl p5  S+p      0:03.20         `-- rpki-client: rrdp 
(rpki-client)
    
The functionality is similar to pstree(1) in the ports collection.

The below changeset borrows heavily from the following two
implementations:

    
https://github.com/freebsd/freebsd-src/commit/044fce530f89a819827d351de364d208a30e9645.patch
    
https://github.com/NetBSD/src/commit/b82f6d00d93d880d3976c4f1e88c33d88a8054ad.patch

Thoughts?

Kind regards,

Job

Index: extern.h
===================================================================
RCS file: /cvs/src/bin/ps/extern.h,v
retrieving revision 1.23
diff -u -p -r1.23 extern.h
--- extern.h    5 Jan 2022 04:10:36 -0000       1.23
+++ extern.h    1 Sep 2022 03:31:36 -0000
@@ -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 *);
+double  getpmem(const struct pinfo *);
+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: print.c
===================================================================
RCS file: /cvs/src/bin/ps/print.c,v
retrieving revision 1.82
diff -u -p -r1.82 print.c
--- print.c     15 Feb 2022 23:16:00 -0000      1.82
+++ print.c     1 Sep 2022 03:31:36 -0000
@@ -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, VAR
        }
 
        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, VAR
 }
 
 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, VAREN
 }
 
 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, VAR
 #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, 
 }
 
 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,
 }
 
 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 
 }
 
 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, VARE
 }
 
 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, VARE
 }
 
 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
 }
 
 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, VAREN
 }
 
 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, V
 }
 
 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, VAR
 }
 
 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, VA
        (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
 }
 
 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, VAREN
 }
 
 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, VAREN
 }
 
 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, VARE
 }
 
 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, VA
 }
 
 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,17 +680,18 @@ 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
-getpmem(const struct kinfo_proc *kp)
+getpmem(const struct pinfo *pi)
 {
+       const struct kinfo_proc *kp = pi->ki;
        double fracmem;
 
        if (mempages == 0)
@@ -672,17 +705,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));
 }
 
 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 +725,9 @@ pagein(const struct kinfo_proc *kp, VARE
 }
 
 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 +735,9 @@ maxrss(const struct kinfo_proc *kp, VARE
 }
 
 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 +745,9 @@ tsize(const struct kinfo_proc *kp, VAREN
 }
 
 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 +755,9 @@ dsize(const struct kinfo_proc *kp, VAREN
 }
 
 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 +816,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: ps.1
===================================================================
RCS file: /cvs/src/bin/ps/ps.1,v
retrieving revision 1.126
diff -u -p -r1.126 ps.1
--- ps.1        5 Jul 2022 15:06:16 -0000       1.126
+++ ps.1        1 Sep 2022 03:31:37 -0000
@@ -39,7 +39,7 @@
 .Sh SYNOPSIS
 .Nm ps
 .Sm off
-.Op Oo Fl Oc Cm AaceHhjkLlmrSTuvwx
+.Op Oo Fl Oc Cm AacdeHhjkLlmrSTuvwx
 .Sm on
 .Op Fl M Ar core
 .Op Fl N Ar system
@@ -83,6 +83,15 @@ This may be somewhat confusing; for exam
 .Xr sh 1
 scripts will show as
 .Dq sh .
+.It Fl d
+Arrange processes into descendancy 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 e
 Display the environment as well.
 .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 cdHhjkLMmNOrSTvWwx
 are extensions to
 .St -p1003.1-2008 .
 .Pp
Index: ps.c
===================================================================
RCS file: /cvs/src/bin/ps/ps.c,v
retrieving revision 1.78
diff -u -p -r1.78 ps.c
--- ps.c        1 Dec 2021 18:21:23 -0000       1.78
+++ ps.c        1 Sep 2022 03:31:37 -0000
@@ -73,6 +73,7 @@ enum sort { DEFAULT, SORTMEM, SORTCPU } 
 static char    *kludge_oldps_options(char *);
 static int      pscomp(const void *, const void *);
 static void     scanvars(void);
+static void     descendant_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 descendancy;
        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;
+       descendancy = 0;
        ttydev = NODEV;
        memf = nlistf = swapf = NULL;
        while ((ch = getopt(argc, argv,
-           "AaCcegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
+           "AaCcdegHhjkLlM:mN:O:o:p:rSTt:U:uvW:wx")) != -1)
                switch (ch) {
                case 'A':
                        all = 1;
@@ -137,6 +141,9 @@ main(int argc, char *argv[])
                case 'c':
                        commandonly = 1;
                        break;
+               case 'd':
+                       descendancy = 1;
+                       break;
                case 'e':                       /* XXX set ufmt */
                        needenv = 1;
                        break;
@@ -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 (descendancy)
+               descendant_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)
 
@@ -484,12 +494,120 @@ kludge_oldps_options(char *s)
 }
 
 static void
+descendant_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 descendancy, tracking the descendancy
+        * 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 = malloc((maxlvl + 7) / 8);
+       memset(path, '\0', (maxlvl + 7) / 8);
+       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)
+                       errx(1, "malloc failed");
+               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++;
+               }
+               strcpy(ki[src].prefix + n * 2, "- ");
+       }
+       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 [-AacdeHhjkLlmrSTuvwx] [-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: ps.h
===================================================================
RCS file: /cvs/src/bin/ps/ps.h,v
retrieving revision 1.10
diff -u -p -r1.10 ps.h
--- ps.h        3 May 2015 06:23:28 -0000       1.10
+++ ps.h        1 Sep 2022 03:31:37 -0000
@@ -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) */
        /*

Reply via email to