git: 090f0e5820ef - main - ps(1): Keywords: New UNSPEC type, rename 'alias', re-order fields

From: Olivier Certner <olce_at_FreeBSD.org>
Date: Mon, 28 Apr 2025 12:23:26 UTC
The branch main has been updated by olce:

URL: https://cgit.FreeBSD.org/src/commit/?id=090f0e5820efc7f9459d1e4eb1be17fb98848df5

commit 090f0e5820efc7f9459d1e4eb1be17fb98848df5
Author:     Olivier Certner <olce@FreeBSD.org>
AuthorDate: 2025-04-25 12:16:56 +0000
Commit:     Olivier Certner <olce@FreeBSD.org>
CommitDate: 2025-04-28 11:56:54 +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
---
 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 37a4a1711445..8fc42d8675e5 100644
--- a/bin/ps/keyword.c
+++ b/bin/ps/keyword.c
@@ -57,185 +57,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);
 
@@ -322,9 +327,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
@@ -332,7 +337,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
@@ -340,11 +345,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 b496858c071b..2f17abdfdde2 100644
--- a/bin/ps/print.c
+++ b/bin/ps/print.c
@@ -747,6 +747,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;
@@ -777,6 +781,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 1787af33021e..f52f67f50151 100644
--- a/bin/ps/ps.h
+++ b/bin/ps/ps.h
@@ -32,7 +32,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;
@@ -65,8 +66,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) */
@@ -82,7 +85,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"