1#!/bin/sh
2
3### BEGIN INIT INFO
4# Provides:          stud
5# Required-Start:    $local_fs $remote_fs
6# Required-Stop:     $local_fs $remote_fs
7# Should-Start:      $syslog
8# Should-Stop:       $syslog
9# Default-Start:     2 3 4 5
10# Default-Stop:      0 1 6
11# Short-Description: Start or stop stud (SSL offloader)
12### END INIT INFO
13
14#######################################################
15#                      GLOBALS                        #
16#######################################################
17
18# instance configuration directory
19CONFIG_DIR="/etc/stud"
20
21# Runtime directory data
22RUNTIME_DIR="/var/run/stud"
23
24#######################################################
25
26#######################################################
27
28stud_single_instance_config_reset() {
29#######################################################
30#            stud instance configuration              #
31#######################################################
32
33# stud listening address
34FRONTEND_ADDRESS="*,8443"
35
36# upstream service address
37BACKEND_ADDRESS="127.0.0.1,80"
38
39# x509 certificate file
40CERT_FILE=""
41
42# TLS only service? Don't set this to 1 if you're
43# offloading HTTPS.
44TLS_ONLY="0"
45
46# cipher suite (run openssl ciphers for full list)
47CIPHER_SUITE="HIGH"
48
49# OpenSSL engine
50ENGINE=""
51
52# Number of worker processes
53WORKERS="1"
54
55# Listen backlog
56BACKLOG=""
57
58# Chroot directory
59CHROOT_DIR=""
60
61# drop privileges and run as specified
62# user if set
63SETUID_USER=""
64
65# use shared cache with specified number of sessions
66# WARNING: stud must be compiled with USE_SHARED_CACHE=1
67SHARED_CACHE_SESSIONS="0"
68
69# Accept cache updates on specified address
70#
71# syntax: HOST,PORT
72#
73# WARNING: stud must be compiled with USE_SHARED_CACHE=1
74#          SHARED_CACHE_SESSIONS must be >= 1
75CACHE_UPDATE_ACCEPT=""
76
77# Send cache updates to specified list space separated peers
78#
79# syntax: HOST1,PORT HOST2,PORT
80#
81# WARNING: stud must be compiled with USE_SHARED_CACHE=1
82#          and CACHE_UPDATE_ACCEPT must be defined
83CACHE_UPDATE_SEND=""
84
85# Force network interface and ttl to receive and send multicast
86# cache updates
87#
88# syntax: IFACE[,TTL]
89#
90# WARNING: stud must be compiled with USE_SHARED_CACHE=1
91#          and CACHE_UPDATE_ACCEPT must be defined
92CACHE_UPDATE_IFACE=""
93
94# default tcp keepalive on client socket in seconds
95CLIENT_TCP_KEEPALIVE_SEC=""
96
97# log to syslog?
98SYSLOG="1"
99
100# Write 1 octet with the IP family followed by the IP
101# address in 4 (IPv4) or 16 (IPv6) octets little-endian
102# to backend before the actual data
103WRITE_IP="0"
104
105# Enable writing HAProxy protocol line to the backend before
106# actual data, see
107# http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
108# for additional info
109WRITE_PROXY="0"
110
111# Enable reading HAProxy protocol line before actual data.
112# This address will be sent to the backend if one of
113# WRITE_IP or WRITE_PROXY is specified.
114READ_PROXY="0"
115
116# Alternative OpenSSL library dir
117# Use this if you'd like to run stud with different
118# version of OpenSSL library
119OPENSSL_LIB_DIR=""
120
121# Semicolon separated list of process affinities; requires
122# taskset(8) utility.
123#
124# SYNTAX:
125#   "<process_number>:<affinity>;<process_number2>:<affinity2>;..."
126#
127# <process_number>:      stud worker process number, starting with 1
128# <affinity>:            process affinity, see taskset(8) for details
129#
130# EXAMPLES:
131#
132#   "1:0"                => bind first process to CPU0
133#
134#   "1:0;2:3-4;3:5;4:7"  => bind first worker process to CPU0,
135#                        second worker process to CPU3 and CPU4,
136#                        third worker process to CPU5 and fourth
137#                        worker process to CPU7
138PROCESS_AFFINITY=""
139
140# Process priority (integer between -19 to 19)
141# lower value means higher priority
142#
143PROCESS_PRIORITY=""
144
145# ulimit -n value before starting single stud instance
146#
147# Comment out or set to 0 to disable ulimit -n
148# setup.
149#
150ULIMIT_N=""
151
152# Additional stud command line options
153#
154# NOTE: set this only if you really know what your're
155#       doing
156#
157# ADDITIONAL_STUD_OPT=""
158
159# EOF
160}
161
162PATH="${PATH}:."
163INSTANCE_NAME=""
164STUD=`which stud 2>/dev/null`
165
166die() {
167  msg_log "FATAL: $@"
168  echo "FATAL: $@" 1>&2
169  exit 1
170}
171
172msg_log() {
173  ident="stud"
174  test ! -z "${INSTANCE_NAME}" && ident="${ident}/${INSTANCE_NAME}"
175  logger -i -t "${ident}" "$@" >/dev/null 2>&1
176}
177
178msg_err() {
179  msg_log "ERROR: $@"
180}
181
182
183_real_single_instance_start() {
184  # check stud binary
185  if [ -z "${STUD}" ] || [ ! -f "${STUD}" ] || [ ! -x "${STUD}" ]; then
186    die "Invalid stud binary: '${STUD}'"
187  fi
188
189  # generate stud command line options
190  opts="-f ${FRONTEND_ADDRESS}"
191  opts="${opts} -b ${BACKEND_ADDRESS}"
192
193  if [ "${TLS_ONLY}" = "1" ]; then
194    opts="${opts} --tls"
195  else
196    opts="${opts} --ssl"
197  fi
198
199  test ! -z "${CIPHER_SUITE}" && opts="${opts} -c ${CIPHER_SUITE}"
200  test ! -z "${ENGINE}" && opts="${opts} -e ${ENGINE}"
201
202  if [ ! -z "${WORKERS}" ] && [ ${WORKERS} -gt 0 ]; then
203    opts="${opts} -n ${WORKERS}"
204  fi
205
206  if [ ! -z "${BACKLOG}" ] && [ ${BACKLOG} -gt 0 ]; then
207    opts="${opts} -B ${BACKLOG}"
208  fi
209
210  if [ ! -z "${CLIENT_TCP_KEEPALIVE_SEC}" ] && [ ${CLIENT_TCP_KEEPALIVE_SEC} -gt 0 ]; then
211    opts="${opts} -k ${CLIENT_TCP_KEEPALIVE_SEC}"
212  fi
213
214  # shared cache sessions...
215  if [ ! -z "${SHARED_CACHE_SESSIONS}" ] && [ ${SHARED_CACHE_SESSIONS} -gt 0 ]; then
216    opts="${opts} -C ${SHARED_CACHE_SESSIONS}"
217
218    # shared cache stuff
219    if [ ! -z "${CACHE_UPDATE_ACCEPT}" ]; then
220      opts="${opts} -U ${CACHE_UPDATE_ACCEPT}"
221
222      c_u=0
223      for h in ${CACHE_UPDATE_SEND}; do
224        test ! -z "${h}" || continue
225        opts="${opts} -P ${h}"
226        c_u=$((c_u + 1))
227      done
228      if [ ${c_u} -lt 1 ]; then
229        die "Cache updates are enabled but CACHE_UPDATE_SEND option seems to be empty."
230      fi
231
232      if [ ! -z "${CACHE_UPDATE_IFACE}" ]; then
233        opts="${opts} -M ${CACHE_UPDATE_IFACE}"
234      fi
235    fi
236
237  fi
238
239  # chroot?
240  test ! -z "${CHROOT_DIR}" && opts="${opts} -r ${CHROOT_DIR}"
241  test ! -z "${SETUID_USER}" && opts="${opts} -u ${SETUID_USER}"
242
243  opts="${opts} -q"
244  test "${SYSLOG}" = "1" && opts="${opts} -s"
245
246  test "${WRITE_IP}" = "1" && opts="${opts} --write-ip"
247  test "${WRITE_PROXY}" = "1" && opts="${opts} --write-proxy"
248  test "${READ_PROXY}" = "1" && opts="${opts} --read-proxy"
249
250  if [ ! -z "${CERT_FILE}" ] && [ -f "${CERT_FILE}" ] && [ -r "${CERT_FILE}" ]; then
251    opts="${opts} ${CERT_FILE}"
252  else
253    die "Invalid or unreadable certificate file '${CERT_FILE}'."
254  fi
255
256  # additional command line options?!
257  if [ ! -z "${ADDITIONAL_STUD_OPT}" ]; then
258    opts="${opts} ${ADDITIONAL_STUD_OPT}"
259  fi
260
261  # priority?!
262  prefix=""
263  if [ ! -z "${PROCESS_PRIORITY}" ]; then
264    prefix="nice -n ${PROCESS_PRIORITY}"
265  fi
266
267  # we want to start stud in a daemon mode...
268  opts="${opts} --daemon"
269
270  # set ulimits!
271  ulimit_set || die "Unable to set stud runtime limits."
272
273  # disable linker stuff
274  unset LD_LIBRARY_PATH
275
276  # set new lib path if requested
277  if [ ! -z "${OPENSSL_LIB_DIR}" -a -d "${OPENSSL_LIB_DIR}" ]; then
278    LD_LIBRARY_PATH="${OPENSSL_LIB_DIR}"
279    export LD_LIBRARY_PATH
280  fi
281
282  # start stud!
283  msg_log "Starting instance '${INSTANCE_NAME}': ${STUD} ${opts}"
284  out=`${prefix} ${STUD} ${opts} 2>&1`
285
286  # remove lib path
287  unset LD_LIBRARY_PATH
288
289  # check invocation
290  stud_pid=`echo "${out}" | tail -n 1 | cut -d " " -f5 | tr -d '.'`
291  if [ -z "${stud_pid}" ]; then
292     die "Empty stud pid. This is extremely weird."
293  fi
294
295  # wait a little bit, check if pid is still alive
296  sleep 0.2 >/dev/null 2>&1
297  if ! kill -0 "${stud_pid}" >/dev/null 2>&1; then
298    die "Stud started successfully as pid ${stud_pid} but died shortly after startup.";
299  fi
300
301  # write pid file!
302  pid_file_write "${INSTANCE_NAME}" "${stud_pid}" || msg_warn "${Error}"
303
304  # set affinity!
305  stud_affinity_set "${stud_pid}" || die "${Error}"
306}
307
308stud_single_instance_start() {
309  name="${1}"
310  if [ -z "${name}" ]; then
311    Error="Unable to stop undefined stud instance."
312    return 1
313  fi
314
315  # check if it is running
316  if stud_single_instance_status "${name}"; then
317    Error="Instance ${name} is already running as pid ${Error}."
318    return 1
319  fi
320
321  # do the real stuff...
322  Error=""
323  out=`_real_single_instance_start 2>&1`
324  rv=$?
325  if [ "${rv}" != "0" ]; then
326    Error="${out}"
327    rv=1
328  fi
329
330  # this is it! :)
331  return $rv
332}
333
334stud_single_instance_stop() {
335  name="${1}"
336  if [ -z "${name}" ]; then
337    Error="Unable to stop undefined stud instance."
338    return 1
339  fi
340
341  # check if it is running
342  stud_single_instance_status "${name}" || return 1
343
344  # time to stop instance
345  pid="${Error}"
346  msg_log "Stopping stud instance '${name}', pid ${pid}."
347
348  ok=0
349  if ! kill "${pid}" >/dev/null 2>&1; then
350    Error="Unable to stop instance: unable to kill pid ${pid}."
351    return 1
352  fi
353
354  # wait for termination
355  i=0
356  while [ ${i} -lt 9 ]; do
357    i=$((i + 1))
358    # are you dead yet?
359    if ! kill -0 "${pid}" >/dev/null 2>&1; then
360      ok=1
361      break
362    fi
363    sleep 0.1 >/dev/null 2>&1
364  done
365
366  # not ok?! try to with headshot...
367  if [ "${ok}" != "1" ]; then
368    msg_log "Gentle stop of instance ${name} failed, trying to stop it with SIGKILL."
369    if ! kill -9 "${pid}"; then
370      Error="Unable to stop instance ${name}: kill(1) failed."
371      return 1
372    fi
373  fi
374
375  return 0
376}
377
378stud_single_instance_restart() {
379  name="${1}"
380  if [ -z "${name}" ]; then
381    Error="Unable to stop undefined stud instance."
382    return 1
383  fi
384
385  # maybe we need to stop it first...
386  if stud_single_instance_status "${name}"; then
387    stud_single_instance_stop "${name}" || return 1
388  fi
389
390  # start it back...
391  Error=""
392  stud_single_instance_start "${name}"
393}
394
395stud_single_instance_status() {
396  Error=""
397  if [ -z "${1}" ]; then
398    Error="Invalid instance name."
399    return 1
400  fi
401
402  # get pid file...
403  pid=`pid_file_read "${1}"`
404
405  # check it...
406  if [ -z "${pid}" ] || ! kill -0 "${pid}" >/dev/null 2>&1; then
407    Error="Instance '${1}' is stopped."
408    return 1
409  fi
410
411  # set pid to Error
412  Error="${pid}"
413  return 0
414}
415
416# reads pid file of specific instance
417pid_file_read() {
418  test -z "${1}" && return 1
419  file="${RUNTIME_DIR}/${1}.pid"
420  test -f "${file}" -a -r "${file}" || return 1
421  head -n 1 "${file}"
422}
423
424# writes pid file for specific instance
425pid_file_write() {
426  test -z "${1}" && return 1
427  test -z "${2}" && return 1
428
429  # check runtime directory
430  if [ ! -e "${RUNTIME_DIR}" ] || [ ! -d "${RUNTIME_DIR}" ] || [ ! -w "${RUNTIME_DIR}" ]; then
431    # try to create directory
432    mkdir -p "${RUNTIME_DIR}" || die "Unable to create missing runtime directory '${RUNTIME_DIR}'"
433  fi
434
435  file="${RUNTIME_DIR}/${1}.pid"
436  echo "${2}" > "${file}"
437}
438
439# lists running instances
440running_instance_list() {
441  list=""
442  for file in ${RUNTIME_DIR}/*.pid; do
443    test -f "${file}" || continue
444
445    fileb=`basename "${file}"`
446    name=`echo "${fileb}" | cut -d. -f1`
447    if [ -z "${name}" ]; then
448      msg_log "Removing bogus pid file '${file}'."
449      rm -f "${file}" >/dev/null 2>&1
450      continue
451    fi
452    pid=`pid_file_read "${name}"`
453    if [ -z "${pid}" ]; then
454      msg_log "Removing bogus pid file '${file}': instance '${name}' doesn't contain pid."
455      rm -f "${file}" >/dev/null 2>&1
456      continue
457    fi
458
459    # is this pid alive?
460    if ! kill -0 "${pid}" >/dev/null 2>&1			; then
461      msg_log "Removing bogus pid file '${file}': instance '${name}' [pid ${pid}] is stopped."
462      rm -f "${file}" >/dev/null 2>&1
463      continue
464    fi
465
466    list="${list} ${name}"
467  done
468  echo ${list}
469}
470
471stud_instances_start() {
472  list="$@"
473  if [ -z "${list}" ]; then
474    list=`stud_config_instances_list`
475  fi
476  if [ -z "${list}" ]; then
477    die "No stud instances configured in directory '${CONFIG_DIR}'."
478  fi
479
480  echo "Starting stud instances:"
481  num_ok=0
482  num_failed=0
483  for instance in ${list}; do
484    echo -n "  ${instance}: "
485    # load configuration
486    if ! stud_single_instance_config_load "${instance}"; then
487      echo "failed: ${Error}"
488      return 1
489    # start instance
490    elif stud_single_instance_start "${instance}"; then
491      echo "done."
492      msg_log "Instance ${name} successfully started."
493      num_ok=$((num_ok + 1))
494    else
495      echo "failed: ${Error}"
496      msg_err "Error starting instance ${name}: ${Error}"
497      num_failed=$((num_failed + 1))
498    fi
499  done
500
501  if [ "${num_failed}" != "0" ]; then
502    return 1
503  else
504    return 0
505  fi
506}
507
508stud_instances_stop() {
509  list="$@"
510  if [ -z "${list}" ]; then
511    list=`running_instance_list`
512  fi
513  if [ -z "${list}" ]; then
514    die "No stud instances are running."
515  fi
516
517  echo "Stopping stud instances:"
518  num_ok=0
519  num_failed=0
520  for instance in ${list}; do
521    echo -n "  ${instance}: "
522    if stud_single_instance_stop "${instance}"; then
523      echo "done."
524      num_ok=$((num_ok + 1))
525      msg_log "Instance ${instance} successfully stopped."
526    else
527      echo "failed: ${Error}"
528      msg_err "Error stopping instance ${instance}: ${Error}"
529      num_failed=$((num_failed + 1))
530    fi
531  done
532
533  if [ "${num_failed}" != "0" ]; then
534    return 1
535  else
536    return 0
537  fi
538}
539
540stud_instances_restart() {
541  list="$@"
542  if [ -z "${list}" ]; then
543    list=`(running_instance_list ; stud_config_instances_list) | tr ' ' '\n' | sort -u | xargs echo`
544  fi
545
546  echo "Restarting stud instances: "
547  num_ok=0
548  num_failed=0
549  for instance in ${list}; do
550    echo -n "  ${instance}: ";
551
552    # load configuration
553    if ! stud_single_instance_config_load "${instance}"; then
554      echo "failed: ${Error}"
555      return 1
556    # restart instance
557    elif stud_single_instance_restart "${instance}"; then
558      echo "done."
559      num_ok=$((num_ok + 1))
560      msg_log "Instance ${instance} successfully restarted."
561    else
562      echo "failed: ${Error}"
563      msg_err "Error restarting instance ${instance}: ${Error}"
564      num_failed=$((num_failed + 1))
565    fi
566  done
567
568  if [ "${num_failed}" != "0" ]; then
569    return 1
570  else
571    return 0
572  fi
573}
574
575stud_instances_status() {
576  list_config=`stud_config_instances_list`
577  list_running=`running_instance_list`
578
579  list_all=`echo ${list_config} ${list_running} | tr ' ' '\n' | sort -u | xargs echo`
580
581  i=0;
582
583  echo "Stud instance status: "
584
585  if [ -z "${list_all}" ]; then
586    die "No instances are configured and/or running."
587  fi
588
589  for instance in ${list_all}; do
590    echo -n "  ${instance}: "
591    if stud_single_instance_status "${instance}"; then
592      echo "running as pid $Error"
593      i=$((i + 1))
594    else
595      echo "stopped"
596    fi
597  done
598
599  if [ ${i} -gt 0 ]; then
600    return 0
601  else
602    return 1
603  fi
604}
605
606stud_config_instances_list() {
607  list=""
608  for file in ${CONFIG_DIR}/*.conf; do
609    test -f "${file}" -a -r "${file}" || continue
610    fileb=`basename "${file}"`
611    name=`echo "${fileb}" | cut -d. -f1`
612    test ! -z "${name}" || continue
613    list="${list} ${name}"
614  done
615
616  echo ${list}
617}
618
619stud_single_instance_config_print() {
620  head -n 151 "$0" | tail -n 123
621}
622
623stud_single_instance_config_load() {
624  file="${CONFIG_DIR}/${1}.conf"
625  INSTANCE_NAME=""
626
627  # reset configuration
628  stud_single_instance_config_reset
629  Error=''
630
631  if [ -f "${file}" -a -r "${file}" ]; then
632    . "${file}" >/dev/null || Error="Unable to load instance configuration file '${file}'."
633  else
634    Error="Invalid or unreadable instance configuration file '${file}'."
635    return 1
636  fi
637
638  # set instance name...
639  INSTANCE_NAME="${1}"
640
641  return 0
642}
643
644stud_instance_worker_pids() {
645  test -z "${1}" && return 1
646  ps -ef | grep  " ${1}  " | grep -v ' 1  ' | grep -v ' grep ' | awk '{print $2}' | xargs echo
647}
648
649# prints worker pid for n-th worker
650# arguments:
651#       $1:     list of worker pids (string)
652#       $2:     worker number
653stud_instance_worker_pid_by_num() {
654  i=0
655  local IFS=" "
656  for e in ${1}; do
657    i=$((i + 1))
658    if [ "${i}" = "${2}" ]; then
659      echo "$e"
660      return 0
661    fi
662  done
663  return 1
664}
665
666stud_affinity_set() {
667  # nothing to set?
668  test -z "$PROCESS_AFFINITY" && return 0
669
670  Error=""
671
672#   "1:0;2:3-4;3:5;4:7"  => bind first haproxy process to CPU0,
673#                        second haproxy process to CPU3 and CPU4,
674#                        third haproxy process to CPU5 and fourth
675#                        process to CPU7
676
677
678  worker_pids=`stud_instance_worker_pids "${1}"`
679
680  local IFS=";"
681  item=""
682  for item in $PROCESS_AFFINITY; do
683    num=`echo "${item}" | cut -f1 -d:`
684    affinity=`echo "${item}" | cut -f2 -d:`
685
686    # validate process number
687    test -z "$num" && continue
688    test ${num} -ge 1 2>&1 || continue
689
690    # validate affinity
691    test -z "${affinity}" && continue
692    # WORKS:        OpenSUSE
693    # DOESNT WORK:  Debian/Ubuntu!!!
694    #echo "${affinity}" | grep -qPi '[^a-f0-9\-\,x]' && continue
695
696    # is this raw affinity mask?
697    raw_affinity=0
698    echo "${affinity}" | grep -qE '^0x' && raw_affinity=1
699
700    # get pid for process id $num
701    pid=`stud_instance_worker_pid_by_num "${worker_pids}" "$num"`
702    test -z "$pid" && continue
703
704    #echo "item: $item; process num: $num; pid: $pid;  affinity: $affinity; raw: $raw_affinity"
705
706    opt="-p"
707    test "${raw_affinity}" = "0" && opt="${opt} -c"
708    opt="${opt} ${affinity}"
709    opt="${opt} ${pid}"
710    # echo "WILL RUN: 'taskset $opt'"
711    msg_log "Setting stud worker number ${num} (pid ${pid}) affinity using command: taskset ${opt}"
712    eval taskset ${opt} >/dev/null 2>&1 || msg_log "Error setting process affinity."
713  done
714}
715
716ulimit_n_set() {
717  if [ -z "$ULIMIT_N" ] || [ "$ULIMIT_N" = "0" ]; then
718    return 0
719  fi
720
721  # try to set maximum possible limit...
722  i="$ULIMIT_N"
723  num=0
724  while [ $i -gt 0 ]; do
725    num=$((num + 1))
726    if ulimit -n "$i" > /dev/null 2>&1; then
727      percentage=$((i*100 / ${ULIMIT_N}))
728      if [ $percentage -lt 75 ]; then
729        Error="Filedescriptor limit set to only $i (${percentage}% of desired value of $ULIMIT_N); check your system settings."
730        return 1
731      fi
732      msg_log "Filedescriptor limit successfully set to $i (${percentage}% of desired value of $ULIMIT_N) after ${num} iteration(s)."
733      return 0
734      break
735    else
736      i=$((i - 100))
737    fi
738  done
739
740  Error="Filedescriptor limit of $ULIMIT_N could not be set."
741  msg_log "$Error"
742  return 1
743}
744
745ulimit_set() {
746  # set fd limit
747  ulimit_n_set || return 1
748
749  # set core file limit
750  ulimit -c unlimited >/dev/null 2>&1
751
752  return 0
753}
754
755printhelp() {
756  cat <<EOF
757Usage: ${MYNAME} {start|stop|restart|status|sample_instance_config} [name, name2, ...]
758
759This is stud SSL offloader multi-instance init script.
760
761OPTIONS:
762  -C  --config-dir        Instance configuration directory (Default: "${CONFIG_DIR}")
763
764                          This directory is searched for files matching *.conf
765                          glob pattern; each file represents single stud instance
766                          configuration file.
767
768  -R  --runtime-dir       Runtime (pid file) directory (Default: "${RUNTIME_DIR}")
769
770      --sample-config     Prints out default single instance configuration
771
772  -V  --version           Prints script version
773  -h  --help              This help message
774EOF
775}
776
777# parse command line...
778TEMP=`getopt -o C:R:Vh --long config-dir:,runtime-dir:,sample-config,version,help -n "$MYNAME" -- "$@"`
779test "$?" != "0" && die "Invalid command line arguments. Run $MYNAME --help for instructions."
780eval set -- "$TEMP"
781while true; do
782  case $1 in
783    -C|--config-dir)
784      CONFIG_DIR="${2}"
785      shift 2
786      ;;
787    -R|--runtime-dir)
788      RUNTIME_DIR="${2}"
789      shift 2
790      ;;
791    --sample-config)
792      stud_single_instance_config_print
793      exit 0
794      ;;
795    -V|--version)
796      echo "$MYNAME $VERSION"
797      exit 0
798      ;;
799    -h|--help)
800      printhelp
801      exit 0
802      ;;
803    --)
804      shift
805      break
806      ;;
807    *)
808      die "Invalid command line arguments. Run $MYNAME --help for instructions."
809      ;;
810  esac
811done
812
813# weed out real action and do something
814case $1 in
815  start)
816    shift
817    stud_instances_start "$@"
818    ;;
819
820  stop)
821    shift
822    stud_instances_stop "$@"
823    ;;
824
825  force-reload|restart)
826    shift
827    stud_instances_restart "$@"
828    ;;
829
830  status)
831    stud_instances_status
832    exit $?
833    ;;
834
835  sample_instance_config|instance_config)
836    stud_single_instance_config_print
837    exit 0
838    ;;
839
840  *)
841    printhelp
842    exit 1
843  ;;
844esac
845
846# EOF
847