/
usr
/
share
/
backup-manager
/
Upload File
HOME
# Copyright � 2005-2016 The Backup Manager Authors # # See the AUTHORS file for details. # # 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. # All functions dedicated to manage the files. #unmount_tmp_dir() #{ # if [[ -n "$mount_point" ]] && # [[ -d $mount_point ]] && # [[ grep $mount_point /etc/mtab >/dev/null 2>&1 ]]; then # umount "$mount_point" > /dev/null 2>&1 || error "unable to unmount \$mount_point" # sleep 1 # rmdir "$mount_point" > /dev/null 2>&1 || error "unable to remove \$mount_point" # fi #} # detect if find supports -H find_opt="" if find -H /tmp > /dev/null 2>&1 ; then find_opt="-H" fi # this will send the appropriate name of archive to # make according to what the user choose in the conf. function get_dir_name() { base="$1" format="$2" debug "get_dir_name ($base, $format)" if [[ "$format" = "long" ]] then # first remove the trailing slash base=${base%/} # every space by a _ dirname=$(echo "$base" | sed 's/ /_/g') # every / by a - dirname=$(echo "$dirname" | sed 's/\//-/g') elif [[ "$format" = "short" ]] then OLDIFS=$IFS export IFS="/" for directory in $base do parent=$directory done dirname=-$directory export IFS=$OLDIFS else echo "" fi echo "$dirname" } # This will take a path and return the size in mega bytes # used on the disk. # Thanks to Michel Grentzinger <mic.grentz@online.fr> function size_of_path() { path="$1" debug "size_of_path ($path)" if [[ -z "$path" ]]; then error "No path given." fi #echo "DEBUG: du --si --block-size=1000k -c $path | tail -n 1 | awk '{print $1}'" >&2 total_size=$(du --si --block-size=1000k -c $path | tail -n 1 | awk '{print $1}') echo $total_size } # Thanks to Michel Grentzinger <mic.grentz@online.fr> function size_left_of_path() { path="$1" debug "size_left_of_path ($path)" if [[ -z "$path" ]]; then error "No path given." fi left=$(df --si --block-size=1000k "$path" | tail -n 1 | awk '{print $4}') echo $left } # Will return the prefix contained in the file name function get_prefix_from_file() { filename="$1" debug "get_prefix_from_file ($filename)" filename=$(basename $filename) prefix=$(echo $filename | sed -e 's/^\([^-]\+\)-.*$/\1/') echo $prefix } # Will return the date contained in the file name function get_date_from_file() { debug "get_date_from_file ($1)" get_date_from_archive "$1" } # This function is here to free each lock previously enabled. # We have to keep in mind that lock must be done for each conffile. # It is not global anymore, and that's the tricky thing. function release_lock() { debug "release_lock()" if [[ -e $lockfile ]]; then # We have to remove the line which contains # the conffile. newfile=$(mktemp ${BM_TEMP_DIR}/lock.XXXXXX) newcontent="" OLDIFS=$IFS IFS=$'\n' for line in $(cat $lockfile) do thisfile=$(echo $line | awk '{print $2}') if [[ ! $conffile = $thisfile ]]; then echo "$line" >> $newfile fi done IFS=$OLDIFS mv $newfile $lockfile fi } # This function try to get a lock, if this is not possible, # backup-manager won't run. # Be aware that a there will be one lock for each conffile used. # If the PID written in the lockfile is not alive, release. function get_lock() { debug "get_lock()" if [[ -e $lockfile ]]; then # look if a lock exists for that conffile (eg, we must find # the path of the conffile in the lockfile) # lockfile format : # $pid $conffile pid=`grep " $conffile " $lockfile | awk '{print $1}'` # be sure that the process is running if [[ ! -z $pid ]]; then unamestr=`uname | xargs | awk '{print tolower($0)}'` # For OSX & fink : if [[ "$unamestr" == 'darwin' ]]; then real_pid=$(ps -p $pid |tail -n +2 |awk '{print $1}') else real_pid=$(ps --no-headers --pid $pid |awk '{print $1}') fi if [[ -z $real_pid ]]; then echo_translated "Removing lock for old PID, \$pid is not running." release_lock #unmount_tmp_dir pid="" fi fi if [[ -n "$pid" ]]; then # we really must not use error or _exit here ! # this is the special point were release_lock should not be called ! echo_translated "A backup-manager process (\$pid) is already running with the conffile \$conffile" exit 1 else pid=$$ info "Getting lock for backup-manager \$pid with \$conffile" echo "$$ $conffile " >> $lockfile fi else pid=$$ info "Getting lock for backup-manager \$pid with \$conffile" echo "$$ $conffile " > $lockfile if [[ ! -e $lockfile ]]; then error "failed (check the file permissions)." exit 1 fi fi } function get_date_from_archive() { file="$1" debug "get_date_from_archive ($file)" date=$(echo $file | sed -e 's/.*\(20[0-9][0-9][0-9][0-9][0-3][0-9]\).*/\1/') echo "$date" } # Returns the name of an archive. # eg: get_name_from_archive "ouranos-usr-bin.20060329.tar.bz2" # usr-bin function get_name_from_archive() { archive="$1" debug "get_name_from_archive ($archive)" archive=$(basename "$archive") # drop the first token before a dash (the prefix) name="${archive#*-}" # drop the right part: everything from the first dot name="${name%%.*}" # done echo "$name" } function get_master_from_archive() { archive="$1" debug "get_master_from_archive ($archive)" archive=$(basename "$archive") master=$(echo "$archive" | sed -e 's/.*\.\(master\)\..*/\1/') if [[ "$master" = "master" ]]; then echo "true" else echo "false" fi } function get_prefix_from_archive() { archive="$1" archive=$(basename "$archive") echo "${archive%%-*}" } function get_newer_master() { prefix="$1" name="$2" date="$3" debug "get_newer_master ($prefix, $name, $date)" master="" for this_master in $BM_REPOSITORY_ROOT/$prefix-$name.*.master.* do this_date=$(get_date_from_archive "$this_master") # is this master newer than the one we are testing? if [[ "$this_date" -gt "$date" ]]; then debug "found this newer master : $this_master" master="$this_master" fi done echo "$this_master" } function clean_file() { file="$1" purge_date="$2" debug "clean_file ($file, $purge_date)" if [[ ! -f "$file" ]]; then error "\$file is not a regular file." fi prefix=$(get_prefix_from_archive "$file") date=$(get_date_from_archive "$file") name=$(get_name_from_archive "$file") master=$(get_master_from_archive "$file") debug "parsing $file ($prefix, $date, $name, $master)" # we assume that if we find that, we have an archive if [[ -n "$date" ]] && [[ "$date" != "$(basename $file)" ]] && [[ -n "$prefix" ]] && [[ "$prefix" != "$(basename $file)" ]] && [[ -n "$name" ]] && [[ "$name" != "$(basename $file)" ]]; then # look if the archive is obsolete if [[ "$date" -lt "$purge_date" ]] || [[ "$date" = "$purge_date" ]]; then # if it's a master, we have to find a newer master around if [[ "$master" = "true" ]]; then master_archive=$(get_newer_master "$prefix" "$name" "$date") # if the master returned is not the same as the one we have, # the one we have can be deleted, because it's older. if [[ "$master_archive" != "$file" ]]; then info "Removing obsolete master backup: \"\$file\"." rm -f "$file" # else, we can only remove the master archive if we cannot find any # incremental archive related. else nb_incrementals=$(ls -l $BM_REPOSITORY_ROOT/$prefix-$name.*.* | wc -l) if [[ "$nb_incrementals" = "1" ]]; then info "Removing obsolete master backup (isolated): \"\$file\"." rm -f $file fi fi # the archive we handle isn't a master backup, we can drop it. else info "Removing archive \"\$file\"." rm -f "$file" fi fi fi } # clean one given repository. # This will take each file that has # a date in its names and will compare # the file's date to the date_to_remove. # If the file's date is older than the date_to_remove # we drop the file. function clean_directory() { directory="$1" debug "clean_directory ($directory)" purge_date=$(date +%Y%m%d --date "$BM_ARCHIVE_TTL days ago") if [[ ! -d $directory ]]; then error "Directory given was not found." fi if [[ "$BM_REPOSITORY_RECURSIVEPURGE" = "true" ]]; then maxdepth="" else maxdepth="-maxdepth 1" fi # First list all the files to process # and ask backup-manager-purge what to remove list=$(mktemp ${BM_TEMP_DIR}/bm-list.XXXXXX) # files & symlinks find $find_opt "$directory" $maxdepth \ \( -type f -o -type l \) -print \ | $bmp --ttl=$BM_ARCHIVE_TTL > $list # Then actually remove the files for archive in `cat $list` do info "Removing archive \"\$archive\"." rm -f $archive done rm -f $list } # This takes a file and the md5sum of that file. # It will look at every archives of the same source # and will replace duplicates (same size) by symlinks. # CONDITION: BM_ARCHIVE_PURGEDUPS = true function purge_duplicate_archives() { file_to_create="$1" if [[ -z "$2" ]]; then debug "purge_duplicate_archives ($file_to_create)" md5hash=$(get_md5sum $file_to_create) else # if the 2nd argument exists, it is the md5sum md5hash="$2" debug "purge_duplicate_archives ($file_to_create, $md5hash)" fi # Only purge if BM_ARCHIVE_PURGEDUPS = true if [[ -z "$BM_ARCHIVE_PURGEDUPS" ]] || [[ "$BM_ARCHIVE_PURGEDUPS" != "true" ]]; then return 0 fi if [[ ! -e $file_to_create ]]; then error "The given file does not exist: \$file_to_create" return 1 fi if [[ -z "$file_to_create" ]]; then error "No file given." fi # we'll parse all the files of the same source date_of_file=$(get_date_from_file $file_to_create) || error "Unable to get date from file." if [[ -z "$date_of_file" ]]; then error "Unable to get date from file." fi file_pattern=$(echo $file_to_create | sed -e "s/\\(.*\\)$date_of_file/\\1\*/") || error "Unable to find the pattern of the file." # loop on each archive occurences (eg: archivename-*-filetype) for file in $file_pattern do # handle only regular files if [[ ! -L $file ]] && [[ "$file" != "$file_to_create" ]]; then # get the date of the file we parse date_of_file=$(get_date_from_file $file) || error "Unable to get date from file." # get the md5 hash of the file we parse, in its .md5 file md5sum_to_check="$(get_md5sum_from_file $file $MD5FILE)" if [[ -z "$md5sum_to_check" ]]; then warning "Unable to find the md5 hash of file \"\$file\" in file \"\$MD5FILE\"." continue fi # if the md5 hashes are the same, purge the duplicate if [[ "$md5hash" = "$md5sum_to_check" ]]; then info "\$file is a duplicate of \$file_to_create (using symlink)." rm -f $file ln -s $file_to_create $file fi fi done } function assert_file_exists() { file="$1" if [[ ! -r "$file" ]]; then warning "File '\$file' does not exist or is not readable." return 1 fi } function assert_file_is_executable() { file="$1" if [[ ! -x "$file" ]]; then warning "File '\$file' is not executable" return 1 fi }