#! /bin/bash #********************************************************************* # # fai-mirror -- create and manage a partial mirror for FAI # # This script is part of FAI (Fully Automatic Installation) # (c) 2004-2019, Thomas Lange, lange@informatik.uni-koeln.de # #********************************************************************* # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; see the file COPYING. If not, write to the # Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, # MA 02111-1307, USA. #********************************************************************* # variables: NFSROOT, FAI_CONFIGDIR, FAI_ETC_DIR export FAI_ROOT=/ # do not execute in chroot, needed for install_packages call export PATH=$PATH:/usr/sbin trap "umount_dirs" EXIT ERR # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - usage() { echo "fai-mirror -- create and manage a partial mirror for FAI." echo "Please read the manual page fai-mirror(1)." exit } # - - - - - - - - - - - - - - - - - - - - - - - - - - die() { local e=$1 # first parameter is the exit code shift echo "$@" >&2 # print error message exit $e } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - excludeclass() { # removes/excludes all classes in $* from $classes local insert eclasses newclass c e eclasses="$*" eclasses=${eclasses//,/ } for c in $classes; do insert=1 for e in $eclasses; do [ $c = $e ] && insert=0 done [ $insert = 1 ] && newclass="$newclass $c" done classes="$newclass" } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - umount_dirs() { [ "$FAI_DEBMIRROR" ] && umount $MNTPOINT 2>/dev/null 1>&2 || true } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - cleandirs() { return # currently nothing to do } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - initialize() { # TODO: root is only needed when FAI_DEBMIRROR is defined. Then we # must mount a directory # we only need some empty dirs set -e mkdir -p $mirrordir/Packages set +e } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - delete_base_packages() { echo "WARNING: base packages can't be deleted on RPM based operating systems." >&2 } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - add_base_packages() { echo "WARNING: base packages can't be added on RPM based operating systems." >&2 } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - set-classes() { local addclasses # if -c is given, ignore -x if [ -n "$cclasses" ]; then export classes=${cclasses//,/ } return fi set +e # all available file names are classes classes=$(cd $FAI_CONFIGDIR/package_config; ls -1 | grep -E -i "^[a-zA-Z0-9_-]+$") addclasses=$(grep -h PACKAGES $FAI_CONFIGDIR/package_config/* | sed -e 's/#.*//' | awk '{printf $3"\n"$4"\n"$5"\n"$6"\n"}') export classes=$(echo -e "$classes\n$addclasses\n" | sort | uniq) [ -n "$exclasses" ] && excludeclass $exclasses set -e } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - mk_class_var_list() { # create a list of files named class/*.var that contain a definition of a variable that is # used in package_config/ # we assume, that variables used in package_config are defined in class/*.var. # For all classes search if there's a variables used in package_config/CLASS # For all variables found look which files class/CLASS.var define these variables. local -a variables=() local filelist classlist sourefiles local c i f #filelist: all files in package_config which are also a defined class for c in $classes; do if [ -f $FAI_CONFIGDIR/package_config/$c ]; then filelist+=" $c" fi done if [ -z "$filelist" ]; then return fi # make the list of variables that are used # regex: $abc or ${abc} variables=($(cd $FAI_CONFIGDIR/package_config;grep -h -P -o '\$[A-Za-z0-9_]+|\$\{[A-Za-z0-9_]+\}' $filelist|sort|uniq)) # debug #for v in ${variables[@]}; do # echo Variable found: $v #done # create a regex like varname= for all variables for i in ${!variables[@]}; do variables[i]=$(echo ${variables[i]} | tr -d /{}$/) variables[i]+="=" done # classlist: make list of files in class, which are also a class for c in $classes; do if [ -f $FAI_CONFIGDIR/class/$c.var ]; then classlist+=" $FAI_CONFIGDIR/class/$c.var" fi done # look for variable definition in this list for f in $classlist; do for i in ${!variables[@]}; do if grep -q -P "${variables[i]}" $f; then sourefiles+=" $f" break fi done done # these files contain a variable definition which is needed echo $sourefiles } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - preserve=0 verbose=0 add=1 qflag=-q bcount=0 setvariables=0 while getopts "a:bBvhx:pc:C:m:s:P:V" opt ; do case "$opt" in a) arch=$OPTARG ;; B) add=0 ; ((bcount++)) ;; b) add=2 ; ((bcount++)) ;; C) cfdir=$OPTARG ;; h) usage ;; x) exclasses="$OPTARG";; c) cclasses="$OPTARG";; m) MAXPACKAGES="$OPTARG";; p) preserve=1;; s) csdir="$OPTARG";; v) verbose=1; vflag=-v; qflag='';; V) setvariables=1 ;; P) aptpref="$OPTARG";; ?) die 1 "Unknown option";; esac done shift $(($OPTIND - 1)) # use FAI_ETC_DIR from environment variable [ -n "$FAI_ETC_DIR" -a -z "$cfdir" ] && echo "Using environment variable \$FAI_ETC_DIR." # use -C option if present otherwise use $FAI_ETC_DIR or default to /etc/fai [ -z "$cfdir" ] && cfdir=${FAI_ETC_DIR:=/etc/fai} cfdir=$(readlink -f $cfdir) # canonicalize path [ ! -d "$cfdir" ] && die 6 "$cfdir is not a directory" [ "$verbose" -eq 1 ] && echo "Using configuration files from $cfdir" [ $bcount -gt 1 ] && die 7 "You can't use -b and -B simultaneously." . $cfdir/fai.conf . $cfdir/nfsroot.conf : ${MNTPOINT:=/media/mirror} # default value export NFSROOT if [ -n "$csdir" ]; then FAI_CONFIGDIR=$csdir # override by -s fi command -v repotrack >&/dev/null || die 8 "repotrack not found. Please install the yum-utils package." [ -n "$exclasses" -a -n "$cclasses" ] && die 3 "Options -x and -c not allowed at the same time." # use first argument if given, use variable mirrordir if not argument was given [ -n "$1" ] && mirrordir=$1 [ -z "$mirrordir" ] && die 2 "Please give the absolute path to the mirror." { echo $mirrordir | grep -E -q '^/'; } || die 4 "Mirrordir must start with a slash /." [ -d $FAI_CONFIGDIR/package_config ] || die 6 "Can't find package config files in $FAI_CONFIGDIR." # set default if undefined : ${MAXPACKAGES:=1} export MAXPACKAGES set-classes if [ "$setvariables" -eq 1 ]; then flist=$(mk_class_var_list) set -a for f in $flist; do echo Sourcing variable definitions in $f source $flist done set +a fi initialize # if we are using nfs mounts for Debian mirror, this may fail here, since inside a chroot environment different dir are used # if sources.list includes file AND FAI_DEBMIRROR is defined we have to mount # otherwise mounting is not needed. call task_mirror if [ "$FAI_DEBMIRROR" ]; then mkdir -p $MNTPOINT mount -r $FAI_DEBMIRROR $MNTPOINT || exit 9 fi [ $add -eq 1 ] && add_base_packages echo "Downloading packages for classes:" $classes for pkg in $(FAI=$FAI_CONFIGDIR install_packages -N -l); do if repotrack ${qflag} -p $mirrordir/Packages ${pkg}; then : else die 9 "ERROR when downloading packages. Your mirror is broken. Use fai-mirror -v for details." fi done umount_dirs trap "" EXIT ERR [ $add -eq 0 ] && delete_base_packages # allow package without the .deb suffix. At least they must start with a char and contain an underscore or hyphen createrepo ${qflag} $mirrordir echo "$0 finished." echo -n "Mirror size and location: ";du -sh $mirrordir cleandirs