# ------------------------------------------------------------------------------ # File manipulation function # This file is part of the init.sh project # Copyright (c) 2019-2021 Geoffray Levasseur # ------------------------------------------------------------------------------ # This file is distributed under 3-clause BSD license. # The complete license agreement can be obtained at: # https://opensource.org/licenses/BSD-3-Clause # ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------ # Backup original installation files # (or any old files if runned several time on same file) backup_dist() { if [[ $# -lt 1 ]]; then prnt E "backupdist(): At least one argument is required." exit 11 fi local file= for file in $@; do local tmstmp=$(stdtime) if [[ -L ${file} ]]; then # With symbolik links we call again backupdist to treat target prnt I "Following the symbolic link $file to do a proper backup..." backupdist $(readlink -f ${file}) elif [[ -f ${file} ]]; then prnt I "Creating a backup of ${file} on $tmstmp..." cp -av $file ${file}.dist.${tmstmp} if [[ $? -ne 0 ]]; then prnt E "backupdist(): Failed copying file." die 12 fi elif [[ -d ${file} ]]; then prnt I "Creation a backup of the directory ${file} on $tmstmp..." cp -av $file ${file}.dist.${tmstmp} if [[ $? -ne 0 ]]; then prnt E "backupdist(): Failed copyind directory recursively." die 12 fi else prnt W "backupdist(): $file don't exists, nothing to do." fi unset tmstmp done unset file } export -f backupdist # ------------------------------------------------------------------------------ # Select source file according to our priority mechanism select_file() { local infile=$1 if [[ -f $MYPATH/repo/hosts/$HOSTNAME/$infile ]]; then local source="$MYPATH/repo/hosts/$HOSTNAME/$infile" elif [[ -f $MYPATH/repo/common/$infile ]]; then local source="$MYPATH/repo/common/$infile" else # Not found in repository, we expect full name local source="$infile" fi unset infile echo $source unset source } # ------------------------------------------------------------------------------ # Select source directory according to our priority mechanism select_directory() { local indir=$1 if [[ -d $MYPATH/repo/hosts/$HOSTNAME/$indir ]]; then local source="$MYPATH/repo/hosts/$HOSTNAME/$indir" elif [[ -d $MYPATH/repo/common/$indir ]]; then local source="$MYPATH/repo/common/$indir" else # Not found in repository, we expect full name local source="$indir" fi unset indir echo $source unset source } # ------------------------------------------------------------------------------ # Install file to the host (specific first then general) # Todo: implement wildcard support install_file() { local filelist="" local i=0 if [[ $# -lt 2 ]]; then prnt E "installfile(): At least two arguments are required." die 11 fi if [[ $(echo $@ | grep "\*\|\?") ]]; then prnt E "installfile(): Wildcards are not authorized." die 7 fi local arg= for arg in $@; do filelist="$filelist $(select_file $arg)" done unset arg # Empty to just obtain the target which is the last element of the list local file= for file in $filelist; do : done if [[ ! $file == /* ]]; then prnt E "installfile(): Target must be on the root filesystem and full path must be provided." die 13 fi unset file if [[ -d $(dirname $i) ]]; then prnt I "Creating required target directory $(dirname $i)..." mkdir -pv $(dirname $i) if [[ $? -ne 0 ]]; then prnt E "installfile(): Can't create target directory!" die 12 fi fi prnt I "Copying files ${filelist} to target directory $(dirname $i)..." cp -av $filelist if [[ $? -ne 0 ]]; then prnt E "installfile(): Couldn't copy some required files!" die 12 fi } export -f installfile # ------------------------------------------------------------------------------ # Add the content of a file at the end of an other append_file() { local srcfile=$(select_file $1) local dstfile=$2 if [[ -e $dstfile ]]; then prnt E "appendfile(): Target must be on the root filesystem and full path must be provided." die 13 fi if [[ ! $dstfile == /* ]]; then prnt E "appendfile(): Target file must exist." die 13 fi prnt I "Adding content to file $dstfile..." cat $srcfile >> $dstfile if [[ $? -ne 0 ]]; then prnt E "appendfile(): Couldn't append a file!" die 12 fi } export -f appendfile # ------------------------------------------------------------------------------ # determine if a directory is empty is_dir_empty() { dir=$1 if [[ -f $dir ]]; then prnt E "isdirempty(): The given parameter is not a directory." die 15 fi if [[ ! -d $dir ]]; then return 0 fi nbfiles=$(ls -a1 $dir | egrep -v '^.$|^..$' | wc -l) if [[ $nbfiles -eq 0 ]]; then return 0 fi return 1 } export -f isdirempty # ------------------------------------------------------------------------------ # copy and patch a file replacing all @var@ by the corresponding value in # the environment or the variable list given in parameter patch_file() { local srcfile=$(select_file $1) && shift local dstfile=$1 && shift local workfile=${dstfile}.work if [[ ! -s $srcfile ]]; then prnt E "patchfile(): Source file is empty, is not a file or don't exists!" die 10 fi # Create a sub-process, to avoid bash environment pollution ( local varlist= pattern= if [[ $# -eq 0 ]] ; then pattern="-e s/<\(.*\)>/\$\1\$\1/g" else local var= for var in $* ; do if ! declare -p $var >/dev/null 2>&1 ; then local $var=$(eval echo \$$var) fi export $var pattern="$pattern -e s/@$var@/\$$var/g" varlist=$varlist\$$var done fi # sed replace with \$$VAR and envsubst do the replace by value sed $pattern $srcfile | envsubst ${varlist:+"$varlist"} > "$workfile" ) local -a rights=( $(stat --printf="%a %u %g" "$srcfile") ) unset srcfile mv "$workfile" "$dstfile" chmod ${rights[0]} "$dstfile" chown ${rights[1]}:${rights[2]} "$dstfile" unset rights dstfile } export -f patchfile # ------------------------------------------------------------------------------ # Put a small header in a file showing it have been automatically modified tag_file() { for f in $@; do local text="# File automatically modified by init.sh on $(stdtime)." if [[ -e $f ]]; then sed -i "1s/^/$text\n/" $f else echo $text > $f sed -i -e "s/modified/generated/" $f fi done } export -f tagfile # ------------------------------------------------------------------------------ # check files exists and return 1 if one do not file_exists() { for f in $@; do if [[ ! -f $(select_file $f) ]]; then echo $f return 1 fi done return 0 } export -f file_exists # ------------------------------------------------------------------------------ # check if file exists and return error if not file_must_exists() { prnt I "Checking $@ files existance..." local mf=$(file_exists $@) if [[ $? -ne 0 ]]; then prnt E "file_must_exists(): The $mf file is missing, can't continue." die 10 fi unset mf } export -f file_must_exists # ------------------------------------------------------------------------------ # check files exists and return 1 if one do not directory_exists() { for d in $@; do if [[ ! -d $(select_directory $d) ]]; then echo $d return 1 fi done return 0 } export -f directory_exists # ------------------------------------------------------------------------------ # check if file exists and return error if not directory_must_exists() { prnt I "Checking $@ directories existance..." local md=$(directory_exists $@) if [[ $? -ne 0 ]]; then prnt E "directory_must_exists(): The $md directory is missing, can't continue." die 10 fi unset md } export -f directory_must_exists # EOF