# -*-Shell-script-*- # # Common functions for build scripts used by various packages # incorporated (e.g., build, myplc, myplc-devel, vserver-reference) # # Marc E. Fiuczynski # Copyright (C) 2007 The Trustees of Princeton University # # $Id$ # function pl_getDefaultDistro() { # FC4 is currently the default release echo "Fedora" return 0 } function pl_getDefaultRelease() { # FC4 is currently the default release echo "4" return 0 } function pl_getDistro() { defaultDistro=$(pl_getDefaultDistro) if [ -f "/etc/redhat-release" ] ; then distro=$(awk ' { print $1 } ' /etc/redhat-release) else distro=$defaultDistro fi echo "$distro" return 0 } function pl_getRelease() { defaultRelease=$(pl_getDefaultRelease) if [ -f "/etc/redhat-release" ] ; then release=$(awk ' { if ($1=="Fedora" && $2=="Core") print $4 ; if (($1=="Fedora" && $2!="Core")||$1=="CentOS") print $3 } ' /etc/redhat-release) [ $release -lt $defaultRelease ] && release=$defaultRelease else release=$defaultRelease fi echo "$release" return 0 } # vserver expects something like fc4 or f7 # for fedora and centos only for now function pl_getReleaseName () { distro=$1; shift release=$1; shift case $distro in [Ff]edora*) if [ "$release" -le 6 ] ; then releasename=fc$release else releasename=f$release fi ;; [Cc]entOS*) old_IFS="$IFS" IFS="." set -- $release IFS="$old_IFS" releasename=centos$1 ;; *) releasename="unknown-name-for-${pl_DISTRO}-please-edit-build.common" echo 1>&2 "build.common: WARNING - releasename not set for distro=$distro" return 1 ;; esac echo "$releasename" return 0 } # figure out which redhat distro we are using (fedora, centos, redhat) pl_DISTRO=$(pl_getDistro) # select basearch of the host devel environment - protected for macos for local tests pl_DISTRO_ARCH=$(uname -i 2>/dev/null|| echo unknownarch) # the release number (plain number) pl_DISTRO_RELEASE=$(pl_getRelease) # the release name - for vserver build - like fc4, f8 or centos4 pl_DISTRO_NAME=$(pl_getReleaseName $pl_DISTRO $pl_DISTRO_RELEASE) # get path to appropriate yumgroups.xml file # Thierry: quick & dirty improvement # this file is updated by the toplevel build, from groups/.xml pl_DISTRO_YUMGROUPS="../../../RPMS/yumgroups.xml" function pl_process_fedora_options () { # Get options shiftcount=0 while getopts "l:r:a:h" opt ; do case $opt in l) pl_DISTRO_URL=$OPTARG let shiftcount=$shiftcount+2 ;; r) pl_DISTRO_RELEASE=$OPTARG let shiftcount=$shiftcount+2 ;; a) pl_DISTRO_ARCH=$OPTARG let shiftcount=$shiftcount+2 ;; h|*) echo "Usage: $0 [OPTION]..." echo " -l url distro mirror location (default: $pl_DISTRO_URL)" echo " -r release distro release number (default: $pl_DISTRO_RELEASE)" echo " -a arch distro architecture (default: $pl_DISTRO_ARCH)" echo "where distro can be either fedora, centos, or redhat" echo " -h This message" exit 1 ;; esac done return $shiftcount } ######################################## handling a root image function pl_root_rpm_macros () { cat <.mirrors" echo " -v Be verbose" echo " -h This message" echo " target selection (defaults based on current build vserver)" echo " -r release Fedora release number (default: $releasever)" echo " -a arch Fedora architecture (default: $basearch)" exit 1 } function pl_root_mkfedora () { echo "* Entering pl_root_mkfedora" "$@" if [ $UID -ne 0 ] ; then echo "Error: You must run this script as root." exit 1 fi # Verbosity verbose=0 # Release and architecture to install : defaults to current vserver's settings or previously parsed fedora_options releasever=$pl_DISTRO_RELEASE basearch=$pl_DISTRO_ARCH # Get options mirrors="" while getopts "l:r:a:vh" opt ; do case $opt in l) mirrors="$mirrors $OPTARG" ;; r) releasever=$OPTARG ;; a) basearch=$OPTARG ;; v) verbose=1 set -x ;; h|*) mkfedora_usage ;; esac done shift $(($OPTIND - 1)) [[ "$#" -lt 3 ]] && mkfedora_usage vroot=$1 ; shift pldistro=$1 ; shift pkgsfile="$@" vroot=$(cd $vroot && pwd -P) [ -d $vroot ] || mkfedora_usage # parse pkgsfile and add to local vars fcdistro=${pl_DISTRO_NAME} pkgs_packages=$(pl_parsePkgs package $fcdistro $pldistro $pkgsfile) pkgs_groups=$(pl_parsePkgs group $fcdistro $pldistro $pkgsfile) # packages to exclude - obsolete, was maybe useful when installing a group pkgs_excludes=$(pl_parsePkgs exclude $fcdistro $pldistro $pkgsfile) pkgs_junk=$(pl_parsePkgs junk $fcdistro $pldistro $pkgsfile) pkgs_precious=$(pl_parsePkgs precious $fcdistro $pldistro $pkgsfile) # formerly related to mkfedora -k pkgs_kexcludes=$(pl_parsePkgs kexclude $fcdistro $pldistro $pkgsfile) # get mirrors if not specified with -l if [ -z "$mirrors" ] ; then mirrorsfile=$(pl_locateDistroFile ../build/ $pldistro "$pldistro.mirrors") mirrors=$(pl_parsePkgs mirror $fcdistro $pldistro $mirrorsfile) fi exclude_kernel="" # add them manually as the output of pl_parsePkgs is line-separated if [ -n "$pkgs_kexcludes" ] ; then exclude_kernel="exclude=" for kexclude in $pkgs_kexcludes ; do exclude_kernel="$exclude_kernel $kexclude" done fi function mkfedora_fetch () { curl --fail --silent --max-time 60 "$1" } # set list of attempted locations according to target distro # xxx all this should go into mirroring/ somehow case $pl_DISTRO in Fedora) if [ $releasever -ge 7 ] ; then # Plain Fedora comes with a new layout attempts=" fedora/releases/$releasever/Everything/$basearch/os linux/releases/$releasever/Everything/$basearch/os $releasever/Everything/$basearch/os core/$releasever/Everything/$basearch/os linux/core/$releasever/$basearch/os " else # Fedora Core attempts=" fedora/core/$releasever/$basearch/os linux/core/$releasever/$basearch/os core/$releasever/$basearch/os $releasever/$basearch/os " fi public_gpg_key=RPM-GPG-KEY-fedora ;; CentOS) # xxx hacky for now # you can use vbuild-fedora-mirror with -f centos5.1 # which is hard-coded in mirroring/centos as well # for now I do the mapping here, mmhh case $releasever in 4) actual=4.6 ;; 5) actual=5.1 ;; *) actual=$releasever ;; esac attempts=" centos/$actual/os/$basearch " public_gpg_key=RPM-GPG-KEY-CentOS-$releasever ;; *) echo "distro $pl_DISTRO not supported in build.common / mkfedora" ; exit 1 esac echo "$0: candidate mirrors" for mirror in $mirrors ; do echo "* candidate mirror $mirror" done baseurl="" for mirror in $mirrors ; do for attempt in $attempts; do attempturl=$mirror/$attempt if mkfedora_fetch $attempturl/repodata/repomd.xml >/dev/null ; then baseurl=$attempturl break 2 fi done done if [ -z "$baseurl" ] ; then echo "Error: $releasever/$basearch/os/repodata/repomd.xml" echo " could not be found in any of the following locations:" echo for mirror in $mirrors ; do for attempt in $attempts ; do echo $mirror/$attempt done done echo mkfedora_usage else echo "* selecting mirror with baseurl=$baseurl" fi # Do not tolerate errors set -e ## make rpms ignore installing stuff to special fs entries like /proc # Because of https://bugzilla.redhat.com/bugzilla/show_bug.cgi?id=52725 # you have to use at least one language beside 'C' # Prevent all locales from being installed in reference image mkdir -p $vroot/etc/rpm pl_root_rpm_macros > $vroot/etc/rpm/macros # Trick rpm and yum, who read the real root /etc/rpm/macros file # rather than the one installed in the reference image, despite what # you might expect the --root and --installroot options to mean. Both # programs always read $HOME/.rpmmacros. export HOME=$vroot/tmp mkdir -p $vroot/tmp pl_root_rpm_macros > $vroot/tmp/.rpmmacros function mkfedora_cleanup () { umount -l $vroot/proc umount -l $vroot/dev/shm umount -l $vroot/dev/pts } # Clean up before exiting if anything goes wrong trap "mkfedora_cleanup" ERR INT # Mount in reference image mount -t devpts none $vroot/dev/pts mount -t tmpfs none $vroot/dev/shm mkdir -p $vroot/proc mount -t proc none $vroot/proc # Create a /var/lib dirs for yum & rpm mkdir -p $vroot/var/lib/yum mkdir -p $vroot/var/lib/rpm mkdir -p $vroot/usr/share/info # Create a dummy /etc/fstab in reference image mkdir -p $vroot/etc cat >$vroot/etc/fstab < $vroot/etc/sysconfig/network # Initialize RPM database in reference image mkdir -p $vroot/var/lib/rpm rpm --root $vroot --initdb rpm --root $vroot --import $baseurl/$public_gpg_key # Initialize yum in reference image mkdir -p $vroot/var/cache/yum $vroot/var/log if [ $releasever -lt 7 ] ; then corename="Core " else corename="" fi cat >$vroot/etc/yum.conf <>$vroot/etc/yum.conf <>$vroot/etc/yum.conf </dev/null ; then echo "* Warning: Missing packages" rpm --root $vroot -q $pkgs_packages | grep "not installed" fi fi if [ -n "$pkgs_groups" ] ; then ## call yum sequentially to get finer-grained info on dependencies for grp in $pkgs_groups ; do echo "* Installing optional group $grp" yum -c $vroot/etc/yum.conf --installroot=$vroot -y $exclude_arg \ groupinstall "$grp" done fi # formerly in bootcd/prep.sh : to optimize footprint if [ -n "$pkgs_junk" ] ; then echo "* Removing unnecessary junk" pushd $vroot # Save precious files [ -n "$pkgs_precious" ] && tar --ignore-failed-read -cpf precious.tar $pkgs_precious # Remove unnecessary junk [ -n "$pkgs_junk" ] && rm -rf $pkgs_junk # Restore precious files [ -n "$pkgs_precious" ] && tar -xpf precious.tar && rm -f precious.tar popd fi # Clean yum cache echo "* Cleaning up" yum -c $vroot/etc/yum.conf --installroot=$vroot -y clean all # Clean RPM state rm -f $vroot/var/lib/rpm/__db* # Set time zone to UTC if [ -f $vroot/usr/share/zoneinfo/UTC -a -f $vroot/etc/localtime ] ; then rm -f $vroot/etc/localtime ln -s /usr/share/zoneinfo/UTC $vroot/etc/localtime fi # remove trap handler, as we are about to call it directly. trap - ERR INT # Clean up mkfedora_cleanup return 0 } function pl_root_tune_image () { root=$1; shift # Disable all services in reference image chroot $root sh -c "/sbin/chkconfig --list | awk '{ print \$1 }' | xargs -i /sbin/chkconfig {} off" # FC2 minilogd starts up during shutdown and makes unmounting # impossible. Just get rid of it. rm -f $root/sbin/minilogd ln -nsf /bin/true $root/sbin/minilogd # This tells the Boot Manager that it is okay to update # /etc/resolv.conf and /etc/hosts whenever the network configuration # changes. Users are free to delete this file. touch $root/etc/AUTO_UPDATE_NET_FILES } # Move specified directories out of a src tree into a dst tree, and # then for each moved directory create a symlink in src to dst. function pl_move_dirs() { root=$1 data=$2 store=$3 shift 3 mkdir -p $root/data for datadir in "$@" ; do mkdir -p ${data}${datadir} if [ -d ${root}/${datadir} -a ! -h ${root}/${datadir} ] ; then (cd ${root} && find ./${datadir} | cpio -p -d -u ../${data}/) fi rm -rf ${root}/${datadir} mkdir -p $(dirname ${root}/${datadir}) ln -nsf ${store}/${datadir} ${root}/${datadir} done } # Construct an image file from given some directory # XXX in the future maybe use livecdtools? function pl_make_image() { root=$1 image=$2 extraspace=$3 # Leave about 100 MB free space and allow for about 20% inode overhead bytes=$((($(du -sb $root | cut -f1) + $extraspace) * 120 / 100)) bs=4096 blocks=$(($bytes / $bs)) dd bs=$bs count=$blocks if=/dev/zero of=$image mkfs.ext3 -b $bs -j -F $image # Temporarily mount it tmp=$(mktemp -d tmp.XXXXXX) mount -o loop $image $tmp trap "umount $tmp; rmdir $tmp" ERR INT # Move files to it (cd $root && tar cpf - .) | (cd $tmp && tar xpf -) # Unmount it umount $tmp rmdir $tmp trap - ERR INT } # Fix permissions on tmp directories function pl_fixtmp_permissions() { root=$1 chmod 1777 $root/tmp $root/usr/tmp $root/var/tmp } function pl_fixdirs() { root=$1 datadirs=$2 for datadir in datadirs ; do if [ -h ${root}/${datadir} ] ; then rm -f ${root}/${datadir} mkdir -p ${root}/${datadir} fi done } ########## .pkgs format # comments start with a # - this is needed only if you use a keyword in a comment function pl_getPkgsAttribute () { keyword=$1; shift file=$1; shift # remove any initial white spaces from the result grep -v '^#' $file | grep --regexp="^${keyword}:" | sed -e "s,${keyword}:,," -e "s,^[[:space:]][[:space:]]*,," } # for a given keyword like 'package' : # we support fcdistro-dependant format, for tokens (pkgname) without whitespace # you can e.g. use # package: pkg1 .. pkgn # package+f8: pkg1 .. pkgn # package-f8: pkg1 .. pkgn # # values can contain @arch@, @fcdistro@ or @pldistro@ that are replaced with the current values # function pl_parsePkgs () { keyword=$1;shift fcdistro=$1; shift pldistro=$1; shift # remaining arguments are paths to the pkgs files # grab regular descriptions all=$(grep -v '^#' "$@" | grep --regexp="^${keyword}:" | sed -e "s,${keyword}:,,") # grab additions add=$(grep -v '^#' "$@" | grep --regexp="^${keyword}+${fcdistro}:" | sed -e "s,${keyword}+${fcdistro}:,,") # grab exclusions sub=$(grep -v '^#' "$@" | grep --regexp="^${keyword}-${fcdistro}:" | sed -e "s,${keyword}-${fcdistro}:,,") for i in $all $add; do for exclude in $sub; do [ "$i" = "$exclude" ] && continue 2 done echo "$i " | sed -e "s,@arch@,$pl_DISTRO_ARCH,g" -e "s,@fcdistro@,$fcdistro,g" -e "s,@pldistro@,$pldistro,g" done return 0 } function pl_getPackages() { fcdistro=$1; shift ; pldistro=$1; shift ; pl_parsePkgs package $fcdistro $pldistro "$@" ; } function pl_getGroups() { fcdistro=$1; shift ; pldistro=$1; shift ; pl_parsePkgs group $fcdistro $pldistro "$@" ; } # locates a pldistro-dependant file # tries first in build//, then in build/planetlab/ function pl_locateDistroFile () { builddir=$1; shift pldistro=$1; shift pkgsfile=$1; shift pkgspath="" # locate it paths="$builddir/config.$pldistro/$pkgsfile $builddir/config.planetlab/$pkgsfile" for path in $paths; do if [ -f $path ] ; then pkgspath=$path break fi done if [ -z "$pkgspath" ] ; then echo 1>&2 "pl_locateDistroFile - in $(pwd) : cannot locate $pkgsfile in $builddir" echo 1>&2 "candidates were $paths" echo "not-found-by-pl_locateDistroFile" return 1 else echo 1>&2 "pl_locateDistroFile: using $pkgspath" echo $pkgspath return 0 fi } function yumgroups_from_pkgs () { builddir=$1; shift pldistro=$1; shift fcdistro=$1; shift pkgsnames=$@ sedargs="-e s,@FCDISTRO@,$fcdistro,g" cat <<__header __header for pkgsname in $pkgsnames; do pkgsfile=$(pl_locateDistroFile $builddir $pldistro $pkgsname) packages=$(pl_getPackages $fcdistro $pldistro $pkgsfile) groupname=$(pl_getPkgsAttribute groupname $pkgsfile | sed $sedargs) groupdesc=$(pl_getPkgsAttribute groupdesc $pkgsfile | sed $sedargs) if [ -z "$groupname" -o -z "$groupdesc" ] ; then echo "Cannot find groupname: and groupdesc: in $pkgsfile -- skipped" 1>&2 continue fi cat << __group_header $(echo $groupname|tr A-Z a-z) $groupname $groupdesc true __group_header for package in $packages; do echo "$package" done cat << __group_footer __group_footer done cat <<__footer __footer }