#!/bin/sh
set -e

err() { >&2 printf '%s\n\n' "$*"; exit 1; }
fatal() { err "${0##*/}: fatal: $*"; }
warn() { err "${0##*/}: warning: $*"; }
usage() {
  err "Usage: ${0##*/} --add|--remove <service-directory> [<service-name>]
       ${0##*/} defaults| defaults-disabled <service-directory> [<service-name>]
       ${0##*/} --list|--check [<service-name>]
       ${0##*/} --up|--down <service-directory>"
}

opt=$1
#test -z "${opt##-*}" || usage
svdir=${2%/}
svname=$3
servicedir=$SVDIR
userservicedir=$SVDIR
test -n "$servicedir" || servicedir=/etc/service
# handle relative symlinks, see #899242
defaultrun=runit/runsvdir/default

if [ "$(id -u)" != 0 ] ; then #user instances
	[ "$(id -u)" -lt '1000' ] && fatal "${0##*/}  : invalid uid"
	username="$(id -u -n)"
	#userservicedir=$SVDIR
	test -n "$userservicedir" || userservicedir=/home/$username/.service
	test -d "$userservicedir" || userservicedir=
	##test -n "$runitsvdir" || runitsvdir=/home/$username/.runit/sv
	##test -n "$cpsvsrc" || cpsvsrc=/usr/share/runit/sv.now #NOTE: requires 'cpsv s' with root privileges
fi

case "$opt" in
  -c|--check) exec >/dev/null; exec 2>/dev/null; opt=-l;;
esac
case "$opt" in
  -l|--list)
    if test -z "$svdir" ; then
      test -n "$userservicedir" &&  exec ls -1 "$servicedir" "$userservicedir"
      exec ls -1 "$servicedir"
    fi
    if [ -h "$servicedir"/"$svdir" ]; then
      printf '%s -> %s\n' "$svdir" "$(readlink "$servicedir"/"$svdir")"
    elif [ -h "$userservicedir"/"$svdir" ]; then
      printf '%s -> %s\n' "$svdir" "$(readlink "$userservicedir"/"$svdir")"
    else
      err "Service $svdir not registered."
    fi
    exit 0
  ;;
  defaults)
    test "$(id -u)" = 0 || fatal "${0##*/} defaults must be run by root."
    opt=-a
    rpolicy=1
  ;;
  defaults-disabled)
    test "$(id -u)" = 0 || fatal "${0##*/} defaults-disabled must be run by root."
    opt=-r
    rpolicy=1
  ;;
  -u|--up|--auto|-d|--down|-n|--noauto|--list|--check)
    [ -z $svname ] || usage
  ;;
esac

test -n "$svdir" || usage
if test -n "${svdir%%/*}" ; then  #name without path
  test -d "$svdir" && fatal "The <service-directory> must start with a slash." #wrong full path
  if [ -n "$username" ]; then #user-service
    test -z "$userservicedir" && fatal "user service directory not found."
    if [ -d /home/$username/.runit/sv/"${svdir%%/*}" ]; then
      svdir=/home/$username/.runit/sv/"${svdir%%/*}"
    else
      fatal "<service-directory> "/home/$username/.runit/sv/${svdir%%/*}" not found."
    fi
    servicedir="$userservicedir"
  else #system wide service
    if  [ -d /etc/sv/"${svdir%%/*}" ]; then
      svdir=/etc/sv/"${svdir%%/*}"
    elif [ -d /usr/share/runit/sv.current/"${svdir%%/*}" ]; then
      svdir=/usr/share/runit/sv.current/"${svdir%%/*}"
    else
      fatal "<service-directory> "${svdir%%/*}" not found."
    fi
  fi
else #full path provided
  test -d "$svdir" ||  fatal "$svdir does not exist, or is not a directory."
  test -z "${svdir%%/*}" ||
  fatal "The <service-directory> must start with a slash."
fi
test -n "$svname" || svname=${svdir##*/}
test -n "${svname##.*}" ||
  fatal "The <service-name> must not start with a dot."
test "$svname" = "${svname#*/}" ||
  fatal "The <service-name> must not contain a slash."
# allow relative symlinks only in 'default' runlevel
test "$defaultrun" = "$(readlink "$servicedir")" && \
  relsymdir=../../../sv
  
case "$opt" in
  -a|--add|enable)
#    test "$(id -u)" = 0 || fatal "${0##*/} -a must be run by root."
    if test -e "$servicedir"/"$svname"; then
      test -h "$servicedir"/"$svname" ||
        fatal "$servicedir/$svname exists, but is not a symbolic link."
      test "$(readlink "$servicedir"/"$svname")" = "$svdir" ||
        test "$(readlink "$servicedir"/"$svname")" = "$svdir"/ ||
          fatal "$servicedir/$svname exists, but doesn't point to $svdir."
      printf '%s\n' "Service $svname already added."
      exit 0
    fi
    ! sv stat "$svdir" >/dev/null 2>&1 ||
      fatal "$svdir is currently controlled by a runsv(8) process."
    if test "${svdir#/etc/}" != "$svdir"; then
      if test ! -h "$svdir"/supervise; then
        rm -rf "$svdir"/supervise
        ln -s /run/runit/supervise/"$svname" "$svdir"/supervise
      fi
      if test -d "$svdir"/log && test ! -h "$svdir"/log/supervise; then
        rm -rf "$svdir"/log/supervise
        ln -s /run/runit/supervise/"$svname".log "$svdir"/log/supervise
      fi
    fi
    if [ -d "$servicedir"/."$svname" ]; then
        if [ -z "$rpolicy" ]; then
            rm "$servicedir"/."$svname"
	else
	    exit 0 # do not override local admin choice to disable
	fi
    fi
    ln -s "$svdir" "$servicedir"/"$svname"
    printf '%s\n' "Service $svname added."
    exit 0
  ;;
  -r|--remove|disable)
#    test "$(id -u)" = 0 || fatal "${0##*/} -r must be run by root."
    test -e "$servicedir"/"$svname" ||
      warn "$servicedir/$svname does not exist."
    test -h "$servicedir"/"$svname" ||
      fatal "$servicedir/$svname is not a symbolic link."
    test "$svdir" = "$(readlink "$servicedir"/"$svname")" ||
      test "$svdir"/ = "$(readlink "$servicedir"/"$svname")" ||
        test "$relsymdir"/"$svname" = "$(readlink "$servicedir"/"$svname")" ||
          fatal "$servicedir/$svname does not point to $svdir."
    if [ -d "$servicedir"/"$svname" ]; then
        if [ -z "$rpolicy" ]; then
	   rm -f "$servicedir"/"$svname"
	else
	    exit 0 # do not override local admin choice to enable
        fi
    fi
    ln -s "$svdir" "$servicedir"/."$svname"
    printf '%s %s\n' \
      "Service $svname removed," \
      "the service daemon received the TERM and CONT signals."
    exit 0
  ;;
  -u|--up|--auto)
    #test "$(id -u)" = 0 || fatal "${0##*/} -u must be run by root."
    svname=$(basename "$svdir")
    test -f "$svdir"/down || warn "The wanted status of $svname is already set to: up"
    rm "$svdir"/down
    printf '%s %s\n' \
      "The wanted status of $svname is set to: up,"
    exit 0
  ;;
   -d|--down|-n|--noauto)
    #test "$(id -u)" = 0 || fatal "${0##*/} -n must be run by root."
    svname=$(basename "$svdir")
    test -f "$svdir"/down && warn "The wanted status of $svname is already set to: down"
    touch "$svdir"/down
    printf '%s %s\n' \
      "The wanted status of $svname is set to: down"
    exit 0 
  ;;
  *) usage
  ;;
esac
