VirtualBox

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

Last change on this file was 107964, checked in by vboxsync, 4 weeks ago

Installer: Linux: Ask VBoxSVC to terminate gacefully and wait for it if it is running during installation, bugref:10850.

This behavior was in place before, however we did not send SIGUSR1 to VBoxSVC
in case of .run installer (or did it in condition which was never true) and we
were waiting too litle to give it a chance to terminate.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 15.9 KB
Line 
1# $Id: routines.sh 107964 2025-01-28 14:18:42Z vboxsync $
2# Oracle VirtualBox
3# VirtualBox installer shell routines
4#
5
6#
7# Copyright (C) 2007-2024 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 # Ask VBoxSVC to terminate gracefully if it is not
130 # busy with handling client requests.
131 kill -USR1 $VBOXSVC_PID
132 # Wait for VBoxSVC to terminate.
133 for attempt in 1 2 3 4 5 6 7 8 9 10; do
134 [ -n "$(pidof VBoxSVC 2> /dev/null)" ] && sleep 1
135 done
136 # Still running?
137 if pidof VBoxSVC > /dev/null 2>&1; then
138 echo 1>&2 "A copy of VirtualBox is currently running. Please close it and try again."
139 abort "Please note that it can take up to ten seconds for VirtualBox to finish running."
140 fi
141 fi
142}
143
144## Creates a systemd wrapper in /lib for an LSB init script
145systemd_wrap_init_script()
146{
147 self="systemd_wrap_init_script"
148 ## The init script to be installed. The file may be copied or referenced.
149 script="$(readlink -f -- "${1}")"
150 ## Name for the service.
151 name="$2"
152 test -x "$script" && test ! "$name" = "" || \
153 { echo "$self: invalid arguments" >&2 && return 1; }
154 test -d /usr/lib/systemd/system && unit_path=/usr/lib/systemd/system
155 test -d /lib/systemd/system && unit_path=/lib/systemd/system
156 test -n "${unit_path}" || \
157 { echo "$self: systemd unit path not found" >&2 && return 1; }
158 conflicts=`sed -n 's/# *X-Conflicts-With: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
159 description=`sed -n 's/# *Short-Description: *\(.*\)/\1/p' "${script}"`
160 required=`sed -n 's/# *Required-Start: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
161 required_target=`sed -n 's/# *X-Required-Target-Start: *\(.*\)/\1/p' "${script}"`
162 startbefore=`sed -n 's/# *X-Start-Before: *\(.*\)/\1/p' "${script}" | sed 's/\$[a-z]*//'`
163 runlevels=`sed -n 's/# *Default-Start: *\(.*\)/\1/p' "${script}"`
164 servicetype=`sed -n 's/# *X-Service-Type: *\(.*\)/\1/p' "${script}"`
165 test -z "${servicetype}" && servicetype="forking"
166 targets=`for i in ${runlevels}; do printf "runlevel${i}.target "; done`
167 before=`for i in ${startbefore}; do printf "${i}.service "; done`
168 after=`for i in ${required_target}; do printf "${i}.target "; done; for i in ${required}; do printf "${i}.service "; done`
169 cat > "${unit_path}/${name}.service" << EOF
170[Unit]
171SourcePath=${script}
172Description=${description}
173Before=${targets}shutdown.target ${before}
174After=${after}
175Conflicts=shutdown.target ${conflicts}
176
177[Service]
178Type=${servicetype}
179Restart=no
180TimeoutSec=5min
181IgnoreSIGPIPE=no
182KillMode=process
183GuessMainPID=no
184RemainAfterExit=yes
185ExecStart=${script} start
186ExecStop=${script} stop
187
188[Install]
189WantedBy=multi-user.target
190EOF
191}
192
193# Checks if systemctl is present and functional (i.e., systemd is the init process).
194use_systemd()
195{
196 systemctl status >/dev/null 2>&1
197}
198
199## Installs a file containing a shell script as an init script. Call
200# finish_init_script_install when all scripts have been installed.
201install_init_script()
202{
203 self="install_init_script"
204 ## The init script to be installed. The file may be copied or referenced.
205 script="$1"
206 ## Name for the service.
207 name="$2"
208
209 test -x "${script}" && test ! "${name}" = "" ||
210 { echo "${self}: invalid arguments" >&2; return 1; }
211 # Do not unconditionally silence the following "ln".
212 test -L "/sbin/rc${name}" && rm "/sbin/rc${name}"
213 ln -s "${script}" "/sbin/rc${name}"
214 if test -x "`which systemctl 2>/dev/null`"; then
215 if use_systemd; then
216 { systemd_wrap_init_script "$script" "$name"; return; }
217 fi
218 fi
219 if test -d /etc/rc.d/init.d; then
220 cp "${script}" "/etc/rc.d/init.d/${name}" &&
221 chmod 755 "/etc/rc.d/init.d/${name}"
222 elif test -d /etc/init.d; then
223 cp "${script}" "/etc/init.d/${name}" &&
224 chmod 755 "/etc/init.d/${name}"
225 else
226 { echo "${self}: error: unknown init type" >&2; return 1; }
227 fi
228}
229
230## Remove the init script "name"
231remove_init_script()
232{
233 self="remove_init_script"
234 ## Name of the service to remove.
235 name="$1"
236
237 test -n "${name}" ||
238 { echo "$self: missing argument"; return 1; }
239 rm -f "/sbin/rc${name}"
240 rm -f /lib/systemd/system/"$name".service /usr/lib/systemd/system/"$name".service
241 rm -f "/etc/rc.d/init.d/$name"
242 rm -f "/etc/init.d/$name"
243}
244
245## Tell systemd services have been installed or removed. Should not be done
246# after each individual one, as systemd can crash if it is done too often
247# (reported by the OL team for OL 7.6, may not apply to other versions.)
248finish_init_script_install()
249{
250 if use_systemd; then
251 systemctl daemon-reload
252 fi
253}
254
255## Did we install a systemd service?
256systemd_service_installed()
257{
258 ## Name of service to test.
259 name="${1}"
260
261 test -f /lib/systemd/system/"${name}".service ||
262 test -f /usr/lib/systemd/system/"${name}".service
263}
264
265## Perform an action on a service
266do_sysvinit_action()
267{
268 self="do_sysvinit_action"
269 ## Name of service to start.
270 name="${1}"
271 ## The action to perform, normally "start", "stop" or "status".
272 action="${2}"
273
274 test ! -z "${name}" && test ! -z "${action}" ||
275 { echo "${self}: missing argument" >&2; return 1; }
276 if systemd_service_installed "${name}"; then
277 systemctl -q ${action} "${name}"
278 elif test -x "/etc/rc.d/init.d/${name}"; then
279 "/etc/rc.d/init.d/${name}" "${action}" quiet
280 elif test -x "/etc/init.d/${name}"; then
281 "/etc/init.d/${name}" "${action}" quiet
282 fi
283}
284
285## Start a service
286start_init_script()
287{
288 do_sysvinit_action "${1}" start
289}
290
291## Stop the init script "name"
292stop_init_script()
293{
294 do_sysvinit_action "${1}" stop
295}
296
297## Extract chkconfig information from a sysvinit script.
298get_chkconfig_info()
299{
300 ## The script to extract the information from.
301 script="${1}"
302
303 set `sed -n 's/# *chkconfig: *\([0-9]*\) *\(.*\)/\1 \2/p' "${script}"`
304 ## Which runlevels should we start in?
305 runlevels="${1}"
306 ## How soon in the boot process will we start, from 00 (first) to 99
307 start_order="${2}"
308 ## How soon in the shutdown process will we stop, from 99 (first) to 00
309 stop_order="${3}"
310 test ! -z "${name}" || \
311 { echo "${self}: missing name" >&2; return 1; }
312 expr "${start_order}" + 0 > /dev/null 2>&1 && \
313 expr 0 \<= "${start_order}" > /dev/null 2>&1 && \
314 test `expr length "${start_order}"` -eq 2 > /dev/null 2>&1 || \
315 { echo "${self}: start sequence number must be between 00 and 99" >&2;
316 return 1; }
317 expr "${stop_order}" + 0 > /dev/null 2>&1 && \
318 expr 0 \<= "${stop_order}" > /dev/null 2>&1 && \
319 test `expr length "${stop_order}"` -eq 2 > /dev/null 2>&1 || \
320 { echo "${self}: stop sequence number must be between 00 and 99" >&2;
321 return 1; }
322}
323
324## Add a service to its default runlevels (annotated inside the script, see get_chkconfig_info).
325addrunlevel()
326{
327 self="addrunlevel"
328 ## Service name.
329 name="${1}"
330
331 test -n "${name}" || \
332 { echo "${self}: missing argument" >&2; return 1; }
333 systemd_service_installed "${name}" && \
334 { systemctl -q enable "${name}"; return; }
335 if test -x "/etc/rc.d/init.d/${name}"; then
336 init_d_path=/etc/rc.d
337 elif test -x "/etc/init.d/${name}"; then
338 init_d_path=/etc
339 else
340 { echo "${self}: error: unknown init type" >&2; return 1; }
341 fi
342 get_chkconfig_info "${init_d_path}/init.d/${name}" || return 1
343 # Redhat based sysvinit systems
344 if test -x "`which chkconfig 2>/dev/null`"; then
345 chkconfig --add "${name}"
346 # SUSE-based sysvinit systems
347 elif test -x "`which insserv 2>/dev/null`"; then
348 insserv "${name}"
349 # Debian/Ubuntu-based systems
350 elif test -x "`which update-rc.d 2>/dev/null`"; then
351 # Old Debians did not support dependencies
352 update-rc.d "${name}" defaults "${start_order}" "${stop_order}"
353 # Gentoo Linux
354 elif test -x "`which rc-update 2>/dev/null`"; then
355 rc-update add "${name}" default
356 # Generic sysvinit
357 elif test -n "${init_d_path}/rc0.d"
358 then
359 for locali in 0 1 2 3 4 5 6
360 do
361 target="${init_d_path}/rc${locali}.d/K${stop_order}${name}"
362 expr "${runlevels}" : ".*${locali}" >/dev/null && \
363 target="${init_d_path}/rc${locali}.d/S${start_order}${name}"
364 test -e "${init_d_path}/rc${locali}.d/"[KS][0-9]*"${name}" || \
365 ln -fs "${init_d_path}/init.d/${name}" "${target}"
366 done
367 else
368 { echo "${self}: error: unknown init type" >&2; return 1; }
369 fi
370}
371
372
373## Delete a service from a runlevel
374delrunlevel()
375{
376 self="delrunlevel"
377 ## Service name.
378 name="${1}"
379
380 test -n "${name}" ||
381 { echo "${self}: missing argument" >&2; return 1; }
382 systemctl -q disable "${name}" >/dev/null 2>&1
383 # Redhat-based systems
384 chkconfig --del "${name}" >/dev/null 2>&1
385 # SUSE-based sysvinit systems
386 insserv -r "${name}" >/dev/null 2>&1
387 # Debian/Ubuntu-based systems
388 update-rc.d -f "${name}" remove >/dev/null 2>&1
389 # Gentoo Linux
390 rc-update del "${name}" >/dev/null 2>&1
391 # Generic sysvinit
392 rm -f /etc/rc.d/rc?.d/[SK]??"${name}"
393 rm -f /etc/rc?.d/[SK]??"${name}"
394}
395
396
397terminate_proc() {
398 PROC_NAME="${1}"
399 SERVER_PID=`pidof $PROC_NAME 2> /dev/null`
400 if [ "$SERVER_PID" != "" ]; then
401 killall -TERM $PROC_NAME > /dev/null 2>&1
402 sleep 2
403 fi
404}
405
406
407# install_python_bindings(PYTHON_BIN PYTHON_VER)
408# failure: non fatal
409#
410## @todo r=andy Merge this code with darwin/VirtualBox/postflight!
411install_python_bindings()
412{
413 PYTHON_BIN="$1"
414 PYTHON_VER="$2"
415
416 # The python binary might not be there, so just exit silently
417 if test -z "$PYTHON_BIN"; then
418 return 0
419 fi
420
421 if test -z "$PYTHON_VER"; then
422 echo 1>&2 "missing argument to install_python_bindings"
423 return 1
424 fi
425
426 echo 1>&2 "Python found: $PYTHON_BIN, installing bindings..."
427
428 # Check if python has working distutils
429 "$PYTHON_BIN" -c "from distutils.core import setup" > /dev/null 2>&1
430 if test "$?" -ne 0; then
431 echo 1>&2 "Python $PYTHON_VER does not have package 'distutils', checking for 'setuptools'..."
432 # Since Python 3.12 there are no distutils anymore. See PEP632.
433 "$PYTHON_BIN" -c "from setuptools import setup" > /dev/null 2>&1
434 if test "$?" -ne 0; then
435 echo 1>&2 "Python $PYTHON_VER also does not have package 'setuptools'. Skipping installation."
436 return 0
437 fi
438 # When we reach here, we have to use 'pip' in order to install our bindings (Python >= 3.12).
439 if test -x "`which pip 2>/dev/null`"; then
440 PYTHON_PIP_BIN=$(which pip)
441 else
442 echo 1>&2 "Python package manager 'pip' not found. Skipping installation."
443 fi
444 fi
445
446 PYTHON_INSTALLER_PATH="$VBOX_INSTALL_PATH/sdk/installer/python"
447
448 # Pass install path via environment
449 export VBOX_INSTALL_PATH
450
451 if [ -n "$PYTHON_PIP_BIN" ]; then
452 # Note: We use '-v' to show verbose output of our setup.py script on error.
453 $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_PIP_BIN} -v install ./vboxapi"
454 else
455 $SHELL -c "cd ${PYTHON_INSTALLER_PATH} && ${PYTHON_BIN} ./vboxapisetup.py install \
456 --record $CONFIG_DIR/python-$CONFIG_FILES"
457 cat "$CONFIG_DIR/python-$CONFIG_FILES" >> "$CONFIG_DIR/$CONFIG_FILES"
458 rm -f "$CONFIG_DIR/python-$CONFIG_FILES"
459 fi
460
461 # Remove files created by Python API setup.
462 rm -rf "$PYTHON_INSTALLER_PATH/build"
463}
464
465## @todo r=andy Merge this code with darwin/VirtualBox/postflight!
466maybe_run_python_bindings_installer() {
467 VBOX_INSTALL_PATH="${1}"
468
469 # Loop over all usual suspect Python executable names and try installing
470 # the VirtualBox API bindings. Needs to prevent double installs which waste
471 # quite a bit of time.
472 PYTHON_VER_INSTALLED=""
473 PYTHON_BINARIES="\
474 python2.7 \
475 python2 \
476 python3.3 \
477 python3.4 \
478 python3.5 \
479 python3.6 \
480 python3.7 \
481 python3.8 \
482 python3.9 \
483 python3.10 \
484 python3.11 \
485 python3.12 \
486 python3 \
487 python"
488
489 for PYTHON_BIN in $PYTHON_BINARIES; do
490 if [ "`$PYTHON_BIN -c 'import sys
491if sys.version_info >= (2, 6) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
492 print(\"test\")' 2> /dev/null`" != "test" ]; then
493 continue
494 fi
495 # Get python major/minor version, and skip if it was already covered.
496 # Uses grep -F to avoid trouble with '.' matching any char.
497 PYTHON_VER="`$PYTHON_BIN -c 'import sys
498print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
499 if echo "$PYTHON_VER_INSTALLED" | grep -Fq ":$PYTHON_VER:"; then
500 continue
501 fi
502 # Record which version will be installed. If it fails there is no point
503 # trying with different executable/symlink reporting the same version.
504 PYTHON_VER_INSTALLED="$PYTHON_VER_INSTALLED:$PYTHON_VER:"
505 install_python_bindings "$PYTHON_BIN" "$PYTHON_VER"
506 done
507 if [ -z "$PYTHON_VER_INSTALLED" ]; then
508 echo 1>&2 "Python (2.7 or 3.3 and later) unavailable, skipping bindings installation."
509 return 1
510 fi
511
512 return 0
513}
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