Job Snijders([email protected]) on 2022.09.01 03:37:59 +0000:
> 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 like it. found some little things below, with those fixed and some
agreement on the option letter (which i dont care about) it has my ok.
>
> 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);
check the result of malloc
> + 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");
why not just 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++;
> + }
> + 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) */
> /*
>