#!/bin/bash
##
## OpenLDAP: Run slapd with parameters via environment variables
##
## SPDX-FileCopyrightText: 2019-2025 SATOH Fumiyasu @ OSSTech Corp., Japan
## SPDX-License-Identifier: GPL-3.0-or-later
##

set -u

if [[ -n ${JOURNAL_STREAM-} || $PPID -eq 1 ]]; then
  PNAME=""
else
  PNAME="$0"
fi

pinfo() {
  if [[ -n ${SLAPD_RUN_INFO-set} ]]; then
    echo "${PNAME:+$PNAME: }INFO: $*" >&2
  fi
}

pwarn() {
  echo "${PNAME:+$PNAME: }WARNING: $*" >&2
}

perror() {
  echo "${PNAME:+$PNAME: }ERROR: $*" >&2
}

pdie() {
  perror "$1"
  exit "${2-1}"
}

pdebug() {
  sed "s#^#${PNAME:+$PNAME: }DEBUG: #" >&2
}

prun() {
  pinfo "Run a command-line: $*"
  "$@"
}

prun_or_die() {
  prun "$@"
  local ret="$?"
  if [[ $ret -ne 0 ]]; then
    pdie "Command failed: $*: $ret" "$ret"
  fi
}

# shellcheck disable=SC2317 # Command appears to be unreachable
envdir() {
  local envdir="$1"; shift
  local envfile envname

  for envfile in "$envdir"/*; do
    [[ -f $envfile ]] || continue
    envname="${envfile##*/}"
    [[ $envname =~ ^[A-Za-z_][A-Za-z_0-9]*$ ]] || continue
    if [[ -s $envfile ]]; then
      ## Prefer external environment variables to envdir
      if eval '[[ -z ${'"$envname"'+set} ]]'; then
        # shellcheck disable=SC2229 # This does not read 'envname'
	IFS= read -r "$envname" <"$envfile" || return $?
        # shellcheck disable=SC2163 # This does not export 'envname'
	export "$envname"
      fi
    else
      unset "$envname"
    fi
  done

  return 0
}

if [[ -n ${SLAPD_RUN_DEBUG-} ]]; then
  PS4="${PNAME:+$PNAME: }DEBUG: "
  set -x
fi

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

: "${SLAPD_RUN_ENVDIR=/opt/osstech/etc/openldap/service/slapd/env}"
if [[ -n $SLAPD_RUN_ENVDIR ]]; then
  prun_or_die envdir "$SLAPD_RUN_ENVDIR"
fi

: "${SLAPD_RUN_ENVFILE=}"
if [[ -n $SLAPD_RUN_ENVFILE ]]; then
  prun_or_die source "$SLAPD_RUN_ENVFILE"
fi

if [[ -n ${SLAPD_SYSLOG_SOCKET_PATH-} ]]; then
  if [[ -S $SLAPD_SYSLOG_SOCKET_PATH ]]; then
    exec &> >(exec logger -t slapd --size=4096 --socket-errors=off -u "$SLAPD_SYSLOG_SOCKET_PATH")
  else
    pwarn "No syslog socket at SLAPD_SYSLOG_SOCKET_PATH environment: $SLAPD_SYSLOG_SOCKET_PATH"
  fi
fi

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

${SLAPD_RUN_PRE:+prun_or_die source "$SLAPD_RUN_PRE"}

## ----------------------------------------------------------------------

: "${SLAPD_COMMAND:=/opt/osstech/sbin/slapd}"
: "${SLAPD_CONF:=/opt/osstech/etc/openldap/slapd.conf}"
: "${SLAPD_DEBUG_LEVEL:=stats}"
: "${SLAPD_SYSLOG_LEVEL:=0}"
: "${SLAPD_SYSLOG_TO_STDERR:=1}"
export SLAPD_SYSLOG_TO_STDERR
: "${SLAPD_USER:=ldap}"
: "${SLAPD_SERVICES:=ldap:/// ldaps:///}"
: "${SLAPD_LDAPI_SERVICE:=ldapi:///}"

: "${SLAPD_LIMIT_CORE:=unlimited}"
: "${SLAPD_LIMIT_NOFILE:=16384}"

## ----------------------------------------------------------------------

if [[ -d $SLAPD_CONF ]]; then
  config_opts=(-F "$SLAPD_CONF")
else
  config_opts=(-f "$SLAPD_CONF")
fi

if [[ -n $SLAPD_SERVICES && -n $SLAPD_LDAPI_SERVICE ]]; then
  if [[ " $SLAPD_SERVICES " != *" $SLAPD_LDAPI_SERVICE "* ]]; then
    SLAPD_SERVICES="$SLAPD_LDAPI_SERVICE $SLAPD_SERVICES"
  fi
fi

## ----------------------------------------------------------------------

IFS=" " read -r -a SLAPD_WRAPPER_OPTIONS <<< "${SLAPD_WRAPPER_OPTIONS-}"
IFS=" " read -r -a SLAPD_OPTIONS <<< "${SLAPD_OPTIONS-}"

SLAPD_RUN_ARGS=(
  ${SLAPD_NO_RUN:+true}
  ${SLAPD_NICE:+nice -n "$SLAPD_NICE"}
  ${SLAPD_IONICE:+ionice ${SLAPD_IONICE_CLASS:+-c "$SLAPD_IONICE_CLASS"} -n "$SLAPD_IONICE"}
  ${SLAPD_WRAPPER_COMMAND:+"$SLAPD_WRAPPER_COMMAND" "${SLAPD_WRAPPER_OPTIONS[@]}"}
  "$SLAPD_COMMAND"
  ${SLAPD_DEBUG_LEVEL:+-d "$SLAPD_DEBUG_LEVEL"}
  ${SLAPD_SYSLOG_LEVEL:+-s "$SLAPD_SYSLOG_LEVEL"}
  ${SLAPD_SYSLOG_FACILITY:+-l "$SLAPD_SYSLOG_FACILITY"}
  "${config_opts[@]}"
  -u "${SLAPD_USER}"
  ${SLAPD_GROUP:+-g "$SLAPD_GROUP"}
  ${SLAPD_SERVICES:+-h "$SLAPD_SERVICES"}
  "${SLAPD_OPTIONS[@]}"
)

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

${SLAPD_UMASK:+prun_or_die umask "$SLAPD_UMASK"}
${SLAPD_WORKINGDIR:+prun_or_die cd "$SLAPD_WORKINGDIR"}

## Seconds
${SLAPD_LIMIT_CPU:+prun_or_die ulimit -t "$SLAPD_LIMIT_CPU"}
## Bytes
${SLAPD_LIMIT_FSIZE:+prun_or_die ulimit -f "$SLAPD_LIMIT_FSIZE"}
## Bytes
${SLAPD_LIMIT_DATA:+prun_or_die ulimit -d "$SLAPD_LIMIT_DATA"}
## Bytes
${SLAPD_LIMIT_STACK:+prun_or_die ulimit -s "$SLAPD_LIMIT_STACK"}
## Bytes
${SLAPD_LIMIT_CORE:+prun_or_die ulimit -c "$SLAPD_LIMIT_CORE"}
## Bytes
${SLAPD_LIMIT_RSS:+prun_or_die ulimit -m "$SLAPD_LIMIT_RSS"}
## Number of File
${SLAPD_LIMIT_NOFILE:+prun_or_die ulimit -n "$SLAPD_LIMIT_NOFILE"}
## Bytes
${SLAPD_LIMIT_AS:+prun_or_die ulimit -v "$SLAPD_LIMIT_AS"}
## Number of Processes
${SLAPD_LIMIT_NPROC:+prun_or_die ulimit -u "$SLAPD_LIMIT_NPROC"}
## Bytes
${SLAPD_LIMIT_MEMLOCK:+prun_or_die ulimit -l "$SLAPD_LIMIT_MEMLOCK"}
## Number of Locks
${SLAPD_LIMIT_LOCKS:+prun_or_die ulimit -x "$SLAPD_LIMIT_LOCKS"}
## Number of Queued Signals
${SLAPD_LIMIT_SIGPENDING:+prun_or_die ulimit -i "$SLAPD_LIMIT_SIGPENDING"}
## Bytes
${SLAPD_LIMIT_MSGQUEUE:+prun_or_die ulimit -q "$SLAPD_LIMIT_MSGQUEUE"}
## Nice Level
${SLAPD_LIMIT_NICE:+prun_or_die ulimit -e "$SLAPD_LIMIT_NICE"}
## Realtime Priority
${SLAPD_LIMIT_RTPRIO:+prun_or_die ulimit -r "$SLAPD_LIMIT_RTPRIO"}

${SLAPD_RUN_POST:+prun_or_die source "$SLAPD_RUN_POST"}

if [[ -n ${SLAPD_RUN_DEBUG-} ]]; then
  { umask; pwd; ulimit -a; env; } |pdebug
fi

prun_or_die exec "${SLAPD_RUN_ARGS[@]}"
