#!/bin/sh # # Description: Remove old dated copies (incs) according to policy # Usage: rm # # shellcheck source=./includes LIBDIR="$(dirname $0)" && . "${LIBDIR}/includes" kill_or_clean_lockfile() { lock_file=${1:-} if [ -f "${lock_file}" ]; then # Get Process ID from the lock file pid=$(cat "${lock_file}") if [ -n "${pid}" ]; then if kill -0 "${pid}" 2> /dev/null; then # Kill the children pkill -9 --parent "${pid}" # Kill the parent kill -9 "${pid}" # Only one bkctld-rm can run in parallel, the latest wins lockfile_date=$(date --date "@$(stat -c %Y ${lock_file})" +"%Y-%m-%d %H:%M:%S") warning "Process \`${pid}' (started at ${lockfile_date}) has been killed by \`$$'" else warning "Process not found at PID \`${pid}'. Ignoring lock file \`${lock_file}'." fi else warning "Empty lockfile \`${lock_file}'. It should contain a PID." fi # Remove the lock file rm -f ${lock_file} fi } incs_to_delete() { jail_name=${1:?} incs_policy_file=${2:?} incs_policy_keep_file=$(new_tmp_file "${jail_name}.incs_policy_keep") incs_list_file=$(new_tmp_file "${jail_name}.incs_list") # loop for each line in jail configuration for incs_policy_line in $(grep "^\+" ${incs_policy_file}); do # inc date in ISO format incs_policy_date=$(relative_date ${incs_policy_line}) echo ${incs_policy_date} >> "${incs_policy_keep_file}" done for inc_name in $(incs_list "${jail_name}"); do echo "${inc_name}" >> ${incs_list_file} done # shellcheck disable=SC2046 incs_to_delete=$(grep -v -f "${incs_policy_keep_file}" "${incs_list_file}") rm -f "${incs_policy_keep_file}" "${incs_list_file}" echo ${incs_to_delete} } delete_inc_btrfs() { jail_name=$1 inc_name=$2 inc_path=$(inc_path "${jail_name}" "${inc_name}") if dry_run; then echo "[dry-run] delete btrfs subvolume ${inc_path}" else /bin/btrfs subvolume delete "${inc_path}" | debug fi } delete_inc_ext4() { jail_name=$1 inc_name=$2 inc_path=$(inc_path "${jail_name}" "${inc_name}") if dry_run; then echo "[dry-run] delete ${inc_path} with rsync from empty directory" else empty=$(new_tmp_dir "empty") rsync --archive --delete "${empty}/" "${inc_path}/" rmdir "${inc_path}/" rmdir "${empty}" fi } lock_file="${LOCKDIR}/rm-global.lock" # shellcheck disable=SC2064 trap "rm -f ${lock_file}; cleanup_tmp;" 0 kill_or_clean_lockfile "${lock_file}" new_lock_file "${lock_file}" jails_list=$(jails_list) jails_total=$(echo $jails_list | wc -w) jails_count=0 for jail_name in ${jails_list}; do jails_count=$((jails_count+1)) incs_policy_file=$(current_jail_incs_policy_file ${jail_name}) # If no incs policy is found, we don't remove incs if [ -n "${incs_policy_file}" ]; then # shellcheck disable=SC2046 incs_to_delete=$(incs_to_delete "${jail_name}" "${incs_policy_file}") incs_total=$(echo ${incs_to_delete} | wc -w) incs_count=0 if [ -n "${incs_to_delete}" ]; then debug "Incs to be deleted for \`${jail_name}' : $(echo "${incs_to_delete}" | tr '\n', ',' | sed 's/,$//')." for inc_name in ${incs_to_delete}; do incs_count=$((incs_count+1)) info "Progress: jail ${jails_count} out of ${jails_total} - inc ${incs_count} out of ${incs_total}" notice "Delete inc \`${inc_name}' for jail \`${jail_name}' : start" inc_path=$(inc_path "${jail_name}" "${inc_name}") if is_btrfs "${inc_path}"; then delete_inc_btrfs "${jail_name}" "${inc_name}" else delete_inc_ext4 "${jail_name}" "${inc_name}" fi notice "Delete inc \`${inc_name}' for jail \`${jail_name}' : finish" done else notice "Skip jail \`${jail_name}' : no inc to delete" fi else notice "Skip jail \`${jail_name}' : incs policy is missing" fi done # Remove the lock file and cleanup tmp files rm -f "${lock_file}" cleanup_tmp