backup (3719B)
1 #!/bin/sh 2 # Copyright (C) 2023, 2024 Vincent Forest (vaplv@posteo.net) 3 # 4 # This program is free software: you can redistribute it and/or modify 5 # it under the terms of the GNU General Public License as published by 6 # the Free Software Foundation, either version 3 of the License, or 7 # (at your option) any later version. 8 # 9 # This program is distributed in the hope that it will be useful, 10 # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 # GNU General Public License for more details. 13 # 14 # You should have received a copy of the GNU General Public License 15 # along with this program. If not, see <http://www.gnu.org/licenses/>. 16 17 set -e 18 19 [ -z "${NEXTBACKUP}" ] && NEXTBACKUP="/etc/nextbackup" 20 21 ################################################################################ 22 # Helper functions 23 ################################################################################ 24 usage() 25 { 26 printf "usage: %s backup_dir files_to_backup\n" "${0##*/}" 27 } 28 29 badseq() 30 { 31 printf "%s: invalid sequence %d\n" "${NEXTBACKUP}" "$1" >&2 32 } 33 34 ################################################################################ 35 # The script 36 ################################################################################ 37 if [ $# -lt 2 ]; then 38 usage >&2 39 exit 1 40 fi 41 42 # Ensure that the directory in which backup files are saved exists 43 dir="$1" 44 mkdir -p "${dir}" 45 shift 1 46 47 # Retrieves the identifiers of the next backup files, i.e. the expected 48 # dump level and the current Hanoi sequence in the backup cycle. 49 entry="" 50 [ -f "${NEXTBACKUP}" ] && entry="$(head -1 "${NEXTBACKUP}")" 51 lvl="$(echo "${entry}" | cut -d' ' -f1)" 52 seq="$(echo "${entry}" | cut -d' ' -f2)" 53 54 # Invalid level or invalid Hanoi sequence => full backup 55 if ! echo "${lvl}" | grep -qe "^[0-9]" \ 56 || ! echo "${seq}" | grep -qe "^[0-2]"; then 57 lvl=0 58 seq=0 59 fi 60 61 suffix="" 62 63 # Define the suffix of level 0 backup files by the date on which it is 64 # issued. In this way, each level 0 does not overwrite a previous level 65 # 0. So, the administrator can archive level 0s according to his or her 66 # backup strategy. It's a simple, elegant way of keeping a backup 67 # history. 68 if [ "${lvl}" -eq 0 ]; then 69 suffix="_$(date +"%Y%m%d%H%M")" 70 71 # Define the suffix for level 1 backup files; this is the only level 72 # that will have several files during a complete backup cycle. Sequence 73 # 0 has no level 1, since it starts with a full backup (i.e. level 0). 74 # In sequence 1, the backup file is suffixed with 'a', while in sequence 75 # 2, it is suffixed with 'b'. 76 elif [ "${lvl}" -eq 1 ]; then 77 case "${seq}" in 78 1) suffix="a" ;; 79 2) suffix="b" ;; 80 *) badseq "${seq}"; exit 1 ;; 81 esac 82 fi 83 84 # Perform backup 85 backup="${dir}/backup${lvl}${suffix}.dump" 86 dump "-${lvl}" -u -f "${backup}" "$@" 87 88 # Test the archive and write log 89 { 90 printf "[%s]\n" "${backup##*/}" 91 restore -f "${backup}" -t 92 } > "${backup%.*}.txt" 93 94 sync 95 96 # Configure the identifiers of the next backup file. A full backup cycle 97 # is built on ordered dump levels relative to 3 Hanoi sequences. The 98 # first Hanoi sequence begins with a full backup, and the other two are 99 # built incrementally from it. 100 # 101 # The levels of a full backup cycle are as follows: 102 # 103 # 0 -> 3 -> 2 -> 5 -> 4 -> 7 -> 6 -> 9 -> 8 104 # 1a -> 3 -> 2 -> 5 -> 4 -> 7 -> 6 -> 9 -> 8 105 # 1b -> 3 -> 2 -> 5 -> 4 -> 7 -> 6 -> 9 -> 8 -> 0 106 case "${lvl}" in 107 0|2|4|6) printf "%d %d" "$((lvl+3))" "${seq}" ;; 108 3|5|7|9) printf "%d %d" "$((lvl-1))" "${seq}" ;; 109 1) printf "3 %d" "${seq}" ;; 110 8) 111 case "${seq}" in 112 0|1) printf "1 %d" "$((seq+1))" ;; 113 2) printf "0 0" ;; 114 *) badseq "${seq}"; exit 1 ;; 115 esac 116 ;; 117 *) badseq "${seq}"; exit 1 ;; 118 esac > "${NEXTBACKUP}"