created ninjahelper

This commit is contained in:
Elijah Saxon 2005-07-04 06:39:00 +00:00
parent 2046272df5
commit 4c8e283994
6 changed files with 687 additions and 0 deletions

182
handlers/easydialog.sh Normal file
View File

@ -0,0 +1,182 @@
#!/bin/bash
# copyright 2002 lmoore@tump.com under the terms of the GNU LGPL.
# whiptail has trouble being called in the foo=$(whiptail ...) fashion for
# some reason. this is very annoying. this means that we need to use
# temporary files to store the answers from the input and list based boxes
# and then read the answers into a REPLY variable. that just really
# stinks, oh well, that's what you get when you have a weak link
# implementation...
#
# inputBox and passwordBox could be refactored to use a common function
test -z "$WIDTH" && WIDTH=0
test -z "$HEIGHT" && HEIGHT=0
BACKTITLE=""
DIALOG=dialog
HELP=
setApplicationTitle() {
BACKTITLE=$*
}
setHelp() {
HELP="$@"
}
setDimension() {
WIDTH=$1
HEIGHT=$2
}
booleanBox() {
$DIALOG --backtitle "$BACKTITLE" --title "$1" \
--yesno "$2" $HEIGHT $WIDTH
}
msgBox() {
$DIALOG --backtitle "$BACKTITLE" --title "$1" \
--msgbox "$2" $HEIGHT $WIDTH
}
gaugeBox() {
$DIALOG --backtitle "$BACKTITLE" --title "$1" \
--gauge "$2" $HEIGHT $WIDTH 0
}
inputBox() {
local temp=$(mktemp -t) || exit 1
trap "rm -f $temp" 0
REPLY=
$DIALOG --backtitle "$BACKTITLE" --title "$1" \
--inputbox "$2" $HEIGHT $WIDTH "$3" 2> $temp
local status=$?
[ $status = 0 ] && REPLY=$(cat $temp)
rm -f $temp
return $status
}
# Xdialog and {dialog,whiptail} use different mechanism to "qoute" the
# values from a checklist. {dialog,whiptail} uses standard double quoting
# while Xdialog uses a "/" as the separator. the slash is arguably better,
# but the double quoting is more standard. anyway, this function can be
# overridden to allow a derived implementation to change it's quoting
# mechanism to the standard double-quoting one. it receives two
# arguements, the file that has the data and the box type.
_listReplyHook() {
cat $1
}
# this is the base implementation of all the list based boxes, it works
# out nicely that way. the real function just passes it's arguments to
# this function with an extra argument specifying the actual box that
# needs to be rendered.
_genericListBox() {
local box=$1
shift 1
local title=$1
local text=$2
shift 2
local temp=$(mktemp -t) || exit 1
trap "rm -f $temp" 0
REPLY=
$DIALOG $HELP --backtitle "$BACKTITLE" --title "$title" \
$box "$text" $HEIGHT $WIDTH 10 \
"$@" 2> $temp
local status=$?
[ $status = 0 ] && REPLY=$(_listReplyHook $temp $box)
rm -f $temp
return $status
}
menuBox() {
_genericListBox --menu "$@"
}
menuBoxHelp() {
HELP="--item-help"
_genericListBox --menu "$@"
status=$?
HELP=
return $status
}
menuBoxHelpFile() {
HELP="--help-button"
_genericListBox --menu "$@"
status=$?
HELP=
return $status
}
checkBox() {
_genericListBox --checklist "$@"
}
radioBox() {
_genericListBox --radiolist "$@"
}
textBox() {
$DIALOG --backtitle "$BACKTITLE" --title "$1" --textbox "$2" $HEIGHT $WIDTH
}
passwordBox() {
local temp=$(mktemp -t) || exit 1
trap "rm -f $temp" 0
REPLY=
$DIALOG --backtitle "$BACKTITLE" --title "$1" \
--passwordbox "$2" $HEIGHT $WIDTH 2> $temp
local status=$?
[ $status = 0 ] && REPLY=$(cat $temp)
rm -f $temp
return $status
}
_form_gap=2
startForm() {
_form_title=$1
_form_items=0
_form_labels=
_form_text=
}
formItem() {
_form_labels[$_form_items]=$1
_form_text[$_form_items]=$2
let "_form_items += 1"
}
displayForm() {
local temp=$(mktemp -t) || exit 1
max_length=0
for ((i=0; i < ${#_form_labels[@]} ; i++)); do
label=${_form_labels[$i]}
length=`expr length $label`
if [ $length -gt $max_length ]; then
max_length=$length
fi
done
let "max_length += 2"
local form=
local xpos=1
for ((i=0; i < $_form_items ; i++)); do
label=${_form_labels[$i]}
text=${_form_text[$i]}
if [ "$text" == "" ]; then
text='_empty_'
fi
form=`echo -e "$form $label $xpos 1" $text "$xpos $max_length 30 30"`
let "xpos += _form_gap"
done
$DIALOG --form "$_form_title" 0 0 20 $form 2> $temp
local status=$?
[ $status = 0 ] && REPLY=$(cat $temp)
rm -f $temp
return $status
}

75
handlers/ldap.helper Normal file
View File

@ -0,0 +1,75 @@
ldap_create_file() {
while true; do
checkBox "ldap action wizard" "check options (slapcat OR ldapsearch)" \
"slapcat" "export ldif using slapcat" on \
"ldapsearch" "export ldif using ldapsearch" off \
"compress" "compress the ldif output files" on
status=$?
compress="compress = off"
method="method = <unset>"
restart="restart = no"
binddn=""
passwordfile=""
[ $status = 1 ] && return;
result="$REPLY"
for opt in $result; do
case $opt in
'"compress"') compress="compress = on";;
'"slapcat"')
method="method = slapcat"
[ "$_RESTART" == "yes" ] && restart="restart = yes"
;;
'"ldapsearch"')
method="method = ldapsearch"
inputBox "ldap action wizard" "ldapsearch requires authentication. Specify here what password file to use. It must have the password with no trailing return and it should not be world readable."
[ $? = 1 ] && return
passwordfile="passwordfile = $REPLY"
inputBox "ldap action wizard" "ldapsearch requires authentication. Specify here what DN to bind as:"
[ $? = 1 ] && return
binddn="binddn = $REPLY"
require_packages ldap-utils
;;
esac
done
get_next_filename $configdirectory/30.ldap
cat > $next_filename <<EOF
$method
$compress
$restart
$binddn
$passwordfile
# backupdir = /var/backups/ldap
# conf = /etc/ldap/slapd.conf
# databases = all
EOF
chmod 000 $next_filename
return
done
}
ldap_wizard() {
bdb=no
ldbm=no
for backend in `grep -e "^backend" /etc/ldap/slapd.conf | awk '{print $2}'`; do
if [ "$backend" == "bdb" -a "$bdb" == "no" ]; then
bdb=yes
elif [ "$backend" == "ldbm" -a "$ldbm" == "no" ]; then
ldbm=yes
fi
done
if [ "$bdb" == "yes" -a "$ldbm" == "no" ]; then
msgBox "ldap action wizard" "It looks like the backend in your slapd.conf is set to BDB. If this is not the case, exit this wizard! From this point on, we will assume BDB backend, which might have disasterious consequences if this is incorrect."
_RESTART=no
ldap_create_file
elif [ "$ldbm" == "yes" ]; then
msgBox "ldap action wizard" "It looks like the backend in your slapd.conf is set to LDBM. Because of this, you will have less options (because it is not safe to use slapcat while slapd is running LDBM)."
_RESTART=yes
ldap_create_file
else
msgBox "ldap action wizard" "I couldn't find any backends in your slapd.conf. Bailing out."
return
fi
}

109
handlers/mysql.helper Normal file
View File

@ -0,0 +1,109 @@
do_mysql_user() {
inputBox "mysql action wizard" "specify a system user:"
do_mysql_final "user = $REPLY"
}
do_mysql_password() {
inputBox "mysql action wizard" "specify a mysql user:"
user=$REPLY
inputBox "mysql action wizard" "specify the mysql user's password:"
password=$REPLY
do_mysql_final "dbusername = $user\ndbpassword = $password"
}
do_mysql_debian() {
_DISABLE_HOTCOPY=yes
do_mysql_final "configfile = /etc/mysql/debian.cnf"
}
do_mysql_user() {
inputBox "mysql action wizard" "what system user does mysql backup use?"
do_mysql_final "user = $REPLY"
}
do_mysql_final() {
if [ -z "$_DISABLE_HOTCOPY" ]; then
checkBox "mysql action wizard" "check options" \
"sqldump" "create a backup using mysqldump (more compat)." off \
"hotcopy" "create a backup using mysqlhotcopy (faster)." on \
"compress" "compress the sql output files" on
status=$?
sqldump="sqldump = off"
hotcopy="hotcopy = off"
else
checkBox "mysql action wizard" "check options" \
"compress" "compress the sql output files" on
status=$?
sqldump="sqldump = on"
hotcopy="hotcopy = off"
fi
[ $status = 1 ] && return;
result="$REPLY"
compress="compress = off"
for opt in $result; do
case $opt in
'"sqldump"') sqldump="sqldump = on";;
'"hotcopy"') hotcopy="hotcopy = on";;
'"compress"') compress="compress = on";;
esac
done
get_next_filename $configdirectory/20.mysql
echo -e $@ > $next_filename
cat >> $next_filename <<EOF
$sqldump
$hotcopy
$compress
# databases = all
# backupdir = /var/backups/mysql
# dbhost = localhost
EOF
chmod 000 $next_filename
}
mysql_wizard() {
while true; do
_DISABLE_HOTCOPY=
menuBoxHelpFile "mysql action wizard" "choose a mysql authentication method:" \
user "change to a linux user first." \
password "manually specify mysql user and password." \
debian "use default mysql user debian-sys-maint."
status=$?
if [ $status = 2 ]; then
# show help.
helptmp="/tmp/backupninja.help.$$"
cat > $helptmp <<EOF
To connect to mysql, backupninja must authenticate.
There are three possible authentication methods:
USER
With this method, you specify a system user. Backupninja will
then become this user before running mysqldump or mysqlhotcopy.
The result is that ~/.my.cnf is used for authentication.
PASSWORD
With this method, you manually specify a mysql user and
password in the backup action configuration.
DEBIAN
With this method, we use the debian-sys-maint user which is
already defined in /etc/mysql/debian.cnf. If you are running
debian, this is recommended, because no further configuration
is needed. The drawback is that this is incompatible with
mysqlhotcopy: you must use mysqldump.
EOF
dialog --textbox $helptmp 0 0
rm $helptmp
fi
[ $status = 1 ] && return;
result="$REPLY"
case "$result" in
"user") do_mysql_user;return;;
"password") do_mysql_password;return;;
"debian") do_mysql_debian;return;;
esac
done
}

69
handlers/rdiff.helper Normal file
View File

@ -0,0 +1,69 @@
rdiff_wizard() {
require_packages rdiff-backup
startForm "rdiff action wizard"
formItem "keep" "60D"
formItem "dest_directory" "/backups/mybackup"
formItem "dest_host" "backuphost"
formItem "dest_user" "backupuser"
displayForm
[ $? = 1 ] && return;
set -- $REPLY
keep=$1
directory=$2
host=$3
user=$4
startForm "rdiff action wizard: includes"
formItem include /var/spool/cron/crontabs
formItem include /var/backups
formItem include /etc
formItem include /root
formItem include /home
formItem include /usr/local/__star__bin
formItem include /var/lib/dpkg/status__star__
formItem include
formItem include
formItem include
displayForm
[ $? = 1 ] && return;
includes=
for i in $REPLY; do
[ "$i" != "_empty_" ] && includes="$includes\ninclude = $i"
done
startForm "rdiff action wizard: excludes"
formItem exclude /home/__star__/.gnupg
formItem exclude
formItem exclude
displayForm
[ $? = 1 ] && return;
excludes=
for i in $REPLY; do
[ "$i" != "_empty_" ] && excludes="$excludes\nexclude = $i"
done
get_next_filename $configdirectory/90.rdiff
cat > $next_filename <<EOF
[source]
type = local
keep = $keep
EOF
echo -e $includes >> $next_filename
echo -e $excludes >> $next_filename
cat >> $next_filename <<EOF
[dest]
type = remote
directory = $directory
host = $host
user = $user
EOF
chmod 000 $next_filename
}

31
handlers/sys.helper Normal file
View File

@ -0,0 +1,31 @@
sys_wizard() {
require_packages hwinfo
checkBox "new sys action" "check options" \
"packages" "list of all installed packages." on \
"partitions" "the partition table of all disks." on \
"hardware" "detailed hardware information" on
[ $? = 1 ] && return;
result="$REPLY"
packages="packages = off"
partitions="partitions = off"
hardware="hardware = off"
for opt in $result; do
case $opt in
'"packages"') packages="packages = on";;
'"partitions"') partitions="partitions = on";;
'"hardware"') hardware="hardware = on";;
esac
done
get_next_filename $configdirectory/10.sys
cat > $next_filename <<EOF
$packages
$partitions
$hardware
# databases = all
# backupdir = /var/backups/mysql
# dbhost = localhost
EOF
chmod 000 $next_filename
}

221
ninjahelper Executable file
View File

@ -0,0 +1,221 @@
#!/bin/bash
####################################################
## Functions
##
## returns the next available file name given a file
## in the form /etc/backup.d/10.sys
## sets variable $returned_filename
##
get_next_filename() {
next_filename=$1
dir=`dirname $next_filename`
file=`basename $next_filename`
number=${file:0:2}
suffix=${file:3}
while [ -f $next_filename ]; do
let "number += 1"
next_filename="$dir/$number.$suffix"
done
}
##
## installs packages (passed in as $@) if not present
##
require_packages() {
for pkg in "$@"; do
installed=`dpkg -s $pkg | grep 'ok installed'`
if [ -z "$installed" ]; then
booleanBox "install $pkg?" "This backup action requires package $pkg. Do you want to install it now?"
if [ $? = 0 ]; then
apt-get install $pkg
echo "hit return to continue...."
read
fi
fi
done
}
doradiobox() {
defaultchoice="red is.pretty on"
choices="green is_nice_too off blue i_love_blue off yellow is.bright off orange make.me.hungry off"
radioBox "radio title" "choose one color" $defaultchoice $choices
case $? in
0) ;;
1) echo "color choice cancelled..."; sleep 1;;
255) echo "something went wrong, exiting..."
exit 1 ;;
esac
result="$REPLY"
msgBox "message title" "you said $result."
}
donew() {
menuBox "new action menu" "select an action to create" \
return "return to main menu" \
sys "general hardware and system info" \
mysql "mysql database backup" \
ldap "ldap database backup" \
rdiff "incremental filesystem backup"
[ $? = 1 ] && return;
result="$REPLY"
case "$result" in
"sys") sys_wizard;;
"mysql") mysql_wizard;;
"ldap") ldap_wizard;;
"rdiff") rdiff_wizard;;
"return") return;;
esac
}
do_rm_action() {
booleanBox "remove action" "Are you sure you want to remove action file $1?"
if [ $? = 0 ]; then
rm $1;
fi
}
do_run() {
backupninja --run $1
echo "Hit return to continue..."
read
}
do_run_test() {
backupninja --test --run $1
echo "Hit return to continue..."
read
}
do_disable() {
dir=`dirname $1`
base=`basename $1`
mv $dir/$base $dir/0-$base
}
do_enable() {
dir=`dirname $1`
base=`basename $1`
mv $dir/$base $dir/${base:2}
}
do_rename() {
dir=`dirname $1`
filename=`basename $1`
inputBox "rename action" "enter a new filename" $filename
mv $dir/$filename $dir/$REPLY
}
doaction() {
action=$1
base=`basename $action`
if [ "${base:0:2}" == "0-" ]; then
enable="enable";
else
enable="disable";
fi
while true; do
menuBox "action menu" "$action $first" \
main "return to main menu" \
view "view configuration" \
xedit "launch external editor" \
$enable "$enable action" \
name "change the filename" \
run "run this action now" \
test "do a test run" \
kill "remove this action"
[ $? = 1 ] && return;
result="$REPLY"
case "$result" in
"view") dialog --textbox $action 0 0;;
"xedit") $EDITOR $action;;
"disable") do_disable $action; return;;
"enable") do_enable $action; return;;
"name") do_rename $action; return;;
"run") do_run $action;;
"test") do_run_test $action;;
"kill") do_rm_action $action; return;;
"main") return;;
esac
done
}
#####################################################
## begin program
conffile="/etc/backupninja.conf"
if [ ! -r "$conffile" ]; then
echo "Configuration file $conffile not found."
exit 1
fi
scriptdir=`grep scriptdirectory $conffile | awk '{print $3}'`
if [ ! -n "$scriptdir" ]; then
echo "Cound not find entry 'scriptdirectory' in $conffile"
exit 1
fi
if [ ! -d "$scriptdir" ]; then
echo "Script directory $scriptdir not found."
exit 1
fi
configdirectory=`grep configdirectory $conffile | awk '{print $3}'`
if [ ! -n "$configdirectory" ]; then
echo "Cound not find entry 'configdirectory' in $conffile"
exit 1
fi
if [ ! -d "$configdirectory" ]; then
echo "Configuration directory $configdirectory not found."
exit 1
fi
. $scriptdir/easydialog.sh
if [ "$UID" != "0" ]; then
msgBox "warning" "ninjahelper must be run by root!"
exit 1
fi
for file in `find $scriptdir -follow -name '*.helper'`; do
. $file
done
setApplicationTitle "ninjahelper"
setDimension 75 19
#####################################################
## main event loop
while true; do
menulist=
action=
let "i = 1"
for file in `find $conf/etc/backup.d/ -type f | sort -n`; do
menulist="$menulist $i $file"
actions[$i]=$file
let "i += 1"
done
menuBox "main menu" "select an action to edit" $menulist \
new "create a new backup action" \
quit "leave ninjahelper"
[ $? = 1 -o $? = 255 ] && exit 0;
choice="$REPLY"
if [ "$choice" == "new" ]; then
donew;
elif [ "$choice" == "quit" ]; then
exit 0;
else
action=${actions[$choice]};
if [ -f "$action" ]; then
doaction $action
else
msgBox "error" "error: cannot find the file '$action'"
fi
fi
done