#   BAREOS® - Backup Archiving REcovery Open Sourced
#
#   Copyright (C) 2013-2020 Bareos GmbH & Co. KG
#
#   This program is Free Software; you can redistribute it and/or
#   modify it under the terms of version three of the GNU Affero General Public
#   License as published by the Free Software Foundation and included
#   in the file LICENSE.
#
#   This program is distributed in the hope that it will be useful, but
#   WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
#   Affero General Public License for more details.
#
#   You should have received a copy of the GNU Affero General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
#   02110-1301, USA.

BAREOS_SCRIPTS_DIR="${BAREOS_SCRIPTS_DIR:-/usr/pkg/lib/bareos/scripts}"
BAREOS_CONFIG_LIB=${BAREOS_SCRIPTS_DIR}/bareos-config-lib.sh
BAREOS_CONFIG_DIR=${BAREOS_CONFIG_DIR:-/usr/pkg/etc/bareos}
BAREOS_SBIN_DIR=${BAREOS_SBIN_DIR:-/usr/pkg/sbin}
DBCHECK="${BAREOS_SBIN_DIR}/bareos-dbcheck -c ${BAREOS_CONFIG_DIR} -B"
AWK="/usr/bin/awk"
PATH=/usr/pkg/bin:/usr/pkg/sbin:${PATH}

SEC_GROUPS="tape disk"

BAREOS_WORKING_DIR="${BAREOS_WORKING_DIR:-/var/db/bareos/working}"
FILE_DAEMON_USER="${BAREOS_FD_GROUP:-root}"
FILE_DAEMON_GROUP="${BAREOS_FD_GROUP:-bareos}"
STORAGE_DAEMON_USER="${BAREOS_SD_USER:-}"
STORAGE_DAEMON_GROUP="${BAREOS_SD_GROUP:-bareos}"
DIRECTOR_DAEMON_USER="${BAREOS_DIR_USER:-}"
DIRECTOR_DAEMON_GROUP="${BAREOS_DIR_GROUP:-bareos}"
DAEMON_USER="$DIRECTOR_DAEMON_USER"
DAEMON_GROUP="$DIRECTOR_DAEMON_GROUP"

DB_NAME="${db_name:-bareos}"
DB_VERSION="${BDB_VERSION:-2192}"
SQL_DDL_DIR="${SQL_DDL_DIR:-/usr/pkg/lib/bareos/scripts/ddl}"
SQLITE_BINDIR=""
MYSQL_BINDIR=""
POSTGRESQL_BINDIR=""
INGRES_BINDIR=""

PASSWORD_SUBST="\
XXX_REPLACE_WITH_DIRECTOR_PASSWORD_XXX \
XXX_REPLACE_WITH_CLIENT_PASSWORD_XXX \
XXX_REPLACE_WITH_STORAGE_PASSWORD_XXX \
XXX_REPLACE_WITH_DIRECTOR_MONITOR_PASSWORD_XXX \
XXX_REPLACE_WITH_CLIENT_MONITOR_PASSWORD_XXX \
XXX_REPLACE_WITH_STORAGE_MONITOR_PASSWORD_XXX \
"

os_type=`uname -s`

is_function()
{
    func=${1-}
    test "$func" && command -v "$func" > /dev/null 2>&1
    return $?
}

# does not work on all shells (only bash),
# therefore removed until a better solution is found
# list_functions()
# {
#     if type typeset >/dev/null 2>&1; then
#         # show available shell functions,
#         # but exclude internal functions (name starts with "_" ...)
#         typeset -F | cut -d " " -f 3 | grep "^[a-z]"
#     else
#         echo "function list not available"
#     fi
# }

info()
{
    echo "Info: $@" >&2
}

warn()
{
    echo "Warning: $@" >&2
}

error()
{
    echo "Error: $@" >&2
}

get_config_lib_file()
{
    # can be used in following way:
    # LIB=`bareos-config get_config_lib_file`
    # . $LIB
    echo "${BAREOS_CONFIG_LIB}"
}

get_user_fd()
{
    echo "${FILE_DAEMON_USER}"
}

get_group_fd()
{
    echo "${FILE_DAEMON_GROUP}"
}

get_user_sd()
{
    echo "${STORAGE_DAEMON_USER}"
}

get_group_sd()
{
    echo "${STORAGE_DAEMON_GROUP}"
}

get_user_dir()
{
    echo "${DIRECTOR_DAEMON_USER}"
}

get_group_dir()
{
    echo "${DIRECTOR_DAEMON_GROUP}"
}

get_bareos_user()
{
   echo "${DAEMON_USER}"
}

get_bareos_dir()
{
   echo "${DAEMON_GROUP}"
}

get_working_dir()
{
    echo "${BAREOS_WORKING_DIR}"
}

get_database_ddl_dir()
{
    echo "${SQL_DDL_DIR}"
}

get_database_version()
{
    echo "${DB_VERSION}"
}

get_database_version_by_release()
{
    param="$1"

    # get release from parameter by stripping everthing after the "-".
    # Example parameter: 13.2.2-926.1
    release=`echo "$param" | sed 's/-.*//'`
    if [ -z "$release" ]; then
        error "failed to get database version for release $param"
        return 1
    fi

    MAP=${SQL_DDL_DIR}/versions.map
    if [ ! -r "$MAP" ]; then
        error "failed to read Bareos database versions map file $MAP"
        return 1
    fi

    MARKER=0
    VERSIONS=`cat "$MAP"; echo "$release=$MARKER"`

    # add marker to list,
    # sort the list reverse, assuming versions x.y.z  and lines x.y.z=db_version,
    # get entry one line after marker
    db_version=`printf "$VERSIONS" | sort -t. -k 1,1rn -k 2,2rn -k 3,3rn | sed -r -n "/[0-9.]+.*=$MARKER$/{ N; s/(.*)=(.*)\n(.*)=(.*)/\4/p }"`

    if [ -z "$db_version" ]; then
        db_version=`sed -n "s/^default=//p" $MAP`
        if [ "$db_version" ]; then
            warn "no database version defined for release $release ($param). Using default version: $db_version"
        else
            error "neither found database version for release $release ($param), nor found default database version in map file $MAP"
            return 1
        fi
    fi

    echo "$db_version"
    return
}

get_database_utility_path()
{
    db_type="${1-}"

    case ${db_type} in
        sqlite3)
            utility="sqlite3"
            bindir="${SQLITE_BINDIR}"
            ;;
        mysql)
            utility="mysql"
            bindir="${MYSQL_BINDIR}"
            ;;
        postgresql)
            utility="psql"
            pg_config --bindir > /dev/null 2>&1
            if [ $? = 0 ]; then
                bindir=`pg_config --bindir`
            else
                bindir="${POSTGRESQL_BINDIR}"
            fi
            ;;
        ingres)
            utility="sql"
            bindir="${INGRES_BINDIR}"
            ;;
        *)
            ;;
    esac

    #
    # First see if the utility is already on the path
    #
    which ${utility} > /dev/null 2>&1
    if [ $? = 0 ]; then
        echo ""
    else
        echo "${bindir}"
    fi
}

[ ${os_type} = Linux ] && \
setup_sd_user()
{
    #
    # Guaranties that storage-daemon user and group exists
    # and storage-daemon user belongs to the required groups.
    #
    # normally, storage-daemon user
    # is already installed by the package preinstall script.
    #

    getent group ${STORAGE_DAEMON_GROUP} > /dev/null || groupadd -r ${STORAGE_DAEMON_GROUP}

    #
    # If the user doesn't exist create a new one otherwise modify it to have the wanted secondary groups.
    #
    if [ -z "${STORAGE_DAEMON_USER}" ]; then
        info "SKIPPED: no storage daemon user specified."
        return 0
    fi

    if getent passwd ${STORAGE_DAEMON_USER} > /dev/null; then
        if [ "${STORAGE_DAEMON_USER}" != "root" ]; then
            #
            # Build a list of all groups the user is already in.
            #
            ADD_GROUPS=""
            CUR_ADD_GROUPS=`id -Gn ${STORAGE_DAEMON_USER}`
            for sec_group in ${CUR_ADD_GROUPS}; do
                [ -z "${USERMOD_CMDLINE}" ] && USERMOD_CMDLINE="usermod -G ${sec_group}" || USERMOD_CMDLINE="${USERMOD_CMDLINE},${sec_group}"
            done

            #
            # See what secondary groups exist for the SD user to be added to.
            #
            for sec_group in ${SEC_GROUPS}; do
                if getent group ${sec_group} >/dev/null; then
                    found=0
                    for group in ${CUR_ADD_GROUPS}; do
                        if [ ${group} = ${sec_group} ]; then
                            found=1
                        fi
                    done

                    if [ ${found} = 0 ]; then
                        [ -z "${ADD_GROUPS}" ] && ADD_GROUPS="${sec_group}" || ADD_GROUPS="${ADD_GROUPS} ${sec_group}"
                        [ -z "${USERMOD_CMDLINE}" ] && USERMOD_CMDLINE="usermod -G ${sec_group}" || USERMOD_CMDLINE="${USERMOD_CMDLINE},${sec_group}"
                    fi
                fi
            done

            #
            # If the user was already created before,
            # Make sure the correct primary group is set otherwise fix it.
            #
            if [ "`id -gn ${STORAGE_DAEMON_USER}`" != "${STORAGE_DAEMON_GROUP}" ]; then
                usermod -g ${STORAGE_DAEMON_GROUP} ${STORAGE_DAEMON_USER} || warn "failed to add groups ${STORAGE_DAEMON_GROUP} to ${STORAGE_DAEMON_USER}"
            fi

            #
            # Add the storage_daemon_user to additional groups (if needed)
            #
            if [ -n "${ADD_GROUPS}" ]; then
                ${USERMOD_CMDLINE} ${STORAGE_DAEMON_USER} || warn "failed: ${USERMOD_CMDLINE} ${STORAGE_DAEMON_USER}"
            fi
        fi
    else
        #
        # User doesn't exist so create it.
        # Determine additional groups the user should be in.
        #
        NEW_ADD_GROUPS=""
        for sec_group in ${SEC_GROUPS}; do
            if getent group ${sec_group}; then
                [ -z "${NEW_ADD_GROUPS}" ] && NEW_ADD_GROUPS="-G ${sec_group}" || NEW_ADD_GROUPS="${NEW_ADD_GROUPS},${sec_group}"
            fi
        done

        #
        # Create a new storage_daemon_user
        #
        useradd -r --comment "bareos" --home ${BAREOS_WORKING_DIR} -g ${STORAGE_DAEMON_GROUP} ${NEW_ADD_GROUPS} --shell /bin/false ${STORAGE_DAEMON_USER} || warn "failed to create user ${STORAGE_DAEMON_USER}"
    fi
}

[ ${os_type} != Linux ] && \
setup_sd_user()
{
   echo "setup_sd_user() is not supported on this platform"
   exit 1
}

get_config_path()
{
    # configuration component (either file or bareos-dir, ...)
    COMPONENT="${1}"

    if [ -f "${COMPONENT}" ]; then
        printf "%s" "${COMPONENT}"
    elif [ -f "${BAREOS_CONFIG_DIR}/${COMPONENT}.conf" ]; then
        printf "%s" "${BAREOS_CONFIG_DIR}/${COMPONENT}.conf"
    elif [ -d "${BAREOS_CONFIG_DIR}/${COMPONENT}.d/" ]; then
        printf "%s" "${BAREOS_CONFIG_DIR}/${COMPONENT}.d/"
    else
        warn "failed to find config for component \"${COMPONENT}\"."
        return 1
    fi
}

get_config_path2()
{
    # configuration component (either file or bareos-dir, ...)
    BASEDIR="${1}"
    COMPONENT="${2}"

    if ! [ -d "${BASEDIR}" ]; then
        warn "base directory \"${BASEDIR}\" does not exists."
        return 1
    fi

    if [ -f "${BASEDIR}/${COMPONENT}.conf" ]; then
        printf "%s" "${BASEDIR}/${COMPONENT}.conf"
    elif [ -d "${BASEDIR}/${COMPONENT}.d/" ]; then
        printf "%s" "${BASEDIR}/${COMPONENT}.d/"
    else
        warn "failed to find config for component \"${COMPONENT}\" in directory \"${BASEDIR}\"."
        return 1
    fi
}


has_config()
{
    # configuration component (either file or bareos-dir, ...)
    COMPONENT="${1}"

    if ! CONFIG_PATH=`get_config_path "${COMPONENT}" 2>/dev/null`; then
        return 1
    fi

    if [ -d "${CONFIG_PATH}" ]; then
        # Check if config files exist.
        # There should a least be 2 configuration files.
        # bareos-dir:
        #   It could be, that only the file MyCatalog.conf exists,
        #   (created by bareos-database-common) but no other files.
        #   In this case, it counts as not configured.
        [ `echo ${CONFIG_PATH}/*/*.conf | wc -l` -gt 2 ]
        return $?
    fi

    # config file exists
    return 0
}

deploy_config()
{
   local RC=1
   ARGS=$#
   SOURCE=${1:-}
   DEST=${2:-}
   COMPONENT=${3:-}

   [ -d "$SOURCE" ] || return 1
   [ -n "$DEST" ] || return 1

   if [ $ARGS -eq 2 ]; then
      deploy_config2 "$SOURCE" "$DEST"
      RC=$?
   elif [ $ARGS -eq 3 ]; then
      deploy_config3 "$SOURCE" "$DEST" "$COMPONENT"
      RC=$?
   fi

   if [ $RC -eq 0 ]; then
      initialize_local_hostname
      initialize_passwords
      if [ "${DAEMON_USER}" -a "${DAEMON_GROUP}" ]; then
         chown -R ${DAEMON_USER}:${DAEMON_GROUP} "$DEST"
      fi
      # chmod ... X: set x on directories, but not on files.
      if [ "$os_type" = "Darwin" ]; then
         # MacOS users from the "admin" group should be able to change the configuration files.
         chgrp -R admin "$DEST"
         chmod -R ug=rwX,o= "$DEST"
      else
         chmod -R u=rwX,g=rX,o= "$DEST"
      fi
   fi

   return $RC
}


deploy_config2()
{
   #
   # Copy configuration from SOURCE to DEST and apply settings.
   # Only copies new files. It does not overwrite existing files.
   #
   # Returns:
   #   0: if new config files have been copied
   #   1: otherwise (on error or if no new config files are available)
   #

   SOURCE=${1:-}
   DEST=${2:-}

   local RC=1

   [ -d "$SOURCE" ] || return 1
   if ! [ -e "$DEST" ]; then
      mkdir -p "$DEST"
   fi

   #
   # Copy all files, but do not overwrite existing file.
   # Use verbose to detect, when new files have been copied.
   # On MacOS, only single letter cp options are available.
   #
   #OUT=`cp --verbose --recursive --no-clobber "$SOURCE/." "$DEST/."`
   OUT=`cp -v -r -n "$SOURCE/." "$DEST/."`
   if [ "$OUT" ]; then
      RC=0
   fi

   return $RC
}

deploy_config3()
{
   #
   # Copy configuration from SOURCE to DEST and apply settings.
   # Only copies new files. It does not overwrite existing files.
   #
   # Returns:
   #   0: if new config files have been copied
   #   1: otherwise (on error or if no new config files are available)
   #

   local RC=1

   SOURCE=${1:-}
   DEST=${2:-}
   COMPONENT=${3:-}

   [ -d "$SOURCE" ] || return 1
   if ! [ -e "$DEST" ]; then
      mkdir -p "$DEST"
   fi

   if ! SOURCE_CONFIG_PATH=`get_config_path2 "${SOURCE}" "${COMPONENT}"`; then
      return 1
   fi

   if [ -d "${SOURCE_CONFIG_PATH}" ]; then
      deploy_config2 "${SOURCE_CONFIG_PATH}" "${DEST}/${COMPONENT}.d/"
      RC=$?
   else
      DEST_CONFIG_PATH="${DEST}/${COMPONENT}.conf"
      if [ ! -f "${DEST_CONFIG_PATH}" ]; then
         cp ${SOURCE_CONFIG_PATH} ${DEST_CONFIG_PATH}
         RC=$?
      fi
   fi

   return $RC
}

get_config_param()
{
   #
   # get parameter values from a Bareos configuration file
   #

   # configuration file
   CFG_FILE="${1-}"
   # section, currently ignored
   SECTION="${2-}"
   # name of the section, currently ignored
   NAME="${3-}"
   # parameter to get from config file
   PARAM="${4-}"
   # default value, if parameter is not found
   DEFAULT="${5-}"

   if [ ! -r "${CFG_FILE}" ]; then
      warn "failed to get parameter ${SECTION} ${NAME} ${PARAM}: can't read ${CFG_FILE}"
      # if default value is given, return it anyway
      [ "$DEFAULT" ] && echo "$DEFAULT"
      return 1
   fi

   # get parameter from configuration file
   VALUE=`egrep -i "^[ 	]*${PARAM}[ 	]*=" ${CFG_FILE} |\
      cut -d'=' -f2 | \
      sed -e 's/[ 	]*"//' -e 's/"//'`
   [ "$VALUE" ] || VALUE="$DEFAULT"
   echo "$VALUE"
}


[ ${os_type} = Linux ] && \
set_config_param()
{
    #
    # set parameter values to a Bareos configuration file
    #

    # Limitations:
    # - multiple directives in one line,
    #   separated by ";"
    #   (could by handled by RS="\n|;", but this could cause problems with other lines)
    #   Possible workaround: get expanded config by "bareos-* -xc"
    # - "}" must be the only character in a line
    # - between "{" and the first directive must be a line break
    # - Name directive must come before directive to modify,
    #   preferably Name is the first directive of a resource
    # - does not handle includes ("@" and include scripts)
    #   Possible workaround: get expanded config by "bareos-* -xc"

    # configuration component (either file or bareos-dir, ...)
    COMPONENT="${1}"
    # section / resource type
    SECTION="${2}"
    # name of the section, currently ignored
    NAME="${3}"
    # parameter to set in the config file
    PARAM="${4}"
    # value to set
    VALUE="${5}"

    if ! CONFIG_PATH=`get_config_path "${COMPONENT}"`; then
        return 1
    fi

    if [ -d "${CONFIG_PATH}" ]; then
        set_config_param_in_directory "${CONFIG_PATH}" "${SECTION}" "${NAME}" "${PARAM}" "${VALUE}"
    else
        set_config_param_in_file "${CONFIG_PATH}" "${SECTION}" "${NAME}" "${PARAM}" "${VALUE}"
    fi

    return
}

[ ${os_type} = Linux ] && \
set_config_param_in_directory()
{
    # configuration file
    DIRECTORY="${1}"
    # section / resource type
    SECTION=`echo "${2}" | tr '[:upper:]' '[:lower:]'`
    # name of the section, currently ignored
    NAME="${3}"
    # parameter to set in the config file
    PARAM="${4}"
    # value to set
    VALUE="${5}"

    if ! [ -e "${DIRECTORY}/${SECTION}" ]; then
        warn "failed to set parameter ${SECTION} ${NAME} ${PARAM} = ${VALUE}: directory ${DIRECTORY}/${SECTION} does not exist"
        return 1
    fi

    FILE="${DIRECTORY}/${SECTION}/${NAME}.conf"
    if ! [ -f "${FILE}" ]; then
        printf "%s {\n  Name = %s\n}\n" "${SECTION}" "${NAME}" > "${FILE}"
    fi
    set_config_param_in_file "${FILE}" "${SECTION}" "${NAME}" "${PARAM}" "${VALUE}"
    return $?
}

[ ${os_type} = Linux ] && \
set_config_param_in_file()
{
    # configuration file
    FILE="${1}"
    # section / resource type
    SECTION="${2}"
    # name of the section, currently ignored
    NAME="${3}"
    # parameter to set in the config file
    PARAM="${4}"
    # value to set
    VALUE="${5}"

    if [ ! -w "${FILE}" ]; then
        warn "failed to set parameter ${SECTION} ${NAME} ${PARAM} = ${VALUE}: can't access file '${FILE}'"
        return 1
    fi

    TEMP=`mktemp`
    $AWK -v SECTION="$SECTION" -v NAME="$NAME" -v PARAM="$PARAM" -v VALUE="$VALUE" '
  BEGIN {
    IGNORECASE = 1;
    FS = "=";
    # could add ; as Record Separator, but this may causes problems if line contains this character.
    #RS="\n|;"
    done = 0
    printed = 0
  };
  level == 1 && /}/ && resourcetype == SECTION && name == NAME && done == 0 {
        printf "  %s = %s\n", PARAM, VALUE
        printf "}\n"
        printed = 1
        done = 1
  };
  /}/ {
    resourcetype="";
    level--;
  };
  /{/ {
        level++;
  };
  level == 1 && /{/ {
        resourcetype=$1;
        gsub("[ {]","",resourcetype)
  };
  level == 1 && resourcetype == SECTION && $1 ~ /^[ ]*Name[ ]*$/ {
        name = $2
        gsub("[ \"]","",name)
        #printf "%s: %s\n", resourcetype, name
  };
  level == 1 && resourcetype == SECTION && name == NAME {
        param = $1
        gsub("[ \"]","",param)
        #printf "found %s => %s\n", param, $2
  };
  level == 1 && resourcetype == SECTION && name == NAME && param == PARAM {
        printf "%s= %s\n", $1, VALUE
        printed = 1
        done = 1
  };
  printed == 0 {
    print $0
  }
  printed == 1 {
    printed = 0
  }
    ' "$FILE" > "$TEMP"
    if [ $? -ne 0 ]; then
        warn "failed to set parameter ${SECTION} ${NAME} ${PARAM} = ${VALUE}: replace failed"
        rm "$TEMP"
        return 1
    fi

    chown --reference="${FILE}" "$TEMP"
    chmod --reference="${FILE}" "$TEMP"

    mv "$TEMP" "$FILE"
    if [ $? != 0 ]; then
        warn "failed to set parameter ${SECTION} ${NAME} ${PARAM} = ${VALUE}: replacing $FILE failed"
        rm -f "$TEMP"
        return 1
    fi
}

[ ${os_type} != Linux ] && \
set_config_param()
{
   echo "set_config_param() is not supported on this platform"
   exit 1
}


get_database_param()
{
    PARAM="${1-}"
    DEFAULT="${2-}"

    # use || to prevent errors
    rc=0
    temp_log="/tmp/bareos-config.$$.log"
    DBCHECK_OUTPUT=`$DBCHECK 2>> $temp_log` || rc=$?
    if [ $rc != 0 ]; then
        echo "${DBCHECK_OUTPUT}" >> $temp_log
        echo "Error: executing $DBCHECK" >> $temp_log
        echo "" >> $temp_log

        # if default value is given, return it anyway
        if [ -n "$DEFAULT" ]; then
            #info "unable to get \"${PARAM}\" from config, using default value \"${DEFAULT}\". Check $temp_log"
            echo "$DEFAULT"
        fi
        #else
        #    info "unable to get \"${PARAM}\" from config, this is usually not an error. Check $temp_log"
        #fi


        return 1
    fi

    # if $temp_log exists, but have only size 0, remove it.
    if [ -f $temp_log -a ! -s $temp_log ]; then
        rm $temp_log
    fi

    # DBCHECK gets the database parameter from the Director config file in a standard format,
    # however, it writes "db_name" (like the environment variables)
    # instead of "dbname" like in the config file.
    # Replace "db_" by "db" to be compatible with the config file.
    VALUE=`echo "$DBCHECK_OUTPUT" | sed "s/^db_/db/" | sed -n "s/^${PARAM}=//p"`

    [ -z "$VALUE" ] && VALUE="$DEFAULT"
    echo "$VALUE"
    return $rc
}

get_database_driver()
{
    DEFAULT="${1-}"
    get_database_param "dbdriver" "$DEFAULT" | grep -v "XXX_REPLACE_WITH_DATABASE_DRIVER_XXX"
    return $?
}

get_database_name()
{
    DEFAULT="${1-}"
    get_database_param "dbname" "$DEFAULT"
    return $?
}

get_database_user()
{
    DEFAULT="${1-}"
    get_database_param "dbuser" "$DEFAULT"
    return $?
}

get_database_password()
{
    DEFAULT="${1-}"
    get_database_param "dbpassword" "$DEFAULT"
    return $?
}

get_databases_installed()
{
    # manually check different backends, to get the correct order
    [ -f ${SQL_DDL_DIR}/creates/postgresql.sql ] && echo "postgresql"
    [ -f ${SQL_DDL_DIR}/creates/mysql.sql ] && echo "mysql"
    [ -f ${SQL_DDL_DIR}/creates/sqlite3.sql ] && echo "sqlite3"
    return 0
}

get_database_driver_default()
{
    if [ -n "$DBTYPE" ]; then
      DBDRIVER=$DBTYPE;
    else
      DBDRIVER=`get_database_driver`
    fi


    if [ -z "$DBDRIVER" ]; then
        DBDRIVER=`get_databases_installed | head -n 1`
    fi

    if [ -z "$DBDRIVER" ]; then
        # fallback and first choice
        DBDRIVER="postgresql"
    fi

    echo "$DBDRIVER"
}

initialize_database_driver()
{
    DBDRIVER=`get_database_driver_default`
    replace "XXX_REPLACE_WITH_DATABASE_DRIVER_XXX" "${DBDRIVER}"
}

is_template_sql_file()
{
    input_file=${1-}

    if [ -z "${input_file}" ]; then
        return 1
    fi

    egrep '@DB_NAME@|@DB_USER@|@DB_PASS@|@DB_VERSION@' ${input_file} > /dev/null 2>&1
    if [ $? != 0 ]; then
        # no variables found in file, this file is not a template.
        return 0
    else
        # variables found, this file is a template, therefore return FALSE
        return 1
    fi
}

get_translated_sql_file()
{
    # replaces variables in a SQL DDL file
    # and returns the result as stdout.

    input_file=${1-}

    if [ -z "${input_file}" ]; then
        return 1
    fi

    if [ ! -f ${input_file} ]; then
        return 2
    fi

    db_type="${db_type:-`get_database_driver_default`}"
    db_name="${db_name:-`get_database_name bareos`}"
    db_user="${db_user:-`get_database_user bareos`}"
    # if $db_password is defined but empty, an empty password will be used ("-" instead of ":-")
    db_password="${db_password-`get_database_password `}"
    db_version=`get_database_version`

    echo "$db_password" | grep '#' > /dev/null 2>&1
    if [ $? = 0 ]; then
        error "database passwords containing # are not supported."
        return 3
    fi

    case ${db_type} in
        sqlite3)
            ;;
        mysql)
            if [ "$db_password" != "" ]; then
                pass="IDENTIFIED BY '$db_password'"
            fi
            ;;
        postgresql)
            if [ "$db_password" != "" ]; then
                pass="PASSWORD '$db_password'"
            fi
            ;;
        ingres)
            if [ "$db_password" != "" ]; then
                pass="WITH PASSWORD = '$db_password'"
            fi
            ;;
        *)
            ;;
    esac

    sed -e "s#@DB_NAME@#${db_name}#" \
        -e "s#@DB_USER@#${db_user}#" \
        -e "s#@DB_PASS@#${pass}#" \
        -e "s#@DB_VERSION@#${db_version}#" \
        ${input_file}
}

get_database_grant_privileges()
{
    # Returns the DDL for granting privileges for a database user.
    # Can be used, to get the SQL commands
    # to create additional database users.
    # If requested, this user can be limited to read-only database access.

    #db_name="$1"
    db_type="${1:-${db_type:-`get_database_driver_default`}}"
    db_user="${2-}"
    db_password="${3-}"
    case "$4" in
        "")
            # full access
            privileges=""
            ;;
        "readonly")
            privileges="-readonly"
            ;;
        *)
            echo "Unknown privileges parameter $4"
            return 1
            ;;
    esac

    case ${db_type} in
        sqlite3)
            ;;
        mysql)
            sql_definitions="${SQL_DDL_DIR}/grants/mysql${privileges}.sql"
            ;;
        postgresql)
            sql_definitions="${SQL_DDL_DIR}/grants/postgresql${privileges}.sql"
            ;;
        ingres)
            sql_definitions="${SQL_DDL_DIR}/grants/ingres${privileges}.sql"
            ;;
        *)
            echo "Unknown database type $1"
            return 1
            ;;
    esac

    if [ ! -z "${sql_definitions}" ]; then
        if [ ! -f ${sql_definitions} ]; then
            echo "Unable to open database table definitions in file ${sql_definitions}"
            return 1
        fi
        get_translated_sql_file ${sql_definitions}
    fi

    return
}

translate_sql_files()
{
    # Translates all available DDL files for one database type.
    # However, currently not used, because it reduced flexibility.

    SOURCE_DIR=${1:-$SQL_DDL_DIR}
    DEST_DIR=${2:-"/var/db/bareos/working/ddl"}

    db_type="${db_type:-`get_database_driver_default`}"

    for i in `find "$SOURCE_DIR" -name "${db_type}*.sql" -print | cut -d'/' -f2-`; do
        dest_file=${DEST_DIR}/$i
        mkdir -p `dirname $dest_file`
        get_translated_sql_file ${SOURCE_DIR}/$i > $dest_file
        # in case of errors, remove file
        if [ $? != 0 ]; then
            rm -f $dest_file
        fi
    done
}

apply_dbconfig_settings()
{
    # this function is only useful on Debian Linux based distributions
    # as dbconfig-common is only available there

    # check if dbconfig configuration file exists
    [ -r "/etc/dbconfig-common/bareos-database-common.conf" ] || return 0
    . /etc/dbconfig-common/bareos-database-common.conf

    # check if dbconfig is enabled
    [ $dbc_install = 'true' ] && [ $dbc_upgrade = 'true' ] || return 0

    if [ -n "$dbc_dbuser" ]; then
        set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbuser" "$dbc_dbuser"
    fi

    if [ -n "$dbc_dbname" ]; then
        set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbname" "$dbc_dbname"
    fi

    case "$dbc_dbtype" in
        pgsql)
            set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbdriver" "postgresql"
            ;;
        mysql)
            set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbdriver" "mysql"
            ;;
        sqlite3)
            set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbdriver" "sqlite3"
            #   dbconfig creates the db file as ${dbc_basepath}/${dbc_dbname}
            #   while bareos expects the sqlite3 db file
            #   as ${dbc_basepath}/${dbc_dbname}.db
            # Therefore a link is created.
            if [ -r "${dbc_basepath}/${dbc_dbname}" ]; then
                BAREOS_SQLITE_DB="`get_working_dir`/`get_database_name $DB_NAME`.db"
                if [ ! -f $BAREOS_SQLITE_DB ]; then
                    ln -s "${dbc_basepath}/${dbc_dbname}" "$BAREOS_SQLITE_DB"
                fi
            fi
            ;;
        *)
            error "unknown database type $dbc_dbtype in /etc/dbconfig-common/bareos-database-common.conf"
            return 1
    esac

    if [ "$dbc_authmethod_user" != "ident" ] && [ "$dbc_dbpass" ]; then
        set_config_param "bareos-dir" "Catalog" "MyCatalog" "dbpassword" "$dbc_dbpass"
    fi
}

get_local_hostname()
{
    # put actual short hostname in configuration files
    # try to get short hostname
    hname=`hostname -s`
    if [ -z "$hname" ]; then
        # try to get long hostname
        hname=`hostname|sed 's/\..*//g'`
        if [ -z "$hname" ]; then
            # set to "localhost"
            hname='localhost'
        fi
    fi
    echo "$hname"
}

replace()
{
    if [ $# -ne 2 ]; then
        return 1
    fi

    SEARCH="$1"
    REPLACE="$2"

    for file in `grep -l ${SEARCH} ${BAREOS_CONFIG_DIR}/*.conf ${BAREOS_CONFIG_DIR}/bareos-*.d/*/*.conf ${BAREOS_CONFIG_DIR}/tray-monitor.d/*/*.conf 2>/dev/null`; do
        if [ -f "$file" ]; then
            if grep "${SEARCH}" "$file"; then
                # do a log-message only if file will be changed, not always
                echo "replacing '${SEARCH}' with '${REPLACE}' in $file"
                if [ "$os_type" = "Darwin" -o "$os_type" = "FreeBSD" ]; then
                     sed -i '' "s#${SEARCH}#${REPLACE}#g" "${file}"
                else
                     sed -i'' "s#${SEARCH}#${REPLACE}#g" "${file}"
                fi
            fi
        fi
    done
    return 0
}

initialize_local_hostname()
{
    #
    # Replace all XXX_REPLACE_WITH_LOCAL_HOSTNAME by the local hostname.
    #
    hname=`get_local_hostname`
    #replace "XXX_REPLACE_WITH_LOCAL_HOSTNAME_XXX-dir" "${hname}-dir"
    replace "XXX_REPLACE_WITH_LOCAL_HOSTNAME_XXX-fd" "${hname}-fd"
    #replace "XXX_REPLACE_WITH_LOCAL_HOSTNAME_XXX-sd" "${hname}-sd"
    #replace "XXX_REPLACE_WITH_LOCAL_HOSTNAME_XXX-mon" "${hname}-mon"
    replace "XXX_REPLACE_WITH_LOCAL_HOSTNAME_XXX" "${hname}"
}

replace_password()
{
    if [ $# -ne 2 ]; then
        return 1
    fi

    SEARCH="$1"
    REPLACE="$2"

    for file in `grep -l ${SEARCH} ${BAREOS_CONFIG_DIR}/*.conf ${BAREOS_CONFIG_DIR}/bareos-*.d/*/*.conf ${BAREOS_CONFIG_DIR}/tray-monitor.d/*/*.conf 2>/dev/null`; do
        echo "replacing '${SEARCH}' in $file"
        if [ "$os_type" = "Darwin" -o "$os_type" = "FreeBSD" ]; then
           sed -i '' "s#${SEARCH}#${REPLACE}#g" "${file}"
        else
           sed -i'' "s#${SEARCH}#${REPLACE}#g" "${file}"
        fi
        # following "sed -i" would work for GNU sed as well as BSD/Mac sed.
        # However, it creates a backup file.
        #sed -i.installer_backup "s#${SEARCH}#${REPLACE}#g" ${file}
    done
    return 0
}

initialize_passwords()
{
    #
    # See if we need to generate a set of random passwords.
    #
    if [ ! -f ${BAREOS_CONFIG_DIR}/.rndpwd ]; then
        for string in ${PASSWORD_SUBST}
        do
           pass=`RANDFILE=/dev/urandom openssl rand -base64 33`
           echo "${string}=${pass}" >> ${BAREOS_CONFIG_DIR}/.rndpwd
        done
        chmod 400 ${BAREOS_CONFIG_DIR}/.rndpwd
    fi

    # Source the passwords
    . ${BAREOS_CONFIG_DIR}/.rndpwd

    for string in ${PASSWORD_SUBST}
    do
        eval "pass=\${$string}"
        if [ ! -z "${pass}" ]; then
            replace_password "${string}" "${pass}"
        fi
    done
}

init()
{
    initialize_local_hostname
    #initialize_director_hostname
    initialize_passwords
    initialize_database_driver
}
