15 Commits
Author SHA1 Message Date
Hartmut Bauer bf8c226bbe prevent ssh errors 2025-05-11 17:38:29 +02:00
Hartmut Bauer 5696e01322 fix remote backup 2025-05-11 15:19:04 +02:00
Hartmut Bauer f96447d0e7 split daily/cron daily 2025-05-11 15:14:48 +02:00
Hartmut Bauer 8eccb0ed59 sort tar archive 2025-05-11 14:56:45 +02:00
Hartmut Bauer 6efd48d3c6 fix log overwrite 2025-05-11 13:48:47 +02:00
Hartmut Bauer 16c8f1afce fix rc handling 2025-05-11 13:48:06 +02:00
Hartmut Bauer 21be8f3864 fix mail.sh, log results of auto update 2025-05-10 14:42:05 +02:00
Hartmut Bauer e7b9cc4e15 all docker references cleared, fixes 2025-05-09 18:57:23 +02:00
Hartmut Bauer 27e0889bd1 mail.sh an neuen Container angepasst 2025-05-08 16:59:25 +02:00
Hartmut Bauer 912d4b9434 Fix DB-Dump 2025-05-05 13:07:14 +02:00
Hartmut Bauer a8a00a9f46 Weitere podman-Anpassungen, DB-Dump geändert 2025-05-05 02:09:02 +02:00
Hartmut Bauer 15f77b6bf5 1st step to podman 2025-04-29 22:56:18 +02:00
Hartmut Bauer 42af16928f weekly SA->SO 2025-04-29 15:28:51 +02:00
Hartmut Bauer 39bdfbd021 bugfix 2025-04-15 22:49:29 +02:00
Hartmut Bauer 0cb2748447 exclude lists from export 2025-04-15 12:15:42 +02:00
7 changed files with 225 additions and 79 deletions

No files matched your search

Executable
+41
View File
@@ -0,0 +1,41 @@
#!/bin/bash
#
# check if container services are running
UNITS="/var/containers/systemd"
FAILED=""
check_service() {
local service=$1
systemctl is-active --user --machine=container@ $service >/dev/null
if [ $? -ne 0 ]; then
FAILED="$FAILED $service"
fi
}
check() {
local type=$1
for i in $UNITS/$type/*.socket; do
check_service $(basename $i)
done
for i in $UNITS/$type/*.container; do
check_service $(basename $i .container).service
done
}
check user
check system
if [ -z "$FAILED" ]; then
echo "OK All services are running"
exit 0
else
echo "#" >&2
echo "# ERROR some services are not running:" >&2
echo "#" >&2
echo "# $FAILED" >&2
echo "#" >&2
exit 1
fi
+1 -1
View File
@@ -3,4 +3,4 @@
HERE=$(dirname "$0") HERE=$(dirname "$0")
# local start # local start
sudo sh -c "nohup $HERE/main.sh -d </dev/null &" sudo sh -c "nohup $HERE/main.sh --dx </dev/null &"
+14 -11
View File
@@ -1,30 +1,33 @@
#!/usr/bin/eval bash #!/usr/bin/eval bash
BACKUP_TARGET=/var/docker/tmp USER_CONTAINERS=
ROOT_CONTAINERS="pihole"
BACKUP_TARGET=/var/containers/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY" NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
backup_daily1() { backup_daily1() {
BACKUP_SOURCE="/var" BACKUP_SOURCE="/var"
BACKUP_EXCLUDE_DIRS=(docker) BACKUP_EXCLUDE_DIRS=(containers)
} }
backup_daily2() { backup_daily2() {
BACKUP_SOURCE="/var/docker" BACKUP_SOURCE="/var/containers"
BACKUP_EXCLUDE_DIRS=(tmp) BACKUP_EXCLUDE_DIRS=(tmp)
} }
before_backup() { before_backup() {
stop_docker stop_containers
return $? return $?
} }
after_backup() { after_backup() {
start_docker let local rc=0
local dock=$? start_containers
let rc=rc+$?
copy_to_nas "$BACKUP_TARGET" "$NAS_TARGET" copy_to_nas "$BACKUP_TARGET" "$NAS_TARGET"
local copy=$? let rc=rc+$?
if [ $dock -eq 0 ] && [ $copy -eq 0 ]; then #check_services
return 0 #let rc=rc+$?
fi return $rc
return 1
} }
+15 -6
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Mail via GMX-Relay versenden (Docker-Image "hb42/smtp") # Mail via GMX-Relay versenden (Podman-Image "smtp-relay")
# #
# Klappt nur direkt im Container, daher ggf. via ssh aufrufen (Annahme: remote user == local user) # Klappt nur direkt im Container, daher ggf. via ssh aufrufen (Annahme: remote user == local user)
# #
@@ -12,10 +12,15 @@
# > mail.sh hb242@pm.me "log whatever" ../log/some.log # > mail.sh hb242@pm.me "log whatever" ../log/some.log
# #
DOCKER=/usr/bin/docker PODMAN=/usr/bin/podman
MAILCONTAINER=smtp #
# -i ist entscheident, damit die restliche Kommandozeile sauber ausgewertet wird
# das ersetzt den expliziten Aufruf mit "sh -c "..." "
SUDO="sudo -u container -i"
MAILCONTAINER=smtp-relay
MAILSERVER_IP=10.4.2.30 MAILSERVER_IP=10.4.2.30
SSH="" REMOTE=""
which ip >/dev/null 2>&1 which ip >/dev/null 2>&1
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
@@ -27,7 +32,7 @@ else
fi fi
if [ "$myip" != "$MAILSERVER_IP" ]; then if [ "$myip" != "$MAILSERVER_IP" ]; then
SSH="ssh $MAILSERVER_IP" REMOTE=yes
fi fi
TO=$1 TO=$1
@@ -44,8 +49,12 @@ fi
# Mail body aus Datei oder STDIN holen # Mail body aus Datei oder STDIN holen
CONTENT=$(cat ${1:--}) CONTENT=$(cat ${1:--})
MAILCMD="$SUDO $PODMAN exec -i $MAILCONTAINER /usr/sbin/sendmail -i -t"
if [ ! -z "$REMOTE" ]; then
MAILCMD="ssh $MAILSERVER_IP $MAILCMD"
fi
# construct mail header + content and pipe to sendmail # construct mail header + content and pipe to sendmail
cat <<EOMB | $SSH $DOCKER exec -i $MAILCONTAINER /usr/sbin/sendmail -i -t cat <<EOMB | $MAILCMD
FROM: hb42@gmx.de FROM: hb42@gmx.de
TO: ${TO} TO: ${TO}
DATE: $(date -R) DATE: $(date -R)
+107 -42
View File
@@ -1,5 +1,6 @@
HOST_NAME=$(hostname -s) HOST_NAME=$(hostname -s)
DAY=$(date +%u) # MO == 1 DAY=$(date +%u) # 1-7, MO is 1
WEEKLY_DAY=7 # SA->SO
NAS_MOUNT_POINT="$(realpath $HERE/../../..)" # Server/bin/backup NAS_MOUNT_POINT="$(realpath $HERE/../../..)" # Server/bin/backup
NAS_ROOT="$NAS_MOUNT_POINT/backups" NAS_ROOT="$NAS_MOUNT_POINT/backups"
@@ -11,20 +12,24 @@ LOG_KEEP_DAYS=14
RESTORE_PATH="$NAS_MOUNT_POINT/Server/restore" RESTORE_PATH="$NAS_MOUNT_POINT/Server/restore"
BACKUP_MASTER_CHECK="/var/docker/vol/proxy" BACKUP_MASTER_CHECK="/var/containers/vol/caddy"
NAS_HOSTNAME=synology NAS_HOSTNAME=synology
NAS_IP=10.4.2.20 NAS_IP=10.4.2.20
NAS_SCRIPT=/volume1/nfs/Server/bin/backup/main.sh NAS_SCRIPT=/volume1/nfs/Server/bin/backup/main.sh
WEEKLY_DAY=1 # SO->MO
PASSPHRASE=L1rfCXu8PHMQsGL0HJWwzQYpCT7f5VboislOTHMaEV PASSPHRASE=L1rfCXu8PHMQsGL0HJWwzQYpCT7f5VboislOTHMaEV
EXT=tgz.gpg EXT=tgz.gpg
LIST_EXT=txt LIST_EXT=list
DOCKER="/usr/bin/docker compose -f /var/docker/run/docker-compose.yml --ansi never" #DOCKER="/usr/bin/docker compose -f /var/docker/run/docker-compose.yml --ansi never"
SYNO_USB=/usr/syno/bin/synousbdisk SYNO_USB=/usr/syno/bin/synousbdisk
SYSTEMCTL_USER="/usr/bin/systemctl --user --machine=container@"
SYSTEMCTL="/usr/bin/systemctl"
PODMAN=" sudo -u container -i podman"
CONTAINER_EXEC_USER=" $PODMAN exec"
CONTAINER_SVC_UPDATE_USER=" $PODMAN auto-update"
CONTAINER_EXEC="podman exec"
LOG_RECIPIENT=hb242@pm.me LOG_RECIPIENT=hb242@pm.me
INFO=INFO INFO=INFO
@@ -95,32 +100,36 @@ prune_logs() {
# ----- db dump ----- # ----- db dump -----
dump_mariadb() { #dump_mariadb() {
log $DEBUG "$DBG dump_mariadb( $@ )" # return 0
local dump_dir=$1 # log $DEBUG "$DBG dump_mariadb( $@ )"
local mysqlconnect="--user=root --password=snafu" # local dump_dir=$1
# local mysqlconnect="--user=root --password=snafu"
log $DEBUG "$DBG > \$DOCKER exec mysql /usr/bin/mariadb --silent --user=xxx --password=xxx -e \"show databases\" -B" #
for db in $($DOCKER exec mysql /usr/bin/mariadb --silent $mysqlconnect -e "show databases" -B 2>>$LOG_FILE | grep -v information_schema 2>>$LOG_FILE | grep -v performance_schema 2>>$LOG_FILE | sed -e 's/\r//' 2>>$LOG_FILE); do # log $DEBUG "$DBG > \$DOCKER exec mysql /usr/bin/mariadb --silent --user=xxx --password=xxx -e \"show databases\" -B"
log $DEBUG "$DBG > \$DOCKER exec mysql /usr/bin/mariadb-dump --hex-blob --user=xxx --password=xxx --databases $db" # for db in $($DOCKER exec mysql /usr/bin/mariadb --silent $mysqlconnect -e "show databases" -B 2>>$LOG_FILE | grep -v information_schema 2>>$LOG_FILE | grep -v performance_schema 2>>$LOG_FILE | sed -e 's/\r//' 2>>$LOG_FILE); do
$DOCKER exec mysql /usr/bin/mariadb-dump --hex-blob $mysqlconnect --databases $db >$dump_dir/$db.sql 2>>$LOG_FILE # log $DEBUG "$DBG > \$DOCKER exec mysql /usr/bin/mariadb-dump --hex-blob --user=xxx --password=xxx --databases $db"
is_error $? false && return 1 # $DOCKER exec mysql /usr/bin/mariadb-dump --hex-blob $mysqlconnect --databases $db >$dump_dir/$db.sql 2>>$LOG_FILE
done # is_error $? false && return 1
return 0 # done
} # return 0
#}
dump_postgresql() { dump_postgresql() {
local pg_container=$1
local dump_dir=$2
log $DEBUG "$DBG dump_postgresql( $@ )" log $DEBUG "$DBG dump_postgresql( $@ )"
local dump_dir=$1 delete_dir $dump_dir
check_directory $dump_dir
# users and roles # users and roles
log $DEBUG "$DBG > \$DOCKER exec -u=postgres postgres pg_dumpall --globals-only" log $DEBUG "$DBG > \$CONTAINER_EXEC_USER -u=postgres $pg_container pg_dumpall --globals-only"
$DOCKER exec -u=postgres postgres pg_dumpall --globals-only > $dump_dir/_globals.sql 2>>$LOG_FILE $CONTAINER_EXEC_USER -u=postgres $pg_container pg_dumpall --globals-only > $dump_dir/_globals.sql 2>>$LOG_FILE
log $DEBUG "$DBG \$DOCKER exec -u=postgres postgres psql -t -c \"select datname from pg_database where not datistemplate\"" log $DEBUG "$DBG \$CONTAINER_EXEC_USER -u=postgres $pg_container psql -t -c \"select datname from pg_database where not datistemplate\""
for db in $($DOCKER exec -u=postgres postgres psql -t -c "select datname from pg_database where not datistemplate" 2>>$LOG_FILE); do for db in $($CONTAINER_EXEC_USER -u=postgres $pg_container psql -t -c "select datname from pg_database where not datistemplate" 2>>$LOG_FILE); do
log $DEBUG "$DBG > \$DOCKER exec -u=postgres postgres pg_dump --create $db" log $DEBUG "$DBG > \$CONTAINER_EXEC_USER -u=postgres $pg_container pg_dump --create $db"
$DOCKER exec -u=postgres postgres pg_dump --create $db > $dump_dir/$db.sql 2>>$LOG_FILE $CONTAINER_EXEC_USER -u=postgres $pg_container pg_dump --create $db > $dump_dir/$db.sql 2>>$LOG_FILE
is_error $? false && return 1 is_error $? false && return 1
done done
return 0 return 0
@@ -141,17 +150,69 @@ check_root() {
fi fi
} }
start_docker() { start_containers() {
log $DEBUG "$DBG start_docker()" local let rc=0
log $DEBUG "$DBG > \$DOCKER up -d" log $DEBUG "$DBG start_containers()"
$DOCKER up -d >>$LOG_FILE 2>&1 # if [ -f /var/docker/run/docker-compose.yml ]; then
return $? # log $DEBUG "$DBG > \$DOCKER up -d"
# $DOCKER up -d >>$LOG_FILE 2>&1
# let rc=rc+$?
# fi
if [ -d /var/containers ]; then
do_start_stop_containers start
let rc=rc+$?
fi
return $rc
} }
stop_docker() { stop_containers() {
log $DEBUG "$DBG stop_docker()" local let rc=0
log $DEBUG "$DBG > \$DOCKER down" log $DEBUG "$DBG stop_containers()"
$DOCKER down >>$LOG_FILE 2>&1 # if [ -f /var/docker/run/docker-compose.yml ]; then
# log $DEBUG "$DBG > \$DOCKER down"
# $DOCKER down >>$LOG_FILE 2>&1
# let rc=rc+$?
# fi
if [ -d /var/containers ]; then
do_start_stop_containers stop
let rc=rc+$?
fi
return $rc
}
do_start_stop_containers() {
local cmd=$1
local let rc=0
log $DEBUG "$DBG do_start_stop_containers() $cmd"
if [ ! -z "$ROOT_CONTAINERS" ]; then
log $DEBUG "$DBG > $SYSTEMCTL $cmd $ROOT_CONTAINERS"
$SYSTEMCTL $cmd $ROOT_CONTAINERS >>$LOG_FILE 2>&1
let rc=rc+$?
fi
if [ ! -z "$USER_CONTAINERS" ]; then
log $DEBUG "$DBG > $SYSTEMCTL_USER $cmd $USER_CONTAINERS"
$SYSTEMCTL_USER $cmd $USER_CONTAINERS >>$LOG_FILE 2>&1
let rc=rc+$?
fi
return $rc
}
update_services() {
log $DEBUG "$DBG update_services()"
mail_log $INFO "$INF update services"
local upd=$($CONTAINER_SVC_UPDATE_USER 2>&1 | tee -a $LOG_FILE | egrep 'registry\s+true' | sed 's/^.* \([^[:space:]]*\/[^[:space:]]*\).*$/\1/g')
check_pipe_rc ${PIPESTATUS[@]}
local rc=$?
for i in $upd; do
mail_log $INFO "$INF $i"
done
return $rc
}
check_services() {
log $DEBUG "$DBG check_services()"
mail_log $INFO "$INF check services"
$HERE/check.sh >>$LOG_FILE 2>&1
return $? return $?
} }
@@ -374,8 +435,8 @@ backup_dir() {
local root=$1 local root=$1
local archive=$2 local archive=$2
local dir=$3 local dir=$3
log $DEBUG "$DBG > tar -c -z --numeric-owner --one-file-system --exclude \"@eaDir\" -C \"$root\" \"$dir\" | gpg --batch -c --passphrase xxxx -o \"$archive\"" log $DEBUG "$DBG > tar -c -z --numeric-owner --one-file-system --sort=name --exclude \"@eaDir\" -C \"$root\" \"$dir\" | gpg --batch -c --passphrase xxxx -o \"$archive\""
tar -c -z --numeric-owner --one-file-system --exclude "@eaDir" -C "$root" "$dir" 2>>$LOG_FILE | gpg --batch -c --passphrase $PASSPHRASE -o "$archive" 2>>$LOG_FILE tar -c -z --numeric-owner --one-file-system --sort=name --exclude "@eaDir" -C "$root" "$dir" 2>>$LOG_FILE | gpg --batch -c --passphrase $PASSPHRASE -o "$archive" 2>>$LOG_FILE
check_pipe_rc ${PIPESTATUS[@]} check_pipe_rc ${PIPESTATUS[@]}
return $? return $?
} }
@@ -434,11 +495,11 @@ set_log_info() {
mail_log $INFO ">>> " mail_log $INFO ">>> "
} }
backup_daily() { cron_backup_daily() {
# "master"-Server startet Backup auf NAS # "master"-Server startet Backup auf NAS
if [ -d $BACKUP_MASTER_CHECK ]; then if [ -d $BACKUP_MASTER_CHECK ]; then
log $DEBUG "$DBG starting daily backup on $NAS_HOSTNAME" log $DEBUG "$DBG starting daily backup on $NAS_HOSTNAME"
run_script_remote $NAS_IP "$NAS_SCRIPT -d" run_script_remote $NAS_IP "$NAS_SCRIPT --dx"
# alte Logs löschen (nur auf einem Server ausführen) # alte Logs löschen (nur auf einem Server ausführen)
prune_logs prune_logs
@@ -451,6 +512,10 @@ backup_daily() {
nohup $THIS_SCRIPT -w >>$LOG_FILE 2>&1 </dev/null & nohup $THIS_SCRIPT -w >>$LOG_FILE 2>&1 </dev/null &
fi fi
backup_daily
}
backup_daily() {
mail_log $INFO ">>>>>>>>>> daily auto backup $VER for $HOST_NAME <<<<<<<<<<" mail_log $INFO ">>>>>>>>>> daily auto backup $VER for $HOST_NAME <<<<<<<<<<"
do_auto_backup backup_daily do_auto_backup backup_daily
@@ -581,7 +646,7 @@ list_archives() {
local target=$1 local target=$1
local targ=${NAS_ROOT//\//\\\/} # slashes escapen local targ=${NAS_ROOT//\//\\\/} # slashes escapen
log $DEBUG "$DBG > find \"$NAS_ROOT\" -type f -name \"*.$EXT\" | sed -E \"s/^$targ//\"" log $DEBUG "$DBG > find \"$NAS_ROOT\" -type f -name \"*.$EXT\" | sed -E \"s/^$targ//\""
find "$NAS_ROOT" -type f -name "*.$EXT" 2>>$LOG_FILE | sed -E "s/^$targ//" 2>>$LOG_FILE find "$NAS_ROOT" -type f -name "*.$EXT" 2>>$LOG_FILE | sed -E "s/^$targ//" 2>>$LOG_FILE | sort
check_pipe_rc ${PIPESTATUS[@]} check_pipe_rc ${PIPESTATUS[@]}
return $? return $?
} }
@@ -855,8 +920,8 @@ do_export() {
mail_log $INFO ">>> " mail_log $INFO ">>> "
mail_log $INFO "$INF exporting $source_path -> $mount_point" mail_log $INFO "$INF exporting $source_path -> $mount_point"
log $DEBUG "$DBG rsync -rti --one-file-system --delete --stats --exclude=@eaDir $source_path $mount_point" log $DEBUG "$DBG rsync -rti --one-file-system --delete --stats --exclude=@eaDir --exclude='*'.$LIST_EXT $source_path $mount_point"
rsync -rti --one-file-system --delete --stats --exclude=@eaDir $source_path $mount_point >>$LOG_FILE 2>&1 rsync -rti --one-file-system --delete --stats --exclude=@eaDir --exclude='*'.$LIST_EXT $source_path $mount_point >>$LOG_FILE 2>&1
is_error $? is_error $?
mail_log $INFO "$INF unmounting USB device $device." mail_log $INFO "$INF unmounting USB device $device."
+20 -1
View File
@@ -3,7 +3,20 @@
# entrypoint for all actions # entrypoint for all actions
# #
VER="2.1.4" # 2.1.17 11.05.2025 - bugfixes, sort tar archive, split daily/cron daily
# 2.1.16 10.05.2025 - fix mail.sh, log results of auto-update
# 2.1.15 09.05.2025 - podman auto-update
# 2.1.14 09.05.2025 - Fix mail.sh, homeserver.target, cleared all docker references
# 2.1.13 08.05.2025 - check if services are running after backup
# 2.1.12 08.05.2025 - mail.sh an neuen Container angepasst
# 2.1.11 05.05.2025 - Fix DB-Dump
# 2.1.10 05.05.2025 - Postgres-Dump auf podman umgestellt
# 2.1.9 02.05.2025 - DB-Dump erweitert, damit Dumps für mehrere postgres möglich sind
# 2.1.8 30.04.2025 - systemctl start/stop eingebaut
# 2.1.7 29.04.2025 - 1. Schritt zur Umstellung auf podman
# 2.1.6 29.04.2025 - weekly backup Sa->SO
VER="2.1.17"
HERE=$(dirname "$0") HERE=$(dirname "$0")
THIS_SCRIPT=$0 THIS_SCRIPT=$0
@@ -57,6 +70,12 @@ while :; do
show_help # Display a usage synopsis. show_help # Display a usage synopsis.
exit 0 exit 0
;; ;;
--dx)
MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root
cron_backup_daily
break
;;
-d|--daily) -d|--daily)
MAIL_LOG_FILE="${log_file_name}.auto.log" MAIL_LOG_FILE="${log_file_name}.auto.log"
check_root check_root
+27 -18
View File
@@ -1,44 +1,53 @@
#!/usr/bin/env bash #!/usr/bin/env bash
DOCKER_ROOT=/var/docker USER_CONTAINERS="homeserver.target"
BACKUP_TARGET=$DOCKER_ROOT/tmp ROOT_CONTAINERS=
#DOCKER_ROOT=/var/docker
CONTAINERS_ROOT=/var/containers
BACKUP_TARGET=$CONTAINERS_ROOT/tmp
NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY" NAS_TARGET="$NAS_ROOT/daily/$HOST_NAME/backup.$DAY"
backup_daily1() { backup_daily1() {
BACKUP_SOURCE="/var" BACKUP_SOURCE="/var"
BACKUP_EXCLUDE_DIRS=(docker) BACKUP_EXCLUDE_DIRS=(containers)
} }
backup_daily2() { backup_daily2() {
BACKUP_SOURCE="/var/docker" BACKUP_SOURCE="/var/containers"
BACKUP_EXCLUDE_DIRS=(vol tmp) BACKUP_EXCLUDE_DIRS=(vol tmp)
} }
backup_daily3() { backup_daily3() {
BACKUP_SOURCE="/var/docker/vol" BACKUP_SOURCE="/var/containers/vol"
BACKUP_EXCLUDE_DIRS=() BACKUP_EXCLUDE_DIRS=()
} }
before_backup() { before_backup() {
dump_mariadb $DOCKER_ROOT/dump/mysql let local rc=0
local mys=$? #dump_mariadb $DOCKER_ROOT/dump/mysql
dump_postgresql $DOCKER_ROOT/dump/postgresql #let rc=rc+$?
local pos=$? dump_postgresql ncd_pg $CONTAINERS_ROOT/dump/nextcloud
if [ $mys -gt 0 ] || [ $pos -gt 0 ]; then let rc=rc+$?
dump_postgresql gitea_pg $CONTAINERS_ROOT/dump/gitea
let rc=rc+$?
if [ $rc -gt 0 ]; then
return 1 return 1
fi fi
stop_docker stop_containers
return $? return $?
} }
after_backup() { after_backup() {
start_docker let local rc=0
local dock=$? start_containers
let rc=rc+$?
copy_to_nas "$BACKUP_TARGET" "$NAS_TARGET" copy_to_nas "$BACKUP_TARGET" "$NAS_TARGET"
local copy=$? let rc=rc+$?
if [ $dock -eq 0 ] && [ $copy -eq 0 ]; then update_services
return 0 let rc=rc+$?
fi check_services
return 1 let rc=rc+$?
return $rc
} }