Monday, October 31, 2005


Our goal in creating UBLinux was to create a distribution of Linux that was created specifically with the needs of UB students, staff, and faculty in mind.
We had a few goals in mind for this project. First, we wanted to make the installation as simple as possible. We also wanted to maintain support of the software through automatic updates. For these reasons (among others), we decided to base our distribution off of Red Hat Enterprise Linux. RHEL provides our ease of installation through the use of kickstart and provides constant updates through the Red Hat Network.
In creating this documentation, we hope to streamline the process for future versions of UBLinux, and also to give back to the community which helped us, bit by bit, create our distro.
For our initial setup we created a directory called /home/ublinux/. This directory would serve as our build directory for the distribution.
mkdir /home/ublinux
We also obtained the RHEL WS 3 ISOs, and mounted them for easy access.
mount -o loop -t iso9660 rhel-3-U2-i386-ws-disc1.iso /mnt/isomount -o loop -t iso9660 rhel-3-U2-i386-ws-disc2.iso /mnt/iso2mount -o loop -t iso9660 rhel-3-U2-i386-ws-disc3.iso /mnt/iso3mount -o loop -t iso9660 rhel-3-U2-i386-ws-disc4.iso /mnt/iso4
Selecting Packages
For UBLinux, we wanted to include only those packages which would be needed by members of UB. We also wanted to make our distro simple and secure enough so a novice user could use it effectively. For this reason, we opted to exclude several development and server packages. Since we were leaving out packages, there was no reason to include them on the CD.
First, we gathered all of the packages included in the RHEL WS 3 distribution, and put them into a folder called RPMS in our build directory.
mkdir /home/ublinux/RPMScp -rf /mnt/iso/RedHat/RPMS/* /home/ublinux/RPMScp -rf /mnt/iso2/RedHat/RPMS/* /home/ublinux/RPMScp -rf /mnt/iso3/RedHat/RPMS/* /home/ublinux/RPMScp -rf /mnt/iso4/RedHat/RPMS/* /home/ublinux/RPMS
At this point, we downloaded the latest RPMS from the Red Hat Network, and replaced them in our RPM pool accordingly. This would ensure that the user would not have to download a large number of updates after installation.
Now comes the difficult part, which is selecting which packages to use. For our purposes, we based the package list off of the RPM list being used in the Public Sites. Taking a look at the kickstart for the pubsites, we can see our list of packages:
#Package install information
%packages --resolvedeps
@ admin-tools
@ authoring-and-publishing
@ base-x
#Add ons
The example above is obviously shortened, but will suffice for this documentation. Entries with a "@" sign before them signify groups, and those without show individual package names. The groups are specified in the comps.xml file, which is located in /RedHat/base of RHEL WS 3 CD1. This file not only lists the groups but also the RPMs associated with it. It is used by the installer during manual package selection (ie Office/Productivity, which contains the Open Office packages). We could edit this file, but since we're using Red Hat's kickstart to specify which packages are installed, it is not necessary.
Using both comps.xml and our package listing from the pubsite kickstart file, we removed all of the extraneous packages from the RPM directory. If you do not have a kickstart to base package selection off of, you could run through the installer up to the point where you select your own packages, then keep track of which packages you select to have installed. There is unfortunately no simple way to do this, and it will be one of the most time consuming steps in this process.
Of course, you also need to worry about dependency issues when selecting packages. One way to resolve this, as suggested in Brett Schwarz's excellent document "Hacking Red Hat Kickstart", is to create a temporary RPM database and then do a test install of all the RPMs, resolving dependency errors as they arise (and they will).
mkdir /tmp/testdbrpm --initdb --dbpath /tmp/testdbrpm --test --dbpath /tmp/testdb -Uvh /home/ublinux/RPMS/*.rpm
Once we've selected all the packages we want in our distro, we can move on to "Creating the Distribution".
Creating the Distribution
Now that you have all of the RPMs you want installed, updated and free of dependency issues, we are now ready to create our distribution. First, we stored the contents of RHEL WS CD1 in /home/ublinux/i386 (for the architecture of the machine). When we copied it we made sure to include every file, especially a .discinfo file which is necessary for the installer to load. Adding CDs 2-4 is unneccesary, as the only pertinent information they contain is additional RPMs. We then remove the following:
hdlists (these will be generated later)rm /home/ublinux/i386/RedHat/base/hdlist*
RPMsrm /home/ublinux/i386/RedHat/RPMS/*
TRANS.TBL files (trash files, every directory will have one)find /home/ublinux/i386 -name TRANS.TBL -exec rm -f {} \;
We will also copy the following files out to edit at a later time. These are the Anaconda image and the Bootdisk image files. If you do not wish to alter these, it is safe to ignore this step.
Anacondamv /home/ublinux/i386/RedHat/base/stage2.img /home/ublinux/
BootDiskmv /home/ublinux/i386/images/bootdisk.img /home/ublinux/
We are now ready to begin. First, we need to install anaconda-runtime and its packages. These will provide the scripts we need to build our own distro. These RPMS are included in RHEL WS 3 Update 2.
anaconda-9.1.2-2.RHEL.i386.rpm (Disc 4)anaconda-help-9.1-3.RHEL.noarch.rpm (Disc 3)anaconda-images-9.1-3.RHEL.noarch.rpm (Disc 3)anaconda-runtime-9.1.2-2.RHEL.i386.rpm (Disc 3)
Make sure these are all installed on the build system.
cp /mnt/iso3/RedHat/RPMS/anaconda-* /home/ublinux/cp /mnt/iso4/RedHat/RPMS/anaconda-* /home/ublinux/sudo rpm -Uvh /home/ublinux/anaconda-*
Now, let's copy all the RPMs we want to install in our distro.
cp /home/ublinux/RPMS/* /home/ublinux/i386/RedHat/RPMS/
To prevent any errors with the subsequent scripts, we'll run the anaconda-runtimes scripts as root.
su -
Then, to prepare to run the anaconda-runtime scripts, we'll need to set the PYTHONPATH variable. If we don't do this, some scripts (such as pkgorder) will not be able to load required modules.
export PYTHONPATH=/usr/lib/anaconda
The first step in running these scripts is to regenerate the hdlist files from our current set of RPMS.
/usr/lib/anaconda-runtime/genhdlist /home/ublinux/i386
Please note the script requires the FULL path of the build directory. Using a relative path (such as /usr/lib/anaconda-runtime/genhdlist i386) will cause the script to fail with a "No such file or directory" error.
Next, we run a script to determine the order in which the packages will be installed, and we store that information in a file for later use.
/usr/lib/anaconda-runtime/pkgorder /home/ublinux/i386/ i386 > /home/ublinux/pkglist
Please note that if you forget to set the PYTHONPATH variable, you will receive the following error:
Traceback (most recent call last):  File "/usr/lib/anaconda-runtime/pkgorder", line 10, in ?    import whiteout
If we wanted to generate our own Anaconda, we could do so with anaconda-runtime's buildinstall script. However, we had some trouble doing that, namely we'd get an error stating
Traceback (most recent call last):  File "/tmp/treedir.5588/instimage/usr/lib/anaconda-runtime/pkgorder", line 10, in ?    import whiteout      ImportError: No module named whiteout
even though the PYTHONPATH variable was already set. It was later concluded that the reason we received this error was that buildinstall believed that we were trying to build a non-WS3 distro on a WS3 machine. While this was not the case, it's possible that because we used a different RPM list than WS3, the script became confused and failed. Without proper documentation for these anaconda-runtime scripts, we were unable to resolve this issue. Instead, we opted to modify stage2.img directly. This is documented in "Customizing Anaconda".
Next, we need to split the distro into sizes friendlier for CD media. With UBLinux 2, we used the splitdistro script in conjunction with build_distro. However, with this version of anaconda-runtime, splitdistro has made way for, and has made the build_distro obsolete. To use, we run the command
/usr/lib/anaconda-runtime/ --arch=i386 --total-discs=3 --bin-discs=3 --release-string="UBLinux 3" --pkgorderfile=/home/ublinux/pkglist --distdir=/home/ublinux/i386 --src-discs=1 --srcdir=/home/ublinux/i386/SRPMS
Please note that you need to specify the --src-discs and --srcdir even if you don't intend to have any source discs in your distro.
We also received an error occasionally (though I was unable to replicate it for the purposes of this documentation). Most errors I received were due to extra carriage returns created by cutting and pasting the command, which were resolved by typing it out instead.
Please note that UBLinux 3.0 is on three CDs. If your distribution is on fewer (or more) CDs, please keep this in mind for the following commands, which are executed on every CD.
The CDs will be in folders inconveniently marked as -disc1, -disc2, -discX, etc, which makes them slightly difficult to target (often being misinterpreted as command line arguments). So it's a good idea to resolve this first
mv /home/ublinux/i386/-disc1 /home/ublinux/i386/disc1mv /home/ublinux/i386/-disc2 /home/ublinux/i386/disc2mv /home/ublinux/i386/-disc3 /home/ublinux/i386/disc3
The last command that needs to be done is to regenerate the hdlist files one more time, now that the RPMS are spread across multiple CDs. This will also allow hdlist to take into account the current package order.
rm -f /home/ublinux/i386/disc1/RedHat/base/hdlist*
/usr/lib/anaconda-runtime/genhdlist --withnumbers --fileorder /home/ublinux/pkglist /home/ublinux/i386/disc[123]
There you have it. You should now have a working customized distro of RHEL WS 3, if you have no intention of altering the bootdisk and anaconda. If this is the case, move forward to "Creating the Kickstart".
For UBLinux 3, however, we wanted to change all of the Red Hat images. We started first with "Editing the Boot Disk".
Editing the Boot Disk
In order to have the CDs bootable, we need to have a boot disk image.
To edit the Boot Disk, we had to get a hold of bootdisk.img from the RHEL WS 3 CD. If you followed the previous section, the bootdisk.img should be located in /home/ublinux. Otherwise, you can grab it from RHEL CD1 in images/bootdisk.img.
There are probably other (and possibly better) ways to do this, however this is how we did it for UBLinux 3.0.
To get started, we need to write the bootdisk image to a blank floppy so that you can modify it:
dd if=/home/ublinux/bootdisk.img of=/dev/fd0 bs=1024
Now you can mount the floppy disk and modify the contents of it. We modified the syslinux.cfg file so that the default option was a ResNet/DHCP network configuration kickstart file, and we also added an option for an install not pre-configured for netw ork use. For information on creating the kickstart files, see "Creating the Kickstart".
default Rprompt 1timeout 600display boot.msgF1 boot.msgF2 options.msgF3 param.msgF4 rescue.msgF5 help.msglabel linux  kernel vmlinuz  append initrd=initrd.imglabel R  kernel vmlinuz  append ks=cdrom:/dhcp.ks.cfg initrd=initrd.imglabel other  kernel vmlinuz  append ks=cdrom:/ppp.ks.cfg initrd=initrd.img
We also modified the various message files to reflect UB specific information. Finally, we modified the splash.lss file so that we have a nice pretty UB graphic in place of the RedHat graphic.
The graphic is in a somewhat odd format, called LSS16. As the name indicates, it is limited to 16 colors. To edit the graphic, first convert it to a PPM:
lss16toppm < splash.lss > splash.ppm
Next, edit the file using The Gimp. Save the resulting file as an indexed gif with no more than 14 colors (plus black and white, for a total of 16). Then, convert the file to a pnm/ppm:
giftopnm < splash.gif > splash.ppm
Before taking the next step and converting the ppm file to an LSS, ensure that the LANG environment variable is set to en_US. RedHat 9's default LANG variable is en_US.UTF-8, which will cause the LSS conversion to fail. To actually convert the ppm to a n lss, use this command:
ppmtolss16 < splash.ppm > splash.lss
A note on the .msg files on the floppy: These are the message files displayed when the appropriate key (as indicated in the syslinux.cfg file) is pressed. The color codes in these files refer to the index of the graphic contained in splash.lss.
After you have modified the files to your liking, we copy the image over to its proper place on disc 1 by creating another floppy image:
dd if=/dev/fd0 of=/home/ublinux/disc1/images/bootdisk.img
With the bootdisk image finished, we moved onto "Customizing Anaconda".
Customizing Anaconda
As mentioned previously, Anaconda is intended to be customized through use of the buildinstall command. As we were having difficulty using this, we instead opted to alter stage2.img (which stores anaconda) directly. First, we need to mount stage2.img and alter its contents. If you followed the previous section, the file should be located in /home/ublinux. Otherwise, you can get the file from RHEL WS 3 CD 1 in /RedHat/base.
First, we mount the image using
mkdir /mnt/anacondamount -o loop /home/ublinux/stage2.img /mnt/anaconda
Now we need to copy the contents to a directory where we can alter the files. The issue with RHEL WS 3 which we didn't experience with RH9 is that there are several hard links here that will NOT transfer over if we simply copied /mnt/anaconda somewhere else. For this reason, we used tar to package the contents of the directory, and then untarred them where we could work on them.
cd /mnt/anacondatar -cvf /home/ublinux/stage2.tar .cd /home/ublinuxmkdir stage2cd stage2tar -xvf /home/ublinux/stage2.tar
If we did not do this this way, then when we included the final stage2.img in our distribution we'd get a "CD Not Found" error when Anaconda would load.
With the contents of stage2.img in an editable directory, you can now alter the images used by the installer located in usr/share/anaconda/pixmaps and the images used in the installation slideshow in usr/share/anaconda/pixmaps/rnotes. You can also edit the text in the left sidebar, which are in HTML format, in usr/share/anaconda/help/[locale].
After you've made the desired modifications, we need to compress this information back into an img file.
cd /home/ublinuxmkcramfs stage2/
Then, copy the altered stage2.img to the RedHat/base directory in the first CD.
cp /home/ublinux/ /home/ublinux/i386/disc1/RedHat/base/stage2.img
Next, let's take a look at how we automated and simplified installation by "Creating the Kickstart".
Creating the Kickstart
For UBLinux, the kickstart files are extremely important. Kickstart is simply a way of automating the Red Hat installation process. However, if you alter the RPMs (without subsequently altering the comps.xml file) you may want to consider creating a specialized kickstart for your distro. This keeps it so users don't try to install packages that you've removed from the CD. For UBLinux users, it also makes the installation process that much easier.
Two kickstart files are present on the UBLinux CD: one for ResNet/DHCP networking configuration, and one for anything other than DHCP. The only difference between the two files is the "network" line near the beginning of the kickstart file.
We won't go into every setting allowed in the kickstart (since Red Hat already did it). The header of the kickstart files is as follows:
# Generated by Kickstart Configurator
# Customized by Jason Lasker, David Aquilina, Joshua Gardner,
#   and David Dudek for UBLinux

network --bootproto=dhcp
#Reboot after installation
#Install Red Hat Linux instead of upgrade
#Use CDROM installation media
#Set Language Support
langsupport zh_CN.GB2312 zh_TW.Big5 cs_CZ da_DK nl_NL fr_FR de_DE is_IS it_IT ja_JP.eucJP
ko_KR.eucKR no_NO pt_PT ru_RU.k0I8r sl_SI es_ES sv_SE uk_UA --default=en_US
#System bootloader configuration
bootloader --location=mbr
#Clear the Master Boot Record
zerombr yes
#System authorization infomation
auth  --useshadow  --enablemd5
#Network information
#Firewall configuration
# We'll do our own firewall config via an RPM
firewall --disabled
#XWindows configuration information
xconfig --depth=24 --resolution=1024x768 --defaultdesktop=GNOME --startxonboot

This specifies settings that we'd like to have default for UBLinux. Some settings were left out so that the user is prompted during installation (such as the root password).
The next section is a listing of the packages to be installed. If you read our section on "Selecting Packages", this should look pretty familiar.
#Package install information
%packages --resolvedeps
@ admin-tools
@ authoring-and-publishing
@ base-x
#Add ons
The --resolvedeps argument means that kickstart will also install any packages that the list requires. Listings with @ signs are groups of packages, and if you list a package it means you install every package that is labeled as either "default" or "mandatory" in comps.xml. xml. You can also exclude particular packages in groups by using "-(package name)".
Finally, there is a %post section where you can specify any post installation scripts you want to run. For UBLinux 3, we use this section to change a few settings (such as configuring UBLinux for USB hotplugging) and install UB specific packages (ICAClient, Mulberry, etc).
# cdrom is not mounted during post
mkdir -p /mnt/postconfig
mount /tmp/cdrom /mnt/postconfig

# copy our postconfig to the installed system
cp -rf /mnt/postconfig/ub-postconfig /mnt/sysimage/tmp/

# Create S99postkickstart to apply SENS config to run at run level 3
cat > /etc/rc3.d/S99postkickstart <<EOKICK
#  Warn the user about what's going to happen:
echo ""
echo ""
echo "Now performing post-KickStart installation tasks.  The"
echo "system will reboot once this is done."
echo ""
echo "Special thanks to Jason Lasker and the SENS team for assistance"
echo "with this post-install script."
echo ""
sleep 5

ln -s /bin/tcsh /usr/local/bin/

#run through post install scripts
/bin/sh /tmp/ub-postconfig/postinstall 2>&1 | tee /var/tmp/postinstall.log > /dev/console    
#Remove postconfig files from tmp
/bin/rm -rf /tmp/ub-postconfig

# Delete this script so it doesn't go again:
rm -f /etc/rc*.d/S99postkickstart
sleep 5

#End of S99postkickstart file

for dir in rc2.d rc5.d; do
    ln /etc/rc3.d/S99postkickstart /etc/$dir/S99postkickstart
chmod 755 /etc/rc3.d/S99postkickstart

In UBLinux 2.0, we simply called "rpm -U *.rpm" to install these packages. However, in UBLinux 3.0, we created a series of scripts that are copied to a temporary directory, and executed these scripts as part of the runlevel. These scripts are designed to destroy themselves after running initially. Doing it this way allowed us to make sure that the postinstall is completed, and also to give the user some form of GUI to see the progress of the postconfig installation.
To see these postconfig scripts, feel free to download the UBLinux 3 Upgrade for RHEL WS 3 from our download site. (Please note: you need to be either on campus or connecting through the UBVPN client to access our download site).
All of the scripts and RPMs we wanted installed were put into a ub-postconfig directory. This directory was then copied to disc 3 of the distro, where the postconfig install would take place.
cp -r ubpostconfig /home/ublinux/i386/disc3
Once finished, we copied dhcp.ks.cfg and ppp.ks.cfg to disc 1 of our distribution.
cp *.ks.cfg /home/ublinux/i386/disc1
The distribution is almost finished. All that is left is to take our discs and package them by "Making the ISOs".
Making the ISOs
The final step in this long process is getting the distro onto a CD for installation. First, we need to make ISOs from our discs, for which we use the mkisofs command. For the first disc, we'll use a few extra arguments to make the CD bootable.
cd /home/ublinux/i386mkisofs -r -T -J -V "UBLinux 3.0 Disk 1 of 3" -b images/bootdisk.img -c isolinux/ -o /home/ublinux/i386/UBLinux3-Disk1.iso /home/ublinux/i386/disc1
For each subsequent CD, we can leave off the -b and -c arguments.
mkisofs -r -T -J -V "UBLinux 3.0 Disk 2 of 3" -o /home/ublinux/i386/UBLinux3-Disk2.iso /home/ublinux/i386/disc2mkisofs -r -T -J -V "UBLinux 3.0 Disk 3 of 3" -o /home/ublinux/i386/UBLinux3-Disk3.iso /home/ublinux/i386/disc3
Finally, you'll need to implant the MD5 into the isos. Forgetting to do this could cause the ISOs to fail the media check, with an error saying "Unable to read the disc checksum from the primary volume descriptor".
To do this, we use the implantmd5sum command, which is part of the anaconda-runtime package:
/usr/lib/anaconda-runtime/implantmd5sum UBLinux3-Disk1.iso/usr/lib/anaconda-runtime/implantmd5sum UBLinux3-Disk2.iso/usr/lib/anaconda-runtime/implantmd5sum UBLinux3-Disk3.iso
To burn these ISOs, use the cdrecord command:
(for <=2.4 kernel)cdrecord -v speed=32 dev=0,0,0 -data UBLinux-Disk1.iso(for 2.6 kernel)cdrecord -v speed=32 dev=ATAPI:0,0,0 -data UBLinux-Disk1.iso


Post a Comment

<< Home