#!/usr/bin/bash
##
## Run Web Services Dynamic Discovery host daemon
## Copyright (c) 2020 SATOH Fumiyasu @ OSS Technology Corp., Japan
##
## License: GNU General Public License version 3
##

set -u

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

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

run_or_die() {
  run "$@" || exit $?
}

warn() {
  echo "${PNAME:+$PNAME: }WARNING: $1" >&2
}

error() {
  echo "${PNAME:+$PNAME: }ERROR: $1" >&2
  exit ${2-1}
}

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

envdir() {
  local envname_prefix='WSDD_'

  local envdir="$1"; shift
  local envfile envname

  for envfile in "$envdir"/*; do
    [[ -f $envfile ]] || continue
    envname="$envname_prefix${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
	IFS= read -r "$envname" <"$envfile" || return $?
	export "$envname"
      fi
    else
      unset "$envname"
    fi
  done

  return 0
}

samba_get_parm() {
  "$samba_tool_command" $samba_tool_options testparm --parameter-name="$1" 2>/dev/null
}

ip2ifname() {
  local ip="$1"; shift

  {
    if type ip &>/dev/null; then
      ip address |sed 's/^[0-9]: //'
    else
      ifconfig -a
    fi
  } \
  |sed -n \
    -e 's/^\([^ ]*\):.*/\1/p' \
    -e 's/inet6\{0,1\} \([0-9a-f:.]*\).*/\1/p' \
  |awk \
    -v ip="$ip" \
    '
      /^[a-z]/ { ifname=$1 }
      /^[^a-z]/ && $1==ip { print ifname }
    ' \
  ;
}

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

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

wsdd_command_default='/opt/osstech/sbin/wsdd'
wsdd_user_default='nobody'

envdir="${WSDD_RUN_ENVDIR-/opt/osstech/etc/wsdd/service/wsdd/env}"

if [[ -n $envdir ]]; then
  run_or_die envdir "$envdir"
fi

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

${WSDD_RUN_PRE:+run_or_die source "$WSDD_RUN_PRE"}

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

user="${WSDD_USER:-$wsdd_user_default}"

if [[ -n ${WSDD_GROUP-} ]]; then
  group="$WSDD_GROUP"
else
  group=$(id -g -n "$user") || error "Failed to detect a primary group of user: $user"
fi

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

samba_tool_command="${WSDD_SAMBA_TOOL_COMMAND:-/opt/osstech/bin/samba-tool}"
samba_tool_options="${WSDD_SAMBA_TOOL_OPTIONS:-}"

if [[ -n $samba_tool_command ]] && type "$samba_tool_command" &>/dev/null; then
  if [[ -z ${WSDD_HOSTNAME-} ]]; then
    WSDD_HOSTNAME=$(samba_get_parm 'netbios name')
  fi

  samba_role=$(samba_get_parm 'server role' |tr a-z A-Z)
  samba_security=$(samba_get_parm 'security' |tr a-z A-Z)
  if [[ $samba_role == @('ACTIVE DIRECTORY DOMAIN CONTROLLER'|'MEMBER SERVER')
  || $samba_security == @(ADS|DOMAIN) ]]; then
    if [[ -z ${WSDD_DOMAIN-} ]]; then
      WSDD_DOMAIN=$(samba_get_parm 'workgroup')
    fi
  else
    if [[ -z ${WSDD_WORKGROUP-} ]]; then
      WSDD_WORKGROUP=$(samba_get_parm 'workgroup')
    fi
  fi

  if [[ -z ${WSDD_INTERFACES-} ]]; then
    for interface in $(samba_get_parm 'interfaces'); do
      ## Remove `/netmask` and `;key=value`
      interface="${interface%%[/;]*}"
      ## Ignore loopback interfaces and key=value
      ## (`samba-tool testparm` can't recognize `ifname;key=value` form?)
      [[ $interface == @(lo*|127.0.0.1|::1|*=*) ]] && continue

      if [[ $interface == @(*.*.*.*|*:*:*) ]]; then
	interface=$(ip2ifname "$interface")
	if [[ -z $interface ]]; then
	  warn "Cannot detect interface name for IP address: $interface"
	  continue
	fi
      fi
      WSDD_INTERFACES="${WSDD_INTERFACES-} ${interface%%[/;]*}"
    done
  fi
fi

wsdd_interface_options=()
for interface in ${WSDD_INTERFACES-}; do
  wsdd_interface_options+=(--interface "$interface")
done

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

WSDD_RUN_ARGS=(
  ${WSDD_NO_RUN:+true}
  ${WSDD_NICE:+nice -n "$WSDD_NICE"}
  ${WSDD_IONICE:+ionice ${WSDD_IONICE_CLASS:+-c "$WSDD_IONICE_CLASS"} -n "$WSDD_IONICE"}
  ${WSDD_WRAPPER_COMMAND:+"$WSDD_WRAPPER_COMMAND" ${WSDD_WRAPPER_OPTIONS-}}
  "${WSDD_COMMAND:-$wsdd_command_default}"
  --user "$user:$group"
  ${WSDD_ROOT:+--chroot "$WSDD_ROOT"}
  ${wsdd_interface_options[0]:+"${wsdd_interface_options[@]}"}
  ${WSDD_HOPLIMIT:+--hoplimit "$WSDD_HOPLIMIT"}
  ${WSDD_UUID:+--uuid "$WSDD_UUID"}
  ${WSDD_HOSTNAME:+--hostname "$WSDD_HOSTNAME"}
  ${WSDD_DOMAIN:+--domain "$WSDD_DOMAIN"}
  ${WSDD_WORKGROUP:+--workgroup "$WSDD_WORKGROUP"}
  ${WSDD_OPTIONS-}
)

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

${WSDD_UMASK:+run_or_die umask "$WSDD_UMASK"}
${WSDD_WORKINGDIR:+run_or_die cd "$WSDD_WORKINGDIR"}

## Seconds
${WSDD_LIMIT_CPU:+run_or_die ulimit -t "$WSDD_LIMIT_CPU"}
## Bytes
${WSDD_LIMIT_FSIZE:+run_or_die ulimit -f "$WSDD_LIMIT_FSIZE"}
## Bytes
${WSDD_LIMIT_DATA:+run_or_die ulimit -d "$WSDD_LIMIT_DATA"}
## Bytes
${WSDD_LIMIT_STACK:+run_or_die ulimit -s "$WSDD_LIMIT_STACK"}
## Bytes
${WSDD_LIMIT_CORE:+run_or_die ulimit -c "$WSDD_LIMIT_CORE"}
## Bytes
${WSDD_LIMIT_RSS:+run_or_die ulimit -m "$WSDD_LIMIT_RSS"}
## Number of File
${WSDD_LIMIT_NOFILE:+run_or_die ulimit -n "$WSDD_LIMIT_NOFILE"}
## Bytes
${WSDD_LIMIT_AS:+run_or_die ulimit -v "$WSDD_LIMIT_AS"}
## Number of Processes
${WSDD_LIMIT_NPROC:+run_or_die ulimit -u "$WSDD_LIMIT_NPROC"}
## Bytes
${WSDD_LIMIT_MEMLOCK:+run_or_die ulimit -l "$WSDD_LIMIT_MEMLOCK"}
## Number of Locks
${WSDD_LIMIT_LOCKS:+run_or_die ulimit -x "$WSDD_LIMIT_LOCKS"}
## Number of Queued Signals
${WSDD_LIMIT_SIGPENDING:+run_or_die ulimit -i "$WSDD_LIMIT_SIGPENDING"}
## Bytes
${WSDD_LIMIT_MSGQUEUE:+run_or_die ulimit -q "$WSDD_LIMIT_MSGQUEUE"}
## Nice Level
${WSDD_LIMIT_NICE:+run_or_die ulimit -e "$WSDD_LIMIT_NICE"}
## Realtime Priority
${WSDD_LIMIT_RTPRIO:+run_or_die ulimit -r "$WSDD_LIMIT_RTPRIO"}

${WSDD_RUN_POST:+run_or_die source "$WSDD_RUN_POST"}

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

run_or_die exec "${WSDD_RUN_ARGS[@]}"
