Handsfree PXE/kickstart Auto Install for Slackware Linux

I have retired the Mutagenix LiveCD for the time being, but you can still find the webpages and the last images released here. I no longer provide support for this project.

Configuring the Auto-install

This page describes a process which I've used to do a handsfree, network booted, auto-install of Slackware Linux. I share this info in the hopes that it is useful, but with absolutely no warranty as to it's effectiveness or use.

Of inestimable value is the work that was done by AlienBOB on the PXE boot and install system, which can be found here. The only change required to update AlienBOB's documentation for Slackware 12.x, is to take into account that the initrd is now a cpio archive.

I will keep a changelog here.

Design Goal:

My primary design goal was to make as few changes as possible to official Slackware files. To that end, I was able to restrict changes to a single official file and introduce only one additional file which does not remain after booting into the newly installed system.

Modified File:

Introduced File:

Prior to beginning here, make sure you have successfully completed a PXE network install ala Alien BOB's instructions. Once that is done, you are ready for the next step.

Unpack the initrd.img using the following command:

gzip -dc ../initrd.img | cpio -i -d -H newc --no-absolute-filenames

Edit initrd/etc/rc.d/rc.S. I've simply added if wrappers around the blocks of code, checking for the cf= commandline option. My changes are highlighted in red.


# if no cf= was passed from the pxeconfig file, present the keyboard dialog, else skip it.
if [ -z "`grep cf= /proc/cmdline`" ]; then
if ! cat /proc/cmdline | grep -q 'kbd=' 2> /dev/null ; then
  echo
  echo
  echo "

# if cf= was passed from the pxeconfig file, start kickstart.sh and forget the rest.
if [ -n "`grep cf= /proc/cmdline`" ]; then
 /usr/lib/setup/kickstart.sh
else
# Provision for unattended network configuration:
/usr/lib/setup/SeTnet boot

# Start dropbear ssh server (only if a configured interface is present):
/etc/rc.d/rc.dropbear start

# Fake login:  (fooled ya! ;^)

cat /etc/issue
echo -n "slackware login: "
read BOGUS_LOGIN
cat /etc/motd
fi

Copy the kickstart.conf config file to into your /tftpboot directory. This file is simply a set of Key -> Value pairs that kickstart.sh (see the following section) sources. Modify the values for your needs. Download the latest version of this config file here. The displayed version may be out of date.

There are a couple of the included options below which are not supported by the kickstart.sh script and are only placeholders until someone sends me a patch ;) I also have not tested all of the various combinations of options.

kickstart.conf

## kickstart config file
## April 23, 2009
## Modprobe network drivers. List of drivers separated by a whitespace, wrapped in quotes.
## SMB installs require the cifs driver
MODULES="e100"

## Configure network
ENET_MODE=static		# [static|dhcp]
ENET_DEVICE=eth0

## if ENET_MODE above is static, set the following variables.
LOCAL_IPADDR=192.168.1.254
LOCAL_NETMASK=255.255.255.0
LOCAL_BROADCAST=192.168.1.255
LOCAL_GATEWAY=192.168.1.31
LOCAL_NAMESERVERS="192.168.1.17 24.225.0.1 24.225.5.2"

## Select Key map: keymap choices can be found in initrd/etc/keymaps.tar.gz
## Do not include the trailing ".bmap"
KEYMAP=us
TZ=US/Central	 	# timezones options can be found in /usr/share/zoneinfo
HWCLOCK=utc			# [utc|localtime]

## start the dropbear ssh server
SSH_SERVER=yes 			# [yes|no]

## Source Config,
NET_SOURCE=NFS 				# [FTP,HTTP,NFS,SMB]
REMOTE_IPADDR=192.168.1.22		# NFS
REMOTE_PATH=/mirror/Slackware/slackware-12.2/slackware # FTP,HTTP,NFS
REMOTE_SHARE=//192.168.1.22/public 	# SMB
REMOTE_URL=ftp://192.168.1.22 		# FTP,HTTP

## drives and partitions
PARTITION_DEVICE=yes		# [yes|no]
DEVICE=/dev/sda			# Ex. /dev/hda, /dev/sda (device, not partition)

# Currently supports four or less partitions
# partition device node,  mountpoint, filesystem[ext2|ext3|xfs|jfs], startGB, endGB, format
PART1=/dev/sda1,/,ext3,0,10GB,format
PART2=/dev/sda2,/home,ext2,10GB,20GB,format
PART3=/dev/sda3,/usr,xfs,20GB,50GB,format
PART4=/dev/sda4,/var,jfs,50GB,80GB,format

## Which packages to install?
PACKAGES=diskset		# [diskset|pkglist|both|none]
## disk sets to install separated by white space, wrapped in quotes
DISK_SETS="a ap n"		# [a|ap|d|e|f|k|kde|kdei|l|n|t|tcl|x|xap|y|ALL}

## packages are installed, lets configure
## Encrypted password.  Escape the .  Default password is kickstart.
ROOT_PW="$1$J7uVdTt7$eMA2vZoGRsGz93tBXWGR4."

## set hostname
HOSTNAME="kickstart"
DOMAIN="example.net"

pkglist.txt

If you want to install a specific subset of packages, instead of, or in addition to, full disksets, you can specify those files in the pkglist.txt file. Make this file available via tftp as well in the /tftpboot directory. Lines that begin with "#" are excluded:
# example pkglist.txt
d/gcc  		## comment about gcc.
d/gettext
d/mercurial
The kickstart.sh script will install all packages that match the filename, so the line d/gcc above will actually install all files that begin with "gcc" in the "d" diskset:

kickstart.sh

Copy the kickstart.sh script to initrd/usr/lib/setup/kickstart.sh. Download the latest version of this file here. The displayed script may be out of date.
#!/bin/sh
## kickstart shell script
## Dan Barber  Apr 23, 2009

KICKSTART=kickstart.conf
PKGLIST=pkglist.txt
MOUNT=/var/log/mount
TARGET=/mnt
TMP=/var/log/setup/tmp

if [ ! -d $TMP ]; then
 mkdir -p $TMP
fi

for CMDELEM in $(cat /proc/cmdline) ; do
 if $(echo $CMDELEM | grep -q "^cf=") ; then
  CONFIGFILE=$(echo $CMDELEM | cut -f2 -d=)
  NET_MOD=$(echo $CONFIGFILE | cut -f1 -d,)
  PROTO=$(echo $CONFIGFILE | cut -f2 -d,)
  DLSERVER=$(echo $CONFIGFILE | cut -f3 -d,)
  KICKSTART=$(echo $CONFIGFILE | cut -f4 -d,)
  PKGLIST=$(echo $CONFIGFILE | cut -f5 -d,)
  dialog --title "FETCHING CONFIGURATION AND PACKAGE LIST" --infobox \
   "
Attempting to fetch a remote configuration file using $PROTO ..." 54 56
 fi
done

if [ -n "$CONFIGFILE" ]; then
 for i in $NET_MOD; do modprobe $i 1>/dev/null 2>/dev/null ; done
  dhcpcd $ENET_DEVICE
 if [ "$PROTO" = "tftp" ]; then
  tftp -g -r $KICKSTART -l $TMP/$KICKSTART $DLSERVER 1>/dev/null 2>&1
  tftp -g -r $PKGLIST -l $TMP/$PKGLIST $DLSERVER 
 elif [ "$PROTO" = "ftp" -o "$PROTO" = "http" ]; then
  wget -q -P $TMP -O $KICKSTART ${PROTO}://${DLSERVER}${KICKSTART}
  wget -q -P $TMP -O $PKGLIST ${PROTO}://${DLSERVER}${PKGLIST}
 fi
fi

if [ -f $TMP/$KICKSTART ]; then
 eval $(grep "^MODULES=" $TMP/$KICKSTART)
 eval $(grep "^ENET_DEVICE=" $TMP/$KICKSTART)
 eval $(grep "^ENET_MODE=" $TMP/$KICKSTART)
 eval $(grep "^LOCAL_IPADDR=" $TMP/$KICKSTART)
 eval $(grep "^LOCAL_NETMASK=" $TMP/$KICKSTART)
 eval $(grep "^LOCAL_BROADCAST=" $TMP/$KICKSTART)
 eval $(grep "^LOCAL_GATEWAY=" $TMP/$KICKSTART)
 eval $(grep "^LOCAL_NAMESERVERS=" $TMP/$KICKSTART)
 eval $(grep "^SSH_SERVER=" $TMP/$KICKSTART)
 eval $(grep "^NET_SOURCE=" $TMP/$KICKSTART)
 eval $(grep "^REMOTE_IPADDR=" $TMP/$KICKSTART)
 eval $(grep "^REMOTE_PATH=" $TMP/$KICKSTART)
 eval $(grep "^REMOTE_SHARE=" $TMP/$KICKSTART)
 eval $(grep "^REMOTE_URL=" $TMP/$KICKSTART)
 eval $(grep "^PARTITION_DEVICE=" $TMP/$KICKSTART)
 eval $(grep "^DEVICE=" $TMP/$KICKSTART)
 eval $(grep "^PART1=" $TMP/$KICKSTART)
 eval $(grep "^PART2=" $TMP/$KICKSTART)
 eval $(grep "^PART3=" $TMP/$KICKSTART)
 eval $(grep "^PART4=" $TMP/$KICKSTART)
 eval $(grep "^PACKAGES=" $TMP/$KICKSTART)
 eval $(grep "^DISK_SETS=" $TMP/$KICKSTART)
 eval $(grep "^ROOT_PW=" $TMP/$KICKSTART)
 eval $(grep "^HOSTNAME=" $TMP/$KICKSTART)
 eval $(grep "^DOMAIN=" $TMP/$KICKSTART)
 eval $(grep "^KEYMAP=" $TMP/$KICKSTART)
 eval $(grep "^TZ=" $TMP/$KICKSTART)
 eval $(grep "^HWCLOCK=" $TMP/$KICKSTART)
fi


for i in $MODULES; do modprobe $i 1>/dev/null 2>/dev/null ; done

if [ "$SSH_SERVER" = "yes" ]; then
 if [ -x /etc/rc.d/rc.dropbear ]; then
  /etc/rc.d/rc.dropbear start
 fi
fi

## Discover partition information
PART1_DEV=`echo $PART1 | awk -F, '{print $1}'`
PART1_MNT=`echo $PART1 | awk -F, '{print $2}'`
PART1_FS=`echo $PART1 | awk -F, '{print $3}'`
PART1_START=`echo $PART1 | awk -F, '{print $4}'`
PART1_END=`echo $PART1 | awk -F, '{print $5}'`
PART1_FORMAT=`echo $PART1 | awk -F, '{print $6}'`
##-----
PART2_DEV=`echo $PART2 | awk -F, '{print $1}'`
PART2_MNT=`echo $PART2 | awk -F, '{print $2}'`
PART2_FS=`echo $PART2 | awk -F, '{print $3}'`
PART2_START=`echo $PART2 | awk -F, '{print $4}'`
PART2_END=`echo $PART2 | awk -F, '{print $5}'`
PART2_FORMAT=`echo $PART2 | awk -F, '{print $6}'`
##-----
PART3_DEV=`echo $PART3 | awk -F, '{print $1}'`
PART3_MNT=`echo $PART3 | awk -F, '{print $2}'`
PART3_FS=`echo $PART3 | awk -F, '{print $3}'`
PART3_START=`echo $PART3 | awk -F, '{print $4}'`
PART3_END=`echo $PART3 | awk -F, '{print $5}'`
PART3_FORMAT=`echo $PART3 | awk -F, '{print $6}'`
##-----
PART4_DEV=`echo $PART4 | awk -F, '{print $1}'`
PART4_MNT=`echo $PART4 | awk -F, '{print $2}'`
PART4_FS=`echo $PART4 | awk -F, '{print $3}'`
PART4_START=`echo $PART4 | awk -F, '{print $4}'`
PART4_END=`echo $PART4 | awk -F, '{print $5}'`
PART4_FORMAT=`echo $PART4 | awk -F, '{print $6}'`

## Partition Device
if [ "$PARTITION_DEVICE" = "yes" ]; then
 #START=0
 #END=`parted $DEVICE print | grep Disk | awk -F: '{print $2}'`
  for i in 1 2 3 4; do
   parted -s $DEVICE rm $i 1>/dev/null 2>/dev/null
  done
 sleep 1
 if [ -n "$PART1_END" ]; then
   parted -s $DEVICE mkpart primary $PART1_START $PART1_END
 fi
 if [ -n "$PART2_END" ]; then
   parted -s $DEVICE mkpart primary $PART2_START $PART2_END
 fi
 if [ -n "$PART3_END" ]; then
   parted -s $DEVICE mkpart primary $PART3_START $PART3_END
 fi
 if [ -n "$PART4_END" ]; then
   parted -s $DEVICE mkpart primary $PART4_START $PART4_END
 fi
fi

if [ "$PART1_FORMAT" = "format" ]; then
  MOUNTED=`df | grep $PART1_DEV`
  if [ "$MOUNTED" != "" ];then
   umount $PART1_DEV
  fi
   if [ "$PART1_FS" = "ext2" ]; then
    mkfs.ext2 $PART1_DEV
   fi
   if [ "$PART1_FS" = "ext3" ]; then
    mkfs.ext2 -j $PART1_DEV
   fi
   if [ "$PART1_FS" = "jfs" ]; then
    mkfs.jfs -q $PART1_DEV
   fi
   if [ "$PART1_FS" = "xfs" ]; then
    mkfs.xfs -f $PART1_DEV
   fi
fi

if [ "$PART2_FORMAT" = "format" ]; then
  MOUNTED=`df | grep $PART2_DEV`
  if [ "$MOUNTED" != "" ];then
   umount $PART2_DEV
  fi
   if [ "$PART2_FS" = "ext2" ]; then
    mkfs.ext2 $PART2_DEV
   fi
   if [ "$PART2_FS" = "ext3" ]; then
    mkfs.ext2 -j $PART2_DEV
   fi
   if [ "$PART2_FS" = "jfs" ]; then
    mkfs.jfs -q $PART2_DEV
   fi
   if [ "$PART2_FS" = "xfs" ]; then
    mkfs.xfs -f $PART2_DEV
   fi
fi

if [ "$PART3_FORMAT" = "format" ]; then
  MOUNTED=`df | grep $PART3_DEV`
  if [ "$MOUNTED" != "" ];then
   umount $PART3_DEV
  fi
   if [ "$PART3_FS" = "ext2" ]; then
    mkfs.ext2 $PART3_DEV
   fi
   if [ "$PART3_FS" = "ext3" ]; then
    mkfs.ext2 -j $PART3_DEV
   fi
   if [ "$PART3_FS" = "jfs" ]; then
    mkfs.jfs -q $PART3_DEV
   fi
   if [ "$PART3_FS" = "xfs" ]; then
    mkfs.xfs -f $PART3_DEV
   fi
fi

if [ "$PART4_FORMAT" = "format" ]; then
  MOUNTED=`df | grep $PART4_DEV`
  if [ "$MOUNTED" != "" ];then
   umount $PART4_DEV
  fi
   if [ "$PART4_FS" = "ext2" ]; then
    mkfs.ext2 $PART4_DEV
   fi
   if [ "$PART4_FS" = "ext3" ]; then
    mkfs.ext2 -j $PART4_DEV
   fi
   if [ "$PART4_FS" = "jfs" ]; then
    mkfs.jfs -q $PART4_DEV
   fi
   if [ "$PART4_FS" = "xfs" ]; then
    mkfs.xfs -f $PART4_DEV
   fi
fi

MOUNTED=`df | grep $PART1_DEV`
if [ "$MOUNTED" = "" ];then
  mount -t$PART1_FS $PART1_DEV /mnt
fi

MOUNTED=`df | grep $PART2_DEV`
if [ "$MOUNTED" = "" ];then
	if [ ! -e /mnt$PART2_MNT ]; then
    mkdir /mnt$PART2_MNT
  fi
  mount -t$PART2_FS $PART2_DEV /mnt$PART2_MNT
fi

MOUNTED=`df | grep $PART3_DEV`
if [ "$MOUNTED" = "" ];then
	if [ ! -e /mnt$PART3_MNT ]; then
    mkdir /mnt$PART3_MNT
  fi
  mount -t$PART3_FS $PART3_DEV /mnt$PART3_MNT
fi

MOUNTED=`df | grep $PART4_DEV`
if [ "$MOUNTED" = "" ];then
	if [ ! -e /mnt$PART4_MNT ]; then
    mkdir /mnt$PART4_MNT
  fi
  mount -t$PART4_FS $PART4_DEV /mnt$PART4_MNT
fi


if [ "$NET_SOURCE" = "NFS" ]; then
 mount -r -t nfs -o nolock $REMOTE_IPADDR:$REMOTE_PATH $MOUNT
elif [ "$NET_SOURCE" = "SMB" ]; then
 mount -t cifs -o ro,guest,sec=none $REMOTE_SHARE $MOUNT
elif [ "$NET_SOURCE" = "FTP" ] || [ "$NET_SOURCE" = "HTTP" ]; then
 echo "FTP and HTTP installs are not yet supported in kickstart."
else 
 echo "$NET_SOURCE is not a valid option."
fi


if [ "$PACKAGES" = "diskset" ];then
 if [ "$DISK_SETS" != "" ]; then
	if  [ "$DISK_SETS" = "ALL" ]; then
   installpkg -root $TARGET -infobox $MOUNT/*/*tgz
	else
   for i in $DISK_SETS; do installpkg -root $TARGET -infobox $MOUNT/$i/*tgz; done
	fi
 fi
elif [ "$PACKAGES" = "pkglist" ];then
 for i in `cat $TMP/pkglist.txt | grep -v "^#"`; do installpkg -root $TARGET -infobox $MOUNT/$i*tgz; done
elif [ "$PACKAGES" = "both" ];then
 if [ "$DISK_SETS" != "" ]; then
  for i in $DISK_SETS; do installpkg -root $TARGET -infobox $MOUNT/$i/*tgz; done
 fi
 for i in `cat $TMP/pkglist.txt`; do installpkg -root $TARGET -infobox $MOUNT/$i*tgz; done
fi

## FSTAB
cat /dev/null > $TARGET/etc/fstab
printf "%-16s %-16s %-11s %-16s %-3s %s
" "$PART1_DEV" "/" "$PART1_FS" "defaults" "1" "1" >> $TARGET/etc/fstab
if [ -n "$PART2_END" ];then 
printf "%-16s %-16s %-11s %-16s %-3s %s
" "$PART2_DEV" "$PART2_MNT" "$PART2_FS" "defaults" "1" "1" >> $TARGET/etc/fstab
fi
if [ -n "$PART3_END" ];then 
printf "%-16s %-16s %-11s %-16s %-3s %s
" "$PART3_DEV" "$PART3_MNT" "$PART3_FS" "defaults" "1" "1" >> $TARGET/etc/fstab
fi
if [ -n "$PART4_END" ];then 
printf "%-16s %-16s %-11s %-16s %-3s %s
" "$PART4_DEV" "$PART4_MNT" "$PART4_FS" "defaults" "1" "1" >> $TARGET/etc/fstab
fi
printf "%-16s %-16s %-11s %-16s %-3s %s
" "#/dev/cdrom" "/mnt/cdrom" "auto" "noauto,owner,ro" "0" "0" >> $TARGET/etc/fstab
printf "%-16s %-16s %-11s %-16s %-3s %s
" "/dev/fd0" "/mnt/floppy" "auto" "noauto,owner" "0" "0" >> $TARGET/etc/fstab
printf "%-16s %-16s %-11s %-16s %-3s %s
" "devpts" "/dev/pts" "devpts" "gid=5,mode=620" "0" "0" >> $TARGET/etc/fstab
printf "%-16s %-16s %-11s %-16s %-3s %s
" "proc" "/proc" "proc" "defaults" "0" "0" >> $TARGET/etc/fstab
printf "%-16s %-16s %-11s %-16s %-3s %s
" "tmpfs" "/dev/shm" "tmpfs" "defaults" "0" "0" >> $TARGET/etc/fstab

## Set Root Passwd
sed "/^root:/d" $TARGET/etc/shadow > $TMP/tmp_shadow
echo "root:$ROOT_PW:14348:0:::::" > $TARGET/etc/shadow
cat $TMP/tmp_shadow >> $TARGET/etc/shadow
rm $TMP/tmp_shadow

## Set Hostname
if [ "$HOSTNAME" != "" ]; then
echo $HOSTNAME.$DOMAIN > $TARGET/etc/HOSTNAME
sed -i -e "s/example.net/$DOMAIN/g" -e "s/darkstar/$HOSTNAME/g" $TARGET/etc/hosts
fi

## Set Keymap
if [ "$KEYMAP" != "" ]; then
	tar xzOf /etc/keymaps.tar.gz $KEYMAP.bmap | loadkmap
  echo "#!/bin/sh" > $TARGET/etc/rc.d/rc.keymap
  echo "# Load the keyboard map.  More maps are in /usr/share/kbd/keymaps." \
  >> $TARGET/etc/rc.d/rc.keymap
  echo "if [ -x /usr/bin/loadkeys ]; then" >> $TARGET/etc/rc.d/rc.keymap
  echo " /usr/bin/loadkeys $KEYMAP" >> $TARGET/etc/rc.d/rc.keymap
  echo "fi" >> $TARGET/etc/rc.d/rc.keymap
  chmod 755 $TARGET/etc/rc.d/rc.keymap
fi

if [ "$TZ" != "" ]; then
   cd $TARGET/etc
   if [ -r $TARGET/usr/share/zoneinfo/$TZ -o \
        -r /var/log/mount/usr/share/zoneinfo/$TZ -o \
        -L $TARGET/usr/share/zoneinfo/$TZ -o \
        -L /var/log/mount/usr/share/zoneinfo/$TZ ]; then
      ln -sf /usr/share/zoneinfo/$TZ localtime-copied-from
      rm -f localtime
      cd ..
      chroot . cp etc/localtime-copied-from etc/localtime
   fi
fi

if [ "$HWCLOCK" != "" ]; then
  echo "# /etc/hardwareclock" > $TARGET/etc/hardwareclock
  echo "#" >> $TARGET/etc/hardwareclock
  echo "# Tells how the hardware clock time is stored." >> $TARGET/etc/hardwareclock
  echo "# You should run timeconfig to edit this file." >> $TARGET/etc/hardwareclock
  echo >> $TARGET/etc/hardwareclock
  echo $HWCLOCK >> $TARGET/etc/hardwareclock
fi



## Configure /etc/rc.d/rc.inet1.conf
if [ "$ENET_MODE" = "dhcp" ]; then
 USE_DHCP=yes
 LOCAL_IPADDR=""
 LOCAL_NETMASK=""
 LOCAL_GATEWAY=""
fi
cat << EOF > $TARGET/etc/rc.d/rc.inet1.conf
# /etc/rc.d/rc.inet1.conf
#
# This file contains the configuration settings for network interfaces.
# If USE_DHCP[interface] is set to "yes", this overrides any other settings.
# If you don't have an interface, leave the settings null ("").

# You can configure network interfaces other than eth0,eth1... by setting
# IFNAME[interface] to the interface's name. If IFNAME[interface] is unset
# or empty, it is assumed you're configuring eth.

# Several other parameters are available, the end of this file contains a
# comprehensive set of examples.

# =============================================================================

# Config information for eth0:
IPADDR[0]="$LOCAL_IPADDR"
NETMASK[0]="$LOCAL_NETMASK"
USE_DHCP[0]="$USE_DHCP"
DHCP_HOSTNAME[0]=""

# Config information for eth1:
IPADDR[1]=""
NETMASK[1]=""
USE_DHCP[1]=""
DHCP_HOSTNAME[1]=""

# Config information for eth2:
IPADDR[2]=""
NETMASK[2]=""
USE_DHCP[2]=""
DHCP_HOSTNAME[2]=""

# Config information for eth3:
IPADDR[3]=""
NETMASK[3]=""
USE_DHCP[3]=""
DHCP_HOSTNAME[3]=""

# Default gateway IP address:
GATEWAY="$LOCAL_GATEWAY"

# Change this to "yes" for debugging output to stdout.  Unfortunately,
# /sbin/hotplug seems to disable stdout so you'll only see debugging output
# when rc.inet1 is called directly.
DEBUG_ETH_UP="no"

## Example config information for wlan0.  Uncomment the lines you need and fill
## in your info.  (You may not need all of these for your wireless network)
#IFNAME[4]="wlan0"
#IPADDR[4]=""
#NETMASK[4]=""
#USE_DHCP[4]="yes"
#DHCP_HOSTNAME[4]="icculus-wireless"
#DHCP_KEEPRESOLV[4]="yes"
#DHCP_KEEPNTP[4]="yes"
#DHCP_KEEPGW[4]="yes"
#DHCP_IPADDR[4]=""
#WLAN_ESSID[4]=BARRIER05
#WLAN_MODE[4]=Managed
##WLAN_RATE[4]="54M auto"
##WLAN_CHANNEL[4]="auto"
##WLAN_KEY[4]="D5AD1F04ACF048EC2D0B1C80C7"
##WLAN_IWPRIV[4]="set AuthMode=WPAPSK | set EncrypType=TKIP | set WPAPSK=96389dc66eaf7e6efd5b5523ae43c7925ff4df2f8b7099495192d44a774fda16"
#WLAN_WPA[4]="wpa_supplicant"
#WLAN_WPADRIVER[4]="ndiswrapper"

## Some examples of additional network parameters that you can use.
## Config information for wlan0:
#IFNAME[4]="wlan0"              # Use a different interface name nstead of
                                # the default 'eth4'
#HWADDR[4]="00:01:23:45:67:89"  # Overrule the card's hardware MAC address
#MTU[4]=""                      # The default MTU is 1500, but you might need
                                # 1360 when you use NAT'ed IPSec traffic.
#DHCP_KEEPRESOLV[4]="yes"       # If you dont want /etc/resolv.conf overwritten
#DHCP_KEEPNTP[4]="yes"          # If you don't want ntp.conf overwritten
#DHCP_KEEPGW[4]="yes"           # If you don't want the DHCP server to change
                                # your default gateway
#DHCP_IPADDR[4]=""              # Request a specific IP address from the DHCP
                                # server
#WLAN_ESSID[4]=DARKSTAR         # Here, you can override _any_ parameter
                                # defined in rc.wireless.conf, by prepending
                                # 'WLAN_' to the parameter's name. Useful for
                                # those with multiple wireless interfaces.
#WLAN_IWPRIV[4]="set AuthMode=WPAPSK | set EncrypType=TKIP | set WPAPSK=thekey"
                                # Some drivers require a private ioctl to be
                                # set through the iwpriv command. If more than
                                # one is required, you can place them in the
                                # IWPRIV parameter (separated with the pipe (|)
                                # character, see the example).
EOF

## configure nameserver
echo "search $DOMAIN" > $TARGET/etc/resolv.conf
for i in $LOCAL_NAMESERVERS; do
echo "nameserver $i" >> $TARGET/etc/resolv.conf
done
	

## Clean up any permission problems
if [ -d $TARGET/usr/src/linux ]; then
  chmod 755 $TARGET/usr/src/linux
fi
if [ ! -d $TARGET/proc ]; then
  mkdir $TARGET/proc
  chown root.root $TARGET/proc
fi
if [ ! -d $TARGET/sys ]; then
  mkdir $TARGET/sys
  chown root.root $TARGET/sys
fi
chmod 1777 $TARGET/tmp
if [ ! -d $TARGET/var/spool/mail ]; then
  mkdir -p $TARGET/var/spool/mail
  chmod 755 $TARGET/var/spool
  chown root.mail $TARGET/var/spool/mail
  chmod 1777 $TARGET/var/spool/mail
fi

## Run the final configs.  Not hands free here.
cat << EOF > $TARGET/etc/lilo.conf
# LILO configuration file
# generated by 'liloconfig'
#
# Start LILO global section
# Append any additional kernel parameters:
append=" vt.default_utf8=0"
boot = $DEVICE

# Boot BMP Image.
# Bitmap in BMP format: 640x480x8
  bitmap = /boot/slack.bmp
# Menu colors (foreground, background, shadow, highlighted
# foreground, highlighted background, highlighted shadow):
  bmp-colors = 255,0,255,0,255,0
# Location of the option table: location x, location y, number of
# columns, lines per column (max 15), "spill" (this is how many
# entries must be in the first column before the next begins to
# be used.  We don't specify it here, as there's just one column.
  bmp-table = 60,6,1,16
# Timer location x, timer location y, foreground color,
# background color, shadow color.
  bmp-timer = 65,27,0,255

# Standard menu.
# Or, you can comment out the bitmap menu above and 
# use a boot message with the standard menu:
#message = /boot/boot_message.txt

# Wait until the timeout to boot (if commented out, boot the
# first entry immediately):
prompt
# Timeout before the first entry boots.
# This is given in tenths of a second, so 600 for every minute:
timeout = 1200
# Override dangerous defaults that rewrite the partition table:
change-rules
  reset
# VESA framebuffer console @ 1024x768x256
vga = 791
# Normal VGA console
# vga = normal
# VESA framebuffer console @ 1024x768x64k
# vga=791
# VESA framebuffer console @ 1024x768x32k
# vga=790
# VESA framebuffer console @ 1024x768x256
# vga=773
# VESA framebuffer console @ 800x600x64k
# vga=788
# VESA framebuffer console @ 800x600x32k
# vga=787
# VESA framebuffer console @ 800x600x256
# vga=771
# VESA framebuffer console @ 640x480x64k
# vga=785
# VESA framebuffer console @ 640x480x32k
# vga=784
# VESA framebuffer console @ 640x480x256
# vga=769
# End LILO global section
# Linux bootable partition config begins
image = /boot/vmlinuz
  root = $PART1_DEV 
  label = Linux
  read-only
# Linux bootable partition config ends
EOF

lilo -C $TARGET/etc/lilo.conf -b $DEVICE


## All done. Let the user know.
cat << EOF > /etc/motd

Your Slackware Network Auto Install is complete.

Reboot. Ensure that your system is not configured
to boot automatically from LAN, unless you want to
reinstall.

EOF

dialog --title "Slackware Auto Install Complete" --cr-wrap --infobox \
"Your Slackware Network Auto Install is complete.
\

\
Reboot. Ensure that your system is not configured \
to boot automatically from LAN, unless you want to \
reinstall. 
" 13 60

Re-pack the initrd.img using the following command:

find . -print | cpio -o -H newc | gzip -9 > ../initrd.img

At this point, simply reboot the client machine and watch for errors.


Different configs for different machines

On any network, you're going to find a multitude of different systems with different requirements for drivers, packages, etc. You can control how different machines are installed and configured by using different PXE config files and initrd images for each of your subsets. There are several ways to do this.

dhcpd.conf

The host portion of your dhcp file should look something like this. Each host must have a (different) fixed address:

host test {
    hardware ethernet 00:50:8d:d7:66:45;
    fixed-address 192.168.1.254;
}
host test2 {
    hardware ethernet 00:11:11:c9:23:f5;
    fixed-address 192.168.1.253;
}

Create separate PXE config files

Find the hexadecimal equivalent of the target IP addresses:

gethostip 192.168.1.254
192.168.1.254 192.168.1.254 C0A801FE

gethostip 192.168.1.253
192.168.1.253 192.168.1.253 C0A801FD

For each of the hexadecimal values, create a PXE config file of the same name:

cp /tftpboot/slackware-12.2/pxelinux.cfg/default /tftpboot/slackware-12.2/pxelinux.cfg/C0A801FE
cp /tftpboot/slackware-12.2/pxelinux.cfg/default /tftpboot/slackware-12.2/pxelinux.cfg/C0A801FD
When you have numerous machines, some of one type and some of another, you can create two different configs and then use symbolic links to point the hexadecimal files to the correct config.

Two machines that share an Intel chipset and are your web servers:

Two machines that share a Broadcom chipset and are your DNS servers:

Edit your new PXE config files to pass the correct options with a cf= tag, and if necessary a nic= tag to pass the nic driver, interface and mode.

Now when the machine boots, it will pull the correct IP address from dhcpd and then be directed to the corresponding PXE config file in /tftpboot/slackware-12.2/pxelinux.cfg/. Add a cf= and optionally, a nic=, tag to the append statement. initrd/etc/rc.d/rc.S will find the cf= in /proc/cmdline, and initiate kickstart.sh. kickstart.sh will load the appropriate network module, tftp the files over and start the automatic, hands free install.

The fields for cf are: cf=,,,[package list]

The fields for nic= are: nic=::[:ipaddr:netmask[:gateway]]

default hugesmp.s
prompt 0
display message.txt
F1 message.txt
F2 f2.txt
label hugesmp.s
  kernel kernels/hugesmp.s/bzImage
  append initrd=broadcom_dns.img load_ramdisk=1 prompt_ramdisk=0 rw 
  cf=tftp,192.168.1.22,kickstart.conf,pkglist.txt 
  nic=e100:eth0:dhcp
  SLACK_KERNEL=hugesmp.s

This script is a down and dirty, get it working effort. This is not an official effort of Slackware or Patrick Volkerding, and is not associated with alienBOB in any way. There is an effort going on right now to bring this functionality to Slackware in a more integrated, elegant manner. As you can tell elegance is not my strength.

That being said, if you fix any issues, extend the functionality, add any type of error checking or make any improvements, please send patches to dan@mutagenix.org.