Manual System Configuration

⇐ table of contents | previous section ⇒


Environment

We find it amazing how borken the default setup is. Depending on how we login, we end up with a completely different environment. The PATH variable, for example, is unnecessarily set (or modified) by init, login and almost every shell profile. It's not too complicated to harmonise things a little bit.

/etc/environment:

# /etc/environment: default environment sourced by
#  - login sh/bash using '. /etc/environmnt'
#  - login csh/tcsh using 'eval `/usr/local/bin/readenv /etc/environment`'
#  - /etc/X11/Xsession.d/10-source-environment using '. /etc/environment'

#  set default locale

export LANG=C

#  set path

export PATH="/bin:/usr/bin:/usr/X11R6/bin:/usr/local/bin"

#  xprint

export XPSERVERLIST="`/etc/init.d/xprint get_xpserverlist`"
export XPRINTER=lp0

$HOME/.environment:

# $HOME/.environment: local environment sourced by
#  - login sh/bash using '. $HOME/.environmnt'
#  - login csh/tcsh using 'eval /usr/local/bin/readenv $HOME/.environment'
#  - $HOME/.Xsession using '. $HOME/.environment'

# add $HOME/bin to the path

export PATH="$HOME/bin:$PATH"

/etc/profile:

# /etc/profile: system-wide shell profile for
#  - interactive login bash
#  - all sh

#  source the default environment

if [ -f /etc/environment ]; then
  . /etc/environment
fi  

#  find out, whether we are a BASH or interactive SH
#  BASH: source /etc/bash.bashrc
#  interactive SH: set prompt

case $BASH in
  *bash*)
    if [ -f /etc/bash.bashrc ]; then
      . /etc/bash.bashrc
    fi
    ;;
  *)
    case "$-" in
      *i*)
        if [ "`id -u`" -eq 0 ]; then
          PS1='# '
        else
          PS1='$ '
        fi
        export PS1
        ;;
      *)
        ;;
    esac
    ;;
esac    

#  set default file permissions

umask 022

/etc/bash.bashrc:

# /etc/bash.bashrc: system wide shell profile for
#  - interactive non-login bash

#  set default prompt depending on UID and TERM

if [ "`id -u`" -eq 0 ]; then
  DELIM="# "
else
  DELIM="$ "
fi

if [ "$TERM" == "linux" ]; then
  PS1="\[\033[4m\]\h:\[\033[0m\] \w"$DELIM
else  
  PS1="\[\033[4m\]\h:\[\033[0m\] "$DELIM
fi
export PS1

#  set shell option "check-window-size"

shopt -s checkwinsize

$HOME/.profile:

# $HOME/.profile: local shell profile for
#  - interactive login bash
#  - all sh

#  source the local environment

if [ -f $HOME/.environment ]; then
  . $HOME/.environment
fi

#  find out, whether we are called as BASH
#  BASH: source $HOME/.bashrc

case $BASH in
  *bash*)
    if [ -f $HOME/.bashrc ]; then
      . $HOME/.bashrc
    fi
    ;;
  *)
    ;;
esac

$HOME/.bashrc:

# $HOME/.bashrc: local shell profile for
#  - interactive non-login bash

#  set xterm titlebar

case "$TERM" in
  *xterm*)
    PROMPT_COMMAND='echo -e -n "\033]2;xterm@$HOSTNAME   $PWD\007"'
    export PROMPT_COMMAND
    ;;
  *)
    ;;
esac    

#  set prompt depending on UID and TERM

if [ "`id -u`" -eq 0 ]; then
  DELIM="# "
else
  DELIM="$ "
fi  

case "$TERM" in
  linux)
    export PS1="\[\033[1m\]\u\[\033[0m\]:\w "$DELIM
    ;;
  *term)
    export PS1="\[\033[1m\]\u\[\033[0m\] "$DELIM
    ;;
esac    

#  set colours and options for 'ls'

eval `dircolors -b /etc/default/dircolors`
alias ls='ls -AF --color=auto'

#  aliases for safety

alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'

/etc/csh.login:

# /etc/csh.login: system-wide shell profile for
#  - login csh/tcsh

#  eval default environtment

if ( -f /etc/environment && -x /usr/local/bin/readenv ) then
  eval `/usr/local/bin/readenv /etc/environment`
endif  

#  set default file permissions

umask 022

/etc/csh.cshrc:

# /etc/csh.cshrc: system-wide shell profile for
#  - all csh/tcsh

#  find out whether we are an interactive tcsh
#  interactive tcsh: set prompt according to UID and TERM

if ( `id -u` ) then
  set delim = ">"
else
  set delim = "#"
endif  

if ! ( $?0 && $?tcsh ) then
  bindkey "\e[1~" beginning-of-line  # Home
  bindkey "\e[7~" beginning-of-line  # Home rxvt
  bindkey "\e[2~" overwrite-mode     # Ins
  bindkey "\e[3~" delete-char        # Delete
  bindkey "\e[4~" end-of-line        # End
  bindkey "\e[8~" end-of-line        # End rxvt
  if ( "$?TERM" == "linux" ) then
    set prompt = "%U%m%u:%B%/%b"$delim" "
  else
    set prompt = "%U%m%u:"$delim" "
  endif
endif

$HOME/.login:

# $HOME/.login: local shell profile for
#  - login csh/tcsh

#  eval the local environment

if ( -f $HOME/.environment && -x /usr/local/bin/readenv ) then
  eval `/usr/local/bin/readenv $HOME/.environment`
endif

$HOME/.cshrc:

# $HOME/.cshrc: local shell profile for
#  - all csh/tcsh

#  find out whether we are an interactive tcsh

if ! ( $?0 && $?tcsh ) then

#  set xterm titlebar

switch ( $TERM )
  case *xterm*:
    alias precmd 'echo -n "\033]2;xterm@${HOST}    $cwd\007"'
    breaksw
  default:
    breaksw
endsw    

#  prompt

if ( $TERM == "linux" ) then
  set prompt = "%B%n%b %/ > "
else
  set prompt = "%B%n%b > "
endif

#  set colours and options for 'ls'

eval `dircolors /etc/default/dircolors`
alias ls 'ls -F --color=auto'

#  aliases for safety

alias rm 'rm -i'
alias cp 'cp -i'
alias mv 'mv -i'

#--- endif

endif

/etc/X11/Xession.d/10-source-environment:

# /etc/X11/Xdession.d/10-source-environment: global X session startup script

# source the default environment

if [ -f /etc/environment ]; then
  . /etc/environment
fi

$HOME/.Xsession:

#!/bin/sh
# $HOME/.Xsession: local X session startup script

#  setup environment

if [ -f $HOME/.environment ]; then
  . $HOME/.environment
fi  

#  setup some fancy desktop background

xsetbg /usr/share/backgrounds/propaganda/vol13.5/A-Little-Exercise-1.JPG

#  start fvwm as window/session manager

fvwm

Note: Contrary to popular belief, the existence of the environment variable PS1 does not indicate an interactive shell. If the current shell is the non-interactive child of an interactive shell, it inherits PS1 from the partent shell. We have to test the shell flags for interactivity.

Source of /usr/local/bin/readenv:

/* readenv.c
 * a little hack to read a file containing statements like
 * export VAR=VALUE
 * and then print them as
 * setenv VAR VALUE
 * to stdout.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main (int argc, char **argv)
{
   char string[2048], *var, *val;
   FILE *file;
   
   if ( argc != 2 ) return EXIT_FAILURE;
   if ( (file = fopen(argv[1], "r")) == NULL ) return EXIT_FAILURE;
   
   do
   {
      fgets(string, sizeof(string), file);
      if ( !feof(file) )
      {
	 val = strstr(string, "export");
	 strsep(&val, " ");
	 var = strsep(&val, "=");
	 if ( var && val ) printf("setenv %s %s;", var, val);
      }
   }
   while (!feof(file));
   
   fclose(file);
   
   return EXIT_SUCCESS;   
}

Note: If we replace export and setenv with alias, this program can also be used to read a shell independent alias definition file.

⇐ table of contents | top ⇒


Network Profile Management

Originally, we had installed a nifty package called laptop-net, which was supposed to autodetect to which network our machine was connected to and then automagically reconfigure the system correspondingly. Unfortunately, this package never worked as advertised and the package maintainer did not bother to answer emails. We therefore decided to scrap laptop-net and roll our own replacement.

Similarly as the laptop-net package, we make the distinction between a network scheme and a network profile. A scheme describes the network interface and the network connection, whereas a profile describes the system configuration, which is selected for a given scheme. The advantage of this setup is that we can this way easily map the same profile to different schemes or different profiles to the same scheme.

The different schemes are defined in the network interface description file /etc/network/interfaces:

/etc/network/interfaces:

# List of automatically initialised interfaces:

auto lo

# Definition of the loop-back interface:

iface lo inet loopback

# Definition of the WLAN0 interface and scheme mappings:

mapping wlan0
  script /usr/local/bin/netscheme

# Definition of the WLAN0 scheme "wlan0-home":

iface wlan0-home inet dhcp
  wireless_mode managed
  wireless_nick <nick>
  wireless_essid <essid>
  wireless_channel <channel>
  wireless_enc on
  wlan_ng_authtype opensystem
  wlan_ng_priv_key128 true
  wlan_ng_key0 01:02:03:04:05:06:07:08:09:0A:0B:0C:0D
  wlan_ng_key1 11:12:13:14:15:16:17:18:19:1A:1B:1C:1D
  wlan_ng_key2 21:22:23:24:25:26:27:28:29:2A:2B:2C:2D
  wlan_ng_key3 31:32:33:34:35:36:37:38:39:3A:3B:3C:3D
  up /usr/local/bin/profile-select
  down /usr/local/bin/profile-deselect

# Definition of the ETH0 interface and scheme mappings:

mapping eth0
  script /usr/local/bin/netscheme

# Definition of the ETH0 scheme "eth0-work":

iface eth0-work inet static
  address xxx.yyy.zzz.149
  netmask 255.255.255.0
  broadcast xxx.yyy.zzz.255
  network xxx.yyy.zzz.0
  gateway xxx.yyy.zzz.254
  dns_domain <fqdn>
  dns_nameservers xxx.yyy.1.1 xxx.yyy.1.5
  up /usr/local/bin/profile-select
  down /usr/local/bin/profile-deselect

# Definition of the ETH0 scheme "eth0-local":

iface eth0-local inet static
  address 10.0.0.1
  netmask 255.255.255.0
  broadcast 10.0.0.255
  network 10.0.0.0
  gateway 10.0.0.2    
  up /usr/local/bin/profile-select
  down /usr/local/bin/profile-deselect

# Definition of the ETH0 scheme "eth0-dhcp":

iface eth0-dhcp inet dhcp
  up /usr/local/bin/profile-select
  down /usr/local/bin/profile-deselect

The script /usr/local/bin/netscheme reads the current network scheme for the given interface, which is saved in the file /var/stete/network/scheme.$INTERFACE.

/usr/local/bin/netscheme:

#!/bin/sh

INTERFACE=$1
SCHEMEFILE=/var/state/network/scheme.$INTERFACE

touch $SCHEMEFILE
cat $SCHEMEFILE

The two interfaces eth0 and wlan0 and their associated schemes are managed by the two scripts /usr/local/bin/eth0 and /usr/local/bin/wlan0, respectively, which differ only in the definition of the assigned interface.

/usr/local/bin/eth0:

#!/bin/sh

prog=`basename $0`
test "X$SUPERCMD" = "X$prog" || exec /usr/bin/super $prog ${1+"$@"}

PATH="/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin"
ADDRESS=""
INTERFACE=eth0
#INTERFACE=wlan0

SCHEMEFILE=/var/state/network/scheme.$INTERFACE

touch $SCHEMEFILE

case "$1" in
   load)
     modprobe $INTERFACE
     ;;
   unload)
     modprobe -r $INTERFACE
     ;;
   up|start)
     echo "$INTERFACE: start"
     ifup $INTERFACE 2> /dev/null
     ;;
   down|stop)
     echo "$INTERFACE: stop"
     ifdown $INTERFACE 2> /dev/null
     rmmod -a; rmmod -a
     ;;
   restart)
     echo "$INTERFACE: restart"
     ifdown $INTERFACE 2> /dev/null
     sleep 1
     ifup $INTERFACE 2> /dev/null
     ;;
   scheme)
     if [ -z "$2" ]; then
       cat $SCHEMEFILE | sed "s/-/ /" | awk '{print $2}'
     else       
       echo "$INTERFACE-$2" > $SCHEMEFILE
     fi
     ;;
   *)
     SCHEME=`cat $SCHEMEFILE | sed "s/-/ /" | awk '{print $2}'`
     SCHEMES=`grep iface /etc/network/interfaces | grep $INTERFACE | sed "s/-/ /" | awk '{printf "%s ", $3 }'`
     echo "Usage: $INTERFACE [up|start|down|stop|restart|scheme [xyz]]"
     echo "where xyz is one of:  $SCHEMES"
     echo "Current scheme is:    $SCHEME"
     ;;
esac

After the interface was brought up with the command wlan0 up, the script profile-select tries to match the assigned IP number against a list of possible IP numbers to select the appropriate network profile. This profile is the installed by copying configuration files and by starting or stopping system services. After the interface was brought down, the script profile-deselect reverts to a special default profile called offline, which does not map to a network scheme.

/usr/local/packages/network/bin/profile-select:

#!/bin/sh

PROFILE_DIR="/etc/network/profiles"
PROFILE_STATE_FILE="/var/run/network/profile"

# Load current profile

PROFILE_CUR=`cat $PROFILE_STATE_FILE | awk '{print $3}'`
PROFILE_NEW="offline"

# Select new profile

ADDRESS=`ifconfig $IFACE | grep inet | sed "s/:/ /" | awk '{print $3}'`

for PROFILE in $(cd $PROFILE_DIR; ls -d [a-z0-9]* 2> /dev/null); do
  PATTERNS="$PROFILE_DIR/$PROFILE/patterns"
  if [ -r "$PATTERNS" ]; then
    for PATTERN in $(cat $PATTERNS); do
      case $ADDRESS in
        ($PATTERN)
	  PROFILE_NEW=$PROFILE
	  break 2
	  ;;
      esac
    done
  fi
done

echo -n "Switching to profile "$PROFILE_NEW": "

# If the new and current profiles are the same, exit here

[ "$PROFILE_NEW" != "$PROFILE_CUR" ] || exit 0

# Run the Stop-Scripts for the current profile

cd $PROFILE_DIR/$PROFILE_CUR/rc.d
for SCRIPT in $(echo "K[0-9][0-9]*"); do
  if [ -n "$SCRIPT" ]; then
    echo -n "."
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT stop &> /dev/null
        ;;
      (*)
        ./$SCRIPT stop &> /dev/null
        ;;
    esac
  fi
done  

# Copy all profile specific files for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/files.d
tar cf - . | (cd /; tar xf -)

# Run Start-Scripts for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/rc.d
for SCRIPT in $(echo "S[0-9][0-9]*"); do
  if [ -n "$SCRIPT" ]; then
    echo -n "."
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT start &> /dev/null
        ;;
      (*)
        ./$SCRIPT start &> /dev/null
        ;;
    esac
  fi
done

# Save new profile

echo $PROFILE_CUR" --> "$PROFILE_NEW > $PROFILE_STATE_FILE
echo " done."

/usr/local/packages/network/bin/profile-deselect:

#!/bin/sh

PROFILE_DIR="/etc/network/profiles"
PROFILE_STATE_FILE="/var/run/network/profile"

# Load the current and new profile

PROFILE_CUR=`cat $PROFILE_STATE_FILE | awk '{print $3}'`
PROFILE_NEW="offline"

echo -n "Switching to profile "$PROFILE_NEW": "

# If the new and current profiles are the same, exit here

[ "$PROFILE_NEW" != "$PROFILE_CUR" ] || exit 0

# Run Stop-Scripts for the current profile

cd $PROFILE_DIR/$PROFILE_CUR/rc.d
for SCRIPT in $(echo K[0-9][0-9]*); do
  if [ -n "$SCRIPT" ]; then
    echo -n "."
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT stop &> /dev/null
        ;;
      (*)
        ./$SCRIPT stop &> /dev/null
        ;;
    esac
  fi
done

# Copy all profile specific files for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/files.d
tar cf - . | (cd /; tar xf -)

# Run the Start-Scripts for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/rc.d
for SCRIPT in $(echo S[0-9][0-9]*); do
  if [ -n "$SCRIPT" ]; then
    echo -n "."
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT start &> /dev/null
        ;;
      (*)
        ./$SCRIPT start &> /dev/null
        ;;
    esac
  fi
done  

# Save new profile

echo $PROFILE_CUR" --> "$PROFILE_NEW > $PROFILE_STATE_FILE
echo " done."

In contrast to the laptop-net package, where a special daemon is supposed to watch the ethernet interface for network connects and disconnects, we have to bring up our interfaces manually using the two scripts eth0 and wlan0. This is no great inconvenience, since this ifd daemon is one part of the laptop-net package, which does not work as advertised.

The actual network profiles are defined in the directory /etc/network/profiles. Each profile corresponds to a subdirectory, whose name is the name of the profile. Within this subdirectory, there are two more subdirectories named files.d and rc.d, repectively, as well as one text file name patters.

The patterns file is a simple list of IP numbers (possibly containing the wildcard *, one IP number per line), to which the corresponding profile should apply:

/etc/network/profiles/at-work/patterns:

xxx.yyy.zzz.*
XXX.YYY.ZZZ.34

The files.d subdirectory contains a tree of more subdirectories and files. This tree is copied as a whole into the root directory / using the tar command just after the network interface has been brought up. Subsequently, all system services named Snn_service in the rc.d directory are started. After the interface has been brought down, all system services named Knn_service are stopped.

The offline profile is special and gets selected if no network scheme is active. This profile may contain the files.d and rc.d directories. The patterns file is not necessary.

Now we want to transfer control of all network related system startup scripts to our network profile management -- without confusing the Debian package management of course. To do so, we have to remove the symlinks from the /etc/rcN.d directories and install them in the /etc/network/profiles/XXXX/rc.d, where XXXX is the name of our profiles. Since the Debian boot-script manager update-rc.d will reinstall these links as long as it find the corresponding script in /etc/init.d, we have to divert these to a different location.

Diverting the boot scripts from init:

#!/bin/sh

mkdir /etc/network/init.d
PACKAGES="dns-clean fetchmail ippl lprng ntp ntpdate ppp scandetd ssh xinetd"
for p in $PACKAGES; do
  dpkg-divert --rename --divert /etc/network/init.d/$p /etc/init.d/$p
  update-rc.d $p remove
done

Now we go to the rc.d directories and create the new symlinks by hand.

Creating the new startup/shutdown symlinks (example):

#> cd /etc/network/profiles
#> mkdir -p XXXX/rc.d YYYY/rc.d ZZZZ/rc.d
#> cd XXXX/rc.d
#> ln -s ../../../init.d/ssh S20ssh
#> ln -s ../../../init.d/ssh K20ssh

To integrate the VPN tunnel into this network profile management, we define a special network profile vpn, which is not mapped to a scheme but can simply replace the current profile on a given scheme.

To initialise the VPN tunnel and to switch to the corresponding profile, we use a simple script:

/usr/local/bin/vpn:

#!/bin/sh

prog=`basename $0`
test "X$SUPERCMD" = "X$prog" || exec /usr/bin/super $prog ${1+"$@"}

PATH="/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin"
ADDRESS=""
export DISPLAY=":0.0"

case "$1" in
   up|start)
     /usr/local/bin/xterm -geometry 156x26-0-0 -e vpnclient connect XXXX &
     while [ "$ADDRESS" == "" ]; do
       ADDRESS=`vpnclient stat tunnel | grep "Client address" | awk '{print $3}'`
       sleep 1
     done
     /usr/local/packages/network/bin/vpn-select
     ;;
   down|stop)
     kill `pidof vpnclient` &> /dev/null
     kill `pidof vpn` &> /dev/null
     /usr/local/packages/network/bin/vpn-deselect
     ;;
   *)
     echo "Usage: vpn [up|start|down|stop]"
     ;;
esac

Note: This script sets DISPLAY=:0.0" and assumes that root has access to this display. Note also: XXXX is the name of the configured VPN profile,

We have to register this script with the super package by adding the following stanza to the configuration file:

/usr/local/bin/vpn:

vpn        /usr/local/bin/vpn uid=root info="start/stop VPN" \
	   <user>

The two scripts vpn-select and vpn-deselect have a similar functionality to profile-select and profile-deselect whith the only exception that we don't have to map a profile but select the special profile vpn after the VPN tunnel has been established and revert to the previously active profile after the VPN tunnel has been closed.

/usr/local/packages/bin/vpn-select:

#!/bin/sh

PROFILE_DIR="/etc/network/profiles"
PROFILE_STATE_FILE="/var/run/network/profile"
VPN_STATE_FILE="/var/run/network/vpn"

# Load current profile

PROFILE_CUR=`cat $PROFILE_STATE_FILE | awk '{print $3}'`
PROFILE_NEW="offline"

# Select new profile

ADDRESS=`vpnclient stat tunnel | grep "Client address" | awk '{print $3}'`

for PROFILE in $(cd $PROFILE_DIR; ls -d [a-z0-9]* 2> /dev/null); do
  PATTERNS="$PROFILE_DIR/$PROFILE/patterns"
  if [ -r "$PATTERNS" ]; then
    for PATTERN in $(cat $PATTERNS); do
      case $ADDRESS in
        ($PATTERN)
	  PROFILE_NEW=$PROFILE
	  break 2
	  ;;
      esac
    done
  fi
done

echo "PROFILE: " $PROFILE_NEW

# If the new and current profiles are the same, exit here

[ "$PROFILE_NEW" != "$PROFILE_CUR" ] || exit 0

# Run the Stop-Scripts for the current profile

cd $PROFILE_DIR/$PROFILE_CUR/rc.d
for SCRIPT in $(echo "K[0-9][0-9]*"); do
  if [ -n "$SCRIPT" ]; then
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT stop
        ;;
      (*)
        ./$SCRIPT stop
        ;;
    esac
  fi
done  

# Copy all profile specific files for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/files.d
tar cf - . | (cd /; tar xf -)

# Run Start-Scripts for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/rc.d
for SCRIPT in $(echo "S[0-9][0-9]*"); do
  if [ -n "$SCRIPT" ]; then
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT start
        ;;
      (*)
        ./$SCRIPT start
        ;;
    esac
  fi
done

# Save new profile

echo $PROFILE_CUR" --> "$PROFILE_NEW > $VPN_STATE_FILE


/usr/local/packages/bin/vpn-deselect:

#!/bin/sh

PROFILE_DIR="/etc/network/profiles"
PROFILE_STATE_FILE="/var/run/network/profile"
VPN_STATE_FILE="/var/run/network/vpn"

# Load the current and new profile

PROFILE_CUR=`cat $VPN_STATE_FILE     | awk '{print $3}'`
PROFILE_NEW=`cat $PROFILE_STATE_FILE | awk '{print $3}'`

echo "PROFILE: " $PROFILE_NEW

# If the new and current profiles are the same, exit here

[ "$PROFILE_NEW" != "$PROFILE_CUR" ] || exit 0

# Run Stop-Scripts for the current profile

cd $PROFILE_DIR/$PROFILE_CUR/rc.d
for SCRIPT in $(echo K[0-9][0-9]*); do
  if [ -n "$SCRIPT" ]; then
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT stop
        ;;
      (*)
        ./$SCRIPT stop
        ;;
    esac
  fi
done

# Copy all profile specific files for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/files.d
tar cf - . | (cd /; tar xf -)

# Run the Start-Scripts for the new profile

cd $PROFILE_DIR/$PROFILE_NEW/rc.d
for SCRIPT in $(echo S[0-9][0-9]*); do
  if [ -n "$SCRIPT" ]; then
    case "$SCRIPT" in
      (*.sh)
        /bin/sh ./$SCRIPT start
        ;;
      (*)
        ./$SCRIPT start
        ;;
    esac
  fi
done  

# Save new profile

echo $PROFILE_CUR" --> "$PROFILE_NEW > $VPN_STATE_FILE

Last but not least we need a small init script, which brings our network profile management into a well defined state upon booting the machine:

/etc/init.d/network_profile:

#!/bin/sh
if [ ! -d /var/run/network ]; then
  mkdir /var/run/network
fi  
echo "offline --> offline" > /var/run/network/profile
echo "offline --> offline" > /var/run/network/vpn

We link this new script into the runlevel directories /etc/rcN.d either by hand or using the update-rc.d command.

⇐ table of contents | top ⇒


X Fontpath Configuration

First of all, there is no real need to install a font server on our laptop. Font servers are typically needed, where we have a bunch of diskless graphics terminals (X terminals), which need to download the fonts from somewhere. But our laptop will certainly not play the font server for somesuch terminals. If available on the local network, we may want to configure for such an external font server, though.

Our display resolution is 133 dpi. The pixmap fonts of XFree86 come, however, in two flavours only: 75 dpi and 100 dpi. We can immediately forget about installing the 75 dpi fonts and settle on the 100 dpi fonts. But even these fonts turn out to be somewhat small when displayed at 133 dpi. Scaling bitmapped fonts is a big no-no, though. It's therefore a good idea to install some natively scalable fonts, e.g. Type 1, Speedo and TrueType fonts.

Since that company, whose name reminds us at a brand of toilet paper, has removed its hitherto freely downloadable TrueType fonts, we have to install the msttcorefonts package from the testing distribution, if we want those fonts. Using the Debian font manager package defoma, the installation of the Type 1, Speedo and TrueType fonts is painless. To make use of all these fonts, we only have to adapt the X server configuration file /etc/X11/XF86Config-4:

/etc/X11/XF86Config-4:

Section "Files"
# External Fontserver:
#       FontPath   "tcp/fontserver:7100"

# Local Fontserver:
#        FontPath   "unix/:7100"

# Unscaled Bitmap Fonts:
        FontPath   "/usr/X11R6/lib/X11/fonts/100dpi:unscaled"
        FontPath   "/usr/X11R6/lib/X11/fonts/misc:unscaled"

# Scalable TrueType and CID Fonts (via DeFoMa):
        FontPath   "/var/lib/defoma/x-ttcidfont-conf.d/dirs/TrueType"
        FontPath   "/var/lib/defoma/x-ttcidfont-conf.d/dirs/CID"

# Scalable Speedo and Type1 Fonts:
        FontPath   "/usr/X11R6/lib/X11/fonts/Speedo"
        FontPath   "/usr/X11R6/lib/X11/fonts/Type1"
        
# Scaled Bitmap Fonts:
#       FontPath   "/usr/X11R6/lib/X11/fonts/75dpi"
#       FontPath   "/usr/X11R6/lib/X11/fonts/misc"
EndSection

Note: We should replace fontserver with the name of our external fontserver (if any). Removing the entry for the local fontserver, if there is none installed, speeds up things considerably. Scaling bitmapped fonts is ugly.

⇐ table of contents | top ⇒


Installing the Cyberbit Unicode TrueType Fonts

As far as we know, the Cyberbit fonts are among the most complete Unicode TrueType fonts (containg nearly 30000 glyphs). It's therefore a good idea to install them.

Installing CyberBit TrueType Fonts:

#> mkdir -p /usr/local/share/fonts/truetype
#> cd /usr/local/share/fonts/truetype
#> wget ftp://ftp.netscape.com/pub/communicator/extras/fonts/windows/Cyberbit.ZIP
#> unzip Cyberbit.ZIP 
#> mv Cyberbit.ttf CyberBit.ttf
#> rm Cyberbit.ZIP
#> defoma-hints truetype CyberBit.ttf >> localfont.hints

Now we have to edit the hint-file manually. Unfortunately, the defoma documentation is somewhat lacking what concerns the installation of large Unicode fonts spanning many codesets. Our hint file is therefore largely based on guesswork.

/usr/local/share/fonts/truetype/localfont.hints:

category truetype
begin /usr/local/share/fonts/truetype/CyberBit.ttf
  Family = BitstreamCyberbit
  FontName = BitstreamCyberbit-Roman
  Encoding = Unicode
  Location = English
  Charset = ISO10646-1
  UniCharset = ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 ISO8859-6 ISO8859-7 ISO8859-8 ISO8859-9 ISO8859-10 ISO8859-11 ISO8859-12 ISO8859-13 ISO8859-14 ISO8859-15 KOI8-R KOI8-U JISX0208 JISX0212 JISX0201 KSX1001 KSX1003 GB3212 GBK GB18030 BIG5 BIG5-HKSCS 
  GeneralFamily = Roman Mincho Symbol
  Weight = Medium
  Width = Variable
  Shape = Serif Upright
  Foundry = bitstream
  Priority = 20
  X-Foundry = bitstream
  X-Family = cyberbit
  X-Weight = medium
  X-Slant = r
end

Finally, we register the fonts with defoma.

Registering the Cyberbit Fonts with defoma:

#> defoma-font -v register-all /usr/local/share/fonts/truetype/localfont.hints

⇐ table of contents | top ⇒


Configuring the Syslog Daemon

Debian's default configuration of the syslog daemon is a mess. Fortunately, the rest of Debian (including the configuration of cron) is very well done, so that it is extremely painless to switch to a different configuration.

/etc/syslog.conf:

#
# SYSLOG by facility
#

auth,authpriv,security.*    -/var/log/service.auth
cron.*                      -/var/log/service.cron
daemon.*                    -/var/log/service.daemon
kernel.*                    -/var/log/service.kernel
lpr.*                       -/var/log/service.lpr
mail.*                      -/var/log/service.mail
news.*                      -/var/log/service.news
syslog.*                    -/var/log/service.syslog
uucp.*                      -/var/log/service.uucp

local0.*                    -/var/log/service.local0
local1.*                    -/var/log/service.local1
local2.*                    -/var/log/service.ppp
local3.*                    -/var/log/service.local3
local4.*                    -/var/log/service.local4
local5.*                    -/var/log/service.local5
local6.*                    -/var/log/service.local6
local7.*                    -/var/log/service.local7

#
# SYSLOG by level
#

*.debug                     -/var/log/level.debug
*.warning                   -/var/log/level.warning
*.error                      /var/log/level.error
*.crit                       /var/log/level.critical
*.alert                      /var/log/level.alert
*.emerg                     *

Reconfiguring the Syslog Daemon:

#> /etc/init.d/sysklogd stop
#> rm `syslogd-listfiles -a`
#> dpkg-divert --rename /etc/service.conf
#> vi /etc/syslog.conf
#> /etc/init.d/sysklogd start

⇐ table of contents | top ⇒


Three Finger Salute

We want to be able to shutdown or reboot our machine from the text console by pressing <CTRL-ALT-DEL> and <CTRL-ALT-INS>, respectively. Both can be configured in /etc/inittab, the former one directly, the latter one by using the kbdrequest feature and defining the key KeyboardSignal as <CTRL-ALT-INS> in the kernel keymaps.

/etc/console/linux-kbdrequest.inc:

control alt keycode 110 = KeyboardSignal

Modification of /etc/console/uk.kmap:

include "linux-kbdrequest"


Modification of /etc/inittab:

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -h now

# Action on special keypress (CTRL-ALT-INS)
kb::kbrequest:/sbin/shutdown -t1 -a -r now

⇐ table of contents | top ⇒


Extending a Logical Volume

Sonner or later we will run out of space on our /home partition. No problem: We just extend the corresponding Logical Volume. Doing so is extremely simple and easy.

Extending the Logical Volume /dev/disk/home:

#> umount /home
#> tune2fs -O ^has_journal
#> e2fsadm -L +10G /dev/disk/home
#> tune2fs -O has_journal
#> mount /home

⇐ table of contents | top ⇒