sued to root.
He was using the command
who am i -- reasonable, since
it's been a staple since the early days of Unix. For those not familiar
with the command,
/usr/bin/who, if given two arguments,
regardless of what those arguments are, will print information about
the current logged-in user. It also offers a
to do the same thing. So
who am i,
who a b,
who -m should all print a line like:
$ who am i akkana pts/1 2010-09-29 09:33 (:0.0)
Except they don't. For me, they printed nothing at all -- which broke my colleague's install script.
A quick poll among friends on IRC showed that
who am i
worked for some people, failed for others, with no obvious logic to it.
It's the terminal
It took some digging to find out what was going on, but the difference
turned out to be the terminal being used. The
-- with or without -m -- gets its info from /var/run/utmp, a
file that maintains a record of who's logged in to the system.
And it turns out some terminals create a utmp entry, while others don't.
|Program||Creates utmp entry?|
I use xterm myself. Xterm is documented (in its man page) to modify
the utmp entry, and it has a command-line flat,
plus two X resources,
None of the three work: setting
XTerm*ptyHandshake: true XTerm*utmpInhibit: falsethen running
xterm +utstill doesn't show up in
who. I guess that's a bug in xterm (or Ubuntu's version of xterm).
How do you get the real user?
who am i clearly isn't a reliable way of getting
the user ID. What can you use instead?
Several people suggested the
id program. It has a
option which supposedly prints the real UID. Unfortunately, what it
really does is print:
$ id -r id: cannot print only names or real IDs in default formatThe man page doesn't offer any suggestions how to use a format other than default, so we're kinda stuck there.
Update: people keep suggesting
id -ru to me.
Evidently I wasn't very clear in this article: the goal is to
get the real id of the login user.
In other words, if you're logged in as mary and using sudo,
you want mary, not root.
Alas, adding -u to id's flags gets only the effective user id: -u
wins over -r. This is very easy to test:
sudo id -ru
prints 0, as does
id -ru inside su.
But elly on Freenode had a great suggestion:
stat -c '%U' `readlink /proc/self/fd/0`What does this do?
/proc/self is a symlink to
a directory where you can find out all sorts of information about
One of the things you can find out about a process is open file
descriptors: in particular, standard input, output and error.
So /proc/self/fd/0 corresponds to standard input
of the current process -- which in the example above is
What is readlink? Well,
/proc/self/fd/0, in the normal case,
is actually a symlink to the terminal controlling the process.
readlink prints the file to which that link points --
for instance, /dev/pts/1. That's the terminal being used.
Now that we know the name of the terminal, all we need to do is find out
who owns it. (This is the information
who am i would have
gotten from utmp, had there been a utmp entry.)
ls -l /dev/pts/1 will show you that it's you, even if you
run it as
sudo ls -l /dev/pts/1. You could take that and
strip off fields to get the username, but
stat, as elly
suggested, is a much better way of doing that.
Put it all together, and
stat -c '%U' `readlink /proc/self/fd/0
gets standard input for the current process, follows the link to get
the controlling terminal, then finds out who owns that terminal.
A similar but slightly shorter solution suggested by Mikachu:
stat -c %u `tty`
[ 16:39 Sep 29, 2010 More linux/cmdline | permalink to this entry ]