#!/bin/ksh
##
## OpenLDAP: Backup slapd databases
## Copyright (c) 2012-2015 SATOH Fumiyasu @ OSS Technology Corp., Japan
##               <http://www.osstech.co.jp/>
##               <https://github.com/fumiyas/>
##
## License: GNU General Public License version 2 or later
##

set -u
umask 0027
renice 1 "$$" >/dev/null 2>&1 || :
ionice -c 3 -p "$$" >/dev/null 2>&1 || :

pdie()
{
  echo "$0: ERROR: $1" 1>&2
  exit 1
}

function ldifunwrap {
  sed \
    -n \
    '1 {h; $ !d}; $ {x; s/\n //g; p}; /^ / {H; d}; /^ /! {x; s/\n //g; p}' \
    "$@" \
  ;
}

## Check if slapd-config(5) (cn=config backend) is used or not
function slapd_config_backend_p {
  [[ -f $1/cn=config.ldif ]]
}

## Options
## ======================================================================

slapdbbacup_conf="${SLAPDBBACKUP_CONF:-/opt/osstech/etc/openldap/slapdbbackup.conf}"
slapcat_cmd="/opt/osstech/sbin/slapcat"
slapd_conf_file_default="/opt/osstech/etc/openldap/slapd.conf"
slapd_conf_dir_default="/opt/osstech/etc/openldap/slapd.d"
backup_dir="/opt/osstech/var/backup/ldap"
backup_maxage="30"

if [[ -f $slapdbbacup_conf ]]; then
  set -e
  . "$slapdbbacup_conf"
  set +e
fi

slapcat_cmd="${SLAPDBBACKUP_SLAPCAT_COMMAND:-$slapcat_cmd}"
slapd_conf="${SLAPDBBACKUP_SLAPD_CONF:-}"
backup_dir="${SLAPDBBACKUP_BACKUP_DIR:-$backup_dir}"
backup_maxage="${SLAPDBBACKUP_BACKUP_MAXAGE:-$backup_maxage}"

if [[ -z $slapd_conf ]]; then
  if slapd_config_backend_p "$slapd_conf_dir_default"; then
    slapd_conf="$slapd_conf_dir_default"
  else
    slapd_conf="$slapd_conf_file_default"
  fi
fi

## ======================================================================

set -A suffixes

if slapd_config_backend_p "$slapd_conf"; then
  suffixes[${#suffixes[@]}]="cn=config"
fi

{
  if slapd_config_backend_p "$slapd_conf"; then
    ldifunwrap "$slapd_conf"/cn=config/olcDatabase=*db.ldif \
    |sed -n \
      -e 's/^dn: .*}/database /p' \
      -e 's/^olcSuffix: /suffix /p' \
    ;
  else
    ## slapd.conf(5)
    sed 's/"//g;s/ *, */,/g' "$slapd_conf"
  fi
} \
|while read -r param value; do
  case "$param" in
  database)
    db_type="$value"
    ;;
  suffix)
    if [ -z "${db_type#[bhm]db}" ]; then
      suffixes[${#suffixes[@]}]="$value"
    fi
    ;;
  esac
done

for suffix in "${suffixes[@]}"; do
  ldif="$backup_dir/$suffix.ldif.gz"
  ldif_new="$ldif.$$.tmp"
  slapcat_failed="$ldif.$$.slapcat.tmp"

  ## Test if the backup directory is writeable
  if ! touch "$ldif_new"; then
    pdie "Backup directory is not writeable"
  fi
  rm -f "$slapcat_failed"

  ("$slapcat_cmd" -b "$suffix" || echo "$?" >"$slapcat_failed") |gzip -1 >"$ldif_new"
  gzip_status="$?"
  if [[ $gzip_status -ne 0 ]] || [[ -f "$slapcat_failed" ]]; then
    wait
    slapcat_status=$(cat "$slapcat_failed" 2>/dev/null)
    rm -f "$ldif_new" "$slapcat_failed"
    if [[ $gzip_status -ne 0 ]]; then
      pdie "gzip failed: exit status $gzip_status"
    fi
    pdie "slapcat failed: exit status $slapcat_status"
  fi

  if [[ -f "$ldif" ]]; then
    backup_age="$backup_maxage"
    if [[ -f "$ldif.$backup_age" ]]; then
      rm -f "$ldif.$backup_age" || exit 1
    fi
    while [[ "$backup_age" -gt 0 ]]; do
      backup_age_prev=$((backup_age - 1))
      if [[ -f "$ldif.$backup_age_prev" ]]; then
	mv "$ldif.$backup_age_prev" "$ldif.$backup_age" || exit 1
      fi
      backup_age="$backup_age_prev"
    done

    mv "$ldif" "$ldif.1" || exit 1
  fi

  mv "$ldif_new" "$ldif" || exit 1
done

exit 0

