Chapter 6. Custom installation

Table of Contents
6.1. Partitioning a hard disk
6.2. Initializing and mounting filesystems
6.3. Installing packages
6.4. Post-install configuration
6.5. Automated installation script

Sometimes you may want to do a custom installation of Slackware Linux, for example to get better understanding of how GNU/Linux systems work, or to prepare an automatic installation script. This chapter outlines the steps that are required to install Slackware Linux manually. A sample installation script is also provided in Section 6.5.

6.1. Partitioning a hard disk

If you have performed a normal installation, you should not have any problems partitioning a disk. You can use the fdisk(8) and cfdisk(8) commands to partition disks. If you are scripting the installation of Slackware Linux it is useful to know that you can pipe fdisk commands to the fdisk binary. For example:


# fdisk /dev/hda << EOF
n
p
1

+10000M
n
p
2

+512M
t
2
82
w
EOF
    

These commands create a primary Linux partition of 10000MB, and a primary Linux swap partition of 512MB. You could store the fdisk commands in different disk profiles, and use one of the profiles based on the specific deployment (e.g. the disk size). For example:


# cat /usr/share/fdisk-profiles/smalldisk | fdisk
    

6.2. Initializing and mounting filesystems

After making at least a swap and a Linux partition, you can initialize the filesystem and swap space and make use of this storage. On systems that are short on memory, you should initialize, and use swap first. We will use the partition layout used in the partitioning example listed above in the following examples. To set up and use swap, execute:


# mkswap /dev/hda2
# swapon /dev/hda2
    

The meaning of these commands is quite obvious. mkswap(8) initializes the swap space, and swapon(8) puts it to use. You will only have to execute mkswap once, but swapon has to be executed during every system boot. This can be done automatically by adding an entry for the swap partition to /etc/fstab, which we will do during a later step.

For now, it is important to initialize the target partitions. This can be done with the mkfs(8) command. You can specify which filesystem should be used by adding the -t parameter. mkfs will automatically invoke a mkfs.filesystem command based on the filesystem that you have chosen. Be aware that the filesystems that can be used depends on the installation kernel that you have booted. If you have booted the bare.i kernel, you can use the ext2, ext3 and reiserfs filesystems.

To initialize an ext3 filesystem, and mount it, you should execute the following commands:


# mkfs -t ext3 /dev/hda1
# mount /dev/hda1 /mnt
    

If you have made separate partitions for certain directories in the root filesystem, e.g. /home, you can also initialize them and mount them at this point. For example:


# mkfs -t ext3 /dev/hda2
# mkdir /mnt/home
# mount /dev/hda2 /mnt/home
    

Finally, you will have to mount your source medium. If you use a CD-ROM, this is easy. Suppose that /dev/hdc is the CD-ROM device file, you can mount the CD-ROM with:


# mount /dev/hdc /var/log/mount
    

Using NFS as the installation medium requires some more steps. First of all, you will have to load the network disk. You can do this by running the network command and inserting a network disk. You can also load this disk from another medium, for example from an USB memory stick. Suppose that you have mounted a USB memory stick on /var/log/mount, you can load the network disk with: network /var/log/mount/network.dsk. After loading the network disk, you will have to configure the network interface. If the NFS server is on the same network, you will only have to assign an IP address to the network interface. For example, to use the address 192.168.2.201, you could execute the following command:


# ifconfig eth0 192.168.2.201
    

You can then load the portmapper, which is necessary for the NFS client to function correctly:


# /sbin/rpc.portmap
    

If the portmapper started correctly, you can mount the NFS volume. But, first make sure that you unmount any filesystem that you have previously mounted at /var/log/mount. If no other filesystems are mounted at /var/log/mount, you can proceed with mounting the NFS volume. Suppose, that you want to mount 192.168.2.1:/home/pub/slackware-current, you should issue the following command:


# mount -r -t nfs -o nolock 192.168.2.1:/home/pub/slackware-current /var/log/mount
    

If no errors where printed when the volume was mounted, it should be accessible through /var/log/mount

6.3. Installing packages

Everything is now set up to start installing packages from the installation medium. Since installpkg(8) is available from the installation system, you can use it to install Slackware Linux packages. To install packages to the target partition(s) mounted on /mnt, add the -root. The following command installs all packages from the source medium:


# installpkg -root /mnt /var/log/mount/slackware/*/*.tgz
    

If you have created tagfiles to define which packages should be installed, then you can use them now (tagfiles are described in Section 18.4). Suppose that you have stored a tagfile for each disk set in /usr/share/tagfiles/small-desktop, you can install packages based on the tagfiles in the following manner:


# for p in [a-z]*; do
        installpkg -root /mnt -tagfile /usr/share/tagfiles/small-desktop/$p/tagfile /var/log/mount/slackware/$p/*.tgz
done
    

6.4. Post-install configuration

The next sections describe the bare minimum of configuration that is necessary to get a running system.

6.4.1. fstab

One of the necessary configuration steps is to create a fstab(5) file, so that the system can look up what partitions or volumes have to be mounted. The format of the /etc/fstab file is described in Section 8.6.4. As a bare minimum you will have to add entries for the / filesystem, the /proc pseudo-filesystem, the devpts pseudo-filesystem, and the swap partition.

With the sample partitioning used earlier in this chapter, you could create a /etc/fstab like this:


#  cat > /mnt/etc/fstab << EOF
/dev/hda2        swap             swap        defaults         0   0
/dev/hda1        /                ext3        defaults         1   1
devpts           /dev/pts         devpts      gid=5,mode=620   0   0
proc             /proc            proc        defaults         0   0
      

6.4.2. LILO

To make the system bootable you will have to configure and install the Linux Loader (LILO). The configuration of LILO is covered in Section 20.1. For this section we will just show a sample LILO configuration, that can be used with the partition layout described in this chapter. The first step is to create the /etc/lilo.conf file:


# cat > /mnt/etc/lilo.conf << EOF
boot = /dev/hda
vga = normal
timeout = 50
image = /boot/vmlinuz
        root = /dev/hda1
        label = Slackware
        read-only
EOF
      

You can then install LILO with /mnt as the LILO root. With /mnt set as the root, LILO will use /etc/lilo.conf from the target partition:


# lilo -r /mnt
      

6.4.3. Networking

The configuration of networking in Slackware Linux is covered in Chapter 23. This section will cover one example of a host that will use DHCP to get an IP address.

The /etc/networks file contains information about known Internet networks. Because we will get network information via DHCP, we will just use 127.0.0.1 as the local network.


# cat > /mnt/etc/networks << EOF
loopback        127.0.0.0
localnet        127.0.0.0
EOF
      

Although we will get a hostname via DHCP, we will still set up a temporary hostname:


# cat > /mnt/etc/HOSTNAME << EOF
sugaree.example.net
EOF
      

Now that the hostname is configured, the hostname and localhost should also be made resolvable, by creating a /etc/hosts database:


# cat > /mnt/etc/hosts << EOF
127.0.0.1       localhost
127.0.0.1       sugaree.example.net     sugaree 
EOF
      

We do not have to create a /etc/resolv.conf, since it will be created automatically by dhcpcd, the DHCP client. So, finally, we can set up the interface in /etc/rc.d/rc.inet1.conf:


# cat > /mnt/etc/rc.d/rc.inet1.conf << EOF
IPADDR[0]=""
NETMASK[0]=""
USE_DHCP[0]="yes"
DHCP_HOSTNAME[0]=""
EOF
      

6.4.4. Tuning initialization scripts

Depending on the purpose of the system that is being installed, it should be decided which initialization scripts should be started. The number of services that are available depends on what packages you have installed. You can get get a list of available scripts with ls(1):


# ls -l /mnt/etc/rc.d/rc.*
      

If the executable bits are set on a script, it will be started, otherwise it will not. Obviously you should keep essential scripts executable, including the runlevel-specific scripts. You can set the executable bit on a script with:


# chmod +x /etc/rc.d/rc.scriptname
      

Or remove it with:


# chmod -x /etc/rc.d/rc.scriptname
      

6.4.5. Configuring the dynamic linker run-time bindings

GNU/Linux uses a cache for loading dynamic libraries. Besides that many programs rely on generic version numbers of libraries (e.g. /usr/lib/libgtk-x11-2.0.so, rather than /usr/lib/libgtk-x11-2.0.so.0.600.8). The cache and library symlinks can be updated in one ldconfig(8) run:


# chroot /mnt /sbin/ldconfig
      

You may not know the chroot(1) command; it is a command that executes a command with a different root than the active root. In this example the root directory is changed to /mnt, and from there chroot(1) runs /sbin/ldconfig binary. After the command has finished the system will return to the shell, which uses the original root. To use chroot(1) with other commands this ldconfig(8) command has to be executed once first, because without initializing the dynamic linker run-time bindings most commands will not execute, due to unresolvable library dependencies.

6.4.6. Setting the root password

Now that the dynamic library cache and links are set up, you can execute commands on the installed system. We will make use of this to set the root password. The passwd(1) can be used to set the password for an existing user (the root user is part of the initial /etc/passwd file). We will use the chroot(1) again to execute the command on the target partition:


# chroot /mnt /usr/bin/passwd root
      

6.4.7. Setting the timezone

On UNIX-like systems it is important to set the timezone correctly, because it is used by various parts of the system. For instance, the timezone is used by NTP to synchronize the system time correctly, or by different networking programs to compute the time difference between a client and a server. On Slackware Linux the timezone can be set by linking /etc/localtime to a timezone file. You can find the timezone for your region by browsing the /mnt/usr/share/zoneinfo directory. Most timezones can be found in the subdirectories of their respective regions. For example to use Europe/Amsterdam as the timezone, you can execute the following commands:


# cd /mnt
# rm -rf etc/localtime
# ln -sf /usr/share/zoneinfo/Europe/Amsterdam etc/localtime
      

After setting the time zone, programs still do not know whether the hardware clock is set to the local time, or to the Coordinated Universal Time (UTC) standard. If you use another operating system on the same machine that does not use UTC it is best to set the hardware clock to the local time. On UNIX-like systems it is a custom to set the system time to UTC. You can set what time the system clock uses, by creating the file /etc/hardwareclock, and putting the word localtime in it if your clock is set to the local time, or UTC when it is set to UTC For example, to use UTC, you can create /etc/hardwareclock in the following manner:


# echo "UTC" > /mnt/etc/hardwareclock
      

6.4.8. Creating the X11 font cache

If you are going to use X11, you will have to initialize the font cache for TrueType and Type1 fonts. This can be done with the fc-cache(1) command:


# chroot /mnt /usr/X11R6/bin/fc-cache
      

6.5. Automated installation script

It is easy to combine the steps of a custom installation into one script, which performs the custom steps automatically. This is ideal for making default server installs or conducting mass roll-outs of Linux clients. This sections contains a sample script that was written by William Park. It is easy to add an installation script to the Slackware Linux medium, especially if you use an installation CD-ROM or boot the installation system from an USB flash drive.

The installation system is stored in one compressed image file, that is available on the distribution medium as isolinux/initrd.img. You can make a copy of this image to your hard disk, and decompress it with gunzip(1):


# mv initrd.img initrd.img.gz
# gunzip initrd.img.gz
    

After decompressing the image, you can mount the file as a disk, using the loopback device:


# mount -o loop initrd.img /mnt/hd
    

You can now add a script to the initrd file by adding it to the directory structure that is available under the mount point. After making the necessary changes, you can unmount the filesystem and compress it:


# umount /mnt/hd
# gzip initd.img
# mv initrd.img.gz initrd.img
    

You can then put the new initrd.img file on the installation medium, and test the script.


#! /bin/sh
# Copyright (c) 2003-2005 by William Park <[email protected]>.
# All rights reserved.
#
# Usage: slackware-install.sh

rm_ln ()                # Usage: rm_ln from to
{
        rm -rf $2; ln -sf $1 $2
}


###############################################################################
echo "Partitioning harddisk..."

(   echo -ne "n\np\n1\n\n+1000M\n"      # /dev/hda1 --> 1GB swap
        echo -ne "n\np\n2\n\n+6000M\n"  # /dev/hda2 --> 6GB /
        echo -ne "t\n1\n82\nw\n"
) | fdisk /dev/hda

mkswap /dev/hda1                # swap
swapon /dev/hda1

mke2fs -c /dev/hda2             # /
mount /dev/hda2 /mnt


###############################################################################
echo "Installing packages..."

mount -t iso9660 /dev/hdc /cdrom        # actually, /var/log/mount
cd /cdrom/slackware
for p in [a-z]*; do             # a, ap, ..., y
        installpkg -root /mnt -priority ADD $p/*.tgz
done

cd /mnt


###############################################################################
echo "Configuring /dev/* stuffs..."

rm_ln psaux dev/mouse           # or, 'input/mice' for usb mouse
rm_ln ttyS0 dev/modem
rm_ln hdc dev/cdrom
rm_ln hdc dev/dvd


###############################################################################
echo "Configuring /etc/* stuffs..."

cat > etc/fstab << EOF
/dev/hda1   swap         swap     defaults         0  0
/dev/hda2   /            ext2     defaults         1  1
devpts      /dev/pts     devpts   gid=5,mode=620   0  0
proc        /proc        proc     defaults         0  0
#
/dev/cdrom  /mnt/cdrom   iso9660  noauto,owner,ro  0  0
/dev/fd0    /mnt/floppy  auto     noauto,owner     0  0
tmpfs       /dev/shm     tmpfs    noauto           0  0
EOF

cat > etc/networks << EOF
loopback        127.0.0.0
localnet        192.168.1.0
EOF
cat > etc/hosts << EOF
127.0.0.1       localhost
192.168.1.1     node1.example.net       node1
EOF
cat > etc/resolv.conf << EOF
search example.net
nameserver 127.0.0.1
EOF
cat > etc/HOSTNAME << EOF
node1.example.net
EOF

## setup.05.fontconfig
chroot . /sbin/ldconfig         # must be run before other program
chroot . /usr/X11R6/bin/fc-cache

chroot . /usr/bin/passwd root

## setup.06.scrollkeeper
chroot . /usr/bin/scrollkeeper-update

## setup.timeconfig
rm_ln /usr/share/zoneinfo/Canada/Eastern  etc/localtime
cat > etc/hardwareclock << EOF
localtime
EOF

## setup.liloconfig
cat > etc/lilo.conf << EOF
boot=/dev/hda
delay=100
vga=normal      # 80x25 char
# VESA framebuffer console:
#   pixel       char    8bit    15bit   16bit   24bit
#   -----       ----    ----    -----   -----   -----
#   1600x1200           796     797     798     799
#   1280x1024   160x64  775     793     794     795
#   1024x768    128x48  773     790     791     792
#   800x600     100x37  771     787     788     789
#   640x480     80x30   769     784     785     786
image=/boot/vmlinuz             # Linux
        root=/dev/hda2
        label=bare.i
        read-only
# other=/dev/hda1               # Windows
#     label=win
#     table=/dev/hda
EOF
lilo -r .

## setup.xwmconfig
rm_ln xinitrc.fvwm95  etc/X11/xinit/xinitrc


###############################################################################
echo "Configuring /etc/rc.d/rc.* stuffs..."

cat > etc/rc.d/rc.keymap << EOF
#! /bin/sh
[ -x /usr/bin/loadkeys ] && /usr/bin/loadkeys us.map
EOF
chmod -x etc/rc.d/rc.keymap

## setup.mouse
cat > etc/rc.d/rc.gpm << 'EOF'
#! /bin/sh
case $1 in
        stop)
            echo "Stopping gpm..."
            /usr/sbin/gpm -k
            ;;
        restart)
            echo "Restarting gpm..."
            /usr/sbin/gpm -k
            sleep 1
            /usr/sbin/gpm -m /dev/mouse -t ps2
            ;;
        start)
            echo "Starting gpm..."
            /usr/sbin/gpm -m /dev/mouse -t ps2
            ;;
        *)
            echo "Usage $0 {start|stop|restart}"
            ;;
esac
EOF
chmod +x etc/rc.d/rc.gpm

## setup.netconfig
cat > etc/rc.d/rc.inet1.conf << EOF
IPADDR=(192.168.1.1)            # array variables
NETMASK=(255.255.255.0)
USE_DHCP=()                     # "yes" or ""
DHCP_HOSTNAME=()
GATEWAY=""
DEBUG_ETH_UP="no"
EOF

cat > etc/rc.d/rc.netdevice << EOF
/sbin/modprobe 3c59x
EOF
chmod +x etc/rc.d/rc.netdevice

## setup.setconsolefont
mv etc/rc.d/rc.font{.sample,}
chmod -x etc/rc.d/rc.font

## setup.services
chmod +x etc/rc.d/rc.bind
chmod +x etc/rc.d/rc.hotplug
chmod +x etc/rc.d/rc.inetd
chmod +x etc/rc.d/rc.portmap
chmod +x etc/rc.d/rc.sendmail
#
chmod -x etc/rc.d/rc.atalk
chmod -x etc/rc.d/rc.cups
chmod -x etc/rc.d/rc.httpd
chmod -x etc/rc.d/rc.ip_forward
chmod -x etc/rc.d/rc.lprng
chmod -x etc/rc.d/rc.mysqld
chmod -x etc/rc.d/rc.pcmcia
chmod -x etc/rc.d/rc.samba
chmod -x etc/rc.d/rc.sshd