How to configure Bourne-based shells to run shell commands in every instance of a shell on a system. This allows environment settings to be changed everywhere without having to logout. For example, all shells can be reconfigured for a new ssh-agent process.
The configuration requires setting a shell trap handler for a kill(1) signal. The trap handler reads shell commands from the file ~/.sh-sourceall and sets them in the current shell environment. The script allsh writes user supplied shell commands into the ~/.sh-sourceall file, then send a USR2 signal to all instances of the shell. The shells then source the shell commands to run from the ~/.sh-sourceall file.
This method should not be used for the superuser account, or where malicious access to the ~/.sh-sourceall file might be possible due to permission problems or the use of an insecure network file system to mount home directories. Denial of service conditions may also be possible if users are able to signal the shell commands of other users, forcing frequent reads on ~/.sh-sourceall.
Shells with poor signal handling such as csh or tcsh will likely not be able to take advantage of this method. Currently, I have only used this method under zsh, though bash and other Bourne-based shells should work.
Shell Configuration
- bash
- zsh
Set the following in ~/.bashrc to configure a USR2 handler.
TRAPUSR2() {
[ -f ~/.sh-sourceall ] && . ~/.sh-sourceall
}
trap TRAPUSR2 USR2
In ~/.zshrc, create a TRAPUSR2 handler to source in the ~/.sh-sourceall file when a USR2 signal is received. Then, quit and restart all shells manually, as zsh may quit if a USR2 signal is sent without a handler for it.
TRAPUSR2() {
[ -f ~/.sh-sourceall ] && . ~/.sh-sourceall
}
allsh Script
The allsh command writes arbitrary shell commands into the ~/.sh-sourceall file, then signals running shells with the USR2 signal. If properly configured and signaled, the shells should read in the commands and run them. For instance, an environment variable can be set in each shell, then unset.
$ allsh export FOO=bar
$ echo $FOO
bar
$ allsh unset FOO
$ echo $FOO
$ cat ~/.sh-sourceall
unset FOO
Another use of allsh would be to read in shell settings from a file written by a command such as ssh-agent. If reading commands from a file via standard input, the - option to allsh must be used, as otherwise allsh assumes the arguments are the commands to be run.
$ echo $SSH_AGENT_PID
$ allsh - < ~/.ssh-agent
$ echo $SSH_AGENT_PID
26391
For more information on setting up ssh-agent, see OpenSSH Public Key Authentication.
Problems
There may be solutions to these problems, though I have not had time yet to investigate them more.
- Refresh
- Security
Have not found a solution to the lack of refresh problem in zsh, whereby the working directory for all open shells can be changed, though the prompt does not update until something is changed in each session in turn. To at least clear the screen on all shells to indicate that a global action has happened, use echoti clear for zsh.
$ allsh 'cd $HOME; echoti clear'
The known file location and signal handling is something of a kluge, and a security risk if an attacker can alter the contents of the ~/.sh-sourceall file. A better solution might involve a pipe or socket that all the shells read from, though that may require adding new code to the shell. The risk is likely no worse than attacks against other shell initialization files such as ~/.profile.
There might also be denial of service conditions possible, dependent on what users have permission to signal the shells, and the contents of the shared ~/.sh-sourceall file.