Ticket #4760: mythtv-database_backup_scripts.patch

File mythtv-database_backup_scripts.patch, 16.5 KB (added by sphery <mtdean@…>, 13 years ago)
  • programs/programs.pro

     
    1111}
    1212
    1313using_backend {
    14     SUBDIRS += mythbackend mythfilldatabase mythtv-setup
     14    SUBDIRS += mythbackend mythfilldatabase mythtv-setup scripts
    1515}
    1616
    1717using_frontend:using_backend {
  • programs/scripts/backup/database_mythconverg_backup.sh

     
     1#!/bin/sh
     2#
     3# database_mythconverg_backup.sh
     4#
     5# Creates a backup of the MythTV database.
     6#
     7# Usage:
     8#    database_mythconverg_backup.sh database_information_file
     9#
     10# This script will be called by mythbackend to create a backup of the MythTV
     11# database.  It will be passed a single command-line argument that provides the
     12# name of a file that contains database configuration information.  The
     13# database_information_file will contain name=value pairs specifying the
     14# following information:
     15#
     16#   DBHostName - The hostname on which the MySQL server is running
     17#   DBPort - The TCP/IP port number to use for the connection.  This may have a
     18#            value of 0, i.e. if the hostname is localhost or if the server is
     19#            using the default MySQL port.
     20#   DBUserName - The database username to use when connecting to the server.
     21#   DBPassword - The password to use when connecting to the server.
     22#   DBName - The name of the database that contains the MythTV data.
     23#   DBSchemaVer - The MythTV schema version of the database
     24#   DBBackupDirectory - The directory in which the backup file should be
     25#                       created.  This directory may have been specially
     26#                       configured by the user as the "DB Backups" storage
     27#                       group.  It is recommended that this directory be
     28#                       used--especially in "common-use" scripts such as those
     29#                       provided by distributions.
     30#   DBBackupFilename - The name of the file in which the backup should be
     31#                      created.  Additional extensions may be added as desired
     32#                      (i.e. adding ".gz" to the file if it's compressed).  If
     33#                      this file is used, it will be displayed in the GUI
     34#                      messages provided for the user.  If the file is not
     35#                      used, the user will not be told where to find the backup
     36#                      file.
     37#
     38# This script relies on the program mysqldump to create the database backup,
     39# awk to parse the database information file, sed to create a "defaults extra
     40# file" to provide the password to the database, and mktemp to securely create
     41# temporary files used to provide a password for mysqldump.  If sed is not
     42# available, the database password will be echo'ed to create the password file.
     43# Since echo is probably a shell builtin, it probably won't appear in process
     44# lists, but even if it does, it is not a long-running process.  If mktemp is
     45# not found, the password file will not be created, but the backup will be
     46# attempted anyway.  In this situation, adding a line "password=DBPassword" to
     47# the "[client]" and/or "[mysqldump]" section of the MySQL options file will
     48# allow the backup to succeed.  If available, gzip will be used to compress the
     49# database backup.
     50#
     51# The script may also be called without arguments, i.e. manually or from a cron
     52# job, to create a backup.  It will attempt to parse the MySQL configuration
     53# files to determine the database information.  If this is unsuccessful, simply
     54# providing a database information file in the format described above will
     55# allow the script to function properly.
     56#
     57# When customizing this script, you should ensure that the script's exit status
     58# reflects the results of the backup.  If the backup was successful, the script
     59# should return 0.  Any non-zero value is considered an error.
     60#
     61
     62# Specify the location of required programs
     63AWK='awk'
     64GZIP='gzip'
     65MKTEMP='mktemp'
     66MYSQLDUMP='mysqldump'
     67SED='sed'
     68
     69# Clean up temporary files, if they were created.
     70do_exit()
     71{
     72    if [ "x${DEFAULTS_EXTRA_FILE}" != "x" ]; then
     73        if [ -f ${DEFAULTS_EXTRA_FILE} ]; then
     74            rm -f ${DEFAULTS_EXTRA_FILE}
     75        fi
     76    fi
     77    if [ "x${TEMPORARY_DB_INFO_FILE}" != "x" ]; then
     78        if [ -f ${TEMPORARY_DB_INFO_FILE} ]; then
     79            rm -f ${TEMPORARY_DB_INFO_FILE}
     80        fi
     81    fi
     82}
     83
     84# Initialize the database information variables
     85# Allows the user to pass in data using environment variables for those values
     86# not specified in the database information file/configuration file (which will
     87# be used in preference to the values in the environment).
     88init_database_information ()
     89{
     90    if [ "x${DBHostName}" = "x" ]; then
     91        DBHostName="UNDEF"
     92    fi
     93    if [ "x${DBPort}" = "x" ]; then
     94        DBPort=-1
     95    fi
     96    if [ "x${DBUserName}" = "x" ]; then
     97        DBUserName="UNDEF"
     98    fi
     99    if [ "x${DBPassword}" = "x" ]; then
     100        DBPassword="UNDEF"
     101    fi
     102    if [ "x${DBName}" = "x" ]; then
     103        DBName="UNDEF"
     104    fi
     105    if [ "x${DBSchemaVer}" = "x" ]; then
     106        DBSchemaVer="UNDEF"
     107    fi
     108    if [ "x${DBBackupDirectory}" = "x" ]; then
     109        DBBackupDirectory="UNDEF"
     110    fi
     111    if [ "x${DBBackupFilename}" = "x" ]; then
     112        DBBackupFilename="UNDEF"
     113    fi
     114}
     115
     116# Read the database information file.
     117# Rather than just source the file, parse it and look for the expected database
     118# configuration information so we don't execute any commands in the file.
     119read_database_information_file()
     120{
     121    if [ ${#} -lt 1 ]; then
     122        echo "Usage: read_database_information_file database_information_file"
     123        return 2
     124    fi
     125    DB_INFO_FILE=${1}
     126    if [ "x${DB_INFO_FILE}" = "x" ]; then
     127        return 2
     128    fi
     129    if [ ${#} -eq 2 ]; then
     130        QUIET=${2}
     131    fi
     132    if [ ! -r ${DB_INFO_FILE} ]; then
     133        if [ "x${QUIET}" = "x" ]; then
     134            echo "${DB_INFO_FILE} does not exist or is not readable."
     135        fi
     136        return 4
     137    fi
     138    OLD_IFS=${IFS}
     139    IFS=$'\n'
     140    VALUES=(`${AWK} 'BEGIN {FS="="; DBHostName=DBPort=DBUserName=DBPassword=\
     141                            DBName=DBSchemaVer=DBBackupDirectory=\
     142                            DBBackupFilename="UNDEF"} \
     143                    /DBHostName/ {DBHostName=$2}; /DBPort/ {DBPort=$2}; \
     144                    /DBUserName/ {DBUserName=$2}; \
     145                    /DBPassword/ {DBPassword=$2}; \
     146                    /DBName/ {DBName=$2}; /DBSchemaVer/ {DBSchemaVer=$2}; \
     147                    /DBBackupDirectory/ {DBBackupDirectory=$2}; \
     148                    /DBBackupFilename/ {DBBackupFilename=$2}; \
     149                    END {printf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n", \
     150                         DBHostName, DBPort, DBUserName, DBPassword, \
     151                         DBName, DBSchemaVer, \
     152                         DBBackupDirectory, DBBackupFilename}' \
     153             "${DB_INFO_FILE}"`)
     154    if [ "x${VALUES[0]}" != "xUNDEF" ]; then
     155        DBHostName=${VALUES[0]}
     156    fi
     157    if [ "x${VALUES[1]}" != "xUNDEF" ]; then
     158        DBPort=${VALUES[1]}
     159    fi
     160    if [ "x${VALUES[2]}" != "xUNDEF" ]; then
     161        DBUserName=${VALUES[2]}
     162    fi
     163    if [ "x${VALUES[3]}" != "xUNDEF" ]; then
     164        DBPassword=${VALUES[3]}
     165    fi
     166    if [ "x${VALUES[4]}" != "xUNDEF" ]; then
     167        DBName=${VALUES[4]}
     168    fi
     169    if [ "x${VALUES[5]}" != "xUNDEF" ]; then
     170        DBSchemaVer=${VALUES[5]}
     171    fi
     172    if [ "x${VALUES[6]}" != "xUNDEF" ]; then
     173        DBBackupDirectory=${VALUES[6]}
     174    fi
     175    if [ "x${VALUES[7]}" != "xUNDEF" ]; then
     176        DBBackupFilename=${VALUES[7]}
     177    fi
     178    IFS=${OLD_IFS}
     179    return 0
     180}
     181
     182# Attempt to find database information in the MythTV config file(s)
     183# This is only used for "manual" execution of the backup script.  The backend
     184# will always provide a database information file, which will be used in
     185# preference to any other configuration files.
     186#
     187# Though we could use a hack to pull the database configuration info from the
     188# MythTV Perl bindings, the bindings require the backend to be running, so that
     189# approach would not be appropriate for a backup/restore script.
     190read_myth_config_file()
     191{
     192    if [ "x${MYTHCONFDIR}" = "x" -a "x${HOME}" != "x" ]; then
     193        MYTHCONFDIR=${HOME}/.mythtv
     194    fi
     195    if [ ! -d ${MYTHCONFDIR} ]; then
     196        unset MYTHCONFDIR
     197    fi
     198    # Prefer the config.xml/UPnP configuration
     199    DATABASE_INFORMATION_FILE=`${MKTEMP}`
     200    status=${?}
     201    TEMPORARY_DB_INFO_FILE="${DATABASE_INFORMATION_FILE}"
     202    if [ ${status} -eq 0 ]; then
     203        if [ -r "${MYTHCONFDIR}/config.xml" ]; then
     204            # Parse the config.xml with a quick regexp hack.  Since this is not
     205            # a full-fledged (or even half-fledged) XML parser, the parsing
     206            # could easily be broken by someone hacking their copy of the
     207            # config.xml file (i.e. having start and end tags on different
     208            # lines, etc.).
     209            ${SED} -n \
     210              -e 's|^.*<DBHostName>\(.\+\)</DBHostName>.*$|DBHostName=\1| p;' \
     211              -e 's|^.*<DBUserName>\(.\+\)</DBUserName>.*$|DBUserName=\1| p;' \
     212              -e 's|^.*<DBPassword>\(.\+\)</DBPassword>.*$|DBPassword=\1| p;' \
     213              -e 's|^.*<DBName>\(.\+\)</DBName>.*$|DBName=\1| p;' \
     214              -e 's|^.*<DBPort>\(.\+\)</DBPort>.*$|DBPort=\1| p;' \
     215              "${MYTHCONFDIR}/config.xml" \
     216                      > "${DATABASE_INFORMATION_FILE}" 2>/dev/null
     217            status=${?}
     218            if [ ${status} -eq 0 ]; then
     219                read_database_information_file "${DATABASE_INFORMATION_FILE}" \
     220                                               "quiet"
     221                status=${?}
     222                if [ ${status} -eq 0 ]; then
     223                    return 0
     224                fi
     225            fi
     226        fi
     227    fi
     228    # Since the config.xml file didn't provide the information, try looking for
     229    # a mysql.txt file.
     230    unset MYSQL_TEXT_FILE
     231    if [ "x{MYTHCONFDIR}" != "x" ]; then
     232        MYSQL_TEXT_FILE="${MYTHCONFDIR}/mysql.txt"
     233    fi
     234    loopstatus=2
     235    for file in /usr/{,local/}{share,etc}/mythtv/mysql.txt \
     236                "${MYSQL_TEXT_FILE}" ; do
     237        read_database_information_file "${file}" "quiet"
     238        status=${?}
     239        if [ ${status} -eq 0 ]; then
     240            loopstatus=0
     241            DATABASE_INFORMATION_FILE="${file}"
     242        fi
     243    done
     244    if [ ${loopstatus} -ne 0 ]; then
     245        echo "Unable to parse database information file."
     246        return ${loopstatus}
     247    fi
     248    return 0
     249}
     250
     251# Check DBUserName, DBPassword, and DBName and use defaults, if undefined.
     252check_database_information()
     253{
     254    if [ "x${DBUserName}" != "xUNDEF" ]; then
     255        DBUserName=mythtv
     256    fi
     257    if [ "x${DBPassword}" != "xUNDEF" ]; then
     258        DBPassword=mythtv
     259    fi
     260    if [ "x${DBName}" = "xUNDEF" ]; then
     261        DBName=mythconverg
     262    fi
     263}
     264
     265check_backup_location()
     266{
     267    if [ "x${DBBackupDirectory}" = "xUNDEF" ]; then
     268        if [ "x${MYTHCONFDIR}" != "x" ]; then
     269            DBBackupDirectory="${MYTHCONFDIR}/backup"
     270            if [ ! -d ${DBBackupDirectory} ]; then
     271                if [ -e ${DBBackupDirectory} ]; then
     272                    DBBackupDirectory=/tmp
     273                else
     274                    mkdir -p ${DBBackupDirectory}
     275                fi
     276            fi
     277        fi
     278        if [ ! -d ${DBBackupDirectory} -o ! -w ${DBBackupDirectory} ]; then
     279            DBBackupDirectory=/tmp
     280        fi
     281    fi
     282    if [ "x${DBBackupFilename}" = "xUNDEF" ]; then
     283        if [ "x${DBSchemaVer}" != "xUNDEF" ]; then
     284            SCHEMA_PART="-${DBSchemaVer}"
     285        fi
     286        DBBackupFilename="${DBName}${SCHEMA_PART}-`date +'%Y%m%d%H%M%S'`.sql"
     287    fi
     288
     289    if [ ! -d ${DBBackupDirectory} ]; then
     290        echo "${DBBackupDirectory} does not exist or is not a directory."
     291        return 8
     292    elif [ ! -w ${DBBackupDirectory} ]; then
     293        echo "${DBBackupDirectory} is not writable."
     294        return 16
     295    fi
     296    if [ -f "${DBBackupDirectory}/${DBBackupFilename}" ]; then
     297        # Exit if the file exists rather than overwrite the file.
     298        echo "${DBBackupDirectory}/${DBBackupFilename} already exists."
     299        # To allow overwriting a file, uncomment the following lines of code.
     300        # Note that doing so could be a serious security issue, especially if
     301        # running mythbackend as root.
     302#        if [ ! -w "${DBBackupDirectory}/${DBBackupFilename}" ]; then
     303#            echo "${DBBackupDirectory}/${DBBackupFilename} already exists"\
     304#                  "and is not writable."
     305            return 32
     306#        fi
     307    fi
     308
     309}
     310
     311# Create a temporary file to provide a password for mysqldump
     312create_defaults_extra_file()
     313{
     314    DEFAULTS_EXTRA_FILE=`${MKTEMP}` || return 1
     315    if [ "x${DATABASE_INFORMATION_FILE}" != "x" -a \
     316         "x${DEFAULTS_EXTRA_FILE}" != "x" ]; then
     317        # Rather than call echo with a command-line argument containing the
     318        # password, use sed to read/transform the ${DATABASE_INFORMATION_FILE}
     319        # contents to a ${DEFAULTS_EXTRA_FILE}
     320        ${SED} -n -e 's/^DBPassword=\(.\+\)/[client]\npassword=\1\n[mysqldump]\npassword=\1/ p' "${DATABASE_INFORMATION_FILE}" > "${DEFAULTS_EXTRA_FILE}" 2>/dev/null
     321        status=${?}
     322        if [ ${status} -eq 0 ]; then
     323            return 0
     324        fi
     325    fi
     326    # Give up on a "secure" approach and just echo the info.  Chances are echo
     327    # will be a shell builtin, so it won't make it to the process list, anyway.
     328    > ${DEFAULTS_EXTRA_FILE}
     329    echo "[client]" >> ${DEFAULTS_EXTRA_FILE}
     330    echo "password=${DBPassword}" >> ${DEFAULTS_EXTRA_FILE}
     331    echo "[mysqldump]" >> ${DEFAULTS_EXTRA_FILE}
     332    echo "password=${DBPassword}" >> ${DEFAULTS_EXTRA_FILE}
     333    return 0
     334}
     335
     336# Print a usage message
     337usage()
     338{
     339    echo "Usage:  ${0} [database_information_file]"
     340}
     341
     342unset DEFAULTS_EXTRA_FILE
     343unset TEMPORARY_DB_INFO_FILE
     344
     345init_database_information
     346
     347if [ ${#} -gt 1 ]; then
     348        usage
     349        do_exit 1
     350elif [ ${#} -eq 1 ]; then
     351    if [ "x${1}" = "x--help" ]; then
     352        usage
     353        do_exit 0
     354    else
     355        DATABASE_INFORMATION_FILE="${1}"
     356        read_database_information_file "${DATABASE_INFORMATION_FILE}"
     357        status=${?}
     358        if [ ${status} -ne 0 ]; then
     359            echo "Unable to parse database information file."
     360            do_exit ${status}
     361        fi
     362    fi
     363else
     364    read_myth_config_file
     365    status=${?}
     366    if [ ${status} -ne 0 ]; then
     367        echo "Unable to parse MythTV configuration files."
     368        do_exit ${status}
     369    fi
     370fi
     371
     372check_database_information
     373
     374check_backup_location
     375status=${?}
     376if [ ${status} -ne 0 ]; then
     377    do_exit ${status}
     378fi
     379
     380unset DEFAULTS_FILE_ARG
     381create_defaults_extra_file
     382if [ ${?} -eq 0 ]; then
     383    DEFAULTS_FILE_ARG="--defaults-extra-file=${DEFAULTS_EXTRA_FILE} "
     384fi
     385
     386unset HOST_ARG
     387if [ "x${DBHostName}" != "xUNDEF" ]; then
     388    HOST_ARG=" --host=${DBHostName}"
     389fi
     390unset PORT_ARG
     391if [ ${DBPort} -gt 0 ]; then
     392    PORT_ARG=" --port=${DBPort}"
     393fi
     394
     395${MYSQLDUMP} ${DEFAULTS_FILE_ARG}${HOST_ARG}${PORT_ARG} \
     396             --user="${DBUserName}" --add-drop-table --add-locks  \
     397             --allow-keywords --complete-insert --extended-insert \
     398             --lock-tables --no-create-db --quick \
     399    "${DBName}" > "${DBBackupDirectory}/${DBBackupFilename}" 2>/dev/null
     400status=${?}
     401
     402if [ ${status} -eq 0 -a \
     403    -e "${DBBackupDirectory}/${DBBackupFilename}" -a \
     404    ! -e "${DBBackupDirectory}/${DBBackupFilename}.gz" ]
     405then
     406    ${GZIP} "${DBBackupDirectory}/${DBBackupFilename}"
     407fi
     408
     409do_exit ${status}
  • programs/scripts/scripts.pro

    Property changes on: programs/scripts/backup/database_mythconverg_backup.sh
    ___________________________________________________________________
    Name: svn:executable
       + *
    
     
     1include ( ../../config.mak )
     2include ( ../../settings.pro )
     3
     4QMAKE_STRIP = echo
     5
     6TEMPLATE = app
     7CONFIG -= moc qt
     8
     9installscripts.path = $${PREFIX}/share/mythtv
     10installscripts.files = backup/*
     11
     12INSTALLS += installscripts
     13
     14SOURCES += dummy.c
  • programs/scripts/dummy.c

     
     1int main(void)
     2{
     3    return 0;
     4}