VirtualBox

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

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

Linux: Additions and host installer: Improve check if distribution is running systemd as init process, bugref:10347.

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1# $Id: routines.sh 98468 2023-02-03 14:54:32Z 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(pythonbin pythondesc)
404# failure: non fatal
405install_python_bindings()
406{
407 pythonbin="$1"
408 pythondesc="$2"
409
410 # The python binary might not be there, so just exit silently
411 if test -z "$pythonbin"; then
412 return 0
413 fi
414
415 if test -z "$pythondesc"; then
416 echo 1>&2 "missing argument to install_python_bindings"
417 return 1
418 fi
419
420 echo 1>&2 "Python found: $pythonbin, installing bindings..."
421
422 # check if python has working distutils
423 "$pythonbin" -c "from distutils.core import setup" > /dev/null 2>&1
424 if test "$?" -ne 0; then
425 echo 1>&2 "Skipped: $pythondesc install is unusable, missing package 'distutils'"
426 return 0
427 fi
428
429 # Pass install path via environment
430 export VBOX_INSTALL_PATH
431 $SHELL -c "cd $VBOX_INSTALL_PATH/sdk/installer && $pythonbin vboxapisetup.py install \
432 --record $CONFIG_DIR/python-$CONFIG_FILES"
433 cat $CONFIG_DIR/python-$CONFIG_FILES >> $CONFIG_DIR/$CONFIG_FILES
434 rm -f $CONFIG_DIR/python-$CONFIG_FILES
435
436 # Remove files created by Python API setup.
437 rm -rf $VBOX_INSTALL_PATH/sdk/installer/build
438}
439
440maybe_run_python_bindings_installer() {
441 VBOX_INSTALL_PATH="${1}"
442
443 # Loop over all usual suspect Python executable names and try installing
444 # the VirtualBox API bindings. Needs to prevent double installs which waste
445 # quite a bit of time.
446 PYTHONS=""
447 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
448 if [ "`$p -c 'import sys
449if sys.version_info >= (2, 6) and (sys.version_info < (3, 0) or sys.version_info >= (3, 3)):
450 print(\"test\")' 2> /dev/null`" != "test" ]; then
451 continue
452 fi
453 # Get python major/minor version, and skip if it was already covered.
454 # Uses grep -F to avoid trouble with '.' matching any char.
455 pyvers="`$p -c 'import sys
456print("%s.%s" % (sys.version_info[0], sys.version_info[1]))' 2> /dev/null`"
457 if echo "$PYTHONS" | grep -Fq ":$pyvers:"; then
458 continue
459 fi
460 # Record which version will be installed. If it fails there is no point
461 # trying with different executable/symlink reporting the same version.
462 PYTHONS="$PYTHONS:$pyvers:"
463 install_python_bindings "$p" "Python $pyvers"
464 done
465 if [ -z "$PYTHONS" ]; then
466 echo 1>&2 "Python (2.6, 2.7 or 3.3 and later) unavailable, skipping bindings installation."
467 return 1
468 fi
469
470 return 0
471}
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