VirtualBox

source: vbox/trunk/src/VBox/Installer/linux/routines.sh@ 98103

Last change on this file since 98103 was 98103, checked in by vboxsync, 23 months ago

Copyright year updates by scm.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 14.5 KB
Line 
1# $Id: routines.sh 98103 2023-01-17 14:15:46Z vboxsync $
2# Oracle VM VirtualBox
3# VirtualBox installer shell routines
4#
5
6#
7# Copyright (C) 2007-2023 Oracle and/or its affiliates.
8#
9# This file is part of VirtualBox base platform packages, as
10# available from https://www.virtualbox.org.
11#
12# This program is free software; you can redistribute it and/or
13# modify it under the terms of the GNU General Public License
14# as published by the Free Software Foundation, in version 3 of the
15# License.
16#
17# This program is distributed in the hope that it will be useful, but
18# WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20# General Public License for more details.
21#
22# You should have received a copy of the GNU General Public License
23# along with this program; if not, see <https://www.gnu.org/licenses>.
24#
25# SPDX-License-Identifier: GPL-3.0-only
26#
27
28ro_LOG_FILE=""
29ro_X11_AUTOSTART="/etc/xdg/autostart"
30ro_KDE_AUTOSTART="/usr/share/autostart"
31
32## Aborts the script and prints an error message to stderr.
33#
34# syntax: abort message
35
36abort()
37{
38 echo 1>&2 "$1"
39 exit 1
40}
41
42## Creates an empty log file and remembers the name for future logging
43# operations
44create_log()
45{
46 ## The path of the file to create.
47 ro_LOG_FILE="$1"
48 if [ "$ro_LOG_FILE" = "" ]; then
49 abort "create_log called without an argument! Aborting..."
50 fi
51 # Create an empty file
52 echo > "$ro_LOG_FILE" 2> /dev/null
53 if [ ! -f "$ro_LOG_FILE" -o "`cat "$ro_LOG_FILE"`" != "" ]; then
54 abort "Error creating log file! Aborting..."
55 fi
56}
57
58## Writes text to standard error, as standard output is masked.
59#
60# Syntax: info text
61info()
62{
63 echo 1>&2 "$1"
64}
65
66## Copies standard input to standard error, as standard output is masked.
67#
68# Syntax: info text
69catinfo()
70{
71 cat 1>&2
72}
73
74## Writes text to the log file
75#
76# Syntax: log text
77log()
78{
79 if [ "$ro_LOG_FILE" = "" ]; then
80 abort "Error! Logging has not been set up yet! Aborting..."
81 fi
82 echo "$1" >> $ro_LOG_FILE
83 return 0
84}
85
86## Writes test to standard output and to the log file
87#
88# Syntax: infolog text
89infolog()
90{
91 info "$1"
92 log "$1"
93}
94
95## Checks whether a module is loaded with a given string in its name.
96#
97# syntax: module_loaded string
98module_loaded()
99{
100 if [ "$1" = "" ]; then
101 log "module_loaded called without an argument. Aborting..."
102 abort "Error in installer. Aborting..."
103 fi
104 lsmod | grep -q $1
105}
106
107## Abort if we are not running as root
108check_root()
109{
110 if [ `id -u` -ne 0 ]; then
111 abort "This program must be run with administrator privileges. Aborting"
112 fi
113}
114
115## Abort if dependencies are not found
116check_deps()
117{
118 for i in ${@}; do
119 type "${i}" >/dev/null 2>&1 ||
120 abort "${i} not found. Please install: ${*}; and try again."
121 done
122}
123
124## Abort if a copy of VirtualBox is already running
125check_running()
126{
127 VBOXSVC_PID=`pidof VBoxSVC 2> /dev/null`
128 if [ -n "$VBOXSVC_PID" ]; then
129 if [ -f /etc/init.d/vboxweb-service ]; then
130 kill -USR1 $VBOXSVC_PID
131 fi
132 sleep 1
133 if pidof VBoxSVC > /dev/null 2>&1; then
134 echo 1>&2 "A copy of VirtualBox is currently running. Please close it and try again."
135 abort "Please note that it can take up to ten seconds for VirtualBox to finish running."
136 fi
137 fi
138}
139
140## Creates a systemd wrapper in /lib for an LSB init script
141systemd_wrap_init_script()
142{
143 self="systemd_wrap_init_script"
144 ## The init script to be installed. The file may be copied or referenced.
145 script="$(readlink -f -- "${1}")"
146 ## Name for the service.
147 name="$2"
148 test -x "$script" && test ! "$name" = "" || \
149 { echo "$self: invalid arguments" >&2 && return 1; }
150 test -d /usr/lib/systemd/system && unit_path=/usr/lib/systemd/system
151 test -d /lib/systemd/system && unit_path=/lib/systemd/system
152 test -n "${unit_path}" || \
153 { echo "$self: systemd unit path not found" >&2 && return 1; }
154 conflicts=`sed -n 's/# *X-Conflicts-With: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
155 description=`sed -n 's/# *Short-Description: *\(.*\)/\1/p' "${script}"`
156 required=`sed -n 's/# *Required-Start: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
157 required_target=`sed -n 's/# *X-Required-Target-Start: *\(.*\)/\1/p' "${script}"`
158 startbefore=`sed -n 's/# *X-Start-Before: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
159 runlevels=`sed -n 's/# *Default-Start: *\(.*\)/\1/p' "${script}"`
160 servicetype=`sed -n 's/# *X-Service-Type: *\(.*\)/\1/p' "${script}"`
161 test -z "${servicetype}" && servicetype="forking"
162 targets=`for i in ${runlevels}; do printf "runlevel${i}.target "; done`
163 before=`for i in ${startbefore}; do printf "${i}.service "; done`
164 after=`for i in ${required_target}; do printf "${i}.target "; done; for i in ${required}; do printf "${i}.service "; done`
165 cat > "${unit_path}/${name}.service" << EOF
166[Unit]
167SourcePath=${script}
168Description=${description}
169Before=${targets}shutdown.target ${before}
170After=${after}
171Conflicts=shutdown.target ${conflicts}
172
173[Service]
174Type=${servicetype}
175Restart=no
176TimeoutSec=5min
177IgnoreSIGPIPE=no
178KillMode=process
179GuessMainPID=no
180RemainAfterExit=yes
181ExecStart=${script} start
182ExecStop=${script} stop
183
184[Install]
185WantedBy=multi-user.target
186EOF
187}
188
189# Checks if systemd is the init system of choice
190use_systemd()
191{
192 # First condition is what halfway recent systemd uses itself, and the
193 # other two checks should cover everything back to v1.
194 test -e /run/systemd/system || test -e /sys/fs/cgroup/systemd || test -e /cgroup/systemd
195}
196
197## Installs a file containing a shell script as an init script. Call
198# finish_init_script_install when all scripts have been installed.
199install_init_script()
200{
201 self="install_init_script"
202 ## The init script to be installed. The file may be copied or referenced.
203 script="$1"
204 ## Name for the service.
205 name="$2"
206
207 test -x "${script}" && test ! "${name}" = "" ||
208 { echo "${self}: invalid arguments" >&2; return 1; }
209 # Do not unconditionally silence the following "ln".
210 test -L "/sbin/rc${name}" && rm "/sbin/rc${name}"
211 ln -s "${script}" "/sbin/rc${name}"
212 if test -x "`which systemctl 2>/dev/null`"; then
213 if use_systemd; then
214 { systemd_wrap_init_script "$script" "$name"; return; }
215 fi
216 fi
217 if test -d /etc/rc.d/init.d; then
218 cp "${script}" "/etc/rc.d/init.d/${name}" &&
219 chmod 755 "/etc/rc.d/init.d/${name}"
220 elif test -d /etc/init.d; then
221 cp "${script}" "/etc/init.d/${name}" &&
222 chmod 755 "/etc/init.d/${name}"
223 else
224 { echo "${self}: error: unknown init type" >&2; return 1; }
225 fi
226}
227
228## Remove the init script "name"
229remove_init_script()
230{
231 self="remove_init_script"
232 ## Name of the service to remove.
233 name="$1"
234
235 test -n "${name}" ||
236 { echo "$self: missing argument"; return 1; }
237 rm -f "/sbin/rc${name}"
238 rm -f /lib/systemd/system/"$name".service /usr/lib/systemd/system/"$name".service
239 rm -f "/etc/rc.d/init.d/$name"
240 rm -f "/etc/init.d/$name"
241}
242
243## Tell systemd services have been installed or removed. Should not be done
244# after each individual one, as systemd can crash if it is done too often
245# (reported by the OL team for OL 7.6, may not apply to other versions.)
246finish_init_script_install()
247{
248 if use_systemd; then
249 systemctl daemon-reload
250 fi
251}
252
253## Did we install a systemd service?
254systemd_service_installed()
255{
256 ## Name of service to test.
257 name="${1}"
258
259 test -f /lib/systemd/system/"${name}".service ||
260 test -f /usr/lib/systemd/system/"${name}".service
261}
262
263## Perform an action on a service
264do_sysvinit_action()
265{
266 self="do_sysvinit_action"
267 ## Name of service to start.
268 name="${1}"
269 ## The action to perform, normally "start", "stop" or "status".
270 action="${2}"
271
272 test ! -z "${name}" && test ! -z "${action}" ||
273 { echo "${self}: missing argument" >&2; return 1; }
274 if systemd_service_installed "${name}"; then
275 systemctl -q ${action} "${name}"
276 elif test -x "/etc/rc.d/init.d/${name}"; then
277 "/etc/rc.d/init.d/${name}" "${action}" quiet
278 elif test -x "/etc/init.d/${name}"; then
279 "/etc/init.d/${name}" "${action}" quiet
280 fi
281}
282
283## Start a service
284start_init_script()
285{
286 do_sysvinit_action "${1}" start
287}
288
289## Stop the init script "name"
290stop_init_script()
291{
292 do_sysvinit_action "${1}" stop
293}
294
295## Extract chkconfig information from a sysvinit script.
296get_chkconfig_info()
297{
298 ## The script to extract the information from.
299 script="${1}"
300
301 set `sed -n 's/# *chkconfig: *\([0-9]*\) *\(.*\)/\1 \2/p' "${script}"`
302 ## Which runlevels should we start in?
303 runlevels="${1}"
304 ## How soon in the boot process will we start, from 00 (first) to 99
305 start_order="${2}"
306 ## How soon in the shutdown process will we stop, from 99 (first) to 00
307 stop_order="${3}"
308 test ! -z "${name}" || \
309 { echo "${self}: missing name" >&2; return 1; }
310 expr "${start_order}" + 0 > /dev/null 2>&1 && \
311 expr 0 \<= "${start_order}" > /dev/null 2>&1 && \
312 test `expr length "${start_order}"` -eq 2 > /dev/null 2>&1 || \
313 { echo "${self}: start sequence number must be between 00 and 99" >&2;
314 return 1; }
315 expr "${stop_order}" + 0 > /dev/null 2>&1 && \
316 expr 0 \<= "${stop_order}" > /dev/null 2>&1 && \
317 test `expr length "${stop_order}"` -eq 2 > /dev/null 2>&1 || \
318 { echo "${self}: stop sequence number must be between 00 and 99" >&2;
319 return 1; }
320}
321
322## Add a service to its default runlevels (annotated inside the script, see get_chkconfig_info).
323addrunlevel()
324{
325 self="addrunlevel"
326 ## Service name.
327 name="${1}"
328
329 test -n "${name}" || \
330 { echo "${self}: missing argument" >&2; return 1; }
331 systemd_service_installed "${name}" && \
332 { systemctl -q enable "${name}"; return; }
333 if test -x "/etc/rc.d/init.d/${name}"; then
334 init_d_path=/etc/rc.d
335 elif test -x "/etc/init.d/${name}"; then
336 init_d_path=/etc
337 else
338 { echo "${self}: error: unknown init type" >&2; return 1; }
339 fi
340 get_chkconfig_info "${init_d_path}/init.d/${name}" || return 1
341 # Redhat based sysvinit systems
342 if test -x "`which chkconfig 2>/dev/null`"; then
343 chkconfig --add "${name}"
344 # SUSE-based sysvinit systems
345 elif test -x "`which insserv 2>/dev/null`"; then
346 insserv "${name}"
347 # Debian/Ubuntu-based systems
348 elif test -x "`which update-rc.d 2>/dev/null`"; then
349 # Old Debians did not support dependencies
350 update-rc.d "${name}" defaults "${start_order}" "${stop_order}"
351 # Gentoo Linux
352 elif test -x "`which rc-update 2>/dev/null`"; then
353 rc-update add "${name}" default
354 # Generic sysvinit
355 elif test -n "${init_d_path}/rc0.d"
356 then
357 for locali in 0 1 2 3 4 5 6
358 do
359 target="${init_d_path}/rc${locali}.d/K${stop_order}${name}"
360 expr "${runlevels}" : ".*${locali}" >/dev/null && \
361 target="${init_d_path}/rc${locali}.d/S${start_order}${name}"
362 test -e "${init_d_path}/rc${locali}.d/"[KS][0-9]*"${name}" || \
363 ln -fs "${init_d_path}/init.d/${name}" "${target}"
364 done
365 else
366 { echo "${self}: error: unknown init type" >&2; return 1; }
367 fi
368}
369
370
371## Delete a service from a runlevel
372delrunlevel()
373{
374 self="delrunlevel"
375 ## Service name.
376 name="${1}"
377
378 test -n "${name}" ||
379 { echo "${self}: missing argument" >&2; return 1; }
380 systemctl -q disable "${name}" >/dev/null 2>&1
381 # Redhat-based systems
382 chkconfig --del "${name}" >/dev/null 2>&1
383 # SUSE-based sysvinit systems
384 insserv -r "${name}" >/dev/null 2>&1
385 # Debian/Ubuntu-based systems
386 update-rc.d -f "${name}" remove >/dev/null 2>&1
387 # Gentoo Linux
388 rc-update del "${name}" >/dev/null 2>&1
389 # Generic sysvinit
390 rm -f /etc/rc.d/rc?.d/[SK]??"${name}"
391 rm -f /etc/rc?.d/[SK]??"${name}"
392}
393
394
395terminate_proc() {
396 PROC_NAME="${1}"
397 SERVER_PID=`pidof $PROC_NAME 2> /dev/null`
398 if [ "$SERVER_PID" != "" ]; then
399 killall -TERM $PROC_NAME > /dev/null 2>&1
400 sleep 2
401 fi
402}
403
404
405# install_python_bindings(pythonbin pythondesc)
406# failure: non fatal
407install_python_bindings()
408{
409 pythonbin="$1"
410 pythondesc="$2"
411
412 # The python binary might not be there, so just exit silently
413 if test -z "$pythonbin"; then
414 return 0
415 fi
416
417 if test -z "$pythondesc"; then
418 echo 1>&2 "missing argument to install_python_bindings"
419 return 1
420 fi
421
422 echo 1>&2 "Python found: $pythonbin, installing bindings..."
423
424 # check if python has working distutils
425 "$pythonbin" -c "from distutils.core import setup" > /dev/null 2>&1
426 if test "$?" -ne 0; then
427 echo 1>&2 "Skipped: $pythondesc install is unusable, missing package 'distutils'"
428 return 0
429 fi
430
431 # Pass install path via environment
432 export VBOX_INSTALL_PATH
433 $SHELL -c "cd $VBOX_INSTALL_PATH/sdk/installer && $pythonbin vboxapisetup.py install \
434 --record $CONFIG_DIR/python-$CONFIG_FILES"
435 cat $CONFIG_DIR/python-$CONFIG_FILES >> $CONFIG_DIR/$CONFIG_FILES
436 rm -f $CONFIG_DIR/python-$CONFIG_FILES
437
438 # Remove files created by Python API setup.
439 rm -rf $VBOX_INSTALL_PATH/sdk/installer/build
440}
441
442maybe_run_python_bindings_installer() {
443 VBOX_INSTALL_PATH="${1}"
444
445 # Loop over all usual suspect Python executable names and try installing
446 # the VirtualBox API bindings. Needs to prevent double installs which waste
447 # quite a bit of time.
448 PYTHONS=""
449 for p in python2.6 python2.7 python2 python3.3 python3.4 python3.5 python3.6 python3.7 python3.8 python3.9 python3.10 python3 python; do
450 if [ "`$p -c 'import sys
451if sys.version_info >= (2, 6) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
452 print(\"test\")' 2> /dev/null`" != "test" ]; then
453 continue
454 fi
455 # Get python major/minor version, and skip if it was already covered.
456 # Uses grep -F to avoid trouble with '.' matching any char.
457 pyvers="`$p -c 'import sys
458print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
459 if echo "$PYTHONS" | grep -Fq ":$pyvers:"; then
460 continue
461 fi
462 # Record which version will be installed. If it fails there is no point
463 # trying with different executable/symlink reporting the same version.
464 PYTHONS="$PYTHONS:$pyvers:"
465 install_python_bindings "$p" "Python $pyvers"
466 done
467 if [ -z "$PYTHONS" ]; then
468 echo 1>&2 "Python (2.6, 2.7 or 3.3 and later) unavailable, skipping bindings installation."
469 return 1
470 fi
471
472 return 0
473}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette