#!/usr/bin/env bash
VERSION=0.9.3
#
# NAME
#     zabbix-dump - Configuration Backup for Zabbix' MySQL or PostgreSQL data
#
# SYNOPSIS
#     This is a MySQL configuration backup script for Zabbix 1.x, 2.x, 3.x and 4.x.
#     It does a full backup of all configuration tables, but only a schema
#     backup of large data tables.
#
#     The script is based on a script by Ricardo Santos
#     (http://zabbixzone.com/zabbix/backuping-only-the-zabbix-configuration/)
#
# CONTRIBUTORS
#      - Ricardo Santos
#      - Jens Berthold (maxhq)
#      - Oleksiy Zagorskyi (zalex)
#      - Petr Jendrejovsky
#      - Jonathan Bayer
#      - Andreas Niedermann (dre-)
#      - Mișu Moldovan (dumol)
#      - Daniel Schneller (dschneller)
#      - Ruslan Ohitin (ruslan-ohitin)
#      - Jonathan Wright (neonardo1)
#      - msjmeyer
#      - Sergey Galkin (sergeygalkin)
#      - Greg Cockburn (gergnz)
#      - yangqi
#      - Johannes Petz (PetzJohannes)
#      - Wesley Schaft (wschaft)
#      - Tiago Cruz (tiago-cruz-movile)
#      - Mario Trangoni (mjtrangoni)
#      - ironbishop
#
# AUTHOR
#     Jens Berthold (maxhq), 2020
#
# LICENSE
#     This script is released under the MIT License (see LICENSE.txt)


#
# DEFAULT VALUES
#
# DO NOT EDIT THESE VALUES!
# Instead, use command line parameters or a config file to specify options.
#
DUMPDIR="$PWD"
DBTYPE="mysql"
DEFAULT_DBHOST="127.0.0.1"
DEFAULT_DBSCHEMA="public"
DEFAULT_DBNAME="zabbix"
DEFAULT_DBUSER="zabbix"
DEFAULT_DBPASS=""
COMPRESSION="gz"
QUIET="no"
REVERSELOOKUP="yes"
GENERATIONSTOKEEP=0
ZBX_CONFIG="/etc/zabbix/zabbix_server.conf"
READ_ZBX_CONFIG="yes"
HANDLE_UNKNOWN="fail"

#
# Show version
#
show_version() {
    echo "zabbix-dump version $VERSION"
    exit
}

if [[ "$1" == "--version" ]]; then show_version; fi

#
# Show help
#
if [[ "$1" == "--help" || "$1" == "-h" ]]; then
    cat <<EOF
USAGE
    $(basename "${BASH_SOURCE[*]}") [options]

OPTIONS
    -t DATABASE_TYPE
        Database type (mysql or psql).
        Default: $DBTYPE

    -H DBHOST
        Hostname/IP of database server (DBMS).
        Default: $DEFAULT_DBHOST

    -P DBPORT
        DBMS port.
        Default for mysql: 3306
        Default for psql:  5432

    -s DBSOCKET
        Path to DBMS socket file.
        Can be used as an alternative to specifying host (and maybe port).

    -S SCHEMA
        Name of database schema (PostgreSQL only).
        Default: $DEFAULT_DBSCHEMA

    -d DATABASE
        Name of Zabbix database.
        Default: $DEFAULT_DBNAME

    -u DBUSER
        DBMS user to access Zabbix database.
        Default: $DEFAULT_DBUSER

    -p DBPASSWORD
        DBMS user password (specify "-" for a prompt).
        Default: no password

    -o DIR
        Save Zabbix database dumps to DIR.
        Default: $DUMPDIR

    -z ZABBIX_CONFIG
        Read database host and credentials from given Zabbix config file.
        Default: $ZBX_CONFIG

    -Z
        Do not try to read the Zabbix server configuration.

    -c MYSQL_CONFIG
        MySQL only:
        Read database host and credentials from given MySQL config file.
        PLEASE NOTE:
        The first "database" option found in the config file is used for
        mysqldump (it needs the database to be specified via command line).

    -r NUM
        Rotate backups while keeping up to NUM generations.
        Uses filename to match.
        Default: keep all backups

    -x
        Compress using XZ instead of GZip.
        PLEASE NOTE:
        XZ compression will take much longer and consume more CPU time
        but the resulting backup will be about half the size of the same
        sql dump compressed using GZip. Your mileage may vary.

    -0
        Do not compress the sql dump

    -n
        Skip reverse lookup of IP address for host.

    -f
        Force backup for unknown tables / forward compatibility:
        Don't complain about unknown tables and make a full backup of them

    -i
        Ingore unknown tables (don't include them into the backup)

    -q
        Quiet mode: no output except for errors (for batch/crontab use).

    -h
    --help
        Show this help.

EXAMPLES
    # read $ZBX_CONFIG to backup local Zabbix server's
    # MySQL database into current directory
    $(basename "${BASH_SOURCE[*]}")

    # ...same for PostgreSQL
    $(basename "${BASH_SOURCE[*]}") -t psql

    # DO NOT read $ZBX_CONFIG,
    # use instead to backup local MySQL database and ask for password
    $(basename "${BASH_SOURCE[*]}") -Z -p -

    # read DB options from given Zabbix config file
    $(basename "${BASH_SOURCE[*]}") -z /opt/etc/zabbix_server.conf

    # specify MySQL database and user, ask for password
    $(basename "${BASH_SOURCE[*]}") -Z -d zabbixdb -u zabbix -p - -o /tmp

    # read DB options from MySQL config file
    $(basename "${BASH_SOURCE[*]}") -c /etc/mysql/mysql.cnf
    # ...and overwrite database name
    $(basename "${BASH_SOURCE[*]}") -c /etc/mysql/mysql.cnf -d zabbixdb

EOF
    exit 1
fi

#
# PARSE COMMAND LINE ARGUMENTS
#
DB_GIVEN=0
while getopts ":c:S:d:H:o:p:P:r:s:t:u:z:0nqxZfiv" opt; do
    case $opt in
        t)  DBTYPE="$OPTARG" ;;
        H)  ODBHOST="$OPTARG" ;;
        s)  ODBSOCKET="$OPTARG" ;;
        S)  ODBSCHEMA="$OPTARG" ;;
        d)  ODBNAME="$OPTARG"; DB_GIVEN=1 ;;
        u)  ODBUSER="$OPTARG" ;;
        P)  ODBPORT="$OPTARG" ;;
        p)  ODBPASS="$OPTARG" ;;
        c)  MYSQL_CONFIG="$OPTARG" ;;
        o)  DUMPDIR="$OPTARG" ;;
        z)  ZBX_CONFIG="$OPTARG" ;;
        Z)  READ_ZBX_CONFIG="no" ;;
        r)  GENERATIONSTOKEEP=$(printf '%.0f' "$OPTARG") ;;
        x)  COMPRESSION="xz" ;;
        0)  COMPRESSION="" ;;
        n)  REVERSELOOKUP="no" ;;
        f)  HANDLE_UNKNOWN="backup" ;;
        i)  HANDLE_UNKNOWN="ignore" ;;
        q)  QUIET="yes" ;;
        v)  show_version ;;
        \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
        :)  echo "Option -$OPTARG requires an argument" >&2; exit 1 ;;
    esac
done

[ -n "$MYSQL_CONFIG" ] && READ_ZBX_CONFIG="no"

# (Try) reading database config from zabbix_server.conf
if [[ "${READ_ZBX_CONFIG}" == "yes" && -f "${ZBX_CONFIG}" && -r "${ZBX_CONFIG}" ]]; then
    [ "$QUIET" == "no" ] && echo "Reading database options from ${ZBX_CONFIG}..."

    # Reading config with awk (instead of source'ing the file) to avoid shell special characters execution
    DBHOST="$(/usr/bin/awk -F'=' '/^DBHost/{ print $2 }' "${ZBX_CONFIG}")"
    DBPORT="$(/usr/bin/awk -F'=' '/^DBPort/{ print $2 }' "${ZBX_CONFIG}")"
    DBNAME="$(/usr/bin/awk -F'=' '/^DBName/{ print $2 }' "${ZBX_CONFIG}")"
    DBSCHEMA="$(/usr/bin/awk -F'=' '/^DBSchema/{ print $2 }' "${ZBX_CONFIG}")"
    DBUSER="$(/usr/bin/awk -F'=' '/^DBUser/{ print $2 }' "${ZBX_CONFIG}")"
    DBPASS="$(/usr/bin/awk -F'=' '/^DBPassword/{ print $2 }' "${ZBX_CONFIG}")"

    # set non-existing variables to their Zabbix defaults (if they are non-empty string)
    [ -z ${DBHOST+x} ] && DBHOST="localhost"

    # Zabbix config has a special treatment for DBHost:
    # > If set to localhost, socket is used for MySQL.
    # > If set to empty string, socket is used for PostgreSQL.
    if [[ ( "$DBTYPE" == "mysql" && "$DBHOST" == "localhost" ) || ( "$DBTYPE" == "psql" && "$DBHOST" == "" ) ]]; then
        [ "$DBTYPE" == "mysql" ] && searchstr="mysql"
        [ "$DBTYPE" == "psql" ] && searchstr="postgres"
        sock=$(netstat -axn | grep -m1 "$searchstr" | sed -r 's/^.*\s+([^ ]+)$/\1/')
        if [[ -n "$sock" && -S $sock ]]; then DBSOCKET="$sock"; DBHOST=""; fi
    else
        DBSOCKET="$(/usr/bin/awk -F'=' '/^DBSocket/{ print $2 }' "${ZBX_CONFIG}")"
    fi

# Otherwise: set default values
else
    # if a MySQL config file is specified we assume it contains all connection parameters
    if [ -z "$MYSQL_CONFIG" ]; then
        DBHOST="$DEFAULT_DBHOST"
        DBNAME="$DEFAULT_DBNAME"
        DBUSER="$DEFAULT_DBUSER"
        DBPASS="$DEFAULT_DBPASS"
    fi
fi

# Always set default ports, even if we read other parameters from zabbix_server.conf
[[ -z "$DBPORT" && "$DBTYPE" == "mysql" ]] && DBPORT="3306"
[[ -z "$DBPORT" && "$DBTYPE" == "psql"  ]] && DBPORT="5432"

# Options specified via command line override defaults or those from zabbix_server.conf (if any)
[ -n "$ODBHOST" ] && DBHOST=$ODBHOST
[ -n "$ODBPORT" ] && DBPORT=$ODBPORT
[ -n "$ODBSOCKET" ] && DBSOCKET=$ODBSOCKET && DBHOST=""
[ -n "$ODBSCHEMA" ] && DBSCHEMA=$ODBSCHEMA
[ -n "$ODBNAME" ] && DBNAME=$ODBNAME
[ -n "$ODBUSER" ] && DBUSER=$ODBUSER
[ -n "$ODBPASS" ] && DBPASS=$ODBPASS

# Password prompt
if [ "$DBPASS" = "-" ]; then
    read -r -s -p "Enter database password for user '$DBUSER' (input will be hidden): " DBPASS
    echo ""
fi

# MySQL config file validations
if [ -n "$MYSQL_CONFIG" ]; then
    if [ ! -r "$MYSQL_CONFIG" ]; then
        echo "ERROR: Cannot read configuration file $MYSQL_CONFIG" >&2
        exit 1
    fi
    # Database name needs special treatment:
    # For mysqldump it has to be specified on the command line!
    # Therefore we need to get it from the config file
    if [ $DB_GIVEN -eq 0 ]; then
        DBNAME=$(grep -m 1 ^database= "$MYSQL_CONFIG" | cut -d= -f2)
    fi
fi

if [ -z "$DBNAME" ]; then
    echo "ERROR: Please specify a database name (option -d)"
    exit 1
fi

#
# CONSTANTS
#
SUFFIX=""; test ! -z $COMPRESSION && SUFFIX=".${COMPRESSION}"

DB_OPTS=()
case $DBTYPE in
    mysql)
        [ -n "$MYSQL_CONFIG" ] && DB_OPTS=("${DB_OPTS[@]}" --defaults-extra-file="$MYSQL_CONFIG")
        [ -n "$DBSOCKET" ] && DB_OPTS=("${DB_OPTS[@]}" -S $DBSOCKET)
        [ -n "$DBHOST" ] && DB_OPTS=("${DB_OPTS[@]}" -h $DBHOST)
        [ -n "$DBUSER" ] && DB_OPTS=("${DB_OPTS[@]}" -u $DBUSER)
        [ -n "$DBPASS" ] && DB_OPTS=("${DB_OPTS[@]}" -p"$DBPASS")
        DB_OPTS=("${DB_OPTS[@]}" -P"$DBPORT")
        DB_OPTS_BATCH=("${DB_OPTS[@]}" --batch --silent)
        [ -n "$DBNAME" ] && DB_OPTS_BATCH=("${DB_OPTS_BATCH[@]}" -D $DBNAME)
        ;;
    psql)
        [ -n "$DBSOCKET" ] && DB_OPTS=("${DB_OPTS[@]}" -h $DBSOCKET)
        [ -n "$DBHOST" ] && DB_OPTS=("${DB_OPTS[@]}" -h $DBHOST)
        [ -n "$DBUSER" ] && DB_OPTS=("${DB_OPTS[@]}" -U $DBUSER)
        DB_OPTS=("${DB_OPTS[@]}" -p"$DBPORT")
        if [ -n "$DBPASS" ]; then
           export PGPASSFILE=$(mktemp -u)
           echo "$DBHOST:$DBPORT:$DBNAME:$DBUSER:$DBPASS" > $PGPASSFILE
           chmod 600 $PGPASSFILE
        fi
        DB_OPTS_BATCH=("${DB_OPTS[@]}" -Atw)
        [ -n "$DBNAME" ] && DB_OPTS_BATCH=("${DB_OPTS_BATCH[@]}" -d $DBNAME)
        ;;
esac

# Log file for errors
ERRORLOG=$(mktemp)

# Host name
if [[ -z "$DBHOST" || "$DBHOST" == "127.0.0.1" || "$DBHOST" == "127.0.0.1" ]]; then
    DBHOSTNAME="$(uname -n)"
else
    DBHOSTNAME="$DBHOST"

    # Try reverse lookup if IP is given
    command -v dig >/dev/null 2>&1
    FIND_DIG=$?
    if [[ "$REVERSELOOKUP" == "yes" && $FIND_DIG -eq 0 && -n "$DBHOST" ]]; then
        # Try resolving a given host ip
        newHostname=$(dig +noall +answer -x "${DBHOST}" | head -n1 | sed -r 's/((\S+)\s+)+([^\.]+)\..*/\3/')
        test \! -z "$newHostname" && DBHOSTNAME="$newHostname"
    fi
fi

#
# CONFIG DUMP
#
if [ "$QUIET" == "no" ]; then
    cat <<-EOF
Configuration:
 - type:     $DBTYPE
EOF
    [ -n "$MYSQL_CONFIG" ] && echo " - cfg file: $MYSQL_CONFIG"
    [ -n "$DBHOST" ]       && echo " - host:     $DBHOST ($DBHOSTNAME)" && echo " - port:     $DBPORT"
    [ -n "$DBSOCKET" ]     && echo " - socket:   $DBSOCKET"
    [ -n "$DBSCHEMA" ]     && echo " - schema:   $DBSCHEMA"
    [ -n "$DBNAME" ]       && echo " - database: $DBNAME"
    [ -n "$DBUSER" ]       && echo " - user:     $DBUSER"
    [ -n "$DUMPDIR" ]      && echo " - output:   $DUMPDIR"
fi

#
# FUNCTIONS
#

# Returns TRUE if argument 1 is part of the given array (remaining arguments)
elementIn () {
    local e
    for e in "${@:2}"; do [[ "$e" == "$1" ]] && return 0; done
    return 1
}
check_binary() {
    if ! which $1 > /dev/null; then
        echo "Executable '$1' not found." >&2
        case $1 in
            mysql)
                echo "(with Debian try \"apt-get install mysql-client\")" >&2 ;;
            psql)
                echo "(with Debian try \"apt-get install postgresql-client\")" >&2 ;;
        esac
        exit 1
    fi
}
clean_psql_pass() {
    if [ $DBTYPE = "psql" -a -n "$PGPASSFILE" ]; then
       rm -f $PGPASSFILE
    fi
}

#
# CHECKS
#
case $DBTYPE in
    mysql)
        check_binary mysqldump ;;
    psql)
        check_binary pg_dump ;;
    *)
        echo "Sorry, database type '$DBTYPE' is not supported."
        echo "Please specify either 'mysql' or 'psql'."
        exit 1 ;;
esac

#
# READ TABLE LIST from __DATA__ section at the end of this script
# (http://stackoverflow.com/a/3477269/2983301)
#
SCHEMAONLY_TABLES=()
KNOWN_TABLES=()
while read -r line; do
    table=$(echo "$line" | cut -d" " -f1)
    echo "$line" | cut -d" " -f5 | grep -qi "SCHEMAONLY"
    test $? -eq 0 && SCHEMAONLY_TABLES+=($table)
    KNOWN_TABLES+=($table)
done < <(sed '0,/^__DATA__$/d' "${BASH_SOURCE[*]}" | tr -s " ")

# paranoid check
if [ ${#SCHEMAONLY_TABLES[@]} -lt 5 ]; then
    echo "ERROR: The number of large data tables configured in this script is less than 5." >&2
    exit 1
fi

#
# BACKUP
#
# Read table list from database
[ "$QUIET" == "no" ] && echo "Fetching list of existing tables..."
case $DBTYPE in
    mysql)
        DB_TABLES=$(mysql "${DB_OPTS_BATCH[@]}" -e "SELECT table_name FROM information_schema.tables WHERE table_schema = '$DBNAME'" 2>$ERRORLOG)
        ;;
    psql)
        DB_TABLES=$(psql "${DB_OPTS_BATCH[@]}" -c "SELECT table_name FROM information_schema.tables WHERE table_schema='public' AND table_catalog='$DBNAME' AND table_type='BASE TABLE'" 2>$ERRORLOG)
        ;;
esac
if [ $? -ne 0 ]; then
    echo "ERROR while trying to access database:" 2>&1;
    cat $ERRORLOG 2>&1;
    clean_psql_pass
    exit 1;
fi

DB_TABLES=$(echo "$DB_TABLES" | sort)
DB_TABLE_NUM=$(echo "$DB_TABLES" | wc -l)

# Check if existing tables are known
UNKNOWN_TABLES=()
while read -r table; do
    elementIn "$table" "${KNOWN_TABLES[@]}" || UNKNOWN_TABLES+=($table)
done <<<"$DB_TABLES"
if [ ${#UNKNOWN_TABLES[@]} -gt 0 ]; then
    if [[ "$QUIET" == "no" || $HANDLE_UNKNOWN == "fail" ]]; then
        echo ""
        [ $HANDLE_UNKNOWN == "fail" ] && echo "ERROR"
        echo "Unknown tables found in database:"
        for tab in "${UNKNOWN_TABLES[@]}"; do echo " - $tab"; done
        [ $HANDLE_UNKNOWN == "backup" ] && echo "They will be included (full data backup) as -f was specified"
        [ $HANDLE_UNKNOWN == "ignore" ] && echo "They will be ignored as -i was specified"
        [ $HANDLE_UNKNOWN == "fail"  ] && echo "To include them (full data backup) specify -f, to ignore them use -i"
        echo ""
    fi
    if [ $HANDLE_UNKNOWN == "fail" ]; then
        clean_psql_pass
        exit 1;
    fi
fi

# Query Zabbix database version
VERSION=""
case $DBTYPE in
    mysql)
        DB_VER=$(mysql "${DB_OPTS_BATCH[@]}" -N -e "select optional from dbversion;" 2>/dev/null)
        ;;
    psql)
        DB_VER=$(psql "${DB_OPTS_BATCH[@]}" -c "select optional from dbversion;" 2>/dev/null)
        ;;
esac
if [ $? -eq 0 ]; then
    # version string is like: 02030015
    re='(.*)([0-9]{2})([0-9]{4})'
    if [[ $DB_VER =~ $re ]]; then
        VERSION="_db-${DBTYPE}-${BASH_REMATCH[1]}.$(( ${BASH_REMATCH[2]} + 0 )).$(( ${BASH_REMATCH[3]} + 0 ))"
    fi
fi

# Assemble file name
DUMPFILENAME_PREFIX="zabbix_cfg_${DBHOSTNAME}"
DUMPFILEBASE="${DUMPFILENAME_PREFIX}_$(date +%Y%m%d-%H%M)${VERSION}.sql"
DUMPFILE="$DUMPDIR/$DUMPFILEBASE"

PROCESSED_SCHEMAONLY_TABLES=()
i=0

mkdir -p "${DUMPDIR}"

[ "$QUIET" == "no" ] && echo "Starting table backups..."
case $DBTYPE in
    mysql)
        # dump schemas
        DUMP_OPTS=(--opt --single-transaction --skip-lock-tables --no-data --routines)
        if [ $HANDLE_UNKNOWN == "ignore" ]; then
            while read -r table; do
                if elementIn "$table" "${UNKNOWN_TABLES[@]}"; then
                    DUMP_OPTS+=(--ignore-table=$DBNAME.$table)
                fi
            done <<<"$DB_TABLES"
        fi

        mysqldump "${DB_OPTS[@]}" "${DUMP_OPTS[@]}" $DBNAME > "$DUMPFILE" 2>$ERRORLOG

        if [ $? -ne 0 ]; then echo $'\nERROR: Could not backup table schemas.\n' >&2; cat $ERRORLOG >&2; exit 1; fi

        # dump data
        DUMP_OPTS=(--opt --single-transaction --skip-lock-tables --no-create-info --skip-extended-insert)
        while read -r table; do
            if elementIn "$table" "${SCHEMAONLY_TABLES[@]}"; then
                DUMP_OPTS+=(--ignore-table=$DBNAME.$table)
                PROCESSED_SCHEMAONLY_TABLES+=($table)
            fi
            if [ $HANDLE_UNKNOWN == "ignore" ]; then
                if elementIn "$table" "${UNKNOWN_TABLES[@]}"; then
                    DUMP_OPTS+=(--ignore-table=$DBNAME.$table)
                fi
            fi
        done <<<"$DB_TABLES"

        mysqldump "${DB_OPTS[@]}" "${DUMP_OPTS[@]}" $DBNAME >> "$DUMPFILE" 2>$ERRORLOG

        if [ $? -ne 0 ]; then echo $'\nERROR: Could not backup table data.\n' >&2; cat $ERRORLOG >&2; exit 1; fi
    ;;
    psql)
        DUMP_OPTS=()
        while read -r table; do
            if [ $HANDLE_UNKNOWN == "ignore" ]; then
                if elementIn "$table" "${UNKNOWN_TABLES[@]}"; then
                    DUMP_OPTS+=(--exclude-table=$table)
                fi
            fi
            if elementIn "$table" "${SCHEMAONLY_TABLES[@]}"; then
                DUMP_OPTS+=(--exclude-table-data=$table)
                PROCESSED_SCHEMAONLY_TABLES+=($table)
            fi
        done <<<"$DB_TABLES"

        [ -n "$DBSCHEMA" ] && DUMP_OPTS=("${DUMP_OPTS[@]}" -n $DBSCHEMA)

        pg_dump "${DB_OPTS[@]}" "${DUMP_OPTS[@]}" -d $DBNAME > "$DUMPFILE" 2>$ERRORLOG

        if [ $? -ne 0 ]; then
            echo $'\nERROR: Could not backup database.\n' >&2
            cat $ERRORLOG >&2
            clean_psql_pass
            exit 1
        fi
    ;;
esac

rm $ERRORLOG

#
# COMPRESS BACKUP
#
if [ "$QUIET" == "no" ]; then
    echo $'\nFor the following large tables only the schema (without data) was stored:'
    for table in "${PROCESSED_SCHEMAONLY_TABLES[@]}"; do echo " - $table"; done

    echo $'\nCompressing backup file...'
fi

EXITCODE=0
if [ "$COMPRESSION" == "gz" ]; then gzip -f "$DUMPFILE"; EXITCODE=$?; fi
if [ "$COMPRESSION" == "xz" ]; then xz   -f "$DUMPFILE"; EXITCODE=$?; fi
if [ $EXITCODE -ne 0 ]; then
    echo $'\nERROR: Could not compress backup file, see previous messages' >&2
    clean_psql_pass
    exit 1
fi

[ "$QUIET" == "no" ] && echo "Backup Completed" && echo "${DUMPFILE}${SUFFIX}"

#
# ROTATE OLD BACKUPS
#
if [ $GENERATIONSTOKEEP -gt 0 ]; then
    [ "$QUIET" == "no" ] && echo "Removing old backups, keeping up to $GENERATIONSTOKEEP"
    REMOVE_OLD_CMD="cd \"$DUMPDIR\" && ls -t \"${DUMPFILENAME_PREFIX}\"* | /usr/bin/awk \"NR>${GENERATIONSTOKEEP}\" | xargs rm -f "
    eval ${REMOVE_OLD_CMD}
    if [ $? -ne 0 ]; then
        echo "ERROR: Could not rotate old backups" >&2
        clean_psql_pass
        exit 1
    fi
fi

clean_psql_pass
exit 0

################################################################################
# List of all known table names.
# The flag SCHEMAONLY marks tables that contain monitoring data (as opposed to
# config data), so only their database schema will be backed up.
#

__DATA__
acknowledges               1.3.1    - 4.4.4     SCHEMAONLY
actions                    1.3.1    - 4.4.4
alerts                     1.3.1    - 4.4.4     SCHEMAONLY
application_discovery      2.5.0    - 4.4.4
application_prototype      2.5.0    - 4.4.4
application_template       2.1.0    - 4.4.4
applications               1.3.1    - 4.4.4
auditlog                   1.3.1    - 4.4.4     SCHEMAONLY
auditlog_details           1.7      - 4.4.4     SCHEMAONLY
autoreg                    1.3.1    - 1.3.4
autoreg_host               1.7      - 4.4.4
conditions                 1.3.1    - 4.4.4
config                     1.3.1    - 4.4.4
config_autoreg_tls         4.4.0    - 4.4.4
corr_condition             3.2.0    - 4.4.4
corr_condition_group       3.2.0    - 4.4.4
corr_condition_tag         3.2.0    - 4.4.4
corr_condition_tagpair     3.2.0    - 4.4.4
corr_condition_tagvalue    3.2.0    - 4.4.4
corr_operation             3.2.0    - 4.4.4
correlation                3.2.0    - 4.4.4
dashboard                  3.4.0    - 4.4.4
dashboard_user             3.4.0    - 4.4.4
dashboard_usrgrp           3.4.0    - 4.4.4
dbversion                  2.1.0    - 4.4.4
dchecks                    1.3.4    - 4.4.4
dhosts                     1.3.4    - 4.4.4
drules                     1.3.4    - 4.4.4
dservices                  1.3.4    - 4.4.4
escalations                1.5.3    - 4.4.4
event_recovery             3.2.0    - 4.4.4     SCHEMAONLY
event_suppress             4.0.0    - 4.4.4     SCHEMAONLY
event_tag                  3.2.0    - 4.4.4     SCHEMAONLY
events                     1.3.1    - 4.4.4     SCHEMAONLY
expressions                1.7      - 4.4.4
functions                  1.3.1    - 4.4.4
globalmacro                1.7      - 4.4.4
globalvars                 1.9.6    - 4.4.4
graph_discovery            1.9.0    - 4.4.4
graph_theme                1.7      - 4.4.4
graphs                     1.3.1    - 4.4.4
graphs_items               1.3.1    - 4.4.4
group_discovery            2.1.4    - 4.4.4
group_prototype            2.1.4    - 4.4.4
groups                     1.3.1    - 3.4.15
help_items                 1.3.1    - 2.1.8
history                    1.3.1    - 4.4.4     SCHEMAONLY
history_log                1.3.1    - 4.4.4     SCHEMAONLY
history_str                1.3.1    - 4.4.4     SCHEMAONLY
history_str_sync           1.3.1    - 2.2.23    SCHEMAONLY
history_sync               1.3.1    - 2.2.23    SCHEMAONLY
history_text               1.3.1    - 4.4.4     SCHEMAONLY
history_uint               1.3.1    - 4.4.4     SCHEMAONLY
history_uint_sync          1.3.1    - 2.2.23    SCHEMAONLY
host_discovery             2.1.4    - 4.4.4
host_inventory             1.9.6    - 4.4.4
host_profile               1.9.3    - 1.9.5
host_tag                   4.2.0    - 4.4.4
hostmacro                  1.7      - 4.4.4
hosts                      1.3.1    - 4.4.4
hosts_groups               1.3.1    - 4.4.4
hosts_profiles             1.3.1    - 1.9.2
hosts_profiles_ext         1.6      - 1.9.2
hosts_templates            1.3.1    - 4.4.4
housekeeper                1.3.1    - 4.4.4
hstgrp                     4.0.0    - 4.4.4
httpstep                   1.3.3    - 4.4.4
httpstep_field             3.4.0    - 4.4.4
httpstepitem               1.3.3    - 4.4.4
httptest                   1.3.3    - 4.4.4
httptest_field             3.4.0    - 4.4.4
httptestitem               1.3.3    - 4.4.4
icon_map                   1.9.6    - 4.4.4
icon_mapping               1.9.6    - 4.4.4
ids                        1.3.3    - 4.4.4
images                     1.3.1    - 4.4.4
interface                  1.9.1    - 4.4.4
interface_discovery        2.1.4    - 4.4.4
item_application_prototype 2.5.0    - 4.4.4
item_condition             2.3.0    - 4.4.4
item_discovery             1.9.0    - 4.4.4
item_preproc               3.4.0    - 4.4.4
item_rtdata                4.4.0    - 4.4.4     SCHEMAONLY
items                      1.3.1    - 4.4.4
items_applications         1.3.1    - 4.4.4
lld_macro_path             4.2.0    - 4.4.4
maintenance_tag            4.0.0    - 4.4.4
maintenances               1.7      - 4.4.4
maintenances_groups        1.7      - 4.4.4
maintenances_hosts         1.7      - 4.4.4
maintenances_windows       1.7      - 4.4.4
mappings                   1.3.1    - 4.4.4
media                      1.3.1    - 4.4.4
media_type                 1.3.1    - 4.4.4
media_type_param           4.4.0    - 4.4.4
node_cksum                 1.3.1    - 2.2.23
node_configlog             1.3.1    - 1.4.7
nodes                      1.3.1    - 2.2.23
opcommand                  1.9.4    - 4.4.4
opcommand_grp              1.9.2    - 4.4.4
opcommand_hst              1.9.2    - 4.4.4
opconditions               1.5.3    - 4.4.4
operations                 1.3.4    - 4.4.4
opgroup                    1.9.2    - 4.4.4
opinventory                3.0.0    - 4.4.4
opmediatypes               1.7      - 1.8.22
opmessage                  1.9.2    - 4.4.4
opmessage_grp              1.9.2    - 4.4.4
opmessage_usr              1.9.2    - 4.4.4
optemplate                 1.9.2    - 4.4.4
problem                    3.2.0    - 4.4.4     SCHEMAONLY
problem_tag                3.2.0    - 4.4.4     SCHEMAONLY
profiles                   1.3.1    - 4.4.4
proxy_autoreg_host         1.7      - 4.4.4
proxy_dhistory             1.5      - 4.4.4
proxy_history              1.5.1    - 4.4.4
regexps                    1.7      - 4.4.4
rights                     1.3.1    - 4.4.4
screen_user                3.0.0    - 4.4.4
screen_usrgrp              3.0.0    - 4.4.4
screens                    1.3.1    - 4.4.4
screens_items              1.3.1    - 4.4.4
scripts                    1.5      - 4.4.4
service_alarms             1.3.1    - 4.4.4
services                   1.3.1    - 4.4.4
services_links             1.3.1    - 4.4.4
services_times             1.3.1    - 4.4.4
sessions                   1.3.1    - 4.4.4
slides                     1.3.4    - 4.4.4
slideshow_user             3.0.0    - 4.4.4
slideshow_usrgrp           3.0.0    - 4.4.4
slideshows                 1.3.4    - 4.4.4
sysmap_element_trigger     3.4.0    - 4.4.4
sysmap_element_url         1.9.0    - 4.4.4
sysmap_shape               3.4.0    - 4.4.4
sysmap_url                 1.9.0    - 4.4.4
sysmap_user                3.0.0    - 4.4.4
sysmap_usrgrp              3.0.0    - 4.4.4
sysmaps                    1.3.1    - 4.4.4
sysmaps_elements           1.3.1    - 4.4.4
sysmaps_link_triggers      1.5      - 4.4.4
sysmaps_links              1.3.1    - 4.4.4
tag_filter                 4.0.0    - 4.4.4
task                       3.2.0    - 4.4.4     SCHEMAONLY
task_acknowledge           3.4.0    - 4.4.4     SCHEMAONLY
task_check_now             4.0.0    - 4.4.4     SCHEMAONLY
task_close_problem         3.2.0    - 4.4.4     SCHEMAONLY
task_remote_command        3.4.0    - 4.4.4     SCHEMAONLY
task_remote_command_result 3.4.0    - 4.4.4     SCHEMAONLY
timeperiods                1.7      - 4.4.4
trends                     1.3.1    - 4.4.4     SCHEMAONLY
trends_uint                1.5      - 4.4.4     SCHEMAONLY
trigger_depends            1.3.1    - 4.4.4
trigger_discovery          1.9.0    - 4.4.4
trigger_tag                3.2.0    - 4.4.4
triggers                   1.3.1    - 4.4.4
user_history               1.7      - 2.4.8
users                      1.3.1    - 4.4.4
users_groups               1.3.1    - 4.4.4
usrgrp                     1.3.1    - 4.4.4
valuemaps                  1.3.1    - 4.4.4
widget                     3.4.0    - 4.4.4
widget_field               3.4.0    - 4.4.4