Index: trunk/src/VBox/Installer/linux/Makefile.kmk
===================================================================
--- trunk/src/VBox/Installer/linux/Makefile.kmk	(revision 44048)
+++ trunk/src/VBox/Installer/linux/Makefile.kmk	(revision 44049)
@@ -19,5 +19,6 @@
 include $(KBUILD_PATH)/subheader.kmk
 
-# Include sub-makefile.
+# Include sub-makefiles.
+include $(PATH_SUB_CURRENT)/install_service/Makefile.kmk
 ifdef VBOX_WITH_TESTCASES
  include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk
Index: trunk/src/VBox/Installer/linux/install_service/Makefile.kmk
===================================================================
--- trunk/src/VBox/Installer/linux/install_service/Makefile.kmk	(revision 44048)
+++ trunk/src/VBox/Installer/linux/install_service/Makefile.kmk	(revision 44049)
@@ -1,5 +1,5 @@
 # $Id$
 ## @file
-# Sub-Makefile for the VirtualBox Guest Addition X11 Client.
+# Sub-Makefile for the Linux installer init file generator.
 #
 
@@ -34,4 +34,16 @@
 endif
 
+INSTALLS.linux += linux-install-service-bin
+linux-install-service-bin_INST =    bin/helpers/
+linux-install-service-bin_MODE =    a+rx,u+w
+linux-install-service-bin_SOURCES = \
+        install_service.sh=>install_service
+
+INSTALLS.linux += linux-install-service-nobin
+linux-install-service-nobin_INST =    bin/helpers/
+linux-install-service-nobin_MODE =    a+r,u+w
+linux-install-service-nobin_SOURCES = \
+        init_template.sh
+
 include $(FILE_KBUILD_SUB_FOOTER)
 
Index: trunk/src/VBox/Installer/linux/install_service/generate_service_file.cpp
===================================================================
--- trunk/src/VBox/Installer/linux/install_service/generate_service_file.cpp	(revision 44048)
+++ trunk/src/VBox/Installer/linux/install_service/generate_service_file.cpp	(revision 44049)
@@ -89,5 +89,5 @@
 "      is supported.  This affects escaping of strings substituted.\n"
 "\n"
-"  --command\n"
+"  --command <command>\n"
 "      The absolute path of the executable file to be started by the service.\n"
 "      No form of quoting should be used here.  Substituted for the sequence\n"
@@ -95,19 +95,19 @@
     RTPrintf(
 "\n"
-"  --arguments <arguments>\n"
-"      The arguments to pass to the executable file when it is started.  ASCII\n"
-"      characters 0 to 31, \"\'\" and 127 should be escaped in C string-style and\n"
-"      spaces inside words should be preceeded by a back slash.  Some systemd-\n"
-"      style \"%%\" sequences may be added at a future time.  Substituted for the\n"
-"      sequence \"%%ARGUMENTS%%\" in the template.\n");
-    RTPrintf(
-"\n"
 "  --description <description>\n"
 "      A short description of the service which can also be used in sentences\n"
-"      like \"<description> failed to start.\".  ASCII characters 0 to 31 and 127\n"
-"      should not be used.  Substituted for the sequence \"%%DESCRIPTION%%\" in the\n"
-"      template.\n"
+"      like \"<description> failed to start.\", as a single parameter.  ASCII\n"
+"      characters 0 to 31 and 127 should not be used.  Substituted for the\n"
+"      sequence \"%%DESCRIPTION%%\" in the template.\n"
 "\n"
 "Other options:\n"
+"\n");
+    RTPrintf(
+"  --arguments <arguments>\n"
+"      The arguments to pass to the executable file when it is started, as a\n"
+"      single parameter.  ASCII characters 0 to 31, \"\'\" and 127 should be escaped\n"
+"      in C string-style and spaces inside words should be preceeded by a back\n"
+"      slash.  Some systemd-style \"%%\" sequences may be added at a future time.\n"
+"      Substituted for the sequence \"%%ARGUMENTS%%\" in the template.\n"
 "\n");
     RTPrintf(
Index: trunk/src/VBox/Installer/linux/install_service/init_template.sh
===================================================================
--- trunk/src/VBox/Installer/linux/install_service/init_template.sh	(revision 44048)
+++ trunk/src/VBox/Installer/linux/install_service/init_template.sh	(revision 44049)
@@ -23,4 +23,8 @@
 # Short-Description: %DESCRIPTION%
 ### END INIT INFO
+
+## @todo We should really replace the daemon starting, stopping and checking
+#        code with a tool of our own written in C, which we could always use
+#        instead of the LSB functions.
 
 cr="
@@ -71,10 +75,6 @@
 LSB_FUNCTIONS="/lib/lsb/init-functions"
 
-## Redhat and Fedora lock directory
-LOCK_FOLDER="/var/lock/subsys/"
-LOCK_FILE="${LOCK_FOLDER}/%SERVICE_NAME%"
-
 # Silently exit if the package was uninstalled but not purged.
-[ -r %COMMAND% ] || exit 0
+test -r %COMMAND% || exit 0
 
 ## The function definition at the start of every non-trivial shell script!
@@ -91,9 +91,71 @@
     exit 0
 }
+
+## Set the error message.
+set_error()
+{
+    test -z "${error}" && error="${1}"
+}
+
+# Gentoo/OpenRC perculiarity.
+if test "x${0}" = "x/sbin/rc" || test "x${0}" = "xrc"; then
+    shift
+fi
+
+# Process arguments.
+action=""
+error=""
+prefix="/var"
+while test x"${#}" != "x0"; do
+    case "${1}" in
+    --lsb-functions)
+        test x"${#}" = "x1" &&
+            set_error "${1}: missing argument."
+        LSB_FUNCTIONS="${2}"
+        shift 2;;
+    --prefix)
+        test x"${#}" = "x1" &&
+            set_error "${1}: missing argument."
+        prefix="${2}"
+        shift 2;;
+    --help)
+        cat << EOF
+Usage:
+
+  ${0} {start|stop|restart|status} [<options>]
+
+  start|stop|restart|status
+      Start/stop/restart/report status for the service.
+
+Options:
+
+  --lsb-functions <script>
+      Take the standard LSB init functions from <script> instead of from the
+      normal location, or use our own versions if <script> is an empty string.
+
+  --prefix <folder>
+      Use the folder <folder> for storing variable data instead of "/var".  The
+      child folder "run" must exist.
+EOF
+        exit 0;;
+    start|stop|restart|force-reload|condrestart|try-restart|reload|status)
+        test -z "${action}" ||
+            set_error "More than one action requested."
+        action="${1}"
+        shift;;
+    *)
+        set_error "Unknown option \"${1}\".  Try \"${0} --help\" for more information."
+        shift;;
+    esac
+done
+
+## Set Redhat and Fedora lock directory
+LOCK_FOLDER="${prefix}/lock/subsys/"
+LOCK_FILE="${LOCK_FOLDER}/%SERVICE_NAME%"
 
 # Use LSB functions if available.  Success and failure messages default to just
 # "echo" if the LSB functions are not available, so call these functions with
 # messages which clearly read as success or failure messages.
-[ -n "${LSB_FUNCTIONS}" ] && [ -f "${LSB_FUNCTIONS}" ] &&
+test -n "${LSB_FUNCTIONS}" && test -f "${LSB_FUNCTIONS}" &&
   . "${LSB_FUNCTIONS}"
 
@@ -101,11 +163,15 @@
     log_success_msg()
     {
-        echo "${*}"
-    }
-
-type log_success_fail >/dev/null 2>&1 ||
-    log_success_fail()
-    {
-        echo "${*}"
+        cat << EOF
+${*}
+EOF
+    }
+
+type log_failure_msg >/dev/null 2>&1 ||
+    log_failure_msg()
+    {
+        cat << EOF
+${*}
+EOF
     }
 
@@ -113,5 +179,5 @@
 pidfilename()
 {
-    echo "/var/run/${1##*/}.pid"
+    echo "${prefix}/run/${1##*/}.pid"
 }
 
@@ -119,5 +185,5 @@
 pidfileofproc()
 {
-    if [ x"${1}" = "x-p" ]; then
+    if test x"${1}" = "x-p"; then
         echo "${2}"
     else
@@ -129,7 +195,10 @@
 pidsfromfile()
 {
-    read -r pids < "${1}" 2>/dev/null
+    pids=""
+    test -r "${1}" &&
+        read -r pids < "${1}" 2>/dev/null
     for i in $pids; do
-        [ 1 -le "${i}" ] || return 1
+        test 1 -le "${i}" || return 1
+    done
     echo "${pids}"
 }
@@ -140,5 +209,5 @@
     binary="${1}"
     shift
-    ps -p "${@}" -f 2>/dev/null | grep -q "${binary}"
+    ps -p "${@}" -f 2>/dev/null | grep "${binary}" >/dev/null
 }
 
@@ -146,7 +215,7 @@
     pidofproc()
     {
-        pidfile="$(pidfileofproc "${@}")"
-        [ "x${1}" = "x-p" ] && shift 2
-        pids="$(pidsfromfile "${pidfile}")"
+        pidfile="`pidfileofproc "${@}"`"
+        test "x${1}" = "x-p" && shift 2
+        pids="`pidsfromfile "${pidfile}"`"
         procrunning "${1}" ${pids} && echo "${pids}"
     }
@@ -155,8 +224,8 @@
     killproc()
     {
-        pidfile="$(pidfileofproc "${@}")"
-        [ "x${1}" = "x-p" ] && shift 2
-        pids="$(pidsfromfile "${pidfile}")"
-        if [ -n "${2}" ]; then
+        pidfile="`pidfileofproc "${@}"`"
+        test "x${1}" = "x-p" && shift 2
+        pids="`pidsfromfile "${pidfile}"`"
+        if test -n "${2}"; then
             procrunning "${1}" ${pids} || return 1
             kill "${2}" ${pids}
@@ -165,14 +234,20 @@
             rm -f "${pidfile}"
             procrunning "${1}" ${pids} || return 0
-            kill "${pid}"
-            time=0
-            while true; do
-                sleep 1
-                procrunning "${1}" ${pids} || break
-                time=$((${time} + 1))
-                if [ "${time}" = "${SHUT_DOWN_TIME_OUT}" ]; then
-                    kill -9 "${pid}"
-                    break
-                fi
+            kill "${pids}"
+            # Short busy wait for the process to terminate.
+            stamp="`times`"
+            while test x"${stamp}" = x"`times`"; do
+                procrunning "${1}" ${pids} || return 0
+            done
+            # Slow sleeping wait if it is still running.
+            for high in "" 1 2 3 4 5 6 7 8 9; do
+                for time in ${high}0 ${high}1 ${high}2 ${high}3 ${high}4 ${high}5 ${high}6 ${high}7 ${high}8 ${high}9; do
+                    sleep 1
+                    procrunning "${1}" ${pids} || return 0
+                    if test "${time}" = "${SHUT_DOWN_TIME_OUT}"; then
+                        kill -9 "${pid}"
+                        return 0
+                    fi
+                done
             done
             return 0
@@ -182,9 +257,9 @@
 start()
 {
-    [ -d "${LOCK_FOLDER}" ] && touch "${LOCK_FILE}"
-    [ -n "$(pidofproc %COMMAND%)" ] && exit 0
+    test -d "${LOCK_FOLDER}" && touch "${LOCK_FILE}"
+    test -n "`pidofproc %COMMAND%`" && exit 0
     %COMMAND% %ARGUMENTS% >/dev/null 2>&1 &
     pid="$!"
-    pidfile="$(pidfilename %COMMAND%)"
+    pidfile="`pidfilename %COMMAND%`"
     echo "${pid}" > "${pidfile}"
     do_success
@@ -201,43 +276,41 @@
 status()
 {
-    [ -n "$(pidofproc %COMMAND%)" ] && exit 0
-    [ -f "$(pidfilename %COMMAND%)" ] && exit 1
-    [ -f "${LOCK_FILE}" ] && exit 2
+    pid="`pidofproc %COMMAND%`"
+    test -n "${pid}" &&
+    {
+        echo "%SERVICE_NAME% running, process ${pid}"
+        exit 0
+    }
+    test -f "`pidfilename %COMMAND%`" &&
+    {
+        echo "%SERVICE_NAME% not running but PID-file present."
+        exit 1
+    }
+    test -f "${LOCK_FILE}" &&
+    {
+        echo "%SERVICE_NAME% not running but lock file present."
+        exit 2
+    }
+    echo "%SERVICE_NAME% not running."
     exit 3
 }
 
-# Gentoo/OpenRC perculiarity.
-if [ "$(which "${0}")" = "/sbin/rc" ]; then
-    shift
-fi
-
-if [ "${1}" = "--lsb-functions" ]; then
-    LSB_FUNCTIONS="${2}"
-    shift 2
-fi
-
-case "${1}" in
+test -z "${error}" || abort "${error}"
+
+case "${action}" in
 start)
+    start;;
+stop)
+    stop;;
+restart|force-reload)
     start
-    ;;
-stop)
-    stop
-    ;;
-restart|force-reload)
-    stop
-    start
-    ;;
+    stop;;
 condrestart|try-restart)
     status || exit 0
     stop
-    start
-    ;;
+    start;;
 reload)
     ;;
 status)
-    status
-    ;;
-*)
-    echo "Usage: ${0} {start|stop|restart|status}"
-    exit 1
+    status;;
 esac
Index: trunk/src/VBox/Installer/linux/install_service/install_service.sh
===================================================================
--- trunk/src/VBox/Installer/linux/install_service/install_service.sh	(revision 44049)
+++ trunk/src/VBox/Installer/linux/install_service/install_service.sh	(revision 44049)
@@ -0,0 +1,225 @@
+#!/bin/sh
+
+#
+# Script to install services within a VirtualBox installation.
+#
+# Copyright (C) 2012 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+
+# Clean up before we start.
+cr="
+"
+tab="	"
+IFS=" ${cr}${tab}"
+'unset' -f unalias
+'unalias' -a 2>/dev/null
+'unset' -f command
+PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
+
+## Script usage documentation.
+## @todo generate_service_file could be called to print its own documentation.
+usage() {
+  cat << EOF
+Usage:
+
+  `basename $0` --help|--usage|<options>
+
+Create a system service which runs a command.  In order to make it possible to
+do this in a simple and portable manner, we place a number of requirements on
+the command to be run:
+ - That it can be started safely even if all its dependencies are not started
+   and will sleep if necessary until it can start work.  Ideally it should start
+   accepting input as early as it can, but delay handling it if necessary.
+ - That it does not background to simplify service process management.
+ - That it can be safely shut down using SIGTERM.
+ - That if all running copies of the main process binary are stopped first the
+   service can be re-started and will do any necessary clean-up automatically.
+ - That any output which must not be lost go either to the system log or to the
+   service's private log.
+
+We currently support System V init only.  This will probably soon be extended
+to BSD init, OpenRC, Pardus Comar and systemd, but probably not Upstart which
+currently requires modifying init files to disable a service.  We also try to
+enable our service (if requested) in all init systems we find, as we do not know
+which one is in active use.  We assume that this will not have any adverse
+effects.
+
+ --help|--usage
+     Print this help text and exit.
+
+Required options:
+
+  --command <command>
+      The absolute path of the executable file to be started by the service.  No
+      form of quoting should be used here.
+
+  --description <description>
+      A short description of the service which can also be used in sentences
+      like "<description> failed to start", as a single parameter.  ASCII
+      characters 0 to 31 and 127 should not be used.
+
+Other options:
+
+  --arguments <arguments>
+      The arguments to pass to the executable file when it is started, as a
+      single parameter. ASCII characters 0 to 31, "'" and 127 should be escaped
+      in C string-style and spaces inside words should be preceeded by a back
+      slash.  Some systemd-style % sequences may be added at a future time.
+
+  --service-name <name>
+      Specify the name of the service.  By default the base name without the
+      extension of the command binary is used.  Only ASCII characters 33 to 126
+      should be used.
+
+  --enabled
+      Enable the service in normal user run-levels by default.  If this option
+      is not used the service will be disabled by default.  If a version of the
+      service was already installed this option (or its absence) will be
+      ignored unless the "--force" option is also specified.
+
+  --force
+      Respect the presence or absence of the "--enabled" flag even if a previous
+      version of the service was already installed with a different enablement
+      state.
+
+  --prefix <prefix>
+      Treat all paths as relative to <prefix> rather than /etc.
+EOF
+}
+
+## The function definition at the start of every non-trivial shell script!
+abort() {
+    ## $1 Error text to output to standard error.
+    cat >&2 << EOF
+$1
+EOF
+    exit 1
+}
+
+enabled=""
+force=""
+PREFIX="/etc/"
+ARGUMENTS=""
+SERVICE_NAME=""
+
+# Process arguments.
+## @todo Pass more through unmodified to generate_service_file to reduce
+#        duplication.  Or then again, maybe the hassle of perserving the
+#        positional parameters is not worth it.
+while test x"${#}" != "x0"; do
+    case "${1}" in
+    "--help|--usage")
+        usage
+        exit 0;;
+    "--enabled")
+        enabled=true
+        shift;;
+    "--force")
+        force=true
+        shift;;
+    "--prefix")
+        test -z "${2}" && abort "${1}: missing argument."
+        PREFIX="${2}"
+        shift 2;;
+    "--command")
+        test -z "${2}" && abort "${1}: missing argument."
+        COMMAND="${2}"
+        shift 2;;
+    "--arguments")
+        test -z "${2}" && abort "${1}: missing argument."
+        ARGUMENTS="${2}"
+        shift 2;;
+    "--description")
+        test -z "${2}" && abort "${1}: missing argument."
+        DESCRIPTION="${2}"
+        shift 2;;
+    "--service-name")
+        test -z "${2}" && abort "${1}: missing argument."
+        SERVICE_NAME="${2}"
+        shift 2;;
+    *)
+        abort "Unknown option ${1}.";;
+    esac
+done
+
+# Check required options and set default values for others.
+test -z "${COMMAND}" &&
+    abort "Please supply a start command."
+test -f "${COMMAND}" && test -x "${COMMAND}" ||
+    abort "The start command must be an executable file."
+case "${COMMAND}" in
+    /*) ;;
+    *) abort "The start command must have an absolute path." ;;
+esac
+test -z "${DESCRIPTION}" &&
+    abort "Please supply a service description."
+# Get the service name from the command path if not explicitly
+# supplied.
+test -z "${SERVICE_NAME}" &&
+    SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)\..*'`"
+test -z "${SERVICE_NAME}" &&
+    SERVICE_NAME="`expr "${COMMAND}" : '.*/\(.*\)'`"
+
+# Get the folder we are running from, as we need other files there.
+script_folder="`dirname "$0"`"
+script_folder="`cd "${script_folder}" && pwd`"
+test -d "${script_folder}" ||
+    abort "Failed to find the folder this command is running from."
+
+# Keep track of whether we found at least one initialisation system.
+found_init=""
+# And whether we found a previous service script/file.
+update=""
+
+# Find the best System V/BSD init path if any is present.
+for path in "${PREFIX}/init.d/rc.d" "${PREFIX}/init.d/" "${PREFIX}/rc.d/init.d" "${PREFIX}/rc.d"; do
+    if test -d "${path}"; then
+        found_init="true"
+        test -f "${path}/${SERVICE_NAME}" && update="true"
+        "${script_folder}/generate_service_file" --format shell --command "${COMMAND}" --arguments "${ARGUMENTS}" --description "${DESCRIPTION}" --service-name "${SERVICE_NAME}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
+        chmod a+x "${path}/${SERVICE_NAME}"
+        # Attempt to install using both system V symlinks and OpenRC, assuming
+        # that both will not be in operation simultaneously (but may be
+        # switchable).  BSD init expects the user to enable services explicitly.
+        if test -z "${update}" || test -n "${force}"; then
+            # Various known combinations of sysvinit rc directories.
+            for i in ${PREFIX}/rc*.d/[KS]??"${SERVICE_NAME}" ${PREFIX}/rc.d/rc*.d/[KS]??"${SERVICE_NAME}"; do
+                rm -f "$i"
+            done
+            # And OpenRC.
+            type rc-update > /dev/null 2>&1 &&
+                rc-update del "${1}" > /dev/null 2>&1
+            # Various known combinations of sysvinit rc directories.
+            if test -n "${enabled}"; then
+                for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do
+                    if test -d "${PREFIX}/${i}"; then
+                        # Paranoia test first.
+                        test -d "${PREFIX}/${i}/K80${SERVICE_NAME}" ||
+                            ln -sf "${path}/${SERVICE_NAME}" "${PREFIX}/${i}/K80${SERVICE_NAME}"
+                    fi
+                done
+                for i in rc3.d rc4.d rc5.d rc.d/rc3.d rc.d/rc4.d rc.d/rc5.d; do
+                    if test -d "${PREFIX}/${i}"; then
+                        # Paranoia test first.
+                        test -d "${PREFIX}/${i}/S20${SERVICE_NAME}" ||
+                            ln -sf "${path}/${SERVICE_NAME}" "${PREFIX}/${i}/S20${SERVICE_NAME}"
+                    fi
+                done
+                # And OpenRC.
+                type rc-update > /dev/null 2>&1 &&
+                    rc-update add "${1}" default > /dev/null 2>&1
+            fi
+        fi
+        break
+    fi
+done
+
+test -z "${found_init}" &&
+    abort "No supported initialisation system found."
Index: trunk/src/VBox/Installer/linux/testcase/Makefile.kmk
===================================================================
--- trunk/src/VBox/Installer/linux/testcase/Makefile.kmk	(revision 44048)
+++ trunk/src/VBox/Installer/linux/testcase/Makefile.kmk	(revision 44049)
@@ -45,3 +45,9 @@
 tstHeadlessXOrg_SOURCES = tstHeadlessXOrg.sh
 
+INSTALLS += tstInstallInit
+TESTING += tstInstallInit
+tstHeadlessXOrg_INST    = $(INST_TESTCASE)
+tstHeadlessXOrg_MODE    = a+rx,u+w
+tstHeadlessXOrg_SOURCES = tstInstallInit.sh
+
 include $(FILE_KBUILD_SUB_FOOTER)
Index: trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh
===================================================================
--- trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh	(revision 44049)
+++ trunk/src/VBox/Installer/linux/testcase/tstInstallInit.sh	(revision 44049)
@@ -0,0 +1,150 @@
+#!/bin/sh
+# $Id$
+#
+# VirtualBox init file creator unit test.
+#
+# Copyright (C) 2012 Oracle Corporation
+#
+# This file is part of VirtualBox Open Source Edition (OSE), as
+# available from http://www.virtualbox.org. This file is free software;
+# you can redistribute it and/or modify it under the terms of the GNU
+# General Public License (GPL) as published by the Free Software
+# Foundation, in version 2 as it comes in the "COPYING" file of the
+# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+#
+
+# This will initially be a skeleton with a couple of tests - add more for quick
+# debugging when you suspect that something isn't working as specified.
+
+tab="	"
+tmpbase="/tmp/tstInstallInit99"
+
+## The function definition at the start of every non-trivial shell script!
+abort()
+{
+  ## $1 Error text to output to standard error in printf format.
+    cat >&2 << EOF
+${TEST_NAME}: $1
+EOF
+    exit 1
+}
+
+## Print a TESTING line.
+print_line()
+{
+    cat >&2 << EOF
+${TEST_NAME}: TESTING $1
+EOF
+}
+
+## Set the failure message if it is not yet set.
+fail_msg()
+{
+    test -z "${failed}" && failed="FAILED: ${1}"
+}
+
+# Get the directory where the script is located and the parent.
+OUR_FOLDER=`dirname "$0"`
+OUR_FOLDER=`cd "${OUR_FOLDER}" && pwd`
+VBOX_FOLDER=`cd "${OUR_FOLDER}/.." && pwd`
+[ -d "${VBOX_FOLDER}" ] ||
+  abort "Failed to change to directory ${VBOX_FOLDER}.\n"
+cd "${VBOX_FOLDER}"
+
+# Get our name for output.
+TEST_NAME="$(basename "$0" .sh)"
+
+# Create a trivial test service in temporary directory $1 with name $2.
+test_service()
+{
+    cat > "${1}/${2}" << EOF
+#!/bin/sh
+trap "touch \"${1}/stopped\"; exit" TERM 
+echo "1: \${1} 2: \${2} 3: \${3}" > "${1}/started"
+while true; do true; done
+EOF
+chmod u+x "${1}/${2}"
+}
+
+# Test some dodgy input values against generate_service_file.
+print_line "generation of shell script from template."
+input='TEST1%DESCRIPTION%%%%SERVICE_NAME% TST2 TEST  %ARGUMENTS%%COMMAND%'
+out=`echo "${input}" |
+    helpers/generate_service_file --command '/usr/bin
+aries/hello
+world' --arguments 'p\x0a0\n\ \t' --format shell --description ''`
+expected='TEST1%hello
+world TST2 TEST  '\''p
+0
+ '"${tab}"\'\''/usr/bin
+aries/hello
+world'\'
+case "${out}" in ${expected})
+echo "SUCCESS";;
+*)
+cat << EOF
+FAILED: expected
+${expected}
+but got
+${out}
+EOF
+esac
+
+# Test an init script installation
+print_line "installing an init script."
+failed=""
+# Create a simulated init system layout.
+tmpdir="${tmpbase}0"
+rm -rf "${tmpdir}"
+mkdir -m 0700 "${tmpdir}" || abort "Failed to create a temporary folder."
+mkdir -p "${tmpdir}/init.d/" "${tmpdir}/rc.d/init.d/"
+for i in 0 1 2 3 4 5 6; do
+    mkdir "${tmpdir}/rc${i}.d/" "${tmpdir}/rc.d/rc${i}.d/"
+done
+mkdir "${tmpdir}/run"
+# Create the service binary.
+test_service "${tmpdir}" "service"
+# And install it.
+helpers/install_service --command "${tmpdir}/service" --arguments "test of my\ arguments" --description "My description" --prefix "${tmpdir}" --enabled
+# Check that the main service file was created as specified.
+if test -x "${tmpdir}/init.d/service"; then
+    grep "Short-Description: My description" "${tmpdir}/init.d/service" >/dev/null ||
+        fail_msg "Description not set in \"${tmpdir}/init.d/service\""
+else
+    fail_msg "\"${tmpdir}/init.d/service\" not correctly created."
+fi
+test -x "${tmpdir}/init.d/rc.d/service" &&
+    fail_msg "\"${tmpdir}/init.d/rc.d/service\" created but shouldn't have been."
+# Try to start the service using the symbolic links which should have been
+# created.
+if "${tmpdir}/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" start >/dev/null; then
+    if grep "1: test 2: of 3: my arguments" "${tmpdir}/started" >/dev/null; then
+        test -f "${tmpdir}/stopped" &&
+            fail_msg "\"${tmpdir}/rc3.d/S20service\" stopped immediately."
+    else
+        fail_msg "\"${tmpdir}/rc3.d/S20service\" did not start correctly."
+    fi
+else
+    fail_msg "could not start \"${tmpdir}/rc3.d/S20service\"."
+fi
+# Check the status.
+"${tmpdir}/rc.d/rc5.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null ||
+    fail_msg "\"${tmpdir}/rc.d/rc5.d/S20service\" reported the wrong status."
+# Try to stop the service using the symbolic links which should have been
+# created.
+if "${tmpdir}/rc.d/rc6.d/K80service" --prefix "${tmpdir}" --lsb-functions "" stop >/dev/null; then
+    test -f "${tmpdir}/stopped" ||
+        echo "\"${tmpdir}/rc.d/rc6.d/K80service\" did not stop correctly."
+else
+    fail_msg "could not stop \"${tmpdir}/rc.d/rc6.d/K80service\"."
+fi
+# Check the status again - now it should be stopped.
+"${tmpdir}/rc.d/rc3.d/S20service" --prefix "${tmpdir}" --lsb-functions "" status >/dev/null &&
+    fail_msg "\"${tmpdir}/rc.d/rc3.d/S20service\" reported the wrong status."
+# Final summary.
+if test -n "${failed}"; then
+    echo "${failed}"
+else
+    echo SUCCESS
+fi
