You'll find, in archives from hacking sites of the era, a whole variety of "utmp editors".
On FreeBSD, for example, one can do everything except filter out the terminals where no-one is logged on yet and print a "FROM" column.
who is the focus of Chapter 2.
On my Mac it seems any two arguments are allowed as an alias for "am i", so long as the first doesn't start with "-".
Looking it up, https://unix.stackexchange.com/questions/108145/is-who-mom-l... suggests it's a well-known in-joke.
FWIW, on my FreeBSD machine, only "who am i"/"who am I" are allowed.
And there is no point in setting the locale, since your program never uses it.
(OK w -f shows this)
This is why I love computing. It's putting abject insanity to good use.
[0] https://github.com/coreutils/coreutils/blob/master/src/who.c
I see some comments here citing a lack of options, most of which appear to have nothing to do with who is logged into the machine.
* Don't parse the output of ps, unless it is my ps command (or plan 9's one, as here). See https://unix.stackexchange.com/a/593198/5132 and https://unix.stackexchange.com/a/578816/5132 , and their further reading, especially Greg Wooledge's article.
* /proc is as portable as ps, but that doesn't really amount to much because neither is really portable at all. Pretty much every operating system's /proc is different; and no implementation of the ps command fully conforms to even the limited subset laid out in the Single Unix Specification.
So maybe yes.
http://cvsweb.openbsd.org/src/usr.bin/who/who.c?rev=1.29&con...
this version appears to derive from rewriting unix who in the 4.4BSD era to replace AT&T code (copyright 1989 / no AT&T in header notes as basis for assumption)
it's not quite an apples to apples comparison as his rewrite doesn't handle any options or cleverness, but it's still a massive jump in LOC.
As a concrete example, the linked-to "who" uses:
if (entry.ut_type != USER_PROCESS)
continue;
The GNU one uses: if (IS_USER_PROCESS (utmp_buf))
The IS_USER_PROCESS() macro is in gnulib's readutmp.h (which would need to be included in the overall line cound): # define IS_USER_PROCESS(U) \
(UT_USER (U)[0] \
&& (UT_TYPE_USER_PROCESS (U) \
|| (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (U) != 0)))
The UT_USER maps to ut_user on some systems, and ut_name on others: /* Accessor macro for the member named ut_user or ut_name. */
# if HAVE_UTMPX_H
# if HAVE_STRUCT_UTMPX_UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_user)
# endif
# if HAVE_STRUCT_UTMPX_UT_NAME
# undef UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_name)
# endif
This is because, as
https://www.gnu.org/software/libc/manual/html_node/Logging-I... points out, "Note that the ut_user member of struct utmp is called ut_name in BSD. Therefore, ut_name is defined as an alias for ut_user in utmp.h"Each of those other macros supports cases where the machine supports a given test, and when it doesn't. Including for machines which don't implement ut_type! (That's what the UT_TYPE_NOT_DEFINED case is for, which falls back to using the time field ... which has its own set of variants!)
Portability is neither options nor cleverness, so I added it to the list of considerations. But then again, most people now don't need to support decades of history and scores of Unix variants.