7 ms·
The Unix `Who` Command
- eesmith 6y agoI was confused - is "who mom hates" supposed to do something interesting? 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-likes-a-real-linux-command 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.
- dredmorbius 6y agoAny two non-option arguments returns the user of the invoking tty. "who is awesome" or "who foo bar" achieves the same result.
- throwaway287391 6y agoI was confused because when I'm in tmux `who am i` (or `who mom hates` or `who -m`) prints nothing. I thought that might've been the joke -- I'm nobody (or something). When I detach from tmux and run it in the login shell directly it works as expected. The phrasing in the man page ("'am i' or 'mom likes' are usual.") is also pretty strange.
- formerly_proven 6y agowho is 66 % waste: w is 300 % shorter and shows up to 721 % more valuable information.
- x87678r 6y agowho shows where the session is coming from which is useful for me where random people connect with the same system account. (OK w -f shows this)
- salawat 6y agoThere's something delightfully absurd about invoking who and getting told where they're logging in from. There's an Abbot and Costello skit in there waiting to come out. This is why I love computing. It's putting abject insanity to good use.
- iso1210 6y agoI was hoping to see why who was better than w or similar, instead I was pleasently surprised to find someone taking a really simple unix command, reverse engineering it, and reimplementing it
- chard_slicks_ 6y agoHis "who" implementation is 73 lines (21 if you remove blank lines and comments). Compare that to 836 in GNU Coreutils[0]. [0] https://github.com/coreutils/coreutils/blob/master/src/who.c https://github.com/coreutils/coreutils/blob/master/src/who.c
- BuildTheRobots 6y ago> Of course, this only mocks the most basic features of the who command and doesn’t handle any option, like the famous `who am i` or `who mom hates`. 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.
- eesmith 6y agoNor is it anywhere near as portability. Though that's not a big issue these days.
- chard_slicks_ 6y agoIf you don't care about all the features then Busybox's implementation will work fine at 170 lines inclusive of comments.
- eesmith 6y agoWow, I touched a nerve I don't understand, to get a -1, so I'll explain myself. The GNU code looks like it's portable to a bunch of OSes, some with and some without a given feature. That sort of portability leads to having a lot of #ifdefs. If you're only going to support a handful of OSes - because that's all most people care about - then of course your code is going to be smaller. 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-In-and-Out.html 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.
- peter_retief 6y agoI love your simple demonstration of strace reverse engineering a UNIX command. Probably a very silly question but I get this compile error? mywho.c:8:13: error: use of undeclared identifier 'LC_ALL' setlocale(LC_ALL, ""); I should solve it myself but since you are here?
- forgotpwd16 6y agoNot the author as I had the same issue, add `#include <locale.h>` after the other headers.
- peter_retief 6y agoThanks for the help! It works!
- cptnapalm 6y agoUnderstanding UNIX/LINUX Programming: A Guide to Theory and Practice by Bruce Molay is a work which has the reader learn system programming by re-implementing UNIX commands. who is the focus of Chapter 2.
- lovehashbrowns 6y agoHow useful is that book nowadays? Is it still worth purchasing?
- audiometry 6y agoYeah wondering if this would be interesting to do as a recreation project. Is copyright 2003 and mostly unvailable -- Amazon dares to "rent" it to me for 45$.... give me a break.
- cptnapalm 6y agoI was messing with it a bit several months ago. You'd have to look up newer data structures, but just looking up the man pages gave me the necessary information. While the implementation may be different now, the fundamentals of UNIX are pretty much the same.
- deleted 6y ago[deleted]
- dn3500 6y agoThe comment "initialize the utmp structure" is wrong. You have declared the struct here but it is uninitialized. And there is no point in setting the locale, since your program never uses it.
- tptacek 6y agoIt's funny to me, because the way I came up in Unix, `utmp` was one of the first things you learned about: you were using Unix not because you installed it but because every system you might want to break into (for instance, to get to IRC through an outdial or a gateway) was running it, and they were all multi-user shell machines, and you wanted to make sure you weren't showing up in `who`. I probably knew the `utmp` format before I knew how to use `find`. You'll find, in archives from hacking sites of the era, a whole variety of "utmp editors".
- JdeBP 6y agoThanks to setlogin()/getlogin() some operating systems are frustratingly close to the point where all of the relevant information can be read straight out of the kernel's process table, without need for coöperatively maintaining a data file. 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.
- indigodaddy 6y agoI’ve found grep to be unreliable or behave unexpectedly with strace. Even when piping to strings first, although not sure if that is of any consequence. Anyone know why that is or experienced the same?
- dn3500 6y agoYou know it outputs to stderr, right? Also if you give it the option "-o -" it doesn't do what you might expect. Other than that I grep the output of strace all the time and it works for me.
- neallindsay 6y agoI was legitimately confused for a second when I saw `Who` capitalized, but it must have been some automatic HN formatting - it's lower-case is the linked blog post.
- Tepix 6y agoNice article. Reading the ‚who(1)‘ manpage would also have revealed ‚utmp‘ to be the relevant file, of course.