blob: ee9f0202d58b36c0ba3ab6251cb43243bcd57e11 [file] [log] [blame]
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01001#!/usr/bin/env bash
2
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +01003DEBIAN_DOCKER_IMAGE="mailcow/backup:latest"
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +01004
5if [[ ! -z ${MAILCOW_BACKUP_LOCATION} ]]; then
6 BACKUP_LOCATION="${MAILCOW_BACKUP_LOCATION}"
7fi
8
9if [[ ! ${1} =~ (backup|restore) ]]; then
10 echo "First parameter needs to be 'backup' or 'restore'"
11 exit 1
12fi
13
14if [[ ${1} == "backup" && ! ${2} =~ (crypt|vmail|redis|rspamd|postfix|mysql|all|--delete-days) ]]; then
15 echo "Second parameter needs to be 'vmail', 'crypt', 'redis', 'rspamd', 'postfix', 'mysql', 'all' or '--delete-days'"
16 exit 1
17fi
18
19if [[ -z ${BACKUP_LOCATION} ]]; then
20 while [[ -z ${BACKUP_LOCATION} ]]; do
21 read -ep "Backup location (absolute path, starting with /): " BACKUP_LOCATION
22 done
23fi
24
25if [[ ! ${BACKUP_LOCATION} =~ ^/ ]]; then
26 echo "Backup directory needs to be given as absolute path (starting with /)."
27 exit 1
28fi
29
30if [[ -f ${BACKUP_LOCATION} ]]; then
31 echo "${BACKUP_LOCATION} is a file!"
32 exit 1
33fi
34
35if [[ ! -d ${BACKUP_LOCATION} ]]; then
36 echo "${BACKUP_LOCATION} is not a directory"
37 read -p "Create it now? [y|N] " CREATE_BACKUP_LOCATION
38 if [[ ! ${CREATE_BACKUP_LOCATION,,} =~ ^(yes|y)$ ]]; then
39 exit 1
40 else
41 mkdir -p ${BACKUP_LOCATION}
42 chmod 755 ${BACKUP_LOCATION}
43 fi
44else
45 if [[ ${1} == "backup" ]] && [[ -z $(echo $(stat -Lc %a ${BACKUP_LOCATION}) | grep -oE '[0-9][0-9][5-7]') ]]; then
46 echo "${BACKUP_LOCATION} is not write-able for others, that's required for a backup."
47 exit 1
48 fi
49fi
50
51BACKUP_LOCATION=$(echo ${BACKUP_LOCATION} | sed 's#/$##')
52SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
53COMPOSE_FILE=${SCRIPT_DIR}/../docker-compose.yml
54ENV_FILE=${SCRIPT_DIR}/../.env
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010055THREADS=$(echo ${THREADS:-1})
56
57if ! [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then
58 echo "Thread input is not a number!"
59 exit 1
60elif [[ "${THREADS}" =~ ^[1-9]+$ ]] ; then
61 echo "Using ${THREADS} Thread(s) for this run."
62 echo "Notice: You can set the Thread count with the THREADS Variable before you run this script."
63fi
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010064
65if [ ! -f ${COMPOSE_FILE} ]; then
66 echo "Compose file not found"
67 exit 1
68fi
69
70if [ ! -f ${ENV_FILE} ]; then
71 echo "Environment file not found"
72 exit 1
73fi
74
75echo "Using ${BACKUP_LOCATION} as backup/restore location."
76echo
77
78source ${SCRIPT_DIR}/../mailcow.conf
79
80if [[ -z ${COMPOSE_PROJECT_NAME} ]]; then
81 echo "Could not determine compose project name"
82 exit 1
83else
84 echo "Found project name ${COMPOSE_PROJECT_NAME}"
85 CMPS_PRJ=$(echo ${COMPOSE_PROJECT_NAME} | tr -cd "[0-9A-Za-z-_]")
86fi
87
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010088if grep --help 2>&1 | head -n 1 | grep -q -i "busybox"; then
89 >&2 echo -e "\e[31mBusyBox grep detected on local system, please install GNU grep\e[0m"
90 exit 1
91fi
92
93
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +010094function backup() {
95 DATE=$(date +"%Y-%m-%d-%H-%M-%S")
96 mkdir -p "${BACKUP_LOCATION}/mailcow-${DATE}"
97 chmod 755 "${BACKUP_LOCATION}/mailcow-${DATE}"
98 cp "${SCRIPT_DIR}/../mailcow.conf" "${BACKUP_LOCATION}/mailcow-${DATE}"
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010099 for bin in docker; do
100 if [[ -z $(which ${bin}) ]]; then
101 >&2 echo -e "\e[31mCannot find ${bin} in local PATH, exiting...\e[0m"
102 exit 1
103 fi
104 done
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100105 while (( "$#" )); do
106 case "$1" in
107 vmail|all)
108 docker run --name mailcow-backup --rm \
109 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200110 -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:ro,z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100111 ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_vmail.tar.gz /vmail
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100112 ;;&
113 crypt|all)
114 docker run --name mailcow-backup --rm \
115 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200116 -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:ro,z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100117 ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_crypt.tar.gz /crypt
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100118 ;;&
119 redis|all)
120 docker exec $(docker ps -qf name=redis-mailcow) redis-cli save
121 docker run --name mailcow-backup --rm \
122 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200123 -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:ro,z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100124 ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_redis.tar.gz /redis
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100125 ;;&
126 rspamd|all)
127 docker run --name mailcow-backup --rm \
128 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200129 -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:ro,z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100130 ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_rspamd.tar.gz /rspamd
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100131 ;;&
132 postfix|all)
133 docker run --name mailcow-backup --rm \
134 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200135 -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:ro,z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100136 ${DEBIAN_DOCKER_IMAGE} /bin/tar --warning='no-file-ignored' --use-compress-program="pigz --rsyncable -p ${THREADS}" -Pcvpf /backup/backup_postfix.tar.gz /postfix
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100137 ;;&
138 mysql|all)
139 SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE})
140 if [[ -z "${SQLIMAGE}" ]]; then
141 echo "Could not determine SQL image version, skipping backup..."
142 shift
143 continue
144 else
145 echo "Using SQL image ${SQLIMAGE}, starting..."
146 docker run --name mailcow-backup --rm \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200147 --network $(docker network ls -qf name=^${CMPS_PRJ}_mailcow-network$) \
148 -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:ro,z \
149 -t --entrypoint= \
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100150 --sysctl net.ipv6.conf.all.disable_ipv6=1 \
151 -v ${BACKUP_LOCATION}/mailcow-${DATE}:/backup:z \
152 ${SQLIMAGE} /bin/sh -c "mariabackup --host mysql --user root --password ${DBROOT} --backup --rsync --target-dir=/backup_mariadb ; \
153 mariabackup --prepare --target-dir=/backup_mariadb ; \
154 chown -R 999:999 /backup_mariadb ; \
155 /bin/tar --warning='no-file-ignored' --use-compress-program='gzip --rsyncable' -Pcvpf /backup/backup_mariadb.tar.gz /backup_mariadb ;"
156 fi
157 ;;&
158 --delete-days)
159 shift
160 if [[ "${1}" =~ ^[0-9]+$ ]]; then
161 find ${BACKUP_LOCATION}/mailcow-* -maxdepth 0 -mmin +$((${1}*60*24)) -exec rm -rvf {} \;
162 else
163 echo "Parameter of --delete-days is not a number."
164 fi
165 ;;
166 esac
167 shift
168 done
169}
170
171function restore() {
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100172 for bin in docker; do
173 if [[ -z $(which ${bin}) ]]; then
174 >&2 echo -e "\e[31mCannot find ${bin} in local PATH, exiting...\e[0m"
175 exit 1
176 fi
177 done
178
179 if [ "${DOCKER_COMPOSE_VERSION}" == "native" ]; then
180 COMPOSE_COMMAND="docker compose"
181
182 elif [ "${DOCKER_COMPOSE_VERSION}" == "standalone" ]; then
183 COMPOSE_COMMAND="docker-compose"
184
185 else
186 echo -e "\e[31mCan not read DOCKER_COMPOSE_VERSION variable from mailcow.conf! Is your mailcow up to date? Exiting...\e[0m"
187 exit 1
188 fi
189
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100190 echo
191 echo "Stopping watchdog-mailcow..."
192 docker stop $(docker ps -qf name=watchdog-mailcow)
193 echo
194 RESTORE_LOCATION="${1}"
195 shift
196 while (( "$#" )); do
197 case "$1" in
198 vmail)
199 docker stop $(docker ps -qf name=dovecot-mailcow)
200 docker run -it --name mailcow-backup --rm \
201 -v ${RESTORE_LOCATION}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200202 -v $(docker volume ls -qf name=^${CMPS_PRJ}_vmail-vol-1$):/vmail:z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100203 ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_vmail.tar.gz
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100204 docker start $(docker ps -aqf name=dovecot-mailcow)
205 echo
206 echo "In most cases it is not required to run a full resync, you can run the command printed below at any time after testing wether the restore process broke a mailbox:"
207 echo
208 echo "docker exec $(docker ps -qf name=dovecot-mailcow) doveadm force-resync -A '*'"
209 echo
210 read -p "Force a resync now? [y|N] " FORCE_RESYNC
211 if [[ ${FORCE_RESYNC,,} =~ ^(yes|y)$ ]]; then
212 docker exec $(docker ps -qf name=dovecot-mailcow) doveadm force-resync -A '*'
213 else
214 echo "OK, skipped."
215 fi
216 ;;
217 redis)
218 docker stop $(docker ps -qf name=redis-mailcow)
219 docker run -it --name mailcow-backup --rm \
220 -v ${RESTORE_LOCATION}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200221 -v $(docker volume ls -qf name=^${CMPS_PRJ}_redis-vol-1$):/redis:z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100222 ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_redis.tar.gz
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100223 docker start $(docker ps -aqf name=redis-mailcow)
224 ;;
225 crypt)
226 docker stop $(docker ps -qf name=dovecot-mailcow)
227 docker run -it --name mailcow-backup --rm \
228 -v ${RESTORE_LOCATION}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200229 -v $(docker volume ls -qf name=^${CMPS_PRJ}_crypt-vol-1$):/crypt:z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100230 ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_crypt.tar.gz
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100231 docker start $(docker ps -aqf name=dovecot-mailcow)
232 ;;
233 rspamd)
234 docker stop $(docker ps -qf name=rspamd-mailcow)
235 docker run -it --name mailcow-backup --rm \
236 -v ${RESTORE_LOCATION}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200237 -v $(docker volume ls -qf name=^${CMPS_PRJ}_rspamd-vol-1$):/rspamd:z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100238 ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_rspamd.tar.gz
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100239 docker start $(docker ps -aqf name=rspamd-mailcow)
240 ;;
241 postfix)
242 docker stop $(docker ps -qf name=postfix-mailcow)
243 docker run -it --name mailcow-backup --rm \
244 -v ${RESTORE_LOCATION}:/backup:z \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200245 -v $(docker volume ls -qf name=^${CMPS_PRJ}_postfix-vol-1$):/postfix:z \
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100246 ${DEBIAN_DOCKER_IMAGE} /bin/tar --use-compress-program="pigz -d -p ${THREADS}" -Pxvf /backup/backup_postfix.tar.gz
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100247 docker start $(docker ps -aqf name=postfix-mailcow)
248 ;;
249 mysql|mariadb)
250 SQLIMAGE=$(grep -iEo '(mysql|mariadb)\:.+' ${COMPOSE_FILE})
251 if [[ -z "${SQLIMAGE}" ]]; then
252 echo "Could not determine SQL image version, skipping restore..."
253 shift
254 continue
255 elif [ ! -f "${RESTORE_LOCATION}/mailcow.conf" ]; then
256 echo "Could not find the corresponding mailcow.conf in ${RESTORE_LOCATION}, skipping restore."
257 echo "If you lost that file, copy the last working mailcow.conf file to ${RESTORE_LOCATION} and restart the restore process."
258 shift
259 continue
260 else
261 read -p "mailcow will be stopped and the currently active mailcow.conf will be modified to use the DB parameters found in ${RESTORE_LOCATION}/mailcow.conf - do you want to proceed? [Y|n] " MYSQL_STOP_MAILCOW
262 if [[ ${MYSQL_STOP_MAILCOW,,} =~ ^(no|n|N)$ ]]; then
263 echo "OK, skipped."
264 shift
265 continue
266 else
267 echo "Stopping mailcow..."
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100268 ${COMPOSE_COMMAND} -f ${COMPOSE_FILE} --env-file ${ENV_FILE} down
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100269 fi
270 #docker stop $(docker ps -qf name=mysql-mailcow)
271 if [[ -d "${RESTORE_LOCATION}/mysql" ]]; then
272 docker run --name mailcow-backup --rm \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200273 -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:rw,z \
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100274 --entrypoint= \
275 -v ${RESTORE_LOCATION}/mysql:/backup:z \
276 ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; /bin/rm -rf /var/lib/mysql/* ; rsync -avh --usermap=root:mysql --groupmap=root:mysql /backup/ /var/lib/mysql/"
277 elif [[ -f "${RESTORE_LOCATION}/backup_mysql.gz" ]]; then
278 docker run \
279 -it --name mailcow-backup --rm \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200280 -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/var/lib/mysql/:z \
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100281 --entrypoint= \
282 -u mysql \
283 -v ${RESTORE_LOCATION}:/backup:z \
284 ${SQLIMAGE} /bin/sh -c "mysqld --skip-grant-tables & \
285 until mysqladmin ping; do sleep 3; done && \
286 echo Restoring... && \
287 gunzip < backup/backup_mysql.gz | mysql -uroot && \
288 mysql -uroot -e SHUTDOWN;"
289 elif [[ -f "${RESTORE_LOCATION}/backup_mariadb.tar.gz" ]]; then
290 docker run --name mailcow-backup --rm \
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +0200291 -v $(docker volume ls -qf name=^${CMPS_PRJ}_mysql-vol-1$):/backup_mariadb/:rw,z \
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100292 --entrypoint= \
293 -v ${RESTORE_LOCATION}:/backup:z \
294 ${SQLIMAGE} /bin/bash -c "shopt -s dotglob ; \
295 /bin/rm -rf /backup_mariadb/* ; \
296 /bin/tar -Pxvzf /backup/backup_mariadb.tar.gz"
297 fi
298 echo "Modifying mailcow.conf..."
299 source ${RESTORE_LOCATION}/mailcow.conf
300 sed -i --follow-symlinks "/DBNAME/c\DBNAME=${DBNAME}" ${SCRIPT_DIR}/../mailcow.conf
301 sed -i --follow-symlinks "/DBUSER/c\DBUSER=${DBUSER}" ${SCRIPT_DIR}/../mailcow.conf
302 sed -i --follow-symlinks "/DBPASS/c\DBPASS=${DBPASS}" ${SCRIPT_DIR}/../mailcow.conf
303 sed -i --follow-symlinks "/DBROOT/c\DBROOT=${DBROOT}" ${SCRIPT_DIR}/../mailcow.conf
304 source ${SCRIPT_DIR}/../mailcow.conf
305 echo "Starting mailcow..."
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +0100306 ${COMPOSE_COMMAND} -f ${COMPOSE_FILE} --env-file ${ENV_FILE} up -d
Matthias Andreas Benkardb382b102021-01-02 15:32:21 +0100307 #docker start $(docker ps -aqf name=mysql-mailcow)
308 fi
309 ;;
310 esac
311 shift
312 done
313 echo
314 echo "Starting watchdog-mailcow..."
315 docker start $(docker ps -aqf name=watchdog-mailcow)
316}
317
318if [[ ${1} == "backup" ]]; then
319 backup ${@,,}
320elif [[ ${1} == "restore" ]]; then
321 i=1
322 declare -A FOLDER_SELECTION
323 if [[ $(find ${BACKUP_LOCATION}/mailcow-* -maxdepth 1 -type d 2> /dev/null| wc -l) -lt 1 ]]; then
324 echo "Selected backup location has no subfolders"
325 exit 1
326 fi
327 for folder in $(ls -d ${BACKUP_LOCATION}/mailcow-*/); do
328 echo "[ ${i} ] - ${folder}"
329 FOLDER_SELECTION[${i}]="${folder}"
330 ((i++))
331 done
332 echo
333 input_sel=0
334 while [[ ${input_sel} -lt 1 || ${input_sel} -gt ${i} ]]; do
335 read -p "Select a restore point: " input_sel
336 done
337 i=1
338 echo
339 declare -A FILE_SELECTION
340 RESTORE_POINT="${FOLDER_SELECTION[${input_sel}]}"
341 if [[ -z $(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) -regex ".*\(redis\|rspamd\|mariadb\|mysql\|crypt\|vmail\|postfix\).*") ]]; then
342 echo "No datasets found"
343 exit 1
344 fi
345
346 echo "[ 0 ] - all"
347 # find all files in folder with *.gz extension, print their base names, remove backup_, remove .tar (if present), remove .gz
348 FILE_SELECTION[0]=$(find "${FOLDER_SELECTION[${input_sel}]}" -maxdepth 1 \( -type d -o -type f \) \( -name '*.gz' -o -name 'mysql' \) -printf '%f\n' | sed 's/backup_*//' | sed 's/\.[^.]*$//' | sed 's/\.[^.]*$//')
349 for file in $(ls -f "${FOLDER_SELECTION[${input_sel}]}"); do
350 if [[ ${file} =~ vmail ]]; then
351 echo "[ ${i} ] - Mail directory (/var/vmail)"
352 FILE_SELECTION[${i}]="vmail"
353 ((i++))
354 elif [[ ${file} =~ crypt ]]; then
355 echo "[ ${i} ] - Crypt data"
356 FILE_SELECTION[${i}]="crypt"
357 ((i++))
358 elif [[ ${file} =~ redis ]]; then
359 echo "[ ${i} ] - Redis DB"
360 FILE_SELECTION[${i}]="redis"
361 ((i++))
362 elif [[ ${file} =~ rspamd ]]; then
363 echo "[ ${i} ] - Rspamd data"
364 FILE_SELECTION[${i}]="rspamd"
365 ((i++))
366 elif [[ ${file} =~ postfix ]]; then
367 echo "[ ${i} ] - Postfix data"
368 FILE_SELECTION[${i}]="postfix"
369 ((i++))
370 elif [[ ${file} =~ mysql ]] || [[ ${file} =~ mariadb ]]; then
371 echo "[ ${i} ] - SQL DB"
372 FILE_SELECTION[${i}]="mysql"
373 ((i++))
374 fi
375 done
376 echo
377 input_sel=-1
378 while [[ ${input_sel} -lt 0 || ${input_sel} -gt ${i} ]]; do
379 read -p "Select a dataset to restore: " input_sel
380 done
381 echo "Restoring ${FILE_SELECTION[${input_sel}]} from ${RESTORE_POINT}..."
382 restore "${RESTORE_POINT}" ${FILE_SELECTION[${input_sel}]}
383fi