1 | #!/bin/sh
|
---|
2 |
|
---|
3 | #
|
---|
4 | # Script to install services within a VirtualBox installation.
|
---|
5 | #
|
---|
6 | # Copyright (C) 2012-2013 Oracle Corporation
|
---|
7 | #
|
---|
8 | # This file is part of VirtualBox Open Source Edition (OSE), as
|
---|
9 | # available from http://www.virtualbox.org. This file is free software;
|
---|
10 | # you can redistribute it and/or modify it under the terms of the GNU
|
---|
11 | # General Public License (GPL) as published by the Free Software
|
---|
12 | # Foundation, in version 2 as it comes in the "COPYING" file of the
|
---|
13 | # VirtualBox OSE distribution. VirtualBox OSE is distributed in the
|
---|
14 | # hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
|
---|
15 | #
|
---|
16 |
|
---|
17 | # Clean up before we start.
|
---|
18 | cr="
|
---|
19 | "
|
---|
20 | tab=" "
|
---|
21 | IFS=" ${cr}${tab}"
|
---|
22 | 'unset' -f unalias
|
---|
23 | 'unalias' -a 2>/dev/null
|
---|
24 | 'unset' -f command
|
---|
25 | PATH=/bin:/sbin:/usr/bin:/usr/sbin:$PATH
|
---|
26 |
|
---|
27 | # Get the folder we are running from, as we need other files there.
|
---|
28 | script_folder="`dirname "$0"`"
|
---|
29 |
|
---|
30 | ## Script usage documentation.
|
---|
31 | usage() {
|
---|
32 | cat << EOF
|
---|
33 | Usage:
|
---|
34 |
|
---|
35 | `basename $0` --help|--enable|--disable|--force-enable|--force-disable
|
---|
36 | |--remove [--prefix <prefix>]
|
---|
37 | -- <pass-through parameters>
|
---|
38 |
|
---|
39 | Create a system service which runs a command. In order to make it possible to
|
---|
40 | do this in a simple and portable manner, we place a number of requirements on
|
---|
41 | the command to be run:
|
---|
42 | - That it can be started safely even if all its dependencies are not started
|
---|
43 | and will sleep if necessary until it can start work. Ideally it should
|
---|
44 | start accepting input as early as it can, but delay handling it if
|
---|
45 | necessary, and delay accessing its dependencies until it actually needs
|
---|
46 | them.
|
---|
47 | - That it does not background to simplify service process management.
|
---|
48 | - That it can be safely shut down using SIGTERM.
|
---|
49 | - That if all running copies of the main process binary are stopped first the
|
---|
50 | service can be re-started and will do any necessary clean-up automatically.
|
---|
51 | - That any output which must not be lost go either to the system log or to the
|
---|
52 | service's private log.
|
---|
53 |
|
---|
54 | We currently support System V init only. This will probably soon be extended
|
---|
55 | to BSD init, OpenRC and systemd, but probably not Upstart which currently
|
---|
56 | requires modifying init files to disable a service. We also try to enable our
|
---|
57 | service (if requested) in all init systems we find, as we do not know which one
|
---|
58 | is in active use. We assume that this will not have any adverse effects.
|
---|
59 |
|
---|
60 | --help|--usage
|
---|
61 | Print this help text and exit.
|
---|
62 |
|
---|
63 | --enable|--disable|--force-enable|--force-disable
|
---|
64 | These actions install the service. If a version of the service was not
|
---|
65 | installed previously, "--enable" and "--force-enable" make it start when
|
---|
66 | entering normal user run-levels and "--disable" and "--force-disable"
|
---|
67 | prevents it from starting when entering any run-level. If a version of
|
---|
68 | the service was already installed previously, "--enable" and "--disable"
|
---|
69 | simply update it without changing when it starts; "--force-enable" and
|
---|
70 | "--force-disable" behave the same as when no previous version was found.
|
---|
71 | Only one of these options or "--remove" may be specified.
|
---|
72 |
|
---|
73 | --remove
|
---|
74 | This action uninstalls the service. It may not be used in combination
|
---|
75 | with "--enable", "--disable", "--force-enable" or "--force-disable".
|
---|
76 |
|
---|
77 | Option:
|
---|
78 |
|
---|
79 | --prefix <prefix>
|
---|
80 | Treat all paths as relative to <prefix> rather than /etc.
|
---|
81 |
|
---|
82 | Pass-through parameters will be passed through to the "generate_service_file"
|
---|
83 | tool.
|
---|
84 | EOF
|
---|
85 | }
|
---|
86 |
|
---|
87 | ## The function definition at the start of every non-trivial shell script!
|
---|
88 | abort() {
|
---|
89 | ## $1 Error text to output to standard error.
|
---|
90 | cat >&2 << EOF
|
---|
91 | $1
|
---|
92 | EOF
|
---|
93 | exit 1
|
---|
94 | }
|
---|
95 |
|
---|
96 | ACTION=""
|
---|
97 | PREFIX="/etc/"
|
---|
98 | SERVICE_NAME=""
|
---|
99 |
|
---|
100 | # Process arguments.
|
---|
101 | while test x"${1}" != "x--"; do
|
---|
102 | case "${1}" in
|
---|
103 | "--help"|"--usage")
|
---|
104 | usage
|
---|
105 | exit 0;;
|
---|
106 | "--enable"|"--disable"|"--force-enable"|"--force-disable"|"--remove")
|
---|
107 | test -z "${ACTION}" || abort "More than one action specified."
|
---|
108 | ACTION="true"
|
---|
109 | ENABLE=""
|
---|
110 | INSTALL="true"
|
---|
111 | UPDATE=""
|
---|
112 | { test "${1}" = "--enable" || test "${1}" = "--disable"; } &&
|
---|
113 | UPDATE="true"
|
---|
114 | { test "${1}" = "--enable" || test "${1}" = "--force-enable"; } &&
|
---|
115 | ENABLE="true"
|
---|
116 | test "${1}" = "--remove" &&
|
---|
117 | INSTALL=""
|
---|
118 | shift;;
|
---|
119 | "--prefix")
|
---|
120 | test -z "${2}" && abort "${1}: missing argument."
|
---|
121 | PREFIX="${2}"
|
---|
122 | shift 2;;
|
---|
123 | *)
|
---|
124 | abort "Unknown option ${1}.";;
|
---|
125 | esac
|
---|
126 | done
|
---|
127 | shift
|
---|
128 |
|
---|
129 | # Check required options and set default values for others.
|
---|
130 | test -z "${ACTION}" &&
|
---|
131 | abort "Please supply an install action."
|
---|
132 |
|
---|
133 | # Get the service name.
|
---|
134 | SERVICE_NAME=`echo "%SERVICE_NAME%" |
|
---|
135 | "${script_folder}/../helpers/generate_service_file" --format shell "${@}"`
|
---|
136 | test -z "${SERVICE_NAME}" &&
|
---|
137 | abort "Please supply a command path."
|
---|
138 |
|
---|
139 | # Keep track of whether we found at least one initialisation system.
|
---|
140 | found_init=""
|
---|
141 |
|
---|
142 | # Find the best System V/BSD init path if any is present.
|
---|
143 | for path in "${PREFIX}/init.d/rc.d" "${PREFIX}/init.d/" "${PREFIX}/rc.d/init.d" "${PREFIX}/rc.d"; do
|
---|
144 | if test -d "${path}"; then
|
---|
145 | # Check permissions for the init path.
|
---|
146 | test -w "${path}" || abort "No permission to write to \"${path}\"."
|
---|
147 | # And for the System V symlink directories.
|
---|
148 | for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do
|
---|
149 | if test -d "${PREFIX}/${i}"; then
|
---|
150 | test -w "${PREFIX}/${i}" ||
|
---|
151 | abort "No permission to write to \"${PREFIX}/${i}\"."
|
---|
152 | fi
|
---|
153 | done
|
---|
154 | # And for the OpenRC symlink directories.
|
---|
155 | if test -d "${PREFIX}/runlevel/"; then
|
---|
156 | test -w "${PREFIX}/runlevel/" ||
|
---|
157 | abort "No permission to write to \"${PREFIX}/runlevel\"".
|
---|
158 | fi
|
---|
159 | found_init="true"
|
---|
160 | update=""
|
---|
161 | test -f "${path}/${SERVICE_NAME}" && update="${UPDATE}"
|
---|
162 | if test -n "${INSTALL}"; then
|
---|
163 | "${script_folder}/../helpers/generate_service_file" --format shell "${@}" < "${script_folder}/init_template.sh" > "${path}/${SERVICE_NAME}"
|
---|
164 | chmod a+x "${path}/${SERVICE_NAME}"
|
---|
165 | else
|
---|
166 | rm "${path}/${SERVICE_NAME}"
|
---|
167 | fi
|
---|
168 | # Attempt to install using both system V symlinks and OpenRC, assuming
|
---|
169 | # that both will not be in operation simultaneously (but may be
|
---|
170 | # switchable). BSD init expects the user to enable services
|
---|
171 | # explicitly.
|
---|
172 | if test -z "${update}"; then
|
---|
173 | # Various known combinations of sysvinit rc directories.
|
---|
174 | for i in "${PREFIX}"/rc*.d/[KS]??"${SERVICE_NAME}" "${PREFIX}"/rc.d/rc*.d/[KS]??"${SERVICE_NAME}"; do
|
---|
175 | rm -f "${i}"
|
---|
176 | done
|
---|
177 | # And OpenRC.
|
---|
178 | test -d "${PREFIX}/runlevel/" &&
|
---|
179 | for i in "/${PREFIX}/runlevel"/*/"${SERVICE_NAME}"; do
|
---|
180 | rm -f "${i}"
|
---|
181 | done
|
---|
182 | # Various known combinations of sysvinit rc directories.
|
---|
183 | if test -n "${ENABLE}"; then
|
---|
184 | for i in rc0.d rc1.d rc6.d rc.d/rc0.d rc.d/rc1.d rc.d/rc6.d; do
|
---|
185 | if test -d "${PREFIX}/${i}"; then
|
---|
186 | # Paranoia test first.
|
---|
187 | test -d "${PREFIX}/${i}/K80${SERVICE_NAME}" ||
|
---|
188 | ln -sf "${path}/${SERVICE_NAME}" "${PREFIX}/${i}/K80${SERVICE_NAME}"
|
---|
189 | fi
|
---|
190 | done
|
---|
191 | for i in rc2.d rc3.d rc4.d rc5.d rc.d/rc2.d rc.d/rc3.d rc.d/rc4.d rc.d/rc5.d; do
|
---|
192 | if test -d "${PREFIX}/${i}"; then
|
---|
193 | # Paranoia test first.
|
---|
194 | test -d "${PREFIX}/${i}/S20${SERVICE_NAME}" ||
|
---|
195 | ln -sf "${path}/${SERVICE_NAME}" "${PREFIX}/${i}/S20${SERVICE_NAME}"
|
---|
196 | fi
|
---|
197 | done
|
---|
198 | # And OpenRC.
|
---|
199 | test -d "${PREFIX}/runlevel/default" &&
|
---|
200 | ln -sf "${path}/${SERVICE_NAME}" "/${PREFIX}/runlevel/default/"
|
---|
201 | fi
|
---|
202 | fi
|
---|
203 | break
|
---|
204 | fi
|
---|
205 | done
|
---|
206 |
|
---|
207 | test -z "${found_init}" &&
|
---|
208 | abort "No supported initialisation system found."
|
---|
209 | exit 0
|
---|