Zugschlus' Shell Startup Magic
My .bashrc file mainly sets environment variables, defines aliases and shell functions.
Noteworthy features include:
- sources /etc/bashrc if that file exists
- sets umask 002 if the default group has the same name as the account name, 022 otherwise
- Adds more directories to $PATH, but only if they actually exist
- Tries to detect if running in a script(1) process, omitting color and other control characters in various parts of the environment, including ls and the shell prompt
- Sets the user prompt to have a different color than the root prompt, using portable functions to work on nearly all terminal types.
My .bash_profile file sources some other startup files and prints some system operating data.
Noteworthy features include:
Sources ~.profile, ~.bashrc, ~/.bash_initshared, if present.
- Invokes df -h, free, and w, avoiding error messages on systems without /proc mounted or in chroot environments.
- Prints ~/.motd, if present, allowing system local reminders to be displayed.
.xsession-local is not strictly a shell startup file, but I'll document it here as well since it does things quite similiar to the shell startup files.
When logging in to an X session, no login shell is invoked, thus preventing some initialization from happening. To avoid this issue, /etc/X11/Xsession.d/60xfree86-common_user-xsession-local (See #252592) invokes ~.xsession-local, which in my environment adds ~.my/bin to the PATH and sources ~.bash_initshare, as my ~.bash_profile does as well.
As mentioned before, .bash_initshared is invoked both by ~.bash_profile and ~.xsession-local, and is thus the place for init stuff that should be present both in console/ssh logins and in X sessions.
Noteworthy functions include:
- Proxy settings from /etc/use-proxy and ~/.use-proxy are pulled in, if the files are present
- ~/.ssh/authorized_keys is automatically built
- ~/.ssh/config is automatically built
On privately owned machines, I have one key per machine and OS installation, and on office machines, I have one key per machine and OS installation that is used to connect to other office machines, and one key per machine and OS installation that is used to connect to private boxes. That way, I don't lose all my access if I have to pull one key after it has been compromised (for example, if I had to disclose the pass phrase to a colleague on the phone to allow her to fix breakage without having access herself).
This complex setup needs some management since I naturally don't want all keys to be in all authorized_keys files on all boxes.
The keys are separated into classes, and each class has one directory in ~/.ssh/authorized_keys.d/. The variable AKC_CLASSES, set in ~/.ssh/authorized_keys.conf, controls which classes are included in ~/.ssh/authorized_keys. ~.bash_initshared does the job of catting all files from the selected class directories together in ~.ssh/authorized_keys.
Having class directories instead of class files allows some files to be locally present, untouched by the distribution system, while others are changed by some distribution mechanism.
If no ~/.ssh/authorized_keys.conf is found, ~/.ssh/authorized_keys is left alone.
A similiar mechanism is used to build ~/.ssh/config. However, due to my notebook being plugged in to a lot of different networks in front or behind firewalls and NAT mechanisms and being used to connect to a lot of different hosts that might be or not be firewalled, the machinery used to build ~/.ssh/config is a little bit more complicated.
My system uses guessnet-ifupdown to determine which network it is connected to. Additional to some other duties, up/down scripts in /etc/network/interfaces take care of the name of the current network scheme being in /etc/network/schemes/active. ~/.bash_initshared pulls the content of that file in to the environment variable $NW_SCHEME.
The classes of configuration files being included in ~/.ssh/config are controlled by the environment variable C_CLASSES set in ~/.ssh/config.conf. All files found in ~/.ssh/config.d/$class and all files found in ~/.ssh/config.d/$class/$NW_SCHEME are catted together into ~/.ssh/config.
This allows a class to contain hosts that are reachable the same way from everywhere, and hosts that need different config entries (for example a ?ProxyCommand directive if my host is outside on the Internet) as well.
Since ~/.ssh/config is not vital to a remote login, that file is removed if ~/.ssh/config.conf is not present.
My shell init files are distributed to the hosts that I work with in an archive called stdacct. Mechanisms to build and to unpack that archive are present as well.
To allow easy unpacking and cleanup jobs, stdacct is a makeself archive with a startup script.
The Makefile is used to create the archive. I packs together my startup files, the files needed for the ~/.ssh magic and some local binaries and scripts I routinely use. Nothing magic in here.
The copystdacct sscript simply re-creates the stdacct archive by invoking make(1), scping the archive over to the target host and invoking it there. Nothing magic in here as well.
The unpackstdacct script has some run-of-the-mill magic. Noteable functions include:
- a shell function rmmd5, which only deletes a file if the md5sum of that file equals one of a list of known values. This is used to clean up files that are not in use any more, but avoids deleting locally changed files
- a shell function rmfile, which only deletes a file if it is either a file or a symlink, avoiding error messages if the file is not present.
- to ensure the possibility of remote logins, ~/.ssh/authorized_keys.conf is created with default values if it does not already exist.
The rest of the scripts uses rmmd5 and rmfile to zap files that are not in use any more. At the end, a login shell is invoked to go through the motions of file generation once, and to leave emergency access open if something went wrong during .ssh directory creation.
I hope that the scripts are helpful for you, and I would appreciate your comments.