Subject: bin/17859: fix ps display of UINT64 values, add 'NOTYET' fields
To: None <gnats-bugs@gnats.netbsd.org>
From: None <dsl@l8s.co.uk>
List: netbsd-bugs
Date: 08/06/2002 18:14:39
>Number:         17859
>Category:       bin
>Synopsis:       fix ps display of UINT64 values, add 'NOTYET' fields
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bin-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Tue Aug 06 10:13:01 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator:     David Laight
>Release:        NetBSD 1.6E
>Organization:
	not today
>Environment:
System: NetBSD snowdrop 1.6E NetBSD 1.6E (GENERIC) #145: Tue Aug 6 11:08:57 BST 2002
dsl@snowdrop:/oldroot/usr/bsd-current/src/sys/arch/i386/compile/GENERIC i386
Architecture: i386
Machine: i386
>Description:
	I wanted to display the p_u[csu]time fields for a process
	(to track down a different bug).  ps doesn't display these
	by default, not in a 'raw' format anyway.

	Also:
	Fixed display of -Omajflt and other UINT64 values
	Display '-' for fields that aren't present because the process
		u area is swapped
	Fix width of TIME column for 1 <= secs < 6 (bug 13552)
	Added idrss, isrss, ixrss and maxrss
>How-To-Repeat:
>Fix:
	The following changes fix ps, getting sensible utime,
	stime and ctime fields requires an additional kernel fix.
Index: extern.h
===================================================================
RCS file: /cvsroot/basesrc/bin/ps/extern.h,v
retrieving revision 1.21
diff -u -r1.21 extern.h
--- extern.h	2002/06/19 08:11:55	1.21
+++ extern.h	2002/08/06 16:56:25
@@ -64,7 +64,6 @@
 void	 maxrss __P((struct kinfo_proc2 *, VARENT *, int));
 void	 nlisterr __P((struct nlist *));
 void	 p_rssize __P((struct kinfo_proc2 *, VARENT *, int));
-void	 pagein __P((struct kinfo_proc2 *, VARENT *, int));
 void	 parsefmt __P((char *));
 void	 pcpu __P((struct kinfo_proc2 *, VARENT *, int));
 void	 pmem __P((struct kinfo_proc2 *, VARENT *, int));
@@ -74,6 +73,8 @@
 struct kinfo_proc2
 	*getkinfo_procfs __P((int, int, int *));
 char	**procfs_getargv __P((const struct kinfo_proc2 *, int));
+void	 puvar __P((struct kinfo_proc2 *, VARENT *, int));
+void	 putimeval __P((struct kinfo_proc2 *, VARENT *, int));
 void	 pvar __P((struct kinfo_proc2 *, VARENT *, int));
 void	 rssize __P((struct kinfo_proc2 *, VARENT *, int));
 void	 runame __P((struct kinfo_proc2 *, VARENT *, int));
Index: keyword.c
===================================================================
RCS file: /cvsroot/basesrc/bin/ps/keyword.c,v
retrieving revision 1.27
diff -u -r1.27 keyword.c
--- keyword.c	2002/04/24 21:41:22	1.27
+++ keyword.c	2002/08/06 16:56:26
@@ -63,14 +63,6 @@
 static VAR *findvar __P((char *));
 static int  vcmp __P((const void *, const void *));
 
-#ifdef NOTINUSE
-	{"stime", "STIME", NULL, 0, cputime},	/* XXX add stime, utime ... */
-	{"utime", "UTIME", NULL, 0, cputime},	/* ... display to cputime() */
-	{"idrss", "IDRSS", NULL, 0, pvar, 0, POFF(p_uru_idrss), ULONG, "d"},
-	{"isrss", "ISRSS", NULL, 0, pvar, 0, POFF(p_uru_isrss), ULONG, "d"},
-	{"ixrss", "IXRSS", NULL, 0, pvar, 0, POFF(p_uru_ixrss), ULONG, "d"},
-#endif
-
 /* Compute offset in common structures. */
 #define	POFF(x)	offsetof(struct kinfo_proc2, x)
 
@@ -83,50 +75,60 @@
 #define	PID(n1, n2, fn, off) \
 	{ n1, n2, NULL, 0, fn, 0, off, INT32, PIDFMT }
 
+#define	PVAR(n1, n2, off, type, fmt) \
+	{ n1, n2, NULL, 0, pvar, 0, off, type, fmt }
+#define	PUVAR(n1, n2, off, type, fmt) \
+	{ n1, n2, NULL, 0, puvar, 0, off, type, fmt }
+
+/* NB: table must be sorted, in vi use:
+ *	:/^VAR/,/end_sort/! sort -t\" +1
+ * breaking long lines just makes the sort harder
+ */
 VAR var[] = {
 	{"%cpu", "%CPU", NULL, 0, pcpu},
 	{"%mem", "%MEM", NULL, 0, pmem},
-	{"acflag", "ACFLG", NULL, 0, pvar, 0, POFF(p_acflag), USHORT, "x"},
+	PVAR("acflag", "ACFLG", POFF(p_acflag), USHORT, "x"),
 	{"acflg", "", "acflag"},
 	{"blocked", "", "sigmask"},
 	{"caught", "", "sigcatch"},
 	{"command", "COMMAND", NULL, COMM|LJUST, command},
-	{"cpu", "CPU", NULL, 0, pvar, 0, POFF(p_estcpu), UINT, "d"},
+	PVAR("cpu", "CPU", POFF(p_estcpu), UINT, "d"),
 	{"cputime", "", "time"},
-	{"f", "F", NULL, 0, pvar, 0, POFF(p_flag), INT, "x"},
+	{"ctime", "CTIME", NULL, 0, putimeval, 0, POFF(p_uctime_sec)},
+	PVAR("f", "F", POFF(p_flag), INT, "x"),
 	{"flags", "", "f"},
-	{"holdcnt", "HOLDCNT", NULL, 0, pvar, 0, POFF(p_holdcnt), INT, "d"},
+	PVAR("holdcnt", "HOLDCNT", POFF(p_holdcnt), INT, "d"),
+	PUVAR("idrss", "IDRSS", POFF(p_uru_idrss), UINT64, "lld"),
 	{"ignored", "", "sigignore"},
-	{"inblk", "INBLK", NULL, 0, pvar, 0, POFF(p_uru_inblock), UINT64, "ldd"},
+	PUVAR("inblk", "INBLK", POFF(p_uru_inblock), UINT64, "lld"),
 	{"inblock", "", "inblk"},
-	{"jobc", "JOBC", NULL, 0, pvar, 0, POFF(p_jobc), SHORT, "d"},
-	{"ktrace", "KTRACE", NULL, 0, pvar, 0, POFF(p_traceflag), INT, "x"},
-	/* XXX */
-	{"ktracep", "KTRACEP", NULL, 0, pvar, 0, POFF(p_tracep), KPTR, "llx"},
+	PUVAR("isrss", "ISRSS", POFF(p_uru_isrss), UINT64, "lld"),
+	PUVAR("ixrss", "IXRSS", POFF(p_uru_ixrss), UINT64, "lld"),
+	PVAR("jobc", "JOBC", POFF(p_jobc), SHORT, "d"),
+	PVAR("ktrace", "KTRACE", POFF(p_traceflag), INT, "x"),
+/*XXX*/	PVAR("ktracep", "KTRACEP", POFF(p_tracep), KPTR, "llx"),
 	{"lim", "LIM", NULL, 0, maxrss},
 	{"login", "LOGIN", NULL, LJUST, logname},
 	{"logname", "", "login"},
 	{"lstart", "STARTED", NULL, LJUST, lstarted},
-	{"majflt", "MAJFLT", NULL, 0, pvar, 0, POFF(p_uru_majflt), UINT64, "ldd"},
-	{"minflt", "MINFLT", NULL, 0, pvar, 0, POFF(p_uru_minflt), UINT64, "ldd"},
-	{"msgrcv", "MSGRCV", NULL, 0, pvar, 0, POFF(p_uru_msgrcv), UINT64, "ldd"},
-	{"msgsnd", "MSGSND", NULL, 0, pvar, 0, POFF(p_uru_msgsnd), UINT64, "ldd"},
+	PUVAR("majflt", "MAJFLT", POFF(p_uru_majflt), UINT64, "lld"),
+	PUVAR("maxrss", "MAXRSS", POFF(p_uru_maxrss), UINT64, "lld"),
+	PUVAR("minflt", "MINFLT", POFF(p_uru_minflt), UINT64, "lld"),
+	PUVAR("msgrcv", "MSGRCV", POFF(p_uru_msgrcv), UINT64, "lld"),
+	PUVAR("msgsnd", "MSGSND", POFF(p_uru_msgsnd), UINT64, "lld"),
 	{"ni", "", "nice"},
 	{"nice", "NI", NULL, 0, pnice},
-	{"nivcsw", "NIVCSW", NULL, 0, pvar, 0, POFF(p_uru_nivcsw), UINT64, "ldd"},
+	PUVAR("nivcsw", "NIVCSW", POFF(p_uru_nivcsw), UINT64, "lld"),
 	{"nsignals", "", "nsigs"},
-	{"nsigs", "NSIGS", NULL, 0, pvar, 0, POFF(p_uru_nsignals), UINT64, "ldd"},
-	{"nswap", "NSWAP", NULL, 0, pvar, 0, POFF(p_uru_nswap), UINT64, "ldd"},
-	{"nvcsw", "NVCSW", NULL, 0, pvar, 0, POFF(p_uru_nvcsw), UINT64, "ldd"},
-	/* XXX */
-	{"nwchan", "WCHAN", NULL, 0, pvar, 0, POFF(p_wchan), KPTR, "llx"},
-	{"oublk", "OUBLK", NULL, 0, pvar, 0, POFF(p_uru_oublock), UINT64, "ldd"},
+	PUVAR("nsigs", "NSIGS", POFF(p_uru_nsignals), UINT64, "lld"),
+	PUVAR("nswap", "NSWAP", POFF(p_uru_nswap), UINT64, "lld"),
+	PUVAR("nvcsw", "NVCSW", POFF(p_uru_nvcsw), UINT64, "lld"),
+/*XXX*/	PVAR("nwchan", "WCHAN", POFF(p_wchan), KPTR, "llx"),
+	PUVAR("oublk", "OUBLK", POFF(p_uru_oublock), UINT64, "lld"),
 	{"oublock", "", "oublk"},
-	/* XXX */
-	{"p_ru", "P_RU", NULL, 0, pvar, 0, POFF(p_ru), KPTR, "llx"},
-	/* XXX */
-	{"paddr", "PADDR", NULL, 0, pvar, 0, POFF(p_paddr), KPTR, "llx"},
-	{"pagein", "PAGEIN", NULL, 0, pagein},
+/*XXX*/	PVAR("p_ru", "P_RU", POFF(p_ru), KPTR, "llx"),
+/*XXX*/	PVAR("paddr", "PADDR", POFF(p_paddr), KPTR, "llx"),
+	PUVAR("pagein", "PAGEIN", POFF(p_uru_majflt), UINT64, "lld"),
 	{"pcpu", "", "%cpu"},
 	{"pending", "", "sig"},
 	PID("pgid", "PGID", pvar, POFF(p__pgid)),
@@ -134,47 +136,45 @@
 	{"pmem", "", "%mem"},
 	PID("ppid", "PPID", pvar, POFF(p_ppid)),
 	{"pri", "PRI", NULL, 0, pri},
-	{"re", "RE", NULL, INF127, pvar, 0, POFF(p_swtime), UINT, "d"},
+	PVAR("re", "RE", POFF(p_swtime), UINT, "d"),
 	GID("rgid", "RGID", pvar, POFF(p_rgid)),
-	/* XXX */
-	{"rlink", "RLINK", NULL, 0, pvar, 0, POFF(p_back), KPTR, "llx"},
+/*XXX*/	PVAR("rlink", "RLINK", POFF(p_back), KPTR, "llx"),
 	{"rss", "RSS", NULL, 0, p_rssize},
 	{"rssize", "", "rsz"},
 	{"rsz", "RSZ", NULL, 0, rssize},
 	UID("ruid", "RUID", pvar, POFF(p_ruid)),
 	{"ruser", "RUSER", NULL, LJUST, runame},
-	{"sess", "SESS", NULL, 0, pvar, 0, POFF(p_sess), KPTR24, "llx"},
+	PVAR("sess", "SESS", POFF(p_sess), KPTR24, "llx"),
 	PID("sid", "SID", pvar, POFF(p_sid)),
-	{"sig", "PENDING",
-	    NULL, 0, pvar, 0, POFF(p_siglist), SIGLIST, "s"},
-	{"sigcatch", "CAUGHT",
-	    NULL, 0, pvar, 0, POFF(p_sigcatch), SIGLIST, "s"},
-	{"sigignore", "IGNORED",
-	    NULL, 0, pvar, 0, POFF(p_sigignore), SIGLIST, "s"},
-	{"sigmask", "BLOCKED",
-	    NULL, 0, pvar, 0, POFF(p_sigmask), SIGLIST, "s"},
-	{"sl", "SL", NULL, INF127, pvar, 0, POFF(p_slptime), UINT, "d"},
+	PVAR("sig", "PENDING", POFF(p_siglist), SIGLIST, "s"),
+	PVAR("sigcatch", "CAUGHT", POFF(p_sigcatch), SIGLIST, "s"),
+	PVAR("sigignore", "IGNORED", POFF(p_sigignore), SIGLIST, "s"),
+	PVAR("sigmask", "BLOCKED", POFF(p_sigmask), SIGLIST, "s"),
+	PVAR("sl", "SL", POFF(p_slptime), UINT, "d"),
 	{"start", "STARTED", NULL, 0, started},
 	{"stat", "", "state"},
 	{"state", "STAT", NULL, LJUST, state},
+	{"stime", "STIME", NULL, 0, putimeval, 0, POFF(p_ustime_sec)},
 	GID("svgid", "SVGID", pvar, POFF(p_gid)),
 	UID("svuid", "SVUID", pvar, POFF(p_uid)),
 	{"tdev", "TDEV", NULL, 0, tdev},
 	{"time", "TIME", NULL, 0, cputime},
 	PID("tpgid", "TGPID", pvar, POFF(p_tpgid)),
-	{"tsess", "TSESS", NULL, 0, pvar, 0, POFF(p_tsess), KPTR, "llx"},
+	PVAR("tsess", "TSESS", POFF(p_tsess), KPTR, "llx"),
 	{"tsiz", "TSIZ", NULL, 0, tsize},
 	{"tt", "TT", NULL, LJUST, tname},
 	{"tty", "TTY", NULL, LJUST, longtname},
 	{"ucomm", "UCOMM", NULL, LJUST, ucomm},
 	UID("uid", "UID", pvar, POFF(p_uid)),
-	{"upr", "UPR", NULL, 0, pvar, 0, POFF(p_usrpri), UCHAR, "d"},
+	PVAR("upr", "UPR", POFF(p_usrpri), UCHAR, "d"),
 	{"user", "USER", NULL, LJUST, uname},
 	{"usrpri", "", "upr"},
+	{"utime", "UTIME", NULL, 0, putimeval, 0, POFF(p_uutime_sec)},
 	{"vsize", "", "vsz"},
 	{"vsz", "VSZ", NULL, 0, vsize},
 	{"wchan", "WCHAN", NULL, LJUST, wchan},
-	{"xstat", "XSTAT", NULL, 0, pvar, 0, POFF(p_xstat), USHORT, "x"},
+	PVAR("xstat", "XSTAT", POFF(p_xstat), USHORT, "x"),
+/* "zzzz" end_sort */
 	{""},
 };
 
@@ -204,6 +204,10 @@
 	char *p;
 {
 	static struct varent *vtail;
+
+	/* dup to avoid zapping arguments, can't free because it
+	   might contain a header. */
+	p = strdup(p);
 
 #define	FMTSEP	" \t,\n"
 	while (p && *p) {
Index: print.c
===================================================================
RCS file: /cvsroot/basesrc/bin/ps/print.c,v
retrieving revision 1.74
diff -u -r1.74 print.c
--- print.c	2002/06/19 08:11:55	1.74
+++ print.c	2002/08/06 16:56:30
@@ -110,8 +110,27 @@
 static void  strprintorsetwidth __P((VAR *, const char *, int));
 
 #define	min(a,b)	((a) <= (b) ? (a) : (b))
-#define	max(a,b)	((a) >= (b) ? (a) : (b))
 
+static int
+iwidth( quad_t v )
+{
+	u_quad_t nlim, lim;
+	int w = 1;
+
+	if (v < 0) {
+		v = -v;
+		w = 2;
+	}
+
+	for (lim = 10; v >= lim; lim = nlim) {
+		nlim = lim * 10;
+		w++;
+		if (nlim < lim)
+			break;
+	}
+	return w;
+}
+
 static char *
 cmdpart(arg0)
 	char *arg0;
@@ -230,13 +249,13 @@
 
 	if (mode == WIDTHMODE) {
 		if (val < 0 && val < v->longestn) {
-			fmtlen = (int)log10((double)-val) + 2;
 			v->longestn = val;
+			fmtlen = iwidth(val);
 			if (fmtlen > v->width)
 				v->width = fmtlen;
 		} else if (val > 0 && val > v->longestp) {
-			fmtlen = (int)log10((double)val) + 1;
 			v->longestp = val;
+			fmtlen = iwidth(val);
 			if (fmtlen > v->width)
 				v->width = fmtlen;
 		}
@@ -659,14 +678,14 @@
 	if (k->p_wchan) {
 		if (k->p_wmesg) {
 			strprintorsetwidth(v, k->p_wmesg, mode);
-			v->width = min(v->width, WMESGLEN);
+			v->width = min(v->width, KI_WMESGLEN);
 		} else {
 			(void)asprintf(&buf, "%-*llx", v->width,
 			    (long long)k->p_wchan);
 			if (buf == NULL)
 				err(1, "%s", "");
 			strprintorsetwidth(v, buf, mode);
-			v->width = min(v->width, WMESGLEN);
+			v->width = min(v->width, KI_WMESGLEN);
 			free(buf);
 		}
 	} else {
@@ -750,18 +769,10 @@
 		psecs = psecs % 100;
 	}
 	if (mode == WIDTHMODE) {
-		/*
-		 * Ugg, this is the only field where a value of 0 longer
-		 * than the column title, and log10(0) isn't good enough.
-		 * Use SECSPERMIN, because secs is divided by that when
-		 * passed to log10().
-		 */
-		if (secs == 0 && v->longestp == 0)
-			secs = SECSPERMIN;
 		if (secs > v->longestp) {
-			/* "+6" for the "%02ld.%02ld" in the printf() below */
-			fmtlen = (int)log10((double)secs / SECSPERMIN) + 1 + 6;
 			v->longestp = secs;
+			/* "+6" for the ":%02ld.%02ld" in the printf() below */
+			fmtlen = iwidth(secs / SECSPERMIN) + 6;
 			if (fmtlen > v->width)
 				v->width = fmtlen;
 		}
@@ -841,18 +852,6 @@
 }
 
 void
-pagein(k, ve, mode)
-	struct kinfo_proc2 *k;
-	VARENT *ve;
-	int mode;
-{
-	VAR *v;
-
-	v = ve->var;
-	intprintorsetwidth(v, k->p_uvalid ? k->p_uru_majflt : 0, mode);
-}
-
-void
 maxrss(k, ve, mode)
 	struct kinfo_proc2 *k;
 	VARENT *ve;
@@ -969,23 +968,22 @@
 		}
 		switch (vok) {
 		case VSIGN:
-			if (val < 0  && val < v->longestn) {
-				fmtlen = (int)log10((double)-val) + 2;
+			if (val < 0 && val < v->longestn) {
 				v->longestn = val;
+				fmtlen = iwidth(val);
 				if (fmtlen > v->width)
 					v->width = fmtlen;
 			} else if (val > 0 && val > v->longestp) {
-				fmtlen = (int)log10((double)val) + 1;
 				v->longestp = val;
+				fmtlen = iwidth(val);
 				if (fmtlen > v->width)
 					v->width = fmtlen;
 			}
 			return;
 		case VUNSIGN:
 			if (uval > v->longestu) {
-				fmtlen = (int)log10((double)uval) + 1;
 				v->longestu = uval;
-				v->width = fmtlen;
+				v->width = iwidth(uval);
 			}
 			return;
 		case VPTR:
@@ -1121,4 +1119,77 @@
 
 	v = ve->var;
 	printval((char *)k + v->off, v, mode);
+}
+
+void
+puvar(k, ve, mode)
+	struct kinfo_proc2 *k;
+	VARENT *ve;
+	int mode;
+{
+	VAR *v;
+
+	v = ve->var;
+
+	if (!k->p_uvalid) {
+		if (mode == PRINTMODE)
+			(void)printf("%*s", v->width, "-");
+		return;
+	}
+
+	printval((char *)k + v->off, v, mode);
+}
+
+void
+putimeval(k, ve, mode)
+	struct kinfo_proc2 *k;
+	VARENT *ve;
+	int mode;
+{
+	VAR *v = ve->var;
+	ulong secs = *(uint32_t *)((char *)k + v->off);
+	ulong usec = *(uint32_t *)((char *)k + v->off + sizeof (uint32_t));
+	int fmtlen;
+
+	if (!k->p_uvalid) {
+		if (mode == PRINTMODE)
+			(void)printf("%*s", v->width, "-");
+		return;
+	}
+
+	if (mode == WIDTHMODE) {
+		if (!secs)
+			/* zero doesn't give correct width... */
+			secs = 1;
+		if (secs > v->longestu) {
+			v->longestu = secs;
+			if (secs <= 999)
+				/* sss.ssssss */
+				fmtlen = iwidth(secs) + 6 + 1;
+			else
+				/* hh:mm:ss.ss */
+				fmtlen = iwidth((secs+1)/3600)
+					+ 2 + 1 + 2 + 1 + 2 + 1;
+			if (fmtlen > v->width)
+				v->width = fmtlen;
+		}
+		return;
+	}
+
+	if (secs < 999)
+		(void)printf( "%*lu.%.6lu", v->width - 6 - 1, secs, usec);
+	else {
+		uint h, m;
+		usec += 5000;
+		if (usec >= 1000000) {
+			usec -= 1000000;
+			secs++;
+		}
+		m = secs / 60u;
+		secs -= m * 60u;
+		h = m / 60u;
+		m -= h * 60u;
+		(void)printf( "%*u:%.2u:%.2lu.%.2lu", v->width - 9, h, m, secs, usec / 10000u );
+	}
+
 }
Index: ps.h
===================================================================
RCS file: /cvsroot/basesrc/bin/ps/ps.h,v
retrieving revision 1.18
diff -u -r1.18 ps.h
--- ps.h	2002/04/24 21:41:22	1.18
+++ ps.h	2002/08/06 16:56:31
@@ -64,7 +64,7 @@
 	short	width;		/* printing width */
 	/*
 	 * The following (optional) elements are hooks for passing information
-	 * to the generic output routine: pvar (that which prints simple
+	 * to the generic output routine: p[u]var (that which prints simple
 	 * elements from struct kinfo_proc2).
 	 */
 	int	off;		/* offset in structure */
>Release-Note:
>Audit-Trail:
>Unformatted: