Shallow Thoughts : : Sep
Akkana's Musings on Open Source Computing and Technology, Science, and Nature.
Wed, 29 Sep 2010
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 you
sudo
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: false
then 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 format
The 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`
Tags: linux, cmdline
[
17:39 Sep 29, 2010
More linux/cmdline |
permalink to this entry |
]
Sun, 26 Sep 2010
Dave was using some old vacation photos to test filesystem performance,
and that made me realize that I had beautiful photos from the same
trip that I hadn't yet turned into desktop backgrounds.
Sometimes I think that my
GIMP Wallpaper
script is the most useful of the GIMP plug-ins I've written.
It's such a simple thing ... but I bet I use it more than any of
my other plug-ins, and since I normally make backgrounds for at least
two resolutions (my 1680x1050 desktop and my 1366x768 laptop),
it certainly saves me a lot of time and hassle.
But an hour into my background-making, I started to have nagging doubts.
I wasn't renaming these images, just keeping the original filenames
from the camera, like pict0828.jpg. What if if some of these
were overwriting images of the same name?
The one thing my script doesn't do is check for that, and
gimp_file_save
doesn't pop up any warnings.
I've always meant to add a check for it.
Of course, once the doubts started, I had to stop generating backgrounds
and start generating code. And I'm happy with the result:
wallpaper-0.4.py warns and won't let you save over an old background
image, but keeps all the logic in one dialog rather than popping up
extra warnings.
Now I can generate backgrounds without worrying that I'm stomping on
earlier ones.
Tags: gimp, programming, gtk
[
22:25 Sep 26, 2010
More gimp |
permalink to this entry |
]
Thu, 23 Sep 2010
I've been learning CouchDB, the hot NoSQL database, as part of my
new job. It's interesting -- a very different mindset compared to
classic databases like MySQL.
There's a fairly good Python package for it, python-couchdb ...
but the documentation is somewhat incomplete and there's very little
else written about it, and virtually no sample code to steal.
That makes it a perfect topic for a Linux Planet tutorial!
So here it is, Part 1:
Snakes
on a Couch! Using Python with CouchDB.
I have a rather fun application for the database I introduce in the
article, but you'll have to wait until Part 2, two weeks from now,
to see the details.
Tags: writing, python, programming, database, couchdb
[
11:55 Sep 23, 2010
More writing |
permalink to this entry |
]
Mon, 13 Sep 2010
I've been setting up a new Lenovo X201 laptop at work.
(Yes, work -- I've somehow fallen into an actual job where I go in to
an actual office at least some of the time. How novel!)
At the office I have a Lenovo docking station, attached to a monitor
and keyboard. The monitor, naturally, has a different resolution from
the laptop's own monitor.
Under Gnome and compiz, when I plugged in the monitor, I could either let
the monitor mirror the laptop display -- in which case X would refuse to
work at greater than 1024x768, much smaller than the native resolution
of either the laptop screen or the external monitor -- or I could call
up the classic two-monitor configuration dialog, where I could
configure the external monitor to be its correct size and sit
alongside the computer's monitor. I had to do this every time I
plugged in.
If I wanted to work on the big screen,
then when I undocked, I had to drag all the windows on all desktops
back to the built-in LCD first, or they'd be lost.
Using just the external monitor and turning off the laptop screen
didn't seem to be an allowed option.
That all lasted for about two days. Gnome and I just don't get along.
Pretty soon gdm was mysteriously refusing to let me log in (probably didn't
like my under-1000 user id), and after wasting half a day fighting
it I gave up and reverted with relief to my familiar Openbox desktop.
But now I'm in the Openbox world and don't have that dialog anyway.
What are my options?
xrandr monitor detection
Fortunately, I already knew about
using
xrandr to send to a projector; it was only a little more complicated
using it for the monitor in the docking station. Running xrandr with
no arguments prints all the displays it currently sees, so you can tell
whether an external display or projector is connected and even what
resolutions it supports.
I used that for a code snippet in my .xinitrc:
# Check whether the external monitor is connected: returns 0 on success
xrandr | grep VGA | grep " connected "
if [ $? -eq 0 ]; then
xrandr --output VGA1 --mode 1600x900;
xrandr --output LVDS1 --off
else
xrandr --output VGA1 --off
xrandr --output LVDS1 --mode 1280x800
fi
That worked nicely. When I start X it checks for an external monitor,
and if it finds one it turns off the laptop display (so it's off when
the laptop is sitting closed in the docking station) and sets the
screen size for the external monitor.
Making it automatic
All well and good. I worked happily all day in the docking station,
suspended the laptop and un-docked it, brought it home, woke it up --
and of course the display was still off. Oops.
Okay, so it also needs the same check when resuming from suspend.
That used to be in /etc/acpi/resume.d, but in Lucid they've
moved it (because we definitely wouldn't want users to get complacent
and think they know how to configure things!) and now it lives in
/etc/pm/sleep.d. I created a new file,
/etc/pm/sleep.d/20_enable_display which looks like this:
#!/bin/sh
case "$1" in
resume)
# Check whether the external monitor is connected:
# returns 0 on success
xrandr | grep VGA | grep " connected "
if [ $? -eq 0 ]; then
xrandr --output VGA1 --mode 1600x900
xrandr --output LVDS1 --off
else
xrandr --output VGA1 --off
xrandr --output LVDS1 --mode 1280x800
fi
hsetroot -center `find -L $HOME/Backgrounds -name "*.*" | $HOME/bin/randomline`
;;
suspend|hibernate)
;;
*)
;;
esac
exit $?
Neat! Now, every time I wake from suspend, the laptop checks whether
an external monitor is connected and sets the resolution accordingly.
And it re-sets the background (using my
random
wallpaper method) so I don't get a tiled background on the big monitor.
Update: hsetroot -fill works better than -center
given that I'm displaying background images on two different
resolutions. Of course, if I wanted to get fancy I could make
separate background sets, one for each monitor, and choose images
from the appropriate set.
We're almost done. Two more possible adjustments.
Detecting undocking
First, while poking around in /etc/acpi I noticed a script
named undock.sh. In theory, I can put the same code snippet in
there, and then if I un-dock the laptop without suspending it first,
it will immediately change resolution. I haven't actually tried that yet.
Projectors
Second, this business of turning off the built-in display if there's
anything plugged into the VGA port is going to break if I use this
laptop for presentations, since a projector will also show up as VGA1.
So the code may need to be a little smarter. For example:
xrandr | grep VGA | grep " connected " | grep 16.0x
The theory here is that an external monitor will be able to do 1680 or
1600, so it will have a line like
VGA1 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 434mm x 270mm
.
The 1680x matches the 16.0x pattern in grep.
A projector isn't likely to do more than 1280, so it won't match the
pattern '16.0x'. However, that isn't very robust; it will probably
fail for one of those fancy new 1920x1080 monitors.
You could extend it with
xrandr | grep VGA | grep " connected " | egrep '16.0x|19.0x'
but that's getting even more hacky ... and it might be time to start
writing some more intelligent code.
Which doubtless I'll do if I ever get a 1920x1080 monitor.
Tags: linux, X11, laptop
[
23:11 Sep 13, 2010
More linux/laptop |
permalink to this entry |
]
Thu, 09 Sep 2010
Part 2 in my Hugin series is out, in which I discuss how to rescue
difficult panoramas that confuse Hugin.
Hugin is an amazing program, but if you get outside the bounds of
the normal "Assistant" steps, the user interface can be a bit
confusing -- and sometimes it does things that are Just Plain Weird.
But with help from some folks on IRC, I found out that a newer
version of Hugin can fix those problems, and worked out how to do
it (as well as lots of ways that seemed like they should work, but
didn't).
Read the gory details in:
Hugin
part 2: Rescuing Difficult Panoramas.
There will be a Hugin Part 3, and possibly even a Part 4, discussing
things Hugin can do beyond panoramas.
Tags: writing, linux, graphics, panorama, hugin
[
14:58 Sep 09, 2010
More writing |
permalink to this entry |
]
Fri, 03 Sep 2010
A couple of weeks ago I posted about
fontasia,
my new font-chooser app.
It's gone through a couple of revisions since then, and Mikael Magnusson
contributed several excellent improvements, like being able to
render each font in the font list.
I'd been holding off on posting 0.3, hoping to have time to do
something about the font buttons -- they really need to be smaller,
so there's space for more categories. But between a new job and
several other commitments, I haven't had time to implement that.
And the fancy font list is so cool it really ought to be shared.
So here it is: fontasia 0.3.
Tags: fonts, programming, python
[
10:31 Sep 03, 2010
More programming |
permalink to this entry |
]