Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 17 May 2009 04:00:44 +0000 (UTC)
From:      Brian Somers <brian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r192239 - head/bin/ps
Message-ID:  <200905170400.n4H40it0013222@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: brian
Date: Sun May 17 04:00:43 2009
New Revision: 192239
URL: http://svn.freebsd.org/changeset/base/192239

Log:
  Add a -d option to ps to display descendant info with the output.
  This is similar to linux's -H (or -f) switch.
  
  MFC after:	3 weeks

Modified:
  head/bin/ps/print.c
  head/bin/ps/ps.1
  head/bin/ps/ps.c
  head/bin/ps/ps.h

Modified: head/bin/ps/print.c
==============================================================================
--- head/bin/ps/print.c	Sun May 17 01:32:47 2009	(r192238)
+++ head/bin/ps/print.c	Sun May 17 04:00:43 2009	(r192239)
@@ -130,9 +130,11 @@ command(KINFO *k, VARENT *ve)
 	if (cflag) {
 		/* If it is the last field, then don't pad */
 		if (STAILQ_NEXT(ve, next_ve) == NULL) {
+			if (k->ki_d.prefix)
+				(void)printf("%s", k->ki_d.prefix);
 			(void)printf("%s", k->ki_p->ki_comm);
 			if (showthreads && k->ki_p->ki_numthreads > 1)
-				printf("/%s", k->ki_p->ki_ocomm);
+				(void)printf("/%s", k->ki_p->ki_ocomm);
 		} else
 			(void)printf("%-*s", v->width, k->ki_p->ki_comm);
 		return;
@@ -140,16 +142,22 @@ command(KINFO *k, VARENT *ve)
 	if ((vis_args = malloc(strlen(k->ki_args) * 4 + 1)) == NULL)
 		errx(1, "malloc failed");
 	strvis(vis_args, k->ki_args, VIS_TAB | VIS_NL | VIS_NOSLASH);
-	if (k->ki_env) {
-		if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1)) == NULL)
-			errx(1, "malloc failed");
-		strvis(vis_env, k->ki_env, VIS_TAB | VIS_NL | VIS_NOSLASH);
-	} else
-		vis_env = NULL;
 
 	if (STAILQ_NEXT(ve, next_ve) == NULL) {
 		/* last field */
+
+		if (k->ki_env) {
+			if ((vis_env = malloc(strlen(k->ki_env) * 4 + 1))
+			    == NULL)
+				errx(1, "malloc failed");
+			strvis(vis_env, k->ki_env,
+			    VIS_TAB | VIS_NL | VIS_NOSLASH);
+		} else
+			vis_env = NULL;
+
 		if (termwidth == UNLIMITED) {
+			if (k->ki_d.prefix)
+				(void)printf("%s", k->ki_d.prefix);
 			if (vis_env)
 				(void)printf("%s ", vis_env);
 			(void)printf("%s", vis_args);
@@ -157,6 +165,9 @@ command(KINFO *k, VARENT *ve)
 			left = termwidth - (totwidth - v->width);
 			if (left < 1) /* already wrapped, just use std width */
 				left = v->width;
+			if ((cp = k->ki_d.prefix) != NULL)
+				while (--left >= 0 && *cp)
+					(void)putchar(*cp++);
 			if ((cp = vis_env) != NULL) {
 				while (--left >= 0 && *cp)
 					(void)putchar(*cp++);
@@ -166,12 +177,12 @@ command(KINFO *k, VARENT *ve)
 			for (cp = vis_args; --left >= 0 && *cp != '\0';)
 				(void)putchar(*cp++);
 		}
+		if (vis_env != NULL)
+			free(vis_env);
 	} else
-		/* XXX env? */
+		/* ki_d.prefix & ki_env aren't shown for interim fields */
 		(void)printf("%-*.*s", v->width, v->width, vis_args);
 	free(vis_args);
-	if (vis_env != NULL)
-		free(vis_env);
 }
 
 void
@@ -182,6 +193,8 @@ ucomm(KINFO *k, VARENT *ve)
 
 	v = ve->var;
 	if (STAILQ_NEXT(ve, next_ve) == NULL) {	/* last field, don't pad */
+		if (k->ki_d.prefix)
+			(void)printf("%s", k->ki_d.prefix);
 		(void)printf("%s", k->ki_p->ki_comm);
 		if (showthreads && k->ki_p->ki_numthreads > 1)
 			printf("/%s", k->ki_p->ki_ocomm);

Modified: head/bin/ps/ps.1
==============================================================================
--- head/bin/ps/ps.1	Sun May 17 01:32:47 2009	(r192238)
+++ head/bin/ps/ps.1	Sun May 17 04:00:43 2009	(r192239)
@@ -29,7 +29,7 @@
 .\"     @(#)ps.1	8.3 (Berkeley) 4/18/94
 .\" $FreeBSD$
 .\"
-.Dd August 21, 2006
+.Dd May 16, 2009
 .Dt PS 1
 .Os
 .Sh NAME
@@ -37,7 +37,7 @@
 .Nd process status
 .Sh SYNOPSIS
 .Nm
-.Op Fl aCcefHhjlmrSTuvwXxZ
+.Op Fl aCcdefHhjlmrSTuvwXxZ
 .Op Fl O Ar fmt | Fl o Ar fmt
 .Op Fl G Ar gid Ns Op , Ns Ar gid Ns Ar ...
 .Op Fl M Ar core
@@ -122,6 +122,15 @@ CPU calculation that ignores
 .Dq resident
 time (this normally has
 no effect).
+.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 eachother.
 .It Fl e
 Display the environment as well.
 .It Fl f

Modified: head/bin/ps/ps.c
==============================================================================
--- head/bin/ps/ps.c	Sun May 17 01:32:47 2009	(r192238)
+++ head/bin/ps/ps.c	Sun May 17 04:00:43 2009	(r192239)
@@ -138,6 +138,7 @@ static int	 addelem_pid(struct listinfo 
 static int	 addelem_tty(struct listinfo *, const char *);
 static int	 addelem_uid(struct listinfo *, const char *);
 static void	 add_list(struct listinfo *, const char *);
+static void	 descendant_sort(KINFO *, int);
 static void	 dynsizevars(KINFO *);
 static void	*expand_list(struct listinfo *);
 static const char *
@@ -163,7 +164,7 @@ static char vfmt[] = "pid,state,time,sl,
 			"%cpu,%mem,command";
 static char Zfmt[] = "label";
 
-#define	PS_ARGS	"AaCce" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ"
+#define	PS_ARGS	"AaCcde" OPT_LAZY_f "G:gHhjLlM:mN:O:o:p:rSTt:U:uvwXxZ"
 
 int
 main(int argc, char *argv[])
@@ -177,7 +178,7 @@ main(int argc, char *argv[])
 	const char *nlistf, *memf;
 	char *cols;
 	int all, ch, elem, flag, _fmt, i, lineno;
-	int nentries, nkept, nselectors;
+	int descendancy, nentries, nkept, nselectors;
 	int prtheader, wflag, what, xkeep, xkeep_implied;
 	char errbuf[_POSIX2_LINE_MAX];
 
@@ -201,7 +202,7 @@ main(int argc, char *argv[])
 	if (argc > 1)
 		argv[1] = kludge_oldps_options(PS_ARGS, argv[1], argv[2]);
 
-	all = _fmt = nselectors = optfatal = 0;
+	all = descendancy = _fmt = nselectors = optfatal = 0;
 	prtheader = showthreads = wflag = xkeep_implied = 0;
 	xkeep = -1;			/* Neither -x nor -X. */
 	init_list(&gidlist, addelem_gid, sizeof(gid_t), "group");
@@ -233,6 +234,9 @@ main(int argc, char *argv[])
 		case 'c':
 			cflag = 1;
 			break;
+		case 'd':
+			descendancy = 1;
+			break;
 		case 'e':			/* XXX set ufmt */
 			needenv = 1;
 			break;
@@ -575,6 +579,8 @@ main(int argc, char *argv[])
 		keepit:
 			next_KINFO = &kinfo[nkept];
 			next_KINFO->ki_p = kp;
+			next_KINFO->ki_d.level = 0;
+			next_KINFO->ki_d.prefix = NULL;
 			next_KINFO->ki_pcpu = getpcpu(next_KINFO);
 			if (sortby == SORTMEM)
 				next_KINFO->ki_memsize = kp->ki_tsize +
@@ -599,6 +605,13 @@ main(int argc, char *argv[])
 	 * sort proc list
 	 */
 	qsort(kinfo, nkept, sizeof(KINFO), pscomp);
+
+	/*
+	 * We want things in descendant order
+	 */
+	if (descendancy)
+		descendant_sort(kinfo, nkept);
+
 	/*
 	 * For each process, call each variable output function.
 	 */
@@ -622,6 +635,9 @@ main(int argc, char *argv[])
 	free_list(&sesslist);
 	free_list(&ttylist);
 	free_list(&uidlist);
+	for (i = 0; i < nkept; i++)
+		free(kinfo[i].ki_d.prefix);
+	free(kinfo);
 
 	exit(eval);
 }
@@ -890,6 +906,116 @@ add_list(struct listinfo *inf, const cha
 	}
 }
 
+static void
+descendant_sort(KINFO *ki, int items)
+{
+	int dst, lvl, maxlvl, n, ndst, nsrc, siblings, src;
+	unsigned char *path;
+	KINFO kn;
+
+	/*
+	 * First, sort the entries by descendancy, tracking the descendancy
+	 * depth in the ki_d.level field.
+	 */
+	src = 0;
+	maxlvl = 0;
+	while (src < items) {
+		if (ki[src].ki_d.level) {
+			src++;
+			continue;
+		}
+		for (nsrc = 1; src + nsrc < items; nsrc++)
+			if (!ki[src + nsrc].ki_d.level)
+				break;
+
+		for (dst = 0; dst < items; dst++) {
+			if (ki[dst].ki_p->ki_pid == ki[src].ki_p->ki_pid)
+				continue;
+			if (ki[dst].ki_p->ki_pid == ki[src].ki_p->ki_ppid)
+				break;
+		}
+
+		if (dst == items) {
+			src += nsrc;
+			continue;
+		}
+
+		for (ndst = 1; dst + ndst < items; ndst++)
+			if (ki[dst + ndst].ki_d.level <= ki[dst].ki_d.level)
+				break;
+
+		for (n = src; n < src + nsrc; n++) {
+			ki[n].ki_d.level += ki[dst].ki_d.level + 1;
+			if (maxlvl < ki[n].ki_d.level)
+				maxlvl = ki[n].ki_d.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 ki_d.prefix (instead of ki_d.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].ki_d.level) == 0) {
+			ki[src].ki_d.prefix = NULL;
+			continue;
+		}
+		if ((ki[src].ki_d.prefix = malloc(lvl * 2 + 1)) == NULL)
+			errx(1, "malloc failed");
+		for (n = 0; n < lvl - 2; n++) {
+			ki[src].ki_d.prefix[n * 2] =
+			    path[n / 8] & 1 << (n % 8) ? '|' : ' ';
+			ki[src].ki_d.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].ki_d.level > lvl)
+					continue;
+				if (ki[dst].ki_d.level == lvl)
+					siblings = 1;
+				break;
+			}
+			if (siblings)
+				path[n / 8] |= 1 << (n % 8);
+			else
+				path[n / 8] &= ~(1 << (n % 8));
+			ki[src].ki_d.prefix[n * 2] = siblings ? '|' : '`';
+			ki[src].ki_d.prefix[n * 2 + 1] = '-';
+			n++;
+		}
+		strcpy(ki[src].ki_d.prefix + n * 2, "- ");
+	}
+	free(path);
+}
+
 static void *
 expand_list(struct listinfo *inf)
 {

Modified: head/bin/ps/ps.h
==============================================================================
--- head/bin/ps/ps.h	Sun May 17 01:32:47 2009	(r192238)
+++ head/bin/ps/ps.h	Sun May 17 04:00:43 2009	(r192239)
@@ -42,6 +42,10 @@ typedef struct kinfo {
 	int ki_valid;		/* 1 => uarea stuff valid */
 	double	 ki_pcpu;	/* calculated in main() */
 	segsz_t	 ki_memsize;	/* calculated in main() */
+	union {
+		int level;	/* used in decendant_sort() */
+		char *prefix;	/* calculated in decendant_sort() */
+	} ki_d;
 } KINFO;
 
 /* Variables. */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200905170400.n4H40it0013222>