Monday, 5 September 2011

Protecting your shell prompt when accessing a chroot

If you run any chroot environments such as schroot, they will generally set your prompt as a reminder that you are actually running within a chroot. For example with schroot, I have:

$ schroot -c oneiric
(oneiric):~$ echo hello
hello
(oneiric):~$ exit
$ 


When you're in the chroot, you get the chroot name prepended to the prompt (here "(oneiric)"). But if you play tricks with your prompt variables (PS1, PS2, etc) using maybe the magic bash PROMPT_COMMAND variable, you need to take care. I use screen, tmux, or byobu so need to take twice the amount of care since:

  • I modify my prompt quite extensively
  • I only have 1 window which multiplexes all my terminals
    (it's easier to make a mistake :)
The problem is that if you forget which window you're in, you may end up modifying the wrong environment - installing packages in a minimal chroot rather than in your main (non-chroot) environment, or maybe trashing your live system rather than a throw-away chroot!


The solution I've adopted is extremely simple: make use of the a simple shell feature that really should get more air-time: read-only variables. Simply modify the prompt variables in your chroot to be read-only. Once done, their value cannot be changed, so they will always show you that you're in a chroot.

To create a read-only variable with bash, use "typeset -r". For example:

$ typeset -r foo=bar
$ echo $foo
bar
$ foo=hello
bash: foo: readonly variable
$ echo $?
1
$

Here's a script fragment I run whenever I create a new chroot:

for file in /srv/chroots/*/etc/bash.bashrc
do
  grep "^PS1=.*debian_chroot" $file &>/dev/null
  if [ $? -eq 0 ]
  then
    # make variable read-only to ensure my clever prompt setting (with
    # screen, etc) don't overwrite the chroot prompt!!
    sudo sed -i 's/^\(PS1=.*$\)/typeset -r \1/g' $file
  else
    echo "ERROR: You need to ensure PS1 shows chroot name" >&2
    exit 1
  fi
done

Now, when I enter a chroot from an environment that attempts to change my prompt I get:

$ schroot -c oneiric
-bash: PS1: readonly variable
(oneiric):~$ 

The message is bash telling me (well, my scripts) that it will not honour the request to change the value of PS1. Yeah, it's slightly icky seeing this warning message, but it's a good reminder of what is going on.

Read-only variables have other uses, particularly for sysadmins that wish to constrain a users activities. For example, it is possible to "lock-down" PATH by making it a read-only variable. However, it's easy to get tripped up with read-onlies:

$ echo $PWD
/home/james
$ typeset -r PWD
$ cd /
-bash: PWD: readonly variable
$ echo $PWD
/home/james
$ pwd
/
$

Oops! :)