On 01/09/22(Thu) 03:37, Job Snijders wrote: > 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?
I'd love to have such feature in base. > 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) */ > /* >