aboutsummaryrefslogtreecommitdiffstats
path: root/lbu.in
diff options
context:
space:
mode:
Diffstat (limited to 'lbu.in')
-rw-r--r--lbu.in554
1 files changed, 554 insertions, 0 deletions
diff --git a/lbu.in b/lbu.in
new file mode 100644
index 0000000..69770e2
--- /dev/null
+++ b/lbu.in
@@ -0,0 +1,554 @@
+#!/bin/sh
+
+# lbu - utility to create local backups.
+# Copyright (c) 2006 Natanael Copa
+# May be distributed under GPL2
+
+VERSION=2.0_alpha7
+sysconfdir=@sysconfdir@
+
+if [ ! -f ${libalpine:="./libalpine.sh"} ]; then
+ libalpine=/usr/share/lbu/libalpine.sh
+ if [ ! -f "$libalpine" ]; then
+ libalpine=/lib/libalpine.sh
+ fi
+fi
+. $libalpine || exit 1
+
+EXCLUDE_LIST="$sysconfdir"/exclude
+INCLUDE_LIST="$sysconfdir"/include
+
+DEFAULT_CIPHER="aes-256-cbc"
+
+LBU_CONF="$sysconfdir"/lbu.conf
+if [ -f "$LBU_CONF" ]; then
+ . "$LBU_CONF"
+fi
+
+UMOUNT_LIST=
+
+usage() {
+ echo "$PROGRAM $VERSION"
+ echo "usage: $PROGRAM <subcommand> [options] [args]
+
+Available subcommands:
+ commit (ci)
+ exclude (ex, delete)
+ include (inc, add)
+ list (ls)
+ package (pkg)
+ status (stat, st)
+ list-backup (lb)
+ revert
+
+Common options:
+ -h Show help for subcommand.
+ -q Quiet mode.
+ -v Verbose mode.
+"
+ exit 1
+}
+
+cleanup() {
+ local i
+ for i in $UMOUNT_LIST; do
+ umount $i
+ done
+}
+
+exit_clean() {
+ cleanup
+ exit 1
+}
+
+mount_once() {
+ if ! grep $1 /proc/mounts >/dev/null; then
+ mount $1 && UMOUNT_LIST="$1 $UMOUNT_LIST"
+ fi
+}
+
+# create backupfile
+backup_apkovl() {
+ local outfile="$1"
+ local d=$( date -u -r "$outfile" "+%Y%m%d%H%M%S" )
+ local backup=$(echo "$outfile" | sed "s/\.apkovl\.tar\.gz/.$d.tar.gz/")
+ vecho "Creating backup $backup"
+ if [ -z "$DRYRUN" ]; then
+ mv "$outfile" "$backup"
+ fi
+}
+
+# verify we have openssl if we want to encrypt
+check_openssl() {
+ [ -z "$ENCRYPTION" ] && return 0
+ OPENSSL=$(which openssl 2>/dev/null) || die "openssl was not found"
+
+ $OPENSSL list-cipher-commands | grep "^$ENCRYPTION$" > /dev/null \
+ || die "Cipher $ENCRYPTION is not supported"
+}
+
+# list_add(char *listfile, char* file...)
+list_add() {
+ local list="$1"
+ shift
+ mkdir -p `dirname "$list"`
+ while [ $# -gt 0 ] ; do
+ filename=`echo "$1" | sed 's:^/\+::'`
+ if grep "^$filename$" "$list" >/dev/null 2>&1 ; then
+ vecho "$filename is already in $list."
+ else
+ vecho "Adding $filename to $list."
+ echo "$filename" >> "$list"
+ fi
+ shift
+ done
+}
+
+# list_delete(char *listfile, char *file...)
+list_delete() {
+ local list="$1"
+ local tmp="$list.old"
+ shift
+ [ -f "$list" ] || return 1
+ while [ $# -gt 0 ] ; do
+ filename=`echo "$1" | sed 's:^/\+::'`
+ mv "$list" "$tmp"
+ vecho "Removing $filename from list."
+ grep -v "^$filename$" "$tmp" > "$list"
+ rm "$tmp"
+ shift
+ done
+}
+
+
+
+#
+# lbu_include - add/remove files to include list
+#
+usage_include() {
+ echo "$PROGRAM $VERSION
+Add filename(s) to include list ($sysconfdir/include)
+
+usage: $PROGRAM include|inc|add [-rv] <file> ...
+ $PROGRAM include|inc|add [-v] -l
+
+Options:
+ -l List contents of include list.
+ -r Remove specified file(s) from include list instead of adding.
+ -v Verbose mode.
+"
+ exit 1
+}
+
+cmd_include() {
+ if [ "$LIST" ] ; then
+ [ $# -gt 0 ] && usage_include
+ show_include
+ return
+ fi
+
+ [ $# -lt 1 ] && usage_include
+ if [ "$REMOVE" ] ; then
+ list_delete "$INCLUDE_LIST" "$@"
+ else
+ list_add "$INCLUDE_LIST" "$@"
+ list_delete "$EXCLUDE_LIST" "$@"
+ fi
+}
+
+show_include() {
+ if [ -f "$INCLUDE_LIST" ] ; then
+ vecho "Include files:"
+ cat "$INCLUDE_LIST"
+ fi
+}
+
+#
+# lbu_package - create a package
+#
+usage_package() {
+ echo "$PROGRAM $VERSION
+Create backup package.
+
+usage: $PROGRAM package|pkg -v [<dirname>|<filename>]
+
+Options:
+ -v Verbose mode.
+
+If <dirname> is a directory, a package named <hostname>.apkovl.tar.gz will
+be created in the specified directory.
+
+If <filename> is specified, and is not a direcotry, a package with the
+specified name willbe created.
+
+If <dirname> nor <filename> is not specified, a package named
+<hostname>.apkovl.tar.gz will be created in current work directory.
+"
+ exit 1
+}
+
+cmd_package() {
+ local pkg="$1"
+ local rc=0
+ local owd="$PWD"
+ local suff="apkovl.tar.gz"
+ local tmpdir tmppkg
+
+ check_openssl
+ init_tmpdir tmpdir
+
+ [ -n "$ENCRYPTION" ] && suff="$suff.$ENCRYPTION"
+
+ # find filename
+ if [ -d "$pkg" ] ; then
+ pkg="$pkg/$(hostname).$suff"
+ elif [ -z "$pkg" ]; then
+ pkg="$PWD/$(hostname).$suff"
+ fi
+
+ tmppkg="$tmpdir/$(basename $pkg)"
+
+ cd "${ROOT:-/}"
+ currentlist=$(apk audit --backup -q)
+ if [ -f var/lib/apk/world ]; then
+ currentlist="$currentlist var/lib/apk/world"
+ fi
+
+ # create tar archive
+ [ -f "$EXCLUDE_LIST" ] && excl="-X $EXCLUDE_LIST"
+ [ -f "$INCLUDE_LIST" ] && incl="-T $INCLUDE_LIST"
+ if [ -n "$VERBOSE" ]; then
+ echo "Archiving the following files:" >&2
+ # we dont want to mess the tar output with the
+ # password prompt. Lets get the tar output first.
+ tar $excl $incl -c -v $currentlist > /dev/null
+ rc=$?
+ fi
+ if [ $rc -eq 0 ]; then
+ if [ -z "$ENCRYPTION" ]; then
+ tar $excl $incl -c $currentlist | gzip -c >"$tmppkg"
+ rc=$?
+ else
+ set -- enc "-$ENCRYPTION" -salt
+ [ -n "$PASSWORD" ] && set -- "$@" -pass pass:"$PASSWORD"
+ tar $excl $incl -c $currentlist | gzip -c \
+ | $OPENSSL "$@" > "$tmppkg"
+ rc=$?
+ fi
+ fi
+ cd "$owd"
+
+ # actually commit unless dryrun mode
+ if [ $rc -eq 0 ]; then
+ if [ -z "$DRYRUN" ]; then
+ if [ "x$pkg" = "x-" ]; then
+ cat "$tmppkg"
+ else
+ cp "$tmppkg" "$pkg"
+ fi
+ fi
+ vecho "Created $pkg"
+ fi
+ return $rc
+}
+
+#
+# lbu list - list files that would go to archive
+#
+usage_list() {
+ echo "$PROGRAM $VERSION
+Lists files that would go to tar package. Same as: 'lbu package -v /dev/null'
+
+usage: $PROGRAM list|ls
+"
+ exit 1
+}
+
+cmd_list() {
+ VERBOSE="-v"
+ cmd_package /dev/null
+}
+
+#
+# lbu_commit - commit config files to writeable media
+#
+usage_commit() {
+ echo "$PROGRAM $VERSION
+Create a backup of config to writeable media.
+
+usage: $PROGRAM commit|ci [-nv] [<media>]
+
+Options:
+ -d Remove old apk overlay files.
+ -e Protect configuration with a password.
+ -n Don't commit, just show what would have been commited.
+ -p <password> Give encryption password on the command-line
+ -v Verbose mode.
+
+The following values for <media> is supported: floppy usb
+If <media> is not specified, the environment variable LBU_MEDIA will be used.
+
+Password protection will use $DEFAULT_CIPHER encryption. Other ciphers can be
+used by setting the DEFAULT_CIPHER or ENCRYPTION environment variables.
+For possible ciphers, try: openssl -v
+
+The password used to encrypt the file, can either be specified with the -p
+option or using the PASSWORD environment variable.
+
+The environment varialbes can also be set in $LBU_CONF
+"
+ exit 1
+}
+
+cmd_commit() {
+ local media mnt statuslist tmplist currentlist
+ local incl excl outfile ovls lines
+
+ check_openssl
+
+ # turn on verbose mode if dryrun
+ [ -n "$DRYRUN" ] && VERBOSE="-v"
+
+ # find what media to use
+ media="${1:-$LBU_MEDIA}"
+ [ -z "$media" ] && usage_commit
+
+ # mount media unles its already mounted
+ mnt=/media/$media
+ [ -d "$mnt" ] || usage
+ mount_once "$mnt" || die "failed to mount $mnt"
+
+ # find the outfile
+ outfile="$mnt/$(hostname).apkovl.tar.gz"
+ if [ -n "$ENCRYPTION" ]; then
+ outfile="$outfile.$ENCRYPTION"
+ fi
+
+
+ # remove old config files
+ if [ -n "$DELETEOLDCONFIGS" ] ; then
+ local rmfiles=$(ls "$mnt/"*.apkovl.tar.gz* 2>/dev/null)
+ if [ -n "$rmfiles" ] ; then
+ if [ -n "$VERBOSE" ]; then
+ echo "Removing old apk overlay files:" >&2
+ echo "$rmfiles"
+ echo "" >&2
+ fi
+ [ -z "$DRYRUN" ] && rm "$mnt/"*.apkovl.tar.gz*
+ fi
+ else
+ lines=$(ls -1 "$mnt"/*.apkovl.tar.gz* 2>/dev/null)
+ if [ "$lines" = "$outfile" ]; then
+ backup_apkovl "$outfile"
+ elif [ -n "$lines" ]; then
+ # More then one apkovl, this is a security concern
+ cleanup
+ eecho "The following apkovl file(s) were found:"
+ eecho "$lines"
+ eecho ""
+ die "Please use -d to replace."
+ fi
+ fi
+
+ # create package
+ if ! cmd_package "$outfile"; then
+ cleanup
+ die "Problems creating archive. aborting"
+ fi
+
+ # delete old backups if needed
+ # poor mans 'head -n -N' done with awk.
+ ls "$mnt"/$(hostname).[0-9][0-9][0-9][0-9]*[0-9].tar.gz 2>/dev/null \
+ | awk '{ a[++i] = $0; } END {
+ print a[0];
+ while (i-- > '"${BACKUP_LIMIT:-0}"') {
+ print a[++j]
+ }
+ }' | xargs rm 2>/dev/null
+
+ # remove obsolete file. some older version of alpine needs this
+ # to be ble to upgrade
+ if [ -z "$DRYRUN" ] && [ -f $mnt/packages.list ]; then
+ echo "Note: Removing packages.list from $(basename $mnt)."
+ echo " $PACKAGES_LIST will be used."
+ rm -f $mnt/packages.list
+ fi
+
+ # make sure data is written
+ sync
+ [ "$media" = "floppy" ] && sleep 1
+
+ # move current to commited.
+ vecho "Successfully saved apk overlay files"
+}
+
+#---------------------------------------------------------------------------
+# lbu_exclude - add remove file(s) from exclude list
+
+usage_exclude() {
+ echo "$PROGRAM $VERSION
+Add filename(s) to exclude list ($sysconfdir/exclude)
+
+usage: $PROGRAM exclude|ex|delete [-rv] <file> ...
+ $PROGRAM exclude|ex|delete [-v] -l
+
+Options:
+ -l List contents of exclude list.
+ -r Remove specified file(s) from exclude list instead of adding.
+ -v Verbose mode.
+"
+ exit 1
+}
+
+cmd_exclude() {
+ if [ "$LIST" ] ; then
+ [ $# -gt 0 ] && usage_exclude
+ show_exclude
+ return
+ fi
+
+ [ $# -lt 1 ] && usage_exclude
+ if [ "$REMOVE" ] ; then
+ list_delete "$EXCLUDE_LIST" "$@"
+ else
+ list_delete "$INCLUDE_LIST" "$@"
+ list_add "$EXCLUDE_LIST" "$@"
+ fi
+}
+
+show_exclude() {
+ if [ -f "$EXCLUDE_LIST" ] ; then
+ vecho "Exclude files:"
+ cat "$EXCLUDE_LIST"
+ fi
+}
+
+#---------------------------------------------------------------------------
+# lbu_listbackup - Show old commits
+usage_listbackup() {
+ cat <<EOF
+$PROGRAM $VERSION
+Show old commits.
+
+usage: $PROGRAM list-backup [<media>]
+
+EOF
+ exit 1
+}
+
+cmd_listbackup() {
+ local media=${1:-"$LBU_MEDIA"}
+ local mnt="/media/$media"
+ [ -z "$media" ] && usage_listbackup
+
+ mount_once "$mnt" || die "failed to mount $mnt"
+ ls -1 "$mnt"/*.[0-9][0-9]*[0-9][0-9].tar.gz* 2>/dev/null | sed 's:.*/::'
+}
+
+#---------------------------------------------------------------------------
+# lbu_revert - revert to old config
+usage_revert() {
+ cat <<EOF
+$PROGRAM $VERSION
+Revert to older commit.
+
+usage: $PROGRAM revert <REVISION> [<media>]
+
+The revision should be one of the files listed by 'lbu list-backup'.
+
+EOF
+}
+
+cmd_revert() {
+ local media=${2:-"$LBU_MEDIA"}
+ [ -z "$media" ] && usage_revert
+ local mnt="/media/$media"
+ local revertto="$mnt/$1"
+ local current="$mnt/$(hostname).apkovl.tar.gz"
+
+ if [ -n "$ENCRYPTION" ]; then
+ current="$current.$ENCRYPTION"
+ fi
+ mount_once "$mnt" || die "failed to mount $mnt"
+ [ -f "$revertto" ] || die "file not found: $revertto"
+ backup_apkovl "$current"
+ vecho "Reverting to $1"
+ [ -z "$DRYRUN" ] && mv "$revertto" "$current"
+}
+
+#---------------------------------------------------------------------------
+# lbu_status - check what files have been changed since last save
+usage_status() {
+ echo "$PROGRAM $VERSION
+Check what files have been changed since last commit.
+
+usage: $PROGRAM status|st [-av]
+
+Options:
+ -a Compare all files, not just since last commit.
+ -v Also show include and exclude lists.
+"
+ exit 1
+}
+
+
+
+#-----------------------------------------------------------
+# Main
+
+cmd=`echo "$PROGRAM" | cut -s -d_ -f2`
+PROGRAM=`echo "$PROGRAM" | cut -d_ -f1`
+if [ -z "$cmd" ] ; then
+ cmd="$1"
+ [ -z "$cmd" ] && usage
+ shift
+fi
+
+# check for valid sub command
+case "$cmd" in
+ include|inc|add) SUBCMD="include";;
+ commit|ci) SUBCMD="commit";;
+ exclude|ex|delete) SUBCMD="exclude";;
+ list|ls) SUBCMD="list";;
+ package|pkg) SUBCMD="package";;
+ status|stat|st) SUBCMD="status";;
+ list-backup|lb) SUBCMD="listbackup";;
+ revert) SUBCMD="revert";;
+ *) usage;;
+esac
+
+# parse common args
+while getopts "adehlM:np:qrv" opt ; do
+ case "$opt" in
+ a) [ $SUBCMD = status ] || usage_$SUBCMD
+ USE_DEFAULT="-a"
+ ;;
+ d) DELETEOLDCONFIGS="yes"
+ ;;
+ e) [ -z "$ENCRYPTION" ] && ENCRYPTION="$DEFAULT_CIPHER"
+ ;;
+ h) usage_$SUBCMD
+ ;;
+ l) LIST="-l"
+ ;;
+ n) [ $SUBCMD = commit ] || usage_$SUBCMD
+ DRYRUN="-n"
+ ;;
+ p) PASSWORD="$OPTARG"
+ ;;
+ q) QUIET="$QUIET -q"
+ ;;
+ r) REMOVE="-r"
+ ;;
+ v) VERBOSE="$VERBOSE -v"
+ ;;
+ esac
+done
+shift `expr $OPTIND - 1`
+
+trap exit_clean SIGINT SIGTERM
+cmd_$SUBCMD "$@"
+retcode=$?
+
+cleanup
+exit $retcode