# -*-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*) if [ "$release" = "4.5" ] ; then # centos 4.5 is just centos4 + enhancements releasename=centos4 else releasename=centos$release fi ;; *) 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) # let mkfedora select one of its mirrors pl_DISTRO_URL="" # 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_makedevs() { vroot=$1 # Clean ${vroot}/dev, but only when ${vroot}!="" [ -n $vroot ] && rm -rf $vroot/dev mkdir -p $vroot/dev mknod -m 666 $vroot/dev/null c 1 3 mknod -m 666 $vroot/dev/zero c 1 5 mknod -m 666 $vroot/dev/full c 1 7 mknod -m 644 $vroot/dev/random c 1 8 mknod -m 644 $vroot/dev/urandom c 1 9 mknod -m 666 $vroot/dev/tty c 5 0 mknod -m 666 $vroot/dev/ptmx c 5 2 # For bash command substitution ln -nsf ../proc/self/fd $vroot/dev/fd # For df and linuxconf touch $vroot/dev/hdv1 # For pseudo ttys mkdir -p $vroot/dev/pts # (Might have to remove the following for vserver-reference.) # for tmpfs mount mkdir -p $vroot/dev/shm # For TUN/TAP mkdir -p $vroot/dev/net mknod -m 600 $vroot/dev/net/tun c 10 200 # For mkinitrd (in case a kernel is being installed) # As well for loop back mounting within a vserver. for i in $(seq 0 255) ; do mknod -m 640 $vroot/dev/loop$i b 7 $i done } function mkfedora_usage() { echo "Usage: mkfedora [OPTION]... [basedir]" echo " -l url Fedora mirror location. Defaults to try:" for mirror in "${mirrors[@]}" ; do echo " $mirror" done echo " -f pkgsfile use this pkgs file for packages, groups, excludes.." echo " -k Exclude kernel* packages from all repositories except bootstrap" 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)" echo " legacy (use -f instead)" echo " -g group1 -g group2 ..." echo " Yumgroups to install (default: none)" echo " -p package1 -p package2 ..." echo " Additional packages to install (default: none)" echo " -x package1 -x package2 ..." echo " Packages to exclude (default: none)" exit 1 } function mkfedora () { echo "* Entering mkfedora " "$@" # Verbosity verbose=0 # Default yum repositories to try mirrors=( file:///data/fedora http://localhost/fedora http://build.planet-lab.org/fedora http://coblitz.codeen.org/coblitz.planet-lab.org/pub/fedora ftp://mirror.cs.princeton.edu/pub/mirrors/fedora ftp://mirror.stanford.edu/pub/mirrors/fedora ftp://rpmfind.net/linux/fedora ) # Release and architecture to install releasever=7 basearch=i386 # Yum groups to install groups=() # Packages to install packages=() # Packages to exclude exclude=() # Exclude kernel* (and related) packages from all repositories except bootstrap exclude_kernel= # PlanetLab development environment if [ -f /etc/planetlab/plc_config ] ; then . /etc/planetlab/plc_config if [ -n "$PLC_DEVEL_FEDORA_URL" ] ; then echo "* mkfedora : setting mirrors from /etc/planetlab/config" mirrors=($PLC_DEVEL_FEDORA_URL) fi fi # Get options while getopts "l:r:a:g:p:x:f:kvh" opt ; do case $opt in l) if echo $OPTARG | grep -q -i '^\(file\|http[s]*\)://' ; then mirrors=($OPTARG) else mirrors=(file://$OPTARG) fi ;; r) releasever=$OPTARG ;; a) basearch=$OPTARG ;; g) groups[${#groups[*]}]="$OPTARG" ;; p) packages[${#packages[*]}]="$OPTARG" ;; x) exclude[${#exclude[*]}]="$OPTARG" ;; f) pkgsfile=$OPTARG ;; k) exclude_kernel="exclude=kernel* ulogd iptables" ;; v) verbose=1 set -x ;; h|*) mkfedora_usage ;; esac done shift $(($OPTIND - 1)) if [ ! -d "$1" ] ; then mkfedora_usage fi vroot=$(cd $1 && pwd -P) if [ $UID -ne 0 ] ; then echo "Error: You must run this script as root." exit 1 fi function mkfedora_fetch () { curl --fail --silent --max-time 60 "$1" } # hard to find two mirrors with a similar layout # set list of attempted locations according to releasever if [ $releasever -ge 7 ] ; then attempts=" linux/releases/$releasever/Everything/$basearch/os $releasever/Everything/$basearch/os core/$releasever/Everything/$basearch/os linux/core/$releasever/$basearch/os " else attempts=" linux/core/$releasever/$basearch/os core/$releasever/$basearch/os $releasever/$basearch/os " fi 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 fi # this used to be for when mkfedora was called within myplc # that is, when the bootcd was recomputed from scratch ### exec 3>&1 ### exec 4>&2 ### if [ $verbose -eq 0 ] ; then ### exec 1>/dev/null ### exec 2>/dev/null ### 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 cat > $vroot/etc/rpm/macros <$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/RPM-GPG-KEY-fedora # 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 "${packages[@]}" | grep "not installed" fi fi if [ ${#groups[*]} -gt 0 ] ; then ## call yum sequentially to get finer-grained info on dependencies for grp in "${groups[@]}" ; do echo "* Installing optional group $grp" yum -c $vroot/etc/yum.conf --installroot=$vroot -y $excludes \ groupinstall "$grp" done fi # FC2 dev %preinstall checks /proc/mounts to make sure that /dev is # not currently mounted as devfs. If it thinks it is, it will refuse # to install the package. On a modern system running udev that mounts # /dev as tmpfs, this check fails. Since we are installing into a # chroot, whether /dev is mounted on the host system or not doesn't # matter. If dev was explicitly mentioned in the packages list, force # its installation. if [ "$releasever" = "2" ] ; then for package in "${packages[@]}" ; do if [ "$package" = "dev" ] && ! rpm --root $vroot -q dev >/dev/null 2>&1 ; then rpm --root $vroot -Uvh --noscripts $baseurl/Fedora/RPMS/dev-3.3.13-1.i386.rpm break fi done 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 # formerly in bootcd/prep.sh : to optimize footprint echo "* Removing unnecessary junk" pushd $vroot # Save precious files [ -n "$precious" ] && tar --ignore-failed-read -cpf precious.tar $precious # Remove unnecessary junk [ -n "$junk" ] && rm -rf $junk # Restore precious files [ -n "$precious" ] && tar -xpf precious.tar && rm -f precious.tar popd # remove trap handler, as we are about to call it directly. trap - ERR INT # Clean up mkfedora_cleanup return 0 } function pl_mkfedora() { root=$1 shift options=$@ pl_makedevs $root [ -n "$pl_DISTRO_URL" ] && options="$options -l $pl_DISTRO_URL" [ -n "$pl_DISTRO_ARCH" ] && options="$options -a $pl_DISTRO_ARCH" [ -n "$pl_DISTRO_RELEASE" ] && options="$options -r $pl_DISTRO_RELEASE" # echo "mkfedora -v $options $root" mkfedora -v $options $root } function pl_setup_chroot() { root=$1; shift options="$@" pl_mkfedora $root $options # 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 $vroot/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 -l $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 # 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 function pl_parsePkgs () { keyword=$1;shift fcdistro=$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 " done return 0 } function pl_getPackages() { fcdistro=$1; shift ; pl_parsePkgs package $fcdistro "$@" ; } function pl_getGroups() { fcdistro=$1; shift ; pl_parsePkgs group $fcdistro "$@" ; } # 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 }