"Who am I?" Maybe nobody!
We hit an interesting problem at work recently. A coworker made a deb package which, during installation, needed to figure out the ID of the user running it, so it could make files writable by that user. Of course, while a package is being installed it's run by root, so the trick is to find out who you were before yousudo
ed
or su
ed 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 -m
option
to do the same thing. So who am i
, who a b
,
and 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 who
program
-- 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.
So:
Program | Creates utmp entry? |
gnome-terminal | yes |
konsole | yes |
xterm | no |
xfterm4 | yes |
terminator | no |
rxvt | no |
roxterm | yes |
I use xterm myself. Xterm is documented (in its man page) to modify
the utmp entry, and it has a command-line flat, +ut
,
plus two X resources, ptyHandshake
and utmpInhibit
.
None of the three work: setting
XTerm*ptyHandshake: true XTerm*utmpInhibit: falsethen running
xterm +ut
still 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?
Okay, so 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 -r
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 /proc/pid
,
a directory where you can find out all sorts of information about
a process.
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 readlink
.
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.
That's you!
A similar but slightly shorter solution suggested by Mikachu:
stat -c %u `tty`
[ 17:39 Sep 29, 2010 More linux/cmdline | permalink to this entry | ]