| Author: | Martin Blais |
|---|---|
| Contact: | blais@furius.ca |
| Status: | First draft: 1999-03 |
| LastUpdate: | $Date$ |
Abstract
Description of a proven organization system for a user's configuration files under UNIX, to support multiple platforms, multiple sites and hosts.
Contents
Unix software configuration files come in many varieties. They are often written in many different (often funny) languages, and for the seasoned hacker are often the result of many many precious hours of tweaking and learning--in my personal case it has become pathological: I dub it the Custom-Configuration Syndrome (CCS), hours and hours spent tailoring my environment.
Obviously, one doesn't want to restart this work everytime he changes location, company, school, platform, etc. Moreover, one may share the same configuration say, at home and at work. For example, my emacs configuration files have been growing with me since I first started using it. For the past almost ten years now, I have been using more or less the same setup that I devised to store my configuration files efficiently and minimally.
This document explains how my configuration files are organized, so that they are easily portable across various platforms and sites.
We assume here that this configuration is to happen for a specific user and so all the paths mentioned in this document are relative to the user's home directory.
It is necessary here to define scopes of applicability to factor the different variables that our configuration files are going to apply to.
Of the five basic scopes, the last three ones are of specific interest. They can be combined. Let's examine the possible combinations:
Note that a site- and host- specific scope does not really make sense, because we assume that a host lies within a specific site. The same applies to a site- and platform- and host- specific scope. Host means site-host.
We must note that in practice, the common, site-specific and platform-specific scopes cover 99% of the cases.
The essence of the configuration files directory is user-specific configuration for your software. A question arises: should software installed by and for the user only be stored in this directory [1]? Technically, it could, since the different scopes support it, and it is easy to get tempted into doing this. It can sometimes be handy to have scripts and other pieces of software related to configuration available on all the platforms and sites.
Installing software in the configuration tree has several drawbacks:
I propose that most of the user's own software installations happen under a different root directory else, which we will call the "local configuration", and that will be identified with the environment variable CONF_LOCAL. Under this directory, a hierarchy similar to the one present under the configuration directory should be present (see description below).
As a degenerate case, CONF_LOCAL can be $HOME, in which case the user's home directory would contain ~/common and ~/plat subdirectory hierarchies.
| [1] | Note that we do not refer here to machine-wide software installations, which are still done in the usual places, i.e. /usr, or /usr/local or /opt or wherever. Sometimes a user wants to install software for him only, or perhaps does not officially have root access (for example, in a university lab setting). |
Basically, each file is split in scope-specific smaller files. A main file "includes" the scope-specific files with whatever mechanism is provided by whatever parsing engine that file is executed by. If it's a shell script, the scope-specific files are are "sourced"; if it's a .emacs lisp file, the scope-specific .emacs files are "loaded", etc.
The dot files that are expected to be found in the user's home directory are symbolically linked with a home-made script to do just that. For example, for my .emacs:
~/.emacs -> conf/common/etc/emacs
Note: often, one must pay attention to the order in which the root scripts include the other scripts.
Initializing a shell's environment properly is rather important, since so many applications depend on it.
Some environment variables are critical to implement this configuration scheme. In our setup, we assume that the following environment variables are always defined. My configuration files depend on the existence of only these variables in their running environment.
Since there are potentiatlly multiple entry points for the initialization files, I set those critical variables in $HOME/.conf; here are typical contents:
CONF=$HOME/p/conf CONF_LOCAL=$HOME/p/conf-local PLAT=`$CONF/common/bin/config.guess` SITE=home HOST=`hostname` # Linux.
This can be sourced by the various initialization files.
The initialization files that get run for various shells do not match the reality of the various scenarios where we desire specific sets of initializations. To simplify and rationalize the selection of the initializations that are performed for each scenario, we define three levels of initialization of the environment:
The trick to creating the configuration correctly is to create generic initialization files that detect the various scenarios described above and which then dispatch to the initialization levels depending on our desire for the various scenarios (see figure).
We create generic dot files in $CONF/init, to which we link, and make these dot files invoke the various initialization steps as we need them.
Here are the scenarios under consideration.
Scenario: Logging into the console.
What gets run: /etc/profile + .bash_profile, .profile
The levels we want: conf, env, bash
Scenario: Logging into an X11 session.
What gets run: /etc/profile + .bash_profile, .profile
The levels we want: conf
Note: we could tolerate environment initializations here but I find it much cleaner not to have it, it runs a lot less code during X session setup, so the chances of something going wrong preventing you from logging in are slim. xprofile is run for those minimal initializations. We do need the basic config variables however, for the window manager commands itself.
Scenario: Remote ssh login.
What gets run: /etc/profile + .bash_profile, .profile
The levels we want: conf, env, bash
Scenario: Starting a shell from the virtual terminal: .bashrc
What gets run: /etc/profile + .bash_profile, .profile
The levels we want: We want: conf, env, bash
An alternative would be to let the X session fully initialize its environment and to do nothing here. This would make the shells start very very fast. A disadvantage with this method is that you cannot simply change the init files and then restart a virtual terminal, you have to fully log out to change your shells' environments.
Scenario: Remote ssh command: .bashrc
What gets run: /etc/profile + .bash_profile, .profile
The levels we want: We want: conf, env
Note that we do not want to run bash specific initializations for non-interactive shells, we want to save time, so that the commands run as fast as possible. However, we like to have a setup where the environment variables and path have been set correctly.
(For reference.)
Interactive
Login
- /etc/profile
- First of: ~/.bash_profile, ~/.bash_login, ~/.profile
Not-login
- ~/.bashrc
Non-interactive
- BASH_ENV, if set.
When graphical session login script is run, whatever happens depends on the Xsession script and on which xdm is used, distribution, etc. For example, gdm checks manually for .profile, .xprofile and more.
Here is the suggested hierarchy for the configuration files directory:
Root of all configuration files:
$CONF
Scope specific directories (see scopes above):
$CONF/init/... global init files,
include all the scopes
$CONF/common/... common (shared) scope
$CONF/plat/$PLAT/... platform scope
$CONF-$SITE/... site scope
$CONF-$SITE/plat/$PLAT/... site and platform scope
$CONF-$SITE/host/$HOST/... host scope
$CONF-$SITE/host/$HOST/plat/$PLAT/... host and platform scope
In addition, I use the same principles to manage my local installs (see section on this above), that is:
$CONF_LOCAL/common/... common stuff, install logs, very local
or installed scripts that I didn't write
$CONF_LOCAL/plat/$PLAT/... platform-specific local installations of software
Under each of those directories the following files and directories can be found:
../etc/... all dot files for that scope
../etc/env environment variables (bourne-shell level)
../etc/bashrc bash-specific settings and environment
../etc/inputrc readline (for bash) keyboard changes
../etc/emacs dot emacs
../etc/Xmodmap modifications to be made to X keyboard mappings
../etc/Xclients X clients to run upon logging in
../etc/procmailrc procmail processing
../etc/ ... LOTS OF OTHER DOT FILES
../bin/ executable scripts
(few and only small binary executables)
../lib/ other files needed by scripts
../lib/python/ Only custom Python libraries/packages (.py)
../lib/perl/ Only custom Perl libraries/packages (.pm)
../lib/java/ java class files (very few and small)
../man/ man pages that I really need outside of
installed applications (very few)
../include/ non application-installed includes (extremely few)
../info/ texinfo documentation for stuff installed under
$CONF (not much)
../share/ application data
../share/images/ images needed for some config stuff
(really few, e.g. some personal window manager icons)
../share/sounds/ sounds needed for some config stuff
(very small files only, and only what is truly necessary)
../app-defaults/ X application-specific resource files
../elisp/ emacs-lisp files and custom packages
../elisp/emacs/ specific to GNU emacs
../elisp/xemacs/ specific to XEmacs (I almost never need it)
../tex/ TeX-related stuff
../tex/bib/ BibTeX bibliography files
../tex/bst/ BibTeX style files
../tex/doc/ LaTeX packages documentation
../tex/inputs/ LaTeX input files (.sty, .cls)
../gnupg/ public keyring and options file
(store your secret keyring somewhere else)
../src/ source code to be built for stuff that is
absolutely necessary for config purposes (almost nothing)
../log/ logs (note: in local installations subdirectory only)
Notes: in practice, some of the files have branching using the configuration variables when it is convenient. For example, in my common scope .emacs, I often branch on the "site" within that single because it is simpler than doing an override in the site-specific file or "not requiring some package" this way.
Here are a few issues that you want to be aware of when designing a system/script for doing your personal backups:
Note
I have built Arnie, a Python script to remote incremental backups in a simple, naive but reliable way.
Eventually, when gigabytes are a laughable and meaningless quantity of data, I would like to group all my email from all my backups and generate a searchable index of it, by parsing the headers and generating keywords from the bodies texts.
Let's examine the path we need to setup for accessing all the scripts the stuff that may be in this configuration. The following directories should be included in the path, if they exist:
$CONF/common/bin $CONF/plat/$PLAT/bin $CONF-$SITE/bin $CONF-$SITE/plat/$PLAT/bin $CONF-$SITE/host/$HOST/bin $CONF-$SITE/host/$HOST/plat/$PLAT/bin $CONF_LOCAL/common/bin $CONF_LOCAL/plat/$PLAT/bin
This makes a pretty long addition to your path. With many UNIX shells, a longer path means a slower lookup for your executables.
A better way to make up the path is to have a script filter out those parts of the path that don't exist. Working this way, the same script can also be reused for for sh- and csh- derived shells, helping maintain consistency and reduce the overhead of maintenance of environment scripts if you use multiple shells. The same principle applies to the library search path LD_LIBRARY_PATH.
If you compile lots of free/open source software, if may be worthwhile to keep logs of how you compiled certain software. The need for this is reduced under Linux now that this information can often be packaged within the different packaging systems (such as RPM).
Installing new software that is using autoconf should be easy. You can use the following command:
./configure --prefix=$CONF_LOCAL/plat/$PLAT
...or if you use multiple platforms at your site:
./configure --prefix=$CONF_LOCAL/common --exec-prefix=$CONF_LOCAL/plat/$PLAT
When remote logging to a machine from an X session, it is convenient to have the DISPLAY environment variable be propagated automatically to the remote session. This is easily carried out if your account is NFS-mounted on the remote machine: a file containing your current DISPLAY can be read and the display set from that. This file can be automatically create at the time where you log on to your X session.
Many of the ideas present in this document originate from interesting discussions with Stefan Monnier and Dominik Madon, a long time ago while we were at EPFL (1994-1995).