#!/bin/sh
##
## Setup a supervised Hyper Estraier estmaster service
## Copyright (c) 2008-2010 SATOH Fumiyasu @ OSS Technology, Inc.
##               <http://www.osstech.co.jp/>
##
## License: GNU General Public License version 2 or later
## Date: 2010-07-11, since 2008-02-05
##

set -u
umask 0022

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

md5()
{
  if type md5sum >/dev/null 2>&1; then
    md5sum |sed 's/ .*//'
  elif type openssl >/dev/null 2>&1; then
    openssl md5
  elif type perl >/dev/null 2>&1; then
    perl -e 'use Digest::MD5 "md5_hex"; print md5_hex(<>)."\n"'
  elif type ruby >/dev/null 2>&1; then
    ruby -e 'require "digest/md5"; print Digest::MD5::hexdigest($stdin.read),"\n"'
  fi
}

sha1()
{
  if type sha1sum >/dev/null 2>&1; then
    sha1sum |sed 's/ .*//'
  elif type openssl >/dev/null 2>&1; then
    openssl sha1
  elif type perl >/dev/null 2>&1; then
    perl -e 'use Digest::SHA1 "sha1_hex"; print sha1_hex(<>)."\n"'
  elif type ruby >/dev/null 2>&1; then
    ruby -e 'require "digest/sha1"; print Digest::SHA1::hexdigest($stdin.read),"\n"'
  fi
}

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

sv_cmd="/opt/osstech/bin/estmaster"
sv_env="
  WORKINGDIR
  NICE
  IONICE
  DATALIMIT
  STACKLIMIT
  OPENFILELIMIT
  COREFILELIMIT
  COMMAND
  ARGV0
  USER
  ROOTDIR
  READONLY
  SINGLETHREAD
  NOLOGTIMESTAMP
"
log_env="
  ARGV0
  USER
  MAXFILESIZE
  MAXLOGFILES
  PROCESSOR
"

if [ $# -ne 4 ]; then
  echo "Usage: $0 /SVDIR /ROOTDIR SVUSER LOGUSER" 1>&2
  exit 1
fi

sv_dir="$1"; shift
est_rootdir="$1"; shift
sv_user="$1"; shift
log_user="$1"; shift

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

sv_group=`id "$sv_user" |sed -n 's/^[^=]*=[^=]*=[0-9]*(\([^)]*\)).*$/\1/p'`
if [ -z "$sv_group" ]; then
  pdie "Cannot determine service user's primary group: $sv_user"
fi
log_group=`id "$log_user" |sed -n 's/^[^=]*=[^=]*=[0-9]*(\([^)]*\)).*$/\1/p'`
if [ -z "$log_group" ]; then
  pdie "Cannot determine log user's primary group: $log_user"
fi
log_dir="$sv_dir/log"

## Create service directory
## ======================================================================

## Hyper Estraier Node Master rootdir
## ----------------------------------------------------------------------

mkdir -m 0750 "$est_rootdir" || exit 1

est_log=`"$sv_cmd" init "$est_rootdir"`
if [ $? -ne 0 ]; then
  est_error=`echo "$est_log" |sed -n 's/^.*	ERROR	//p' >&2`
  pdie "estmaster init failed: ${est_error:-unknown error}"
fi

rm "$est_rootdir/_log" || exit 1
ln -s "$log_dir/main/current" "$est_rootdir/_log" || exit 1

perl -i.orig -p \
  -e 's/^(bindaddr:).*$/$1 127.0.0.1/;' \
  -e 's/^(authmode:).*$/$1 3/;' \
  -e 's/^(recvmax:).*$/$1 10240/;' \
  -e 's/^(maxconn:).*$/$1 100/;' \
  -e 's/^(searchmax:).*$/$1 2000/;' \
  -e 's/^(limittextsize:).*$/$1 5120/;' \
  -e 's/^(cachesize:).*$/$1 512/;' \
  -e 's!^(logfile:).*$!$1 /dev/null!;' \
  -e 's!^(backupcmd:).*$!$1 '"$est_rootdir/backup.ksh $est_rootdir/../backup 3"'!;' \
  "$est_rootdir/_conf" \
  || exit 1

pass=`(set; echo ${RANDOM-}; date; ps -ef) |sha1`
(umask 0077; echo "$pass" >"$est_rootdir/_pass") || exit 1
pass_hash=`echo "$pass" |tr -d '\n' |md5` || exit 1
echo "admin	$pass_hash	s	Admin	Admin" >"$est_rootdir/_user" || exit 1

chown -hR "$sv_user:$sv_group" "$est_rootdir" || exit 1

cat <<'EOT_BACKUP_KSH' >"$est_rootdir/backup.ksh" || exit 1
#!/bin/ksh

set -u

LC_ALL="C"
PATH="/bin:/usr/bin"
export LC_ALL PATH

if [[ $# -ne 3 ]]; then
  echo "Usage: $0 BACKUP_DIR MAX_AGE TARGET"
  exit 1
fi

backup_dir="$1"; shift
age_max="$1"; shift
target="$1"; shift
backup_new="$backup_dir/${target##*/}.0"

disk_free=$(df -k "$backup_dir" |sed -n 's/^.*  *\([1-9][0-9]*\)  *[1-9]*[0-9]% .*$/\1/p')
disk_required=$(du -sk "$target" |awk '{print $1}')
[[ $disk_free -gt $disk_required ]] || { echo "Not enough disk" 1>&2; exit 1; }

rm -rf "$backup_new" || exit 1
cp -rp "$target" "$backup_new" || { rm -rf "$backup_new"; exit 1; }

rm -rf "$backup_dir/${target##*/}.$age_max" || exit 1

age="$age_max"
while [[ $age -gt 0 ]]; do
  prev="$backup_dir/${target##*/}.$(($age - 1))"
  next="$backup_dir/${target##*/}.$age"
  age=$(($age - 1))
  [[ -e $prev ]] || continue
  [[ -e $next ]] && continue
  mv "$prev" "$next"
done

exit 0
EOT_BACKUP_KSH

chmod +x "$est_rootdir/backup.ksh"

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

mkdir "$sv_dir" || exit 1
mkdir "$sv_dir/env" || exit 1

## The "once" is an OSSTech-specific file and is used by
## /etc/init.d/svinit, not for supervise(8).
touch "$sv_dir/down" "$sv_dir/once" || exit 1

for env in $sv_env; do
  touch "$sv_dir/env/$env" || exit 1
done
echo "$sv_cmd" >"$sv_dir/env/COMMAND" || exit 1
echo "$sv_user" >"$sv_dir/env/USER" || exit 1
echo "$est_rootdir" >"$sv_dir/env/ROOTDIR" || exit 1
echo "set" >"$sv_dir/env/NOLOGTIMESTAMP" || exit 1

cat <<'EOT_SV_RUN' >"$sv_dir/run" || exit 1
#!/bin/sh

## NOTE: The --no-log-timestamp option is OSSTech estmaster specific.

exec 2>&1
exec envdir ./env sh -c '
  ${WORKINGDIR:+cd} ${WORKINGDIR:+"$WORKINGDIR"}
  pid_file="$ROOTDIR/_pid"
  if [ -f "$pid_file" ]; then
    echo "WARNING: staled pid file?: $pid_file" 1>&2
    ps -p "`cat "$pid_file"`" >/dev/null 2>&1 || rm "$pid_file"
  fi
  echo "PID: $$"
  env |sort |sed "s/^/Environment: /"
  set -- \
    ${NICE:+nice} ${NICE:+-n} ${NICE:+"$NICE"} \
    ${IONICE:+ionice} ${IONICE:+-n} ${IONICE:+"$IONICE"} \
    softlimit \
      ${DATALIMIT:+"-d$DATALIMIT"} \
      ${STACKLIMIT:+"-s$STACKLIMIT"} \
      ${OPENFILELIMIT:+"-o$OPENFILELIMIT"} \
      ${COREFILELIMIT:+"-c$COREFILELIMIT"} \
    setuidgid "$USER" \
    argv0 \
    "$COMMAND" \
    "${ARGV0:-sv:`pwd`}" \
      start \
      ${READONLY:+-ro} \
      ${SINGLETHREAD:+-st} \
      ${NOLOGTIMESTAMP:+--no-log-timestamp} \
      "$ROOTDIR" \
    ;
  echo "Execute: $@"
  wait
  exec "$@"
'
EOT_SV_RUN
chmod 0755 "$sv_dir/run" || exit 1

## Create multilog directory
## ======================================================================

mkdir "$log_dir" || exit 1
mkdir "$log_dir/env" || exit 1
mkdir -m 0750 "$log_dir/main" || exit 1
chown "$log_user:$log_group" "$log_dir/main" || exit 1
touch "$log_dir/status" || exit 1
chown "$log_user:$log_group" "$log_dir/status" || exit 1

for env in $log_env; do
  touch "$log_dir/env/$env" || exit 1
done
echo "$log_user" >"$log_dir/env/USER" || exit 1
echo "2000000" >"$log_dir/env/MAXFILESIZE" || exit 1
echo "20" >"$log_dir/env/MAXLOGFILES" || exit 1
echo "gzip -1" >"$log_dir/env/PROCESSOR" || exit 1

cat <<'EOT_LOG_RUN' >"$log_dir/run" || exit 1
#!/bin/sh
exec 2>&1
exec envdir ./env sh -c '
  exec \
    setuidgid "$USER" \
    argv0 \
    multilog \
    "${ARGV0:-multilog:`pwd`}" \
    t \
    ${MAXFILESIZE:+"s$MAXFILESIZE"} \
    ${MAXLOGFILES:+"n$MAXLOGFILES"} \
    ${PROCESSOR:+"!$PROCESSOR"} \
    ./main
'
EOT_LOG_RUN
chmod 0755 "$log_dir/run" || exit 1

exit 0

