#!/bin/bash #These are functions useful to the uml projects. They are GPL'd. #Copyright 1999-2002, William Stearns and #Jeff Dike #TODO rm touch and sudo, remove sudo /bin's True=0 #As far as bash is concerned False=1 #Start conditional functions if [ -f /usr/lib/samlib/samlib ]; then #Load Shell Accessible Module library . /usr/lib/samlib/samlib else #Missing samlib echo 'Warning: you must install samlib. See' >>/dev/stderr echo 'http://www.stearns.org/samlib/' >>/dev/stderr echo 'Exiting.' >>/dev/stderr exit 1 fi rpm_add_deps () { #Given a list of packages, adds the supporting packages in the right order. #Keep list of reordered rpms; only # them if they're reordered twice or more. REORDEREDRPMS=" " CondMkdir var/lib/rpm CondMkdir var/tmp if [ ! -f $RPMPROVIDES ]; then if [ -n "$Verbose" ]; then echo Preparing .provides list >>/dev/stderr ; fi for ONERPM in $RPMDIR/*.rpm ; do $SUDO rpm -qp --provides $ONERPM | sed -e 's/ =.*//' -e "s@^@${ONERPM}\&@" >>$RPMPROVIDES $SUDO rpm -qpl $ONERPM | sed -e "s@^@${ONERPM}\&@" >>$RPMPROVIDES done for ONERPM in $RPMDIR/*.rpm ; do #Add package names at the end as a last gasp "provides" PackageNameProvides=`$SUDO rpm -qp --queryformat "%{NAME}" $ONERPM | sed -e "s@^@${ONERPM}\&@"` if [ -z "`grep ^$PackageNameProvides$ $RPMPROVIDES`" ]; then #If that line's not already in the file, add it. echo "$PackageNameProvides" >>$RPMPROVIDES fi done fi RPMS="" for rpm in $* ; do RPMS="$RPMS $(rpm_file $rpm)" done RPMS="$RPMS " LISTOK="" while [ "$LISTOK" != "YES" ]; do #clear >>/dev/stderr if [ -n "$Verbose" ]; then echo >>/dev/stderr echo Working on `echo $RPMS | sed -e "s@$RPMDIR/*@@g"` >>/dev/stderr fi LISTOK="YES" $SUDO rm -f var/lib/rpm/* $SUDO rpm --root $CURRENTDIR --initdb for rpm in $RPMS ; do # if [ -n "$Verbose" ]; then # echo Installed: `$SUDO rpm -qa --root $CURRENTDIR` >>/dev/stderr # #$(rpm_params $DIST $rpm) removed from following command # echo Attempting: rpm -i --root $CURRENTDIR $(rpm_file $rpm) --justdb --ignoresize --excludedocs >>/dev/stderr # fi if ! NEEDEDTEXT="$($SUDO rpm -i --root $CURRENTDIR $(rpm_file $rpm) $(rpm_params $DIST $rpm) --justdb --ignoresize --excludedocs 2>&1 )" ; then # if [ "$rpm" = "/usr/src/rh62source/glibc-2.1.3-21.i386.rpm" ]; then echo "${NEEDEDTEXT}" | \ grep -v 'error: failed dependencies:' | \ grep -v 'is needed by' | \ sed -e 's/^/**** /' >>/dev/stderr # $SUDO rpm -i --root $CURRENTDIR $(rpm_file $rpm) $(rpm_params $DIST $rpm) -vv # fi NEEDEDRESOURCE=$(echo "$NEEDEDTEXT" | grep 'is needed by' | head -1 | awk '{print $1}') if [ -n "$NEEDEDRESOURCE" ]; then export NEEDEDRESOURCE case $(echo $(grep "&$NEEDEDRESOURCE *$" $RPMPROVIDES | wc -l)) in 0) echo '******** 0 rpms provide ' $NEEDEDRESOURCE . OOPS. >>/dev/stderr ;; 1) : ;; *) if [ -n "$Verbose" ]; then echo '2+ rpms provide ' $NEEDEDRESOURCE . Using the first one of: >>/dev/stderr grep "&$NEEDEDRESOURCE *$" $RPMPROVIDES >>/dev/stderr fi ;; esac NEEDEDRPM=$(grep "&$NEEDEDRESOURCE *$" $RPMPROVIDES | head -1 | sed -e 's@&.*@@') # if [ -n "$Verbose" ]; then # echo NRPM "$NEEDEDRPM" >>/dev/stderr # echo "$NEEDEDRPM" is needed to satisfy "$rpm" . >>/dev/stderr # fi if echo "$RPMS" | grep -q "[# ]$NEEDEDRPM[# ]" ; then if [ -n "$Verbose" ]; then echo Stripping $NEEDEDRPM to reorder before $rpm . | sed -e "s@$RPMDIR/*@@g" >>/dev/stderr # echo Stripping $NEEDEDRPM to reorder before $rpm . >>/dev/stderr # if [ "$NEEDEDRPM" = "/mnt/mirrors/buildsource//tu/7/info-4.0-11.i586.rpm" ] && [ "$rpm" = "/mnt/mirrors/buildsource//tu/7/grep-2.4.2-7.i586.rpm" ]; then # read JUNK # exit # fi fi RPMS=`echo "$RPMS" | sed -e "s@#$NEEDEDRPM#@#@" -e "s@[# ]$NEEDEDRPM[# ]@ @"` if echo "$REORDEREDRPMS" | grep -q " $NEEDEDRPM "; then #If it's already been reordered, use # to link them if [ -n "$Verbose" ]; then echo -n '#' >>/dev/stderr ; fi RPMS=`echo "$RPMS" | sed -e "s@\([ #]\)$rpm\([ #]\)@\1$NEEDEDRPM#$rpm\2@"` else if [ -n "$Verbose" ]; then echo -n '-' >>/dev/stderr ; fi RPMS=`echo "$RPMS" | sed -e "s@\([ #]\)$rpm\([ #]\)@\1$NEEDEDRPM $rpm\2@"` REORDEREDRPMS=" $REORDEREDRPMS $NEEDEDRPM " fi # if [ -n "$Verbose" ]; then # echo ${NEEDEDRPM}: $REORDEREDRPMS >>/dev/stderr # sleep 1 >>/dev/stderr # fi else RPMS=`echo "$RPMS" | sed -e "s@ $rpm @ $NEEDEDRPM $rpm @"` fi # if [ "$rpm" = "/usr/src/rh62source/info-4.0-5.i386.rpm" ]; then # echo >>/dev/stderr # echo X${NEEDEDRESOURCE}X >>/dev/stderr # echo X${NEEDEDRPM}X >>/dev/stderr # echo "X${NEEDEDTEXT}X" >>/dev/stderr # read JUNK #sleep 4 # fi LISTOK="NO" continue 2 fi fi done done $SUDO rm -f ./var/lib/rpm/* $SUDO rmdir var/lib/rpm var/lib var #$SUDO rpm --root $CURRENTDIR --initdb echo $RPMS echo $RPMS >>/dev/stderr # if [ -n "$Verbose" ]; then # ( for ONERPM in $RPMS ; do # echo $ONERPM | sed -e "s@$RPMDIR/@@g" # done ) | sort # fi } rpm_params() { #Params: distribution name, package name(s) # #Returns the custom parameters needed to install an rpm. #Occasionally we run across a broken dist that requires a certain rpm #option to install an rpm or group of rpms. #NOTE - the following attempts to drop a fork or two in a routine that gets called a lot #Remove when other dists need this. # if [ "$1" = "tu-7" ]; then NOORDER='' #See below for suggested use. NODEPS='' #Similarly RPMOPTIONS='' #Use the ' RPMOPTIONS=" $RPMOPTIONS --noorder " ' aproach for other options for ONERPMBASE in `echo $* | tr '#' ' '` ; do case $1 in #Assume that the RedHat and Immunix distributions require that the #libtermcap, util-linux, tcpdump, Mesa, devfsd, and modutils packages #be installed without dependencies: # rh*|im*) #One can also specify a particular OS ver, such as rh62 # case $ONERPMBASE in # libtermcap*|util-linux*|tcpdump*|Mesa*|devfsd*|modutils*) # NODEPS='--nodeps' # ;; # esac # ;; #Other dists and packages here... #One other useful param for Caldera (cl)/lisa and Turbolinux (tl) info #and bash is --noorder. It handles the #"loop in prerequisite chain: info bash info" problem. *sigh* #also: "kernel mkinitrd util-linux kernel" tu-7) case $ONERPMBASE in *info*|*kernel*) NOORDER='--noorder' ;; esac ;; rh-9) case $ONERPMBASE in *glibc-common*) NODEPS='--nodeps' ;; esac esac done echo $RPMOPTIONS $NOORDER $NODEPS # fi } rpm_file() { if [ -n "`echo $* | grep '#'`" ]; then NEWSEPCHAR=' ' else NEWSEPCHAR='#' fi SEPCHAR=' ' #we have to separate this block from previous blocks for ONERPMBASE in `echo $* | tr '#' ' '` ; do case $ONERPMBASE in *.rpm) echo -n "$SEPCHAR$ONERPMBASE" ;; *) local name=$ONERPMBASE set $RPMDIR/$ONERPMBASE[-0-9]*.rpm if [ $# -ne 1 ]; then echo >>/dev/stderr echo Found too many rpms for $name >>/dev/stderr echo -n "$SEPCHAR$1" elif [ ! -f $1 ]; then echo >>/dev/stderr echo Found no rpms for $name >>/dev/stderr else echo -n "$SEPCHAR$1" fi ;; esac SEPCHAR="$NEWSEPCHAR" done } function get_data() { local prompt=$1 local default=$2 local verify=$3 local answer="" local err_msg while true; do echo -n "$prompt [$default]: " 1>&2 read answer [ "$answer" = "" ] && answer=$default [ $verify != "" ] && err_msg=`$verify $answer` && break [ "$err_msg" != "" ] && echo -e $err_msg 1>&2 done echo $answer } function verify_yn() { local answer=$1 local res=true echo "Please answer 'y' or 'n'" [ "$1" = "y" ] || [ "$1" = "n" ] } function verify_fs() { local file=$1; local res=true local ok="y" if [ -b "$file" ] then ok=`get_data "\"$file\" is a block device - confirm that you want to install into it" y verify_yn` elif [ -d "$file" ] then ok=`get_data "\"$file\" is a directory - confirm that you want to install into it" y verify_yn` elif [ -f "$file" ] then ok=`get_data "\"$file\" already exists - OK to delete it" y verify_yn` elif [ -e $file ] then ok=`get_data "\"$file\" is not a plain file - OK to delete it" y \ verify_yn` fi [ "$ok" = "y" ] } function verify_size() { local size=$1 local err="" local space=`df \`dirname $FSFILE\` | tail -1 | awk '{print $4}'` space=$(( $space / 1024 )) local mnt=`df \`dirname $FSFILE\` | tail -1 | awk '{print $6}'` if [ `expr "$size" : '[0-9]*'` -ne `expr length "$size"` ] then err="The size must be a number, containing only digits" elif [ "$size" -lt 100 ] then err="The size should be at least 100" elif [ $space -lt "$size" ] then err="There is not enough free space in $mnt (available space : \ $space M)" fi echo $err [ "$err" = "" ] } function verify_mnt() { local dir=$1 local err="" if [ ! -d "$dir" ] then err="$dir is not a directory" elif [ ! -d "$dir/RedHat/RPMS" ] then err="$dir seems not to be a Red Hat distribution ($dir/RedHat/RPMS \n\ doesn't exist or isn't a directory)" fi echo $err [ "$err" = "" ] } function verify_sudo() { local sudo=$1 local err="" if [ "$sudo" = "" ] then err="" elif [ ! -f "$sudo" ] || [ ! -x "$sudo" ] || [ ! -u "$sudo" ] then err="\"$sudo\" is not an setuid root executable file" fi echo $err [ "$err" = "" ] } CondMkdir () { while [ -n "$1" ]; do if [ -e "$1" ]; then if [ ! -d "$1" ]; then echo "$1" exists but is not a directory, exiting. exit 1 fi else $SUDO mkdir --parents "$1" fi shift done } ChooseRpmToDelete () { #This takes two rpm filenames on the command line and echoes back to #stdout which, if either, to delete. A 1 is returned if rpm 1 is to #be nuked, 2 if rpm 2. Return code of True means there is a file to #delete. if [ "$#" != "2" ]; then echo Incorrect number of args to ChooseRpmToDelete: \""$*"\", exiting. >>/dev/stderr exit 1 fi if [ ! -f "$1" ] || [ ! -f "$2" ]; then echo Either "$1" or "$2" is not a file, exiting. >>/dev/stderr exit 1 fi Rpm1Name=`rpm -q --queryformat "%{NAME}" -p "$1"` Rpm2Name=`rpm -q --queryformat "%{NAME}" -p "$2"` if [ "$Rpm1Name" != "$Rpm2Name" ]; then #Not the same base package name, keep both. Future compares may delete one or the other. return $False fi Rpm1Arch=`rpm -q --queryformat "%{ARCH}" -p "$1"` Rpm2Arch=`rpm -q --queryformat "%{ARCH}" -p "$2"` if [ "$Rpm1Arch" != "$Rpm2Arch" ]; then #We have different architectures. Keep the higher, suggest deletion of the lower. if [ "$Rpm1Arch" = "i386" ]; then echo "1" ; return $True elif [ "$Rpm2Arch" = "i386" ]; then echo "2" ; return $True elif [ "$Rpm1Arch" = "i486" ]; then echo "1" ; return $True elif [ "$Rpm2Arch" = "i486" ]; then echo "2" ; return $True elif [ "$Rpm1Arch" = "i586" ]; then echo "1" ; return $True elif [ "$Rpm2Arch" = "i586" ]; then echo "2" ; return $True elif [ "$Rpm1Arch" = "athlon" ]; then echo "1" ; return $True elif [ "$Rpm2Arch" = "athlon" ]; then echo "2" ; return $True else echo "Unable to resolve preferred architecture between \"$1\" and \"$2\", exiting." >>/dev/stderr exit 1 fi fi Rpm1Buildtime=`rpm -q --queryformat "%{BUILDTIME}" -p "$1"` Rpm2Buildtime=`rpm -q --queryformat "%{BUILDTIME}" -p "$2"` if [ $Rpm1Buildtime -gt $Rpm2Buildtime ]; then echo "2" ; return $True elif [ $Rpm1Buildtime -lt $Rpm2Buildtime ]; then echo "1" ; return $True else echo "Identical arch and buildstamps, how do I handle \"$1\" and \"$2\"? Exiting." >>/dev/stderr exit 1 fi } CleanOldRpms () { #This function is designed to delete the older/less desirable versions #of two or more rpms that provide the same thing. The sole parameter #is the name of a directory holding the RPMs to be deleted. if [ $# != 1 ]; then echo "Too few/many args to CleanOldRpms: \"$*\", exiting." >>/dev/stderr exit 1 fi if [ ! -d "$1" ]; then echo "\"$1\" is not a directory, exiting." >>/dev/stderr exit 1 fi cd $1 if [ "`pwd`" != "`echo $1 | sed -e 's@/$@@' -e 's@//@/@g'`" ]; then echo Not in the right directory, exiting. exit 1 fi LastFile='' for TestFile in *.rpm ; do if [ -z "$LastFile" ]; then LastFile="$TestFile" continue fi if SuggestDeleteFile=`ChooseRpmToDelete "$LastFile" "$TestFile"` ; then if [ -n "$Verbose" ]; then echo -n "Deciding between \"$LastFile\" and \"$TestFile\". " ; fi case $SuggestDeleteFile in 1) if [ -n "$Verbose" ]; then echo "Deleting $LastFile" ; fi rm -f "$LastFile" LastFile="$TestFile" ;; 2) if [ -n "$Verbose" ]; then echo "Deleting $TestFile" ; fi rm -f "$TestFile" #DO NOT assign testfile to lastfile ;; *) echo "Umm, just what was I supposed to delete? \"$SuggestDeleteFile\". Exiting" >>/dev/stderr exit 1 ;; esac else #Test function didn't suggest deleting either, just continue #echo -e "$LastFile\t$TestFile" LastFile="$TestFile" fi done cd - } LinkIn () { #Hardlinks all the files in the CL specified dirs and hardlinks them #into the current directory. while [ -n "$1" ]; do if [ -d "$1" ]; then find "$1" -type f -exec ln -f {} . \; elif [ -f "$1" ]; then ln -f "$1" . fi shift done } BuildOneRoot () { if [ "$#" != 4 ]; then echo "Incorrect number of params \"$#\" to BuildOneRoot, exiting" >>/dev/stderr exit fi #Params: DistroName="$1" #(rh, md, co, etc.) DistroVersion="$2" #(5.1, 6.2, 7.0, etc.) Description="$3" #(fullserver, apacheonly, mailserver, etc. Matches requested RPMS.) RequestedRpms="$4" #(Space separated list of rpms needed, such as "apache- sendmail- bash-". Make sure you use quotes.) BuildTop=${BuildTop:-/mnt/mirrors/buildsource/} CondMkdir $BuildTop if ! cd $BuildTop ; then echo Unable to change to $BuildTop, exiting. >>/dev/stderr sleep 5 exit 1 fi if cd $DistroName/$DistroVersion ; then cd ../.. showstate "Building $DistroName $DistroVersion $Description ... building root filesystem" export RPMS="$RequestedRpms" export RPMDIR="$BuildTop/$DistroName/$DistroVersion" export FSFILE="root_fs.${DistroName}-${DistroVersion}-${Description}.pristine.`date +%Y%m%d`" ./mkrootfs ${DistroName}-${DistroVersion} chmod 444 $FSFILE showstate "Building $DistroName $DistroVersion $Description ... compressing root filesystem in background" rm -f "${FSFILE}.bz2" nice bzip2 -9 $FSFILE & #Add in "-k" to keep original when we have lots of disk space to spare else echo Unable to change to $BuildTop/$DistroName/$DistroVersion >>/dev/stderr fi } #Check that we have the needed samlib library functions for ONEFUNC in addline askYN bits2mask broadcastof delline max networkof showstate substline ; do if ! type $ONEFUNC >/dev/null 2>/dev/null ; then echo "Missing $ONEFUNC , please update samlib from" >>/dev/stderr echo "http://www.pobox.com/~wstearns/" >>/dev/stderr echo "Exiting." >>/dev/stderr exit 1 fi done