VirtualBox

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

Last change on this file since 58585 was 58585, checked in by vboxsync, 9 years ago

Installers/linux (host): remove the creative and over-engineered init script handling from VBoxHeadlessXorg.sh. If anyone wishes to use it in future they will have to write their own service handling, which they would probably have had to anyway, given that the old one did not support systemd.

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