VirtualBox

source: vbox/trunk/src/VBox/Installer/linux/scripts/VBoxHeadlessXOrg.sh@ 85416

Last change on this file since 85416 was 82968, checked in by vboxsync, 5 years ago

Copyright year updates by scm.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 12.6 KB
Line 
1#!/bin/sh
2# $Id: VBoxHeadlessXOrg.sh 82968 2020-02-04 10:35:17Z vboxsync $
3## @file
4# VirtualBox X Server auto-start service.
5#
6
7#
8# Copyright (C) 2012-2020 Oracle Corporation
9#
10# This file is part of VirtualBox Open Source Edition (OSE), as
11# available from http://www.virtualbox.org. This file is free software;
12# you can redistribute it and/or modify it under the terms of the GNU
13# General Public License (GPL) as published by the Free Software
14# Foundation, in version 2 as it comes in the "COPYING" file of the
15# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17#
18
19PATH=$PATH:/bin:/sbin:/usr/sbin
20
21## Start one or several X servers in the background for use with headless
22# rendering. For details, options and configuration see the usage() function
23# further down.
24#
25# I have tried to follow the best practices I could find for writing a Linux
26# service (and doing it in shell script) which should work well with
27# traditional and modern service systems using minimal init or service files.
28# In our case this boils down to:
29# * Start with a single command line, stop using one of ${EXIT_SIGNALS} below.
30# * Stopping with a signal can be done safely using the pid stored in the
31# pid-file and our (presumably unique) command name. For this reason we
32# only support running one instance of the service though.
33# * Start in the foreground. Systems without proper service control can take
34# care of the backgrounding in the init script.
35# * Clean up all sub-processes (X servers) ourselves when we are stopped
36# cleanly and don't provide any other way to clean them up automatically (in
37# case we are stopped uncleanly) as we don't know of a generic safe way to
38# do so, though some service management systems (i.e. systemd) can do so.
39# (A more thorough automatic clean-up would be possible if Xorg didn't
40# potentially have to be run as root, so that we could run all processes
41# using a service-specific user account and just terminate all processes
42# run by that user to clean up.)
43
44## Default configuration file name.
45# @note This is not very nice - /etc/default is actually Debian-specific.
46CONFIGURATION_FILE=/etc/default/virtualbox
47## The name of this script.
48SCRIPT_NAME="$0"
49## The service name.
50SERVICE_NAME="vboxheadlessxorg"
51## The service description.
52SERVICE_DESCRIPTION="Headless rendering service"
53## Signals and conditions which may be used to terminate the service.
54EXIT_SIGNALS="EXIT HUP INT QUIT ABRT TERM"
55## The default run-time data folder.
56DEFAULT_RUN_FOLDER="/var/run/${SERVICE_NAME}/"
57## The default X server configuration directory.
58DEFAULT_CONFIGURATION_FOLDER="${DEFAULT_RUN_FOLDER}/xorg.conf.d/"
59## The extra data key used to provide the list of available X server displays.
60EXTRA_DATA_KEY_DISPLAYS="HeadlessXServer/Displays"
61## The extra data key used to specify the X server authority file.
62EXTRA_DATA_KEY_AUTH="HeadlessXServer/AuthFile"
63
64## Print usage information for the service script.
65## @todo Perhaps we should support some of the configuration file options from
66# the command line. Opinions welcome.
67## @todo Possibly extract this information for the user manual.
68usage() {
69 cat << EOF
70Usage:
71
72 $(basename "${SCRIPT_NAME}") [<options>]
73
74Start one or several X servers in the background for use with headless
75rendering. We only support X.Org Server at the moment. On service start-up available graphics devices are detected and an X server configuration file is
76generated for each. We attempt to start an X server process for each
77configuration file. The process is configurable by setting values in a file as
78described below.
79
80Options:
81
82 -c|--conf-file Specify an alternative locations for the configuration
83 file. The default location is:
84 "${CONFIGURATION_FILE}"
85
86 --help|--usage Print this text.
87
88The optional configuration file should contain a series of lines of the form
89"KEY=value". It will be read in as a command shell sub-script. Here is the
90current list of possible key settings with a short explanation. Usually it
91should be sufficient to change the value of \${HEADLESS_X_ORG_USERS} and to
92leave all other settings unchanged.
93
94 HEADLESS_X_ORG_CONFIGURATION_FOLDER
95 The folder where the X server configuration files are to be created.
96
97 HEADLESS_X_ORG_LOG_FOLDER
98 The folder where log files will be saved.
99
100 HEADLESS_X_ORG_LOG_FILE
101 The main log file name.
102
103 HEADLESS_X_ORG_RUN_FOLDER
104 The folder to store run-time data in.
105
106 HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES
107 Command to execute to wait until all dependencies for the X servers are
108 available. The default command waits until the udev event queue has
109 settled. The command may return failure to signal that it has given up.
110 No arguments may be passsed.
111
112 HEADLESS_X_ORG_USERS
113 List of users who will have access to the X servers started and for whom we
114 will provide the configuration details via VirtualBox extra data. This
115 variable is only used by the commands in the default configuration
116 (\${HEADLESS_X_ORG_SERVER_PRE_COMMAND} and
117 \${HEADLESS_X_ORG_SERVER_POST_COMMAND}), and not by the service itself.
118
119 HEADLESS_X_ORG_FIRST_DISPLAY
120 The first display number which will be used for a started X server. The
121 others will use the following numbers.
122
123 HEADLESS_X_ORG_SERVER_PRE_COMMAND
124 Command to execute once to perform any set-up needed before starting the
125 X servers, such as setting up the X server authentication. The default
126 command creates an authority file for each of the users in the list
127 \${HEADLESS_X_ORG_USERS} and generates server configuration files for all
128 detected graphics cards. No arguments may be passed.
129
130 HEADLESS_X_ORG_SERVER_COMMAND
131 The default X server start-up command. It will be passed three parameters
132 - in order, the screen number to use, the path of the X.Org configuration
133 file to use and the path of the X server log file to create.
134
135 HEADLESS_X_ORG_SERVER_POST_COMMAND
136 Command to execute once the X servers have been successfully started. It
137 will be passed a single parameter which is a space-separated list of the
138 X server screen numbers. By default this stores the service configuration
139 information to VirtualBox extra data for each of the users in the list
140 from the variable HEADLESS_X_ORG_USERS: the list of displays is set to the
141 key "${EXTRA_DATA_KEY_DISPLAYS}" and the path of the authority file to
142 "${EXTRA_DATA_KEY_AUTH}".
143EOF
144}
145
146# Default configuration.
147HEADLESS_X_ORG_CONFIGURATION_FOLDER="${DEFAULT_CONFIGURATION_FOLDER}"
148HEADLESS_X_ORG_LOG_FOLDER="/var/log/${SERVICE_NAME}"
149HEADLESS_X_ORG_LOG_FILE="${SERVICE_NAME}.log"
150HEADLESS_X_ORG_RUN_FOLDER="/var/run/${SERVICE_NAME}"
151HEADLESS_X_ORG_USERS=""
152HEADLESS_X_ORG_FIRST_DISPLAY=40
153X_AUTH_FILE="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
154
155default_wait_for_prerequisites()
156{
157 udevadm settle || udevsettle # Fails if no udevadm.
158}
159HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES="default_wait_for_prerequisites"
160
161default_pre_command()
162{
163 # Create new authority file.
164 echo > "${X_AUTH_FILE}"
165 # Create the xorg.conf files.
166 mkdir -p "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}" || return 1
167 display="${HEADLESS_X_ORG_FIRST_DISPLAY}"
168 for i in /sys/bus/pci/devices/*; do
169 read class < "${i}/class"
170 case "${class}" in *03????)
171 address="${i##*/}"
172 address="${address%%:*}${address#*:}"
173 address="PCI:${address%%.*}:${address#*.}"
174 read vendor < "${i}/vendor"
175 case "${vendor}" in *10de|*10DE) # NVIDIA
176 cat > "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/xorg.conf.${display}" << EOF
177Section "Module"
178 Load "glx"
179EndSection
180Section "Device"
181 Identifier "Device${display}"
182 Driver "nvidia"
183 Option "UseDisplayDevice" "none"
184EndSection
185Section "Screen"
186 Identifier "Screen${display}"
187 Device "Device${display}"
188EndSection
189Section "ServerLayout"
190 Identifier "Layout${display}"
191 Screen "Screen${display}"
192 Option "AllowMouseOpenFail" "true"
193 Option "AutoAddDevices" "false"
194 Option "AutoAddGPU" "false"
195 Option "AutoEnableDevices" "false"
196 Option "IsolateDevice" "${address}"
197EndSection
198EOF
199 esac
200 # Add key to the authority file.
201 key="$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | od -An -x)"
202 xauth -f "${X_AUTH_FILE}" add :${display} . "${key}"
203 display=`expr ${display} + 1`
204 esac
205 done
206 # Duplicate the authority file.
207 for i in ${HEADLESS_X_ORG_USERS}; do
208 cp "${X_AUTH_FILE}" "${X_AUTH_FILE}.${i}"
209 chown "${i}" "${X_AUTH_FILE}.${i}"
210 done
211}
212HEADLESS_X_ORG_SERVER_PRE_COMMAND="default_pre_command"
213
214default_command()
215{
216 auth="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
217 # screen=$1
218 # conf_file=$2
219 # log_file=$3
220 trap "kill \${PID}; sleep 5; kill -KILL \${PID} 2>/dev/null" ${EXIT_SIGNALS}
221 Xorg :"${1}" -auth "${auth}" -config "${2}" -logverbose 0 -logfile /dev/null -verbose 7 > "${3}" 2>&1 &
222 PID="$!"
223 wait
224 exit
225}
226HEADLESS_X_ORG_SERVER_COMMAND="default_command"
227
228default_post_command()
229{
230 # screens=$1
231 for i in ${HEADLESS_X_ORG_USERS}; do
232 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_DISPLAYS} \"${1}\""
233 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_AUTH} \"${HEADLESS_X_ORG_RUN_FOLDER}/xauth\""
234 done
235}
236HEADLESS_X_ORG_SERVER_POST_COMMAND="default_post_command"
237
238## The function definition at the start of every non-trivial shell script!
239abort() {
240 ## $@, ... Error text to output to standard error in printf format.
241 printf "$@" >&2
242 exit 1
243}
244
245## Milder version of abort, when we can't continue because of a valid condition.
246abandon() {
247 ## $@, ... Text to output to standard error in printf format.
248 printf "$@" >&2
249 exit 0
250}
251
252abort_usage() {
253 usage >&2
254 abort "$@"
255}
256
257# Print a banner message
258banner() {
259 cat << EOF
260${VBOX_PRODUCT} VBoxHeadless X Server start-up service Version ${VBOX_VERSION_STRING}
261(C) 2005-${VBOX_C_YEAR} ${VBOX_VENDOR}
262All rights reserved.
263
264EOF
265}
266
267# Get the directory where the script is located.
268SCRIPT_FOLDER=$(dirname "${SCRIPT_NAME}")"/"
269[ -r "${SCRIPT_FOLDER}generated.sh" ] ||
270 abort "${LOG_FILE}" "Failed to find installation information.\n"
271. "${SCRIPT_FOLDER}generated.sh"
272
273# Parse our arguments.
274while [ "$#" -gt 0 ]; do
275 case $1 in
276 -c|--conf-file)
277 [ "$#" -gt 1 ] ||
278 {
279 banner
280 abort "%s requires at least one argument.\n" "$1"
281 }
282 CONFIGURATION_FILE="$2"
283 shift
284 ;;
285 --help|--usage)
286 banner
287 usage
288 exit 0
289 ;;
290 *)
291 banner
292 abort_usage "Unknown argument $1.\n"
293 ;;
294 esac
295 shift
296done
297
298[ -r "${CONFIGURATION_FILE}" ] && . "${CONFIGURATION_FILE}"
299
300# Change to the root directory so we don't hold any other open.
301cd /
302
303# If something fails here we will catch it when we create the directory.
304[ -e "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
305 [ -d "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
306 rm -rf "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null &&
307mv "${HEADLESS_X_ORG_LOG_FOLDER}" "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null
308mkdir -p "${HEADLESS_X_ORG_LOG_FOLDER}" 2>/dev/null ||
309{
310 banner
311 abort "Failed to create log folder \"${HEADLESS_X_ORG_LOG_FOLDER}\".\n"
312}
313mkdir -p "${HEADLESS_X_ORG_RUN_FOLDER}" 2>/dev/null ||
314{
315 banner
316 abort "Failed to create run folder \"${HEADLESS_X_ORG_RUN_FOLDER}\".\n"
317}
318exec > "${HEADLESS_X_ORG_LOG_FOLDER}/${HEADLESS_X_ORG_LOG_FILE}" 2>&1
319
320banner
321
322# Wait for our dependencies to become available.
323if [ -n "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ]; then
324 "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ||
325 abort "Service prerequisites not available.\n"
326fi
327
328# Do any pre-start setup.
329if [ -n "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ]; then
330 "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ||
331 abort "Pre-requisite failed.\n"
332fi
333
334X_SERVER_PIDS=""
335X_SERVER_SCREENS=""
336trap "kill \${X_SERVER_PIDS} 2>/dev/null" ${EXIT_SIGNALS}
337space="" # Hack to put spaces between the pids but not before or after.
338for conf_file in "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}"/*; do
339 [ x"${conf_file}" = x"${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/*" ] &&
340 ! [ -e "${conf_file}" ] &&
341 abort "No configuration files found.\n"
342 filename="$(basename "${conf_file}")"
343 screen="$(expr "${filename}" : "xorg\.conf\.\(.*\)")"
344 [ 0 -le "${screen}" ] 2>/dev/null ||
345 abort "Badly formed file name \"${conf_file}\".\n"
346 log_file="${HEADLESS_X_ORG_LOG_FOLDER}/Xorg.${screen}.log"
347 "${HEADLESS_X_ORG_SERVER_COMMAND}" "${screen}" "${conf_file}" "${log_file}" &
348 X_SERVER_PIDS="${X_SERVER_PIDS}${space}$!"
349 X_SERVER_SCREENS="${X_SERVER_SCREENS}${space}${screen}"
350 space=" "
351done
352
353# Do any post-start work.
354if [ -n "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" ]; then
355 "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" "${X_SERVER_SCREENS}" ||
356 abort "Post-command failed.\n"
357fi
358
359wait
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