#!/bin/sh
##
## Do ad-hoc backup LDAP data from OpenLDAP server (slapd) into LDIF
##
## Copyright (c) 2006-2007 SATOH Fumiyasu @ OSS Technology, Japan
##                         <http://www.osstech.co.jp/>
##
## Date: 2006-06-09, since 2006-04-07
##

## NOTE:
##	OpenLDAP has no way to do completely online-backup.
##	I think that this script is not usefull in few cases,
##	but is usefull in most cases.

set -e
set -u
umask 0027
renice 1 "$$" >/dev/null 2>&1

flag_norun=""
flag_stdout=""
slapd_conf="/etc/openldap/slapd.conf"
ldap_bind_dn="`sed -n 's/^rootdn[ \t]*\("\)*\([^"]*[^ \t"]\).*$/\2/p' "$slapd_conf"`"
ldap_bind_secret="/etc/openldap/ldap.secret"
ldap_uri="`sed -n 's/^updateref[ \t]*\("\)*\([^"]*[^ \t"]\).*$/\2/p' "$slapd_conf"`"
ldap_base="`sed -n 's/^suffix[ \t]*\("\)*\([^"]*[^ \t"]\).*$/\2/p' "$slapd_conf"`"
dst_maxage="30"
date_format="%Y%m%d%H%M"

if [ x"$ldap_uri" = x"" ]; then
    ldap_uri="ldap://127.0.0.1"
fi

if [ x"$ldap_bind_dn" = x"" ]; then
    ldap_bind_dn="cn=admin,$ldap_base"
fi
if expr _"$ldap_bind_dn" : _".*," >/dev/null; then
    : OK
else
    ldap_bind_dn="$ldap_bind_dn,$ldap_base"
fi

if type bzip2 >/dev/null 2>&1; then
    dst_compressor="bzip2"
    dst_suffix=".ldif.bz2"
elif type gzip >/dev/null 2>&1; then
    dst_compressor="gzip"
    dst_suffix=".ldif.gz"
elif type compress >/dev/null 2>&1; then
    dst_compressor="compress"
    dst_suffix=".ldif.Z"
else
    dst_compressor="cat"
    dst_suffix=".ldif"
fi

cmd_usage="Usage: $0 [OPTIONS] DIR

Options [default]:
 -H URI
    URI to the LDAP server [$ldap_uri]
 -b BASE
    Target DN base [$ldap_base]
 -D DN
    Distinguished Name to bind to the LDAP server
    [$ldap_bind_dn]
 -y FILE
    Password for simple authentication [$ldap_bind_secret]
 -e DAY
    Expires backups older than DAYs [$dst_maxage]
"

while getopts nH:D:b:y:e:F: opt; do
    case "$opt" in
    n)
	flag_norun="yes"
	;;
    H)
	ldap_uri="$OPTARG"
	;;
    D)
	ldap_bind_dn="$OPTARG"
	;;
    b)
	ldap_base="$OPTARG"
	;;
    y)
	ldap_bind_secret="$OPTARG"
	;;
    e)
	dst_maxage="$OPTARG"
	;;
    F)
	date_format="$OPTARG"
	;;
    *)
	exit 1
	;;
    esac
done
shift `expr $OPTIND - 1`

if [ $# -lt 1 ] || [ $# -gt 1 ]; then
    echo "$cmd_usage"
    exit 0
fi

dst_dir="$1"; shift

dst_prefix="$ldap_base"
dst_ldif="$dst_dir/$dst_prefix.`date "+$date_format"`$dst_suffix"

if [ x"$dst_dir" = x"-" ]; then
    flag_stdout="yes"
fi
if [ -n "$flag_norun" ]; then
    echo "ldif: $dst_ldif"
    echo "compressor: $dst_compressor"
fi

if [ -n "$flag_stdout" ] || [ -n "$flag_norun" ]; then
    dst_compressor="cat"
    dst_ldif="/dev/stdout"
else
    if [ ! -d "$dst_dir" ]; then
	echo "$0: error: destination directory does not exist: $dst_dir" 1>&2
	exit 1
    fi
    if [ -e "$dst_ldif" ]; then
	echo "$0: error: destination file already exists: $dst_ldif" 1>&2
	exit 1
    fi
fi

## Do ad-hoc backup
${flag_norun:+echo "search:"} ldapsearch \
    -l 0 -z 0 -LLL \
    -H "$ldap_uri" \
    -x -D "$ldap_bind_dn" -y "$ldap_bind_secret" \
    -b "$ldap_base" \
    -s sub \
|"$dst_compressor" \
>"$dst_ldif"

if [ -n "$flag_stdout" ]; then
    exit 0
fi

if [ "$dst_maxage" -ge 1 ]; then
    ## Remove old backups
    find "$dst_dir" -name "$dst_prefix.*$dst_suffix" -mtime "+$dst_maxage" -print0 \
    |xargs -0 ${flag_norun:+echo "expire:"} rm -f
fi

exit 0

## ChangeLog:
##
## 2006-06-09 SATOH Fumiyasu @ MIRACLE LINUX Co.
##	* Append $ldap_base to $ldap_bind_dn if it doesn't have ",".
##	* Remove old backups only if [ "$dst_maxage" -ge 1 ].
##
## 2006-06-07 SATOH Fumiyasu @ MIRACLE LINUX Co.
##	* Use "cn=admin,$ldap_base" as $ldap_bind_dn if rootdn not defined
##	  in the slapd.conf.
##
## 2006-05-27 SATOH Fumiyasu @ MIRACLE LINUX Co.
##	* Fix regex for sed(1) to strip '"'.
##
## 2006-04-07 SATOH Fumiyasu @ MIRACLE LINUX Co.
##	* First release.
##
