245 ■ ■ ■ CHAPTER 38 LinuxGold-SystemBuild B uilding a system manually can be fun. Building many systems manually is tedious and prone to error, especially when all systems should be built in exactly the same way. For this reason, Kickstart by Red Hat, Jumpstart by Sun, and other utilities were created to automate a network-based system build that is based on preset parameters. These utili- ties work well when you are building new systems on a regular basis. The downside of this method is that a client is required to be on the network and it needs to have access to the server to do a system build. Also, a build server needs to be set up and maintained, but if you are building only a moderate number of systems, it may not be worth the extra effort to set up a build server. The build script in this chapter has a small image size and can be run from a bootable CD. The CD boots and then automatically calls a script that partitions and formats the hard disk. The script then proceeds to install a preconfigured OS image to the system hard disk. This method has the advantage of having no network or build-server requirements. The newly built system can also have site-specific configurations that may not be part of a standard installation. The script has the added advantage that it can install applications that may not be in a proprietary format, such as an RPM (Red Hat Package Manager). The process I used was to find a Linux live distribution on a single boot CD that was designed to be customizable. I chose the “Roll your own Linux Rescue or Setup CD.” 1 There are now many distributions like this, including live DVD images for larger installa- tions, but at the time this one seemed to be the best choice. You install this distribution on a hard disk on a running system, from which you can customize the final CD image. The gold image file and this script are placed into the dis- tribution directory tree, and the final modification is to change the live CD startup script to call your build script. The last task is to run the script that came with the distribution to create the final .iso file, which you would then burn to a CD. The resulting CD auto- matically boots and runs this install script, prepares the hard drive, and installs the customized system image. I refer to the image as the gold image because it is the master copy of the system being installed. The process of building a master gold system is basically manual. Once the template sys- tem is built, fully customized, and tuned to your environment, you should create an image 1. http://www.phenix.bnl.gov/~purschke/RescueCD 246 CHAPTER 38 ■ LINUXGOLD-SYSTEMBUILD file from that disk. The gold system will then mount an NFS server (at /mnt/nfs) with suffi- cient space for the image and run the following command to create the image file. This command creates a compressed tar file of the whole disk on the running gold system. It excludes the contents of the /proc and /mnt/nfs directories because they are specific to the gold system, and you can’t use the contents if they are propagated to sub- sequent builds. tar cvfz /mnt/nfs/wholedisk.tar.gz / --exclude /proc/* \ --exclude /mnt/nfs/* Most of the build script is for preparing the hard disk to accept the final image created from the gold system. The process determines the hard-drive geometry parameters and bases the partitioning on those values, since the disk model and manufacturer are likely to vary from system to system. Once the disk has been prepared, the script creates the file systems and unarchives the gold image. First we assign a bunch of variables that determine and store the architecture parameters of the hard disk; we will use them to create the input file for sfdisk, which is a Linux parti- tion-table manipulator. Additionally, they determine the amount of memory on the system and then use double the memory value for the swap partition. It is safe to calculate swap memory as double the amount of base memory. The value in /proc/cpuinfo that contains the total amount of memory on a system may vary depending on the live CD image that is being used. To deal with this case, the egrep command checks for two of the possible values. If you choose a different live CD, you may want to check that these are valid. #!/bin/sh bytes_per_cyl=`sfdisk -l /dev/hda | grep Units | awk '{print $5}'` tracks_per_cyl=`sfdisk -l /dev/hda | grep Disk | awk '{print $5}'` sectors_per_track=`sfdisk -l /dev/hda | grep Disk | awk '{print $7}'` sectors_per_cyl=$(($tracks_per_cyl*$sectors_per_track)) bytes_per_sector=$(($bytes_per_cyl/$sectors_per_cyl)) cyl_count=`sfdisk -l /dev/hda | grep Disk | awk '{print $3}'` usable_cyl=$(($cyl_count-4)) disk_in_sectors=$((($sectors_per_cyl*$usable_cyl)-$sectors_per_track)) mem_in_bytes=`cat /proc/meminfo | egrep "MemTotal:|Mem:" | awk '{print $2}'` swap_in_bytes=$(($mem_in_bytes*2)) The input file that is sent to sfdisk specifies the size of each partition in sectors. The following function (sector_calc) takes its input in bytes and converts the number of bytes into sectors. It also determines whether the file system fits evenly on cylinder boundaries. If not, the function rounds up the value to the next cylinder. sector_calc () { size=$1 slice_in_sectors=$(($size/$bytes_per_sector)) slice_in_cyl=$(($slice_in_sectors/$sectors_per_cyl)) slice_rem=$(($size%$bytes_per_sector)) if [ $slice_rem -ne 0 ] CHAPTER 38 ■ LINUXGOLD-SYSTEMBUILD 247 then slice_in_cyl=$(($slice_in_cyl+1)) slice_in_sectors=$((($slice_in_cyl*$sectors_per_cyl)-$sectors_per_track)) else slice_in_sectors=$((($slice_in_cyl*$sectors_per_cyl)-$sectors_per_track)) fi } Now the script determines the size in sectors for each of the file systems that will be on the final build by sending the file-system size values to the sector_calc function. sector_calc $swap_in_bytes swap_in_sectors=$slice_in_sectors sector_calc 250000000 root_in_sectors=$slice_in_sectors sector_calc 30000000 boot_in_sectors=$slice_in_sectors sector_calc 1000000000 var_in_sectors=$slice_in_sectors sector_calc 512000000 home_in_sectors=$slice_in_sectors sector_calc 512000000 tmp_in_sectors=$slice_in_sectors A lot of file systems were part of this build, but it would be trivial to modify the code to remove unnecessary ones or to add your own file systems to match your gold build. The last two file systems split in half whatever is left over after the other file systems are allocated. This was done in my environment because we used these two partitions more heavily than the rest and wanted to distribute the remainder of the space evenly. Their sector calculations are slightly different because they are based on the size of the whole disk minus the other file systems. rest_of_disk_in_sectors=$(($disk_in_sectors-$swap_in_sectors-\ $boot_in_sectors-$root_in_sectors-$var_in_sectors-$home_in_sectors-\ $tmp_in_sectors)) usr_in_sectors=$(($rest_of_disk_in_sectors/2/$sectors_per_cyl*\ $sectors_per_cyl)) usrlocal_in_sectors=$usr_in_sectors We need to define and write the partition-table file that will be used to format the new system’s hard disk. We begin by reproducing the partitioning output from sfdisk -d /dev/hda. That command dumps the partition table in a format that can be used as input to subsequently partition another disk. You would want to do this on your gold 248 CHAPTER 38 ■ LINUXGOLD-SYSTEMBUILD system to make sure the script output and the gold partition table match while account- ing for any hard drive–architecture variations. PARTTAB=/tmp/parts.out double_sectors_per_track=$((2*$sectors_per_track)) cat > $PARTTAB <<SOMETAG # partition table of /dev/hda unit: sectors The interesting scripting technique here is the use of the cat command to enter text in a free format. Here cat takes input from the code up to the tag SOMETAG and then redirects that output to the output file specified by $PARTTAB. This code structure is called a here- document. A here-document is where free-format text, opened and closed by a delimiter (SOMETAG) in this case, is used as input to another code structure, such as a loop or, in this case, a variable. The previous version of this code had each of the lines of text individually redirected to the output file. This technique makes the code less cluttered and easier to read; you can find more details about this in Chapter 28. This code may be somewhat daunting to read and comprehend because of the format- ting and the length of each line. With a bit of close examination, however, you’ll see it isn’t quite as complex as it might seem. /dev/hda1 :\ start=$sectors_per_track,size=$boot_in_sectors,Id=83,bootable /dev/hda2 : start=$(($sectors_per_track+$boot_in_sectors)),size=$\ (($disk_in_sectors-$boot_in_sectors)),Id=5 /dev/hda3 : start=0,size=0,Id=0 /dev/hda4 : start=0,size=0,Id=0 /dev/hda5 : start=$(($double_sectors_per_track+$boot_in_sectors)),\ size=$usr_in_sectors,Id=83 /dev/hda6 : start=$\ (($double_sectors_per_track+$boot_in_sectors+$usr_in_sectors)),\ size=$usrlocal_in_sectors,Id=83 /dev/hda7 : start=$\ (($double_sectors_per_track+$boot_in_sectors+\ $usr_in_sectors+$usrlocal_in_sectors)),size=$var_in_sectors,Id=83 /dev/hda8 : start=$\ (($double_sectors_per_track+$boot_in_sectors+\ $usr_in_sectors+$usrlocal_in_sectors+$var_in_sectors)),\ size=$home_in_sectors,Id=83 /dev/hda9 : start=$\ (($double_sectors_per_track+$boot_in_sectors+\ $usr_in_sectors+$usrlocal_in_sectors+$var_in_sectors+\ $home_in_sectors)),size=$tmp_in_sectors,Id=83 /dev/hda10 : start=$\ (($double_sectors_per_track+$boot_in_sectors+\ CHAPTER 38 ■ LINUXGOLD-SYSTEMBUILD 249 $usr_in_sectors+$usrlocal_in_sectors+$var_in_sectors+\ $home_in_sectors+$tmp_in_sectors)),size=$swap_in_sectors,Id=82 /dev/hda11 : start=$\ (($double_sectors_per_track+$boot_in_sectors+\ $usr_in_sectors+$usrlocal_in_sectors+$var_in_sectors+\ $home_in_sectors+$tmp_in_sectors+$swap_in_sectors)),\ size=$root_in_sectors,Id=83 SOMETAG Each line is simply a partition definition. They are all part of the cat output that is being written to the file that will build the file-system structure on the hard disk. Each line is of the following form: /dev/partition : start={start sector},size={sectors},Id={partition type},[bootable] The start (start=) and size (size=) calculations are very long and may get a little confus- ing. If you read these lines in order starting at /dev/hda5, you’ll see that the calculation just increments the start position of the file system by the size of the previous file system. Finally you are able to install the newly created partition table to the disk. sfdisk -f /dev/hda < $PARTTAB Now you can create all ext2 file systems on disk. Of course, you may want to use other file-system types. for slice in 1 5 6 7 8 9 11 do echo Making file system on slice $slice . mke2fs /dev/hda$slice done We create a mount point in /tmp for accessing the hard drive and mount the root parti- tion to it. Note that when this script is running, the /tmp directory is part of a ramdisk from the live CD. Once the root partition has been mounted, the script creates all other drive mount points on the physical disk. mkdir -p /tmp/root mount /dev/hda11 /tmp/root for dir in boot usr var home tmp do mkdir -p /tmp/root/$dir done Since there is some dependency between the file systems, the mounting process needs to happen in the proper order: the lowest-level partitions should be mounted first. mount /dev/hda1 /tmp/root/boot mount /dev/hda5 /tmp/root/usr if [ ! -d /tmp/root/usr/local ] 250 CHAPTER 38 ■ LINUXGOLD-SYSTEMBUILD then mkdir /tmp/root/usr/local fi mount /dev/hda6 /tmp/root/usr/local mount /dev/hda7 /tmp/root/var mount /dev/hda8 /tmp/root/home mount /dev/hda9 /tmp/root/tmp Here is where the prepared disk is populated. We unarchive the whole disk-image file onto the newly formatted hard drive. All the files should land in the correct file system, since the file system has been partitioned in exactly the same way as the original gold system. cd /tmp/root tar xvfzp /usr/wholedisk.tar.gz cd / Once that is complete, you need to create the swap partition and install the boot loader. The chroot command runs the lilo boot loader installation based on the hard drive /root directory, and not from the root of the CD. Of course, if you choose to use grub instead of lilo, you’ll need to modify this command. mkswap /dev/hda10 chroot /tmp/root lilo -C /etc/lilo.conf We have reached the end of the installation process. The script dismounts all partitions in the proper order. Partition 6 should be dismounted first since /usr/local is attached to /usr, and partition 11 should be dismounted last since it is /root. Now when the newly built system is rebooted, it should be an exact duplicate of your original gold system except for any hard-drive size differences. All that is left to do is to make system-specific changes, such as entering your IP address and a system name, and then you can connect the finished system to the network. for slice in 6 1 5 7 8 9 11 do umount /dev/hda$slice done . 245 ■ ■ ■ CHAPTER 38 Linux Gold-System Build B uilding a system manually can be fun. Building many systems manually is tedious and. access to the server to do a system build. Also, a build server needs to be set up and maintained, but if you are building only a moderate number of systems,