git: 8cc27ecb1971 - stable/14 - ps(1): Keywords: New UNSPEC type, rename 'alias', re-order fields

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Thu, 01 May 2025 19:51:35 UTC
The branch stable/14 has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=8cc27ecb19711c62903bd82233334181fd854457

commit 8cc27ecb19711c62903bd82233334181fd854457
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-04-25 12:16:56 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-05-01 19:37:03 +0000

    ps(1): Keywords: New UNSPEC type, rename 'alias', re-order fields
    
    This is in preparation for a change in how aliases are resolved, itself
    in preparation for being able to quickly identify columns displaying the
    same information (same final keyword).
    
    Add the new UNSPEC ("unspecified") type, as the keywords' type field is
    only used by the kvar() and rvar() output routines, and has no meaning
    for alias keywords.  In particular, this will allow to check that no
    specific type is associated to any alias.  An immediate benefit is that
    now most keywords have UNSPEC as their "type", which now makes
    kvar()/rvar() explicitly fail (instead of trying to print a character,
    as the previous CHAR type was requesting).  A developer introducing new
    keywords via copy-paste will thus be reminded that it also needs to set
    'type' meaningfully if using kvar()/rvar() as the output routine.
    
    Rename field 'alias' of keywords ('VAR' type) into 'aliased'.  Move it
    just after the keyword's name, as it makes it easier to spot aliases in
    the list.  Make it a union, as a subsequent commit will... alias it with
    a pointer to another 'VAR' structure.  Turn aliases' header string (""
    for all aliases) into NULL.  It is currently not used, but will be when
    introducing the new "merge" procedure for aliases (where it will mean:
    Use the header of the aliased keyword).
    
    While here, rename vars[] into the more descriptive keywords[].
    
    MFC after:      3 days
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 090f0e5820efc7f9459d1e4eb1be17fb98848df5)
---
 bin/ps/keyword.c | 349 ++++++++++++++++++++++++++++---------------------------
 bin/ps/print.c   |   7 ++
 bin/ps/ps.h      |   9 +-
 3 files changed, 190 insertions(+), 175 deletions(-)

diff --git a/bin/ps/keyword.c b/bin/ps/keyword.c
index 40986550b92b..154d26039cdb 100644
--- a/bin/ps/keyword.c
+++ b/bin/ps/keyword.c
@@ -63,185 +63,190 @@ static int  vcmp(const void *, const void *);
 #define	PIDFMT	"d"
 
 /* PLEASE KEEP THE TABLE BELOW SORTED ALPHABETICALLY!!! */
-static VAR var[] = {
-	{"%cpu", "%CPU", NULL, "percent-cpu", 0, pcpu, 0, CHAR, NULL},
-	{"%mem", "%MEM", NULL, "percent-memory", 0, pmem, 0, CHAR, NULL},
-	{"acflag", "ACFLG", NULL, "accounting-flag", 0, kvar, KOFF(ki_acflag),
-	    USHORT, "x"},
-	{"acflg", "", "acflag", NULL, 0, NULL, 0, CHAR, NULL},
-	{"args", "COMMAND", NULL, "arguments", COMM|LJUST|USER, arguments, 0,
-	    CHAR, NULL},
-	{"blocked", "", "sigmask", NULL, 0, NULL, 0, CHAR, NULL},
-	{"caught", "", "sigcatch", NULL, 0, NULL, 0, CHAR, NULL},
-	{"class", "CLASS", NULL, "login-class", LJUST, loginclass, 0, CHAR,
-	    NULL},
-	{"comm", "COMMAND", NULL, "command", LJUST, ucomm, 0, CHAR, NULL},
-	{"command", "COMMAND", NULL, "command", COMM|LJUST|USER, command, 0,
-	    CHAR, NULL},
-	{"cow", "COW", NULL, "copy-on-write-faults", 0, kvar, KOFF(ki_cow),
-	    UINT, "u"},
-	{"cpu", "C", NULL, "on-cpu", 0, cpunum, 0, CHAR, NULL},
-	{"cputime", "", "time", NULL, 0, NULL, 0, CHAR, NULL},
-	{"dsiz", "DSIZ", NULL, "data-size", 0, kvar, KOFF(ki_dsize), PGTOK,
-	    "ld"},
-	{"egid", "", "gid", NULL, 0, NULL, 0, CHAR, NULL},
-	{"egroup", "", "group", NULL, 0, NULL, 0, CHAR, NULL},
-	{"emul", "EMUL", NULL, "emulation-envirnment", LJUST, emulname, 0,
-	    CHAR, NULL},
-	{"etime", "ELAPSED", NULL, "elapsed-time", USER, elapsed, 0, CHAR,
-	    NULL},
-	{"etimes", "ELAPSED", NULL, "elapsed-times", USER, elapseds, 0, CHAR,
-	    NULL},
-	{"euid", "", "uid", NULL, 0, NULL, 0, CHAR, NULL},
-	{"f", "F", NULL, "flags", 0, kvar, KOFF(ki_flag), LONG, "lx"},
-	{"f2", "F2", NULL, "flags2", 0, kvar, KOFF(ki_flag2), INT, "08x"},
-	{"fib", "FIB", NULL, "fib", 0, kvar, KOFF(ki_fibnum), INT, "d"},
-	{"flags", "", "f", NULL, 0, NULL, 0, CHAR, NULL},
-	{"flags2", "", "f2", NULL, 0, NULL, 0, CHAR, NULL},
-	{"gid", "GID", NULL, "gid", 0, kvar, KOFF(ki_groups), UINT, UIDFMT},
-	{"group", "GROUP", NULL, "group", LJUST, egroupname, 0, CHAR, NULL},
-	{"ignored", "", "sigignore", NULL, 0, NULL, 0, CHAR, NULL},
-	{"inblk", "INBLK", NULL, "read-blocks", USER, rvar, ROFF(ru_inblock),
-	    LONG, "ld"},
-	{"inblock", "", "inblk", NULL, 0, NULL, 0, CHAR, NULL},
-	{"jail", "JAIL", NULL, "jail-name", LJUST, jailname, 0, CHAR, NULL},
-	{"jid", "JID", NULL, "jail-id", 0, kvar, KOFF(ki_jid), INT, "d"},
-	{"jobc", "JOBC", NULL, "job-control-count", 0, kvar, KOFF(ki_jobc),
-	    SHORT, "d"},
-	{"ktrace", "KTRACE", NULL, "ktrace", 0, kvar, KOFF(ki_traceflag), INT,
-	    "x"},
-	{"label", "LABEL", NULL, "label", LJUST, label, 0, CHAR, NULL},
-	{"lim", "LIM", NULL, "memory-limit", 0, maxrss, 0, CHAR, NULL},
-	{"lockname", "LOCK", NULL, "lock-name", LJUST, lockname, 0, CHAR, NULL},
-	{"login", "LOGIN", NULL, "login-name", LJUST, logname, 0, CHAR, NULL},
-	{"logname", "", "login", NULL, 0, NULL, 0, CHAR, NULL},
-	{"lstart", "STARTED", NULL, "start-time", LJUST|USER, lstarted, 0,
-	    CHAR, NULL},
-	{"lwp", "LWP", NULL, "thread-id", 0, kvar, KOFF(ki_tid), UINT,
-	    LWPFMT},
-	{"majflt", "MAJFLT", NULL, "major-faults", USER, rvar, ROFF(ru_majflt),
-	    LONG, "ld"},
-	{"minflt", "MINFLT", NULL, "minor-faults", USER, rvar, ROFF(ru_minflt),
-	    LONG, "ld"},
-	{"msgrcv", "MSGRCV", NULL, "received-messages", USER, rvar,
-	    ROFF(ru_msgrcv), LONG, "ld"},
-	{"msgsnd", "MSGSND", NULL, "sent-messages", USER, rvar,
-	    ROFF(ru_msgsnd), LONG, "ld"},
-	{"mwchan", "MWCHAN", NULL, "wait-channel", LJUST, mwchan, 0, CHAR,
-	    NULL},
-	{"ni", "", "nice", NULL, 0, NULL, 0, CHAR, NULL},
-	{"nice", "NI", NULL, "nice", 0, kvar, KOFF(ki_nice), CHAR, "d"},
-	{"nivcsw", "NIVCSW", NULL, "involuntary-context-switches", USER, rvar,
-	    ROFF(ru_nivcsw), LONG, "ld"},
-	{"nlwp", "NLWP", NULL, "threads", 0, kvar, KOFF(ki_numthreads), UINT,
-	    NLWPFMT},
-	{"nsignals", "", "nsigs", NULL, 0, NULL, 0, CHAR, NULL},
-	{"nsigs", "NSIGS", NULL, "signals-taken", USER, rvar,
-	    ROFF(ru_nsignals), LONG, "ld"},
-	{"nswap", "NSWAP", NULL, "swaps", USER, rvar, ROFF(ru_nswap), LONG,
-	    "ld"},
-	{"nvcsw", "NVCSW", NULL, "voluntary-context-switches", USER, rvar,
-	    ROFF(ru_nvcsw), LONG, "ld"},
-	{"nwchan", "NWCHAN", NULL, "wait-channel-address", LJUST, nwchan, 0,
-	    CHAR, NULL},
-	{"oublk", "OUBLK", NULL, "written-blocks", USER, rvar,
-	    ROFF(ru_oublock), LONG, "ld"},
-	{"oublock", "", "oublk", NULL, 0, NULL, 0, CHAR, NULL},
-	{"paddr", "PADDR", NULL, "process-address", 0, kvar, KOFF(ki_paddr),
-	    KPTR, "lx"},
-	{"pagein", "PAGEIN", NULL, "pageins", USER, pagein, 0, CHAR, NULL},
-	{"pcpu", "", "%cpu", NULL, 0, NULL, 0, CHAR, NULL},
-	{"pending", "", "sig", NULL, 0, NULL, 0, CHAR, NULL},
-	{"pgid", "PGID", NULL, "process-group", 0, kvar, KOFF(ki_pgid), UINT,
-	    PIDFMT},
-	{"pid", "PID", NULL, "pid", 0, kvar, KOFF(ki_pid), UINT, PIDFMT},
-	{"pmem", "", "%mem", NULL, 0, NULL, 0, CHAR, NULL},
-	{"ppid", "PPID", NULL, "ppid", 0, kvar, KOFF(ki_ppid), UINT, PIDFMT},
-	{"pri", "PRI", NULL, "priority", 0, pri, 0, CHAR, NULL},
-	{"re", "RE", NULL, "residency-time", INF127, kvar, KOFF(ki_swtime),
-	    UINT, "d"},
-	{"rgid", "RGID", NULL, "real-gid", 0, kvar, KOFF(ki_rgid), UINT,
-	    UIDFMT},
-	{"rgroup", "RGROUP", NULL, "real-group", LJUST, rgroupname, 0, CHAR,
-	    NULL},
-	{"rss", "RSS", NULL, "rss", 0, kvar, KOFF(ki_rssize), PGTOK, "ld"},
-	{"rtprio", "RTPRIO", NULL, "realtime-priority", 0, priorityr,
-	    KOFF(ki_pri), CHAR, NULL},
-	{"ruid", "RUID", NULL, "real-uid", 0, kvar, KOFF(ki_ruid), UINT,
-	    UIDFMT},
-	{"ruser", "RUSER", NULL, "real-user", LJUST, runame, 0, CHAR, NULL},
-	{"sid", "SID", NULL, "sid", 0, kvar, KOFF(ki_sid), UINT, PIDFMT},
-	{"sig", "PENDING", NULL, "signals-pending", 0, kvar, KOFF(ki_siglist),
-	    INT, "x"},
-	{"sigcatch", "CAUGHT", NULL, "signals-caught", 0, kvar,
-	    KOFF(ki_sigcatch), UINT, "x"},
-	{"sigignore", "IGNORED", NULL, "signals-ignored", 0, kvar,
-	    KOFF(ki_sigignore), UINT, "x"},
-	{"sigmask", "BLOCKED", NULL, "signal-mask", 0, kvar, KOFF(ki_sigmask),
-	    UINT, "x"},
-	{"sl", "SL", NULL, "sleep-time", INF127, kvar, KOFF(ki_slptime), UINT,
-	    "d"},
-	{"ssiz", "SSIZ", NULL, "stack-size", 0, kvar, KOFF(ki_ssize), PGTOK,
-	    "ld"},
-	{"start", "STARTED", NULL, "start-time", LJUST|USER, started, 0, CHAR,
-	    NULL},
-	{"stat", "", "state", NULL, 0, NULL, 0, CHAR, NULL},
-	{"state", "STAT", NULL, "state", LJUST, state, 0, CHAR, NULL},
-	{"svgid", "SVGID", NULL, "saved-gid", 0, kvar, KOFF(ki_svgid), UINT,
-	    UIDFMT},
-	{"svuid", "SVUID", NULL, "saved-uid", 0, kvar, KOFF(ki_svuid), UINT,
-	    UIDFMT},
-	{"systime", "SYSTIME", NULL, "system-time", USER, systime, 0, CHAR,
-	    NULL},
-	{"tdaddr", "TDADDR", NULL, "thread-address", 0, kvar, KOFF(ki_tdaddr),
-	    KPTR, "lx"},
-	{"tdev", "TDEV", NULL, "terminal-device", 0, tdev, 0, CHAR, NULL},
-	{"tdnam", "", "tdname", NULL, 0, NULL, 0, CHAR, NULL},
-	{"tdname", "TDNAME", NULL, "thread-name", LJUST, tdnam, 0, CHAR,
-	    NULL},
-	{"tid", "", "lwp", NULL, 0, NULL, 0, CHAR, NULL},
-	{"time", "TIME", NULL, "cpu-time", USER, cputime, 0, CHAR, NULL},
-	{"tpgid", "TPGID", NULL, "terminal-process-gid", 0, kvar,
-	    KOFF(ki_tpgid), UINT, PIDFMT},
-	{"tracer", "TRACER", NULL, "tracer", 0, kvar, KOFF(ki_tracer), UINT,
-	    PIDFMT},
-	{"tsid", "TSID", NULL, "terminal-sid", 0, kvar, KOFF(ki_tsid), UINT,
-	    PIDFMT},
-	{"tsiz", "TSIZ", NULL, "text-size", 0, kvar, KOFF(ki_tsize), PGTOK,
-	    "ld"},
-	{"tt", "TT ", NULL, "terminal-name", 0, tname, 0, CHAR, NULL},
-	{"tty", "TTY", NULL, "tty", LJUST, longtname, 0, CHAR, NULL},
-	{"ucomm", "UCOMM", NULL, "accounting-name", LJUST, ucomm, 0, CHAR,
-	    NULL},
-	{"uid", "UID", NULL, "uid", 0, kvar, KOFF(ki_uid), UINT, UIDFMT},
-	{"upr", "UPR", NULL, "user-priority", 0, upr, 0, CHAR, NULL},
-	{"uprocp", "UPROCP", NULL, "process-address", 0, kvar, KOFF(ki_paddr),
-	    KPTR, "lx"},
-	{"user", "USER", NULL, "user", LJUST, username, 0, CHAR, NULL},
-	{"usertime", "USERTIME", NULL, "user-time", USER, usertime, 0, CHAR,
-	    NULL},
-	{"usrpri", "", "upr", NULL, 0, NULL, 0, CHAR, NULL},
-	{"vmaddr", "VMADDR", NULL, "vmspace-address", 0, kvar, KOFF(ki_vmspace),
-	    KPTR, "lx"},
-	{"vsize", "", "vsz", NULL, 0, NULL, 0, CHAR, NULL},
-	{"vsz", "VSZ", NULL, "virtual-size", 0, vsize, 0, CHAR, NULL},
-	{"wchan", "WCHAN", NULL, "wait-channel", LJUST, wchan, 0, CHAR, NULL},
-	{"xstat", "XSTAT", NULL, "exit-status", 0, kvar, KOFF(ki_xstat),
-	    USHORT, "x"},
+static VAR keywords[] = {
+	{"%cpu", {NULL}, "%CPU", "percent-cpu", 0, pcpu, 0, UNSPEC, NULL},
+	{"%mem", {NULL}, "%MEM", "percent-memory", 0, pmem, 0, UNSPEC, NULL},
+	{"acflag", {NULL}, "ACFLG", "accounting-flag", 0, kvar, KOFF(ki_acflag),
+	 USHORT, "x"},
+	{"acflg", {"acflag"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"args", {NULL}, "COMMAND", "arguments", COMM|LJUST|USER, arguments, 0,
+	 UNSPEC, NULL},
+	{"blocked", {"sigmask"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"caught", {"sigcatch"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"class", {NULL}, "CLASS", "login-class", LJUST, loginclass, 0,
+	 UNSPEC, NULL},
+	{"comm", {NULL}, "COMMAND", "command", LJUST, ucomm, 0, UNSPEC, NULL},
+	{"command", {NULL}, "COMMAND", "command", COMM|LJUST|USER, command, 0,
+	 UNSPEC, NULL},
+	{"cow", {NULL}, "COW", "copy-on-write-faults", 0, kvar, KOFF(ki_cow),
+	 UINT, "u"},
+	{"cpu", {NULL}, "C", "on-cpu", 0, cpunum, 0, UNSPEC, NULL},
+	{"cputime", {"time"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"dsiz", {NULL}, "DSIZ", "data-size", 0, kvar, KOFF(ki_dsize),
+	 PGTOK, "ld"},
+	{"egid", {"gid"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"egroup", {"group"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"emul", {NULL}, "EMUL", "emulation-envirnment", LJUST, emulname, 0,
+	 UNSPEC, NULL},
+	{"etime", {NULL}, "ELAPSED", "elapsed-time", USER, elapsed, 0,
+	 UNSPEC, NULL},
+	{"etimes", {NULL}, "ELAPSED", "elapsed-times", USER, elapseds, 0,
+	 UNSPEC, NULL},
+	{"euid", {"uid"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"f", {NULL}, "F", "flags", 0, kvar, KOFF(ki_flag), LONG, "lx"},
+	{"f2", {NULL}, "F2", "flags2", 0, kvar, KOFF(ki_flag2), INT, "08x"},
+	{"fib", {NULL}, "FIB", "fib", 0, kvar, KOFF(ki_fibnum), INT, "d"},
+	{"flags", {"f"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"flags2", {"f2"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"gid", {NULL}, "GID", "gid", 0, kvar, KOFF(ki_groups), UINT, UIDFMT},
+	{"group", {NULL}, "GROUP", "group", LJUST, egroupname, 0, UNSPEC, NULL},
+	{"ignored", {"sigignore"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"inblk", {NULL}, "INBLK", "read-blocks", USER, rvar, ROFF(ru_inblock),
+	 LONG, "ld"},
+	{"inblock", {"inblk"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"jail", {NULL}, "JAIL", "jail-name", LJUST, jailname, 0, UNSPEC, NULL},
+	{"jid", {NULL}, "JID", "jail-id", 0, kvar, KOFF(ki_jid), INT, "d"},
+	{"jobc", {NULL}, "JOBC", "job-control-count", 0, kvar, KOFF(ki_jobc),
+	 SHORT, "d"},
+	{"ktrace", {NULL}, "KTRACE", "ktrace", 0, kvar, KOFF(ki_traceflag),
+	 INT, "x"},
+	{"label", {NULL}, "LABEL", "label", LJUST, label, 0, UNSPEC, NULL},
+	{"lim", {NULL}, "LIM", "memory-limit", 0, maxrss, 0, UNSPEC, NULL},
+	{"lockname", {NULL}, "LOCK", "lock-name", LJUST, lockname, 0,
+	 UNSPEC, NULL},
+	{"login", {NULL}, "LOGIN", "login-name", LJUST, logname, 0,
+	 UNSPEC, NULL},
+	{"logname", {"login"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"lstart", {NULL}, "STARTED", "start-time", LJUST|USER, lstarted, 0,
+	 UNSPEC, NULL},
+	{"lwp", {NULL}, "LWP", "thread-id", 0, kvar, KOFF(ki_tid),
+	 UINT, LWPFMT},
+	{"majflt", {NULL}, "MAJFLT", "major-faults", USER, rvar, ROFF(ru_majflt),
+	 LONG, "ld"},
+	{"minflt", {NULL}, "MINFLT", "minor-faults", USER, rvar, ROFF(ru_minflt),
+	 LONG, "ld"},
+	{"msgrcv", {NULL}, "MSGRCV", "received-messages", USER, rvar,
+	 ROFF(ru_msgrcv), LONG, "ld"},
+	{"msgsnd", {NULL}, "MSGSND", "sent-messages", USER, rvar,
+	 ROFF(ru_msgsnd), LONG, "ld"},
+	{"mwchan", {NULL}, "MWCHAN", "wait-channel", LJUST, mwchan, 0,
+	 UNSPEC, NULL},
+	{"ni", {"nice"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"nice", {NULL}, "NI", "nice", 0, kvar, KOFF(ki_nice), CHAR, "d"},
+	{"nivcsw", {NULL}, "NIVCSW", "involuntary-context-switches", USER, rvar,
+	 ROFF(ru_nivcsw), LONG, "ld"},
+	{"nlwp", {NULL}, "NLWP", "threads", 0, kvar, KOFF(ki_numthreads),
+	 UINT, NLWPFMT},
+	{"nsignals", {"nsigs"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"nsigs", {NULL}, "NSIGS", "signals-taken", USER, rvar,
+	 ROFF(ru_nsignals), LONG, "ld"},
+	{"nswap", {NULL}, "NSWAP", "swaps", USER, rvar, ROFF(ru_nswap),
+	 LONG, "ld"},
+	{"nvcsw", {NULL}, "NVCSW", "voluntary-context-switches", USER, rvar,
+	 ROFF(ru_nvcsw), LONG, "ld"},
+	{"nwchan", {NULL}, "NWCHAN", "wait-channel-address", LJUST, nwchan, 0,
+	 UNSPEC, NULL},
+	{"oublk", {NULL}, "OUBLK", "written-blocks", USER, rvar,
+	 ROFF(ru_oublock), LONG, "ld"},
+	{"oublock", {"oublk"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"paddr", {NULL}, "PADDR", "process-address", 0, kvar, KOFF(ki_paddr),
+	 KPTR, "lx"},
+	{"pagein", {NULL}, "PAGEIN", "pageins", USER, pagein, 0, UNSPEC, NULL},
+	{"pcpu", {"%cpu"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"pending", {"sig"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"pgid", {NULL}, "PGID", "process-group", 0, kvar, KOFF(ki_pgid),
+	 UINT, PIDFMT},
+	{"pid", {NULL}, "PID", "pid", 0, kvar, KOFF(ki_pid), UINT, PIDFMT},
+	{"pmem", {"%mem"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"ppid", {NULL}, "PPID", "ppid", 0, kvar, KOFF(ki_ppid), UINT, PIDFMT},
+	{"pri", {NULL}, "PRI", "priority", 0, pri, 0, UNSPEC, NULL},
+	{"re", {NULL}, "RE", "residency-time", INF127, kvar, KOFF(ki_swtime),
+	 UINT, "d"},
+	{"rgid", {NULL}, "RGID", "real-gid", 0, kvar, KOFF(ki_rgid),
+	 UINT, UIDFMT},
+	{"rgroup", {NULL}, "RGROUP", "real-group", LJUST, rgroupname, 0,
+	 UNSPEC, NULL},
+	{"rss", {NULL}, "RSS", "rss", 0, kvar, KOFF(ki_rssize), PGTOK, "ld"},
+	{"rtprio", {NULL}, "RTPRIO", "realtime-priority", 0, priorityr,
+	 KOFF(ki_pri), UNSPEC, NULL},
+	{"ruid", {NULL}, "RUID", "real-uid", 0, kvar, KOFF(ki_ruid),
+	 UINT, UIDFMT},
+	{"ruser", {NULL}, "RUSER", "real-user", LJUST, runame, 0, UNSPEC, NULL},
+	{"sid", {NULL}, "SID", "sid", 0, kvar, KOFF(ki_sid), UINT, PIDFMT},
+	{"sig", {NULL}, "PENDING", "signals-pending", 0, kvar, KOFF(ki_siglist),
+	 INT, "x"},
+	{"sigcatch", {NULL}, "CAUGHT", "signals-caught", 0, kvar,
+	 KOFF(ki_sigcatch), UINT, "x"},
+	{"sigignore", {NULL}, "IGNORED", "signals-ignored", 0, kvar,
+	 KOFF(ki_sigignore), UINT, "x"},
+	{"sigmask", {NULL}, "BLOCKED", "signal-mask", 0, kvar, KOFF(ki_sigmask),
+	 UINT, "x"},
+	{"sl", {NULL}, "SL", "sleep-time", INF127, kvar, KOFF(ki_slptime),
+	 UINT, "d"},
+	{"ssiz", {NULL}, "SSIZ", "stack-size", 0, kvar, KOFF(ki_ssize),
+	 PGTOK, "ld"},
+	{"start", {NULL}, "STARTED", "start-time", LJUST|USER, started, 0,
+	 UNSPEC, NULL},
+	{"stat", {"state"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"state", {NULL}, "STAT", "state", LJUST, state, 0, UNSPEC, NULL},
+	{"svgid", {NULL}, "SVGID", "saved-gid", 0, kvar, KOFF(ki_svgid),
+	 UINT, UIDFMT},
+	{"svuid", {NULL}, "SVUID", "saved-uid", 0, kvar, KOFF(ki_svuid),
+	 UINT, UIDFMT},
+	{"systime", {NULL}, "SYSTIME", "system-time", USER, systime, 0,
+	 UNSPEC, NULL},
+	{"tdaddr", {NULL}, "TDADDR", "thread-address", 0, kvar, KOFF(ki_tdaddr),
+	 KPTR, "lx"},
+	{"tdev", {NULL}, "TDEV", "terminal-device", 0, tdev, 0, UNSPEC, NULL},
+	{"tdnam", {"tdname"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"tdname", {NULL}, "TDNAME", "thread-name", LJUST, tdnam, 0,
+	 UNSPEC, NULL},
+	{"tid", {"lwp"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"time", {NULL}, "TIME", "cpu-time", USER, cputime, 0, UNSPEC, NULL},
+	{"tpgid", {NULL}, "TPGID", "terminal-process-gid", 0, kvar,
+	 KOFF(ki_tpgid), UINT, PIDFMT},
+	{"tracer", {NULL}, "TRACER", "tracer", 0, kvar, KOFF(ki_tracer),
+	 UINT, PIDFMT},
+	{"tsid", {NULL}, "TSID", "terminal-sid", 0, kvar, KOFF(ki_tsid),
+	 UINT, PIDFMT},
+	{"tsiz", {NULL}, "TSIZ", "text-size", 0, kvar, KOFF(ki_tsize),
+	 PGTOK, "ld"},
+	{"tt", {NULL}, "TT ", "terminal-name", 0, tname, 0, UNSPEC, NULL},
+	{"tty", {NULL}, "TTY", "tty", LJUST, longtname, 0, UNSPEC, NULL},
+	{"ucomm", {NULL}, "UCOMM", "accounting-name", LJUST, ucomm, 0,
+	 UNSPEC, NULL},
+	{"uid", {NULL}, "UID", "uid", 0, kvar, KOFF(ki_uid), UINT, UIDFMT},
+	{"upr", {NULL}, "UPR", "user-priority", 0, upr, 0, UNSPEC, NULL},
+	{"uprocp", {NULL}, "UPROCP", "process-address", 0, kvar, KOFF(ki_paddr),
+	 KPTR, "lx"},
+	{"user", {NULL}, "USER", "user", LJUST, username, 0, UNSPEC, NULL},
+	{"usertime", {NULL}, "USERTIME", "user-time", USER, usertime, 0,
+	 UNSPEC, NULL},
+	{"usrpri", {"upr"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"vmaddr", {NULL}, "VMADDR", "vmspace-address", 0, kvar,
+	 KOFF(ki_vmspace), KPTR, "lx"},
+	{"vsize", {"vsz"}, NULL, NULL, 0, NULL, 0, UNSPEC, NULL},
+	{"vsz", {NULL}, "VSZ", "virtual-size", 0, vsize, 0, UNSPEC, NULL},
+	{"wchan", {NULL}, "WCHAN", "wait-channel", LJUST, wchan, 0,
+	 UNSPEC, NULL},
+	{"xstat", {NULL}, "XSTAT", "exit-status", 0, kvar, KOFF(ki_xstat),
+	 USHORT, "x"},
 };
 
+static const size_t known_keywords_nb = nitems(keywords);
+
 void
 showkey(void)
 {
 	const VAR *v;
-	const VAR *const end = var + nitems(var);
+	const VAR *const end = keywords + known_keywords_nb;
 	const char *sep;
 	int i;
 
 	i = 0;
 	sep = "";
 	xo_open_list("key");
-	for (v = var; v < end; ++v) {
+	for (v = keywords; v < end; ++v) {
 		const char *const p = v->name;
 		const int len = strlen(p);
 
@@ -328,9 +333,9 @@ findvar(char *p, struct velisthead *const var_list, int user, char **header)
 		*hp++ = '\0';
 
 	key.name = p;
-	v = bsearch(&key, var, nitems(var), sizeof(VAR), vcmp);
+	v = bsearch(&key, keywords, known_keywords_nb, sizeof(VAR), vcmp);
 
-	if (v && v->alias) {
+	if (v && v->aliased) {
 		/*
 		 * If the user specified an alternate-header for this
 		 * (aliased) format-name, then we need to copy that
@@ -338,7 +343,7 @@ findvar(char *p, struct velisthead *const var_list, int user, char **header)
 		 * process the alias.
 		 */
 		if (hp == NULL)
-			parsefmt(v->alias, var_list, user);
+			parsefmt(v->aliased, var_list, user);
 		else {
 			/*
 			 * XXX - This processing will not be correct for
@@ -346,11 +351,11 @@ findvar(char *p, struct velisthead *const var_list, int user, char **header)
 			 * keywords.  Presently there are no aliases
 			 * which do that.
 			 */
-			rflen = strlen(v->alias) + strlen(hp) + 2;
+			rflen = strlen(v->aliased) + strlen(hp) + 2;
 			realfmt = malloc(rflen);
 			if (realfmt == NULL)
 				xo_errx(1, "malloc failed");
-			snprintf(realfmt, rflen, "%s=%s", v->alias, hp);
+			snprintf(realfmt, rflen, "%s=%s", v->aliased, hp);
 			parsefmt(realfmt, var_list, user);
 			free(realfmt);
 		}
diff --git a/bin/ps/print.c b/bin/ps/print.c
index a3f8f244648d..c12a8dd8fbe1 100644
--- a/bin/ps/print.c
+++ b/bin/ps/print.c
@@ -758,6 +758,10 @@ printval(void *bp, const VAR *v)
 #define	CHKINF127(n)	(((n) > 127) && (v->flag & INF127) ? 127 : (n))
 
 	switch (v->type) {
+	case UNSPEC:
+		xo_errx(1, "cannot print value of unspecified type "
+		    "(internal error)");
+		break;
 	case CHAR:
 		(void)asprintf(&str, ofmt, *(char *)bp);
 		break;
@@ -788,6 +792,9 @@ printval(void *bp, const VAR *v)
 	case PGTOK:
 		(void)asprintf(&str, ofmt, ps_pgtok(*(u_long *)bp));
 		break;
+	default:
+		xo_errx(1, "unknown type (internal error)");
+		break;
 	}
 
 	return (str);
diff --git a/bin/ps/ps.h b/bin/ps/ps.h
index 800e732262e9..7c4c5541b8eb 100644
--- a/bin/ps/ps.h
+++ b/bin/ps/ps.h
@@ -34,7 +34,8 @@
 #include <sys/queue.h>
 
 #define	UNLIMITED	0	/* unlimited terminal width */
-enum type { CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK };
+enum type { UNSPEC, /* For output routines that don't care and aliases. */
+	    CHAR, UCHAR, SHORT, USHORT, INT, UINT, LONG, ULONG, KPTR, PGTOK };
 
 typedef struct kinfo_str {
 	STAILQ_ENTRY(kinfo_str) ks_next;
@@ -67,8 +68,10 @@ STAILQ_HEAD(velisthead, varent);
 /* Structure representing one available keyword. */
 typedef struct var {
 	const char *name;	/* name(s) of variable */
+	union {
+		const char	*aliased; /* keyword this one is an alias to */
+	};
 	const char *header;	/* default header */
-	const char *alias;	/* aliases */
 	const char *field;	/* xo field name */
 #define	COMM	0x01		/* needs exec arguments and environment (XXX) */
 #define	LJUST	0x02		/* left adjust on output (trailing blanks) */
@@ -84,7 +87,7 @@ typedef struct var {
 	 */
 	size_t	off;		/* offset in structure */
 	enum	type type;	/* type of element */
-	const char *fmt;	/* printf format */
+	const char *fmt;	/* printf format (depends on output routine) */
 } VAR;
 
 #include "extern.h"