VirtualBox

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

Last change on this file since 104389 was 103028, checked in by vboxsync, 10 months ago

Main/Python: Big revamp to modernize our vboxapi Python package to now use a so-called src-layout, which also can be used with pip directly. Also added compatibility w/ Python 3.12 where distutils are not shipped anymore. We also now do have automatic linting for our code, which hopefully should improve quality in this area. Moved some Python-related files into an own sub folder so that it's more clear to which these belong to. The "sdk/installer" directories also have an own "python" sub directory where the stuff resides now. The Windows installer also uses "sdk/installer" instead of "sdk/install", to match the other platforms. bugref:10579

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