VirtualBox

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

Last change on this file since 46712 was 46352, checked in by vboxsync, 12 years ago

Installer/linux/headlessxorg: a number of updates.

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 13.4 KB
Line 
1#!/bin/sh
2# $Id: VBoxHeadlessXOrg.sh 46352 2013-05-31 21:07:53Z vboxsync $
3#
4# VirtualBox X Server auto-start service.
5#
6# Copyright (C) 2012-2013 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 --install Install the service to run at system start-up.
85
86 --uninstall Revert the installation done by the "--install" option.
87
88 --help|--usage Print this text.
89
90The optional configuration file should contain a series of lines of the form
91"KEY=value". It will be read in as a command shell sub-script. Here is the
92current list of possible key settings with a short explanation. Usually it
93should be sufficient to change the value of \${HEADLESS_X_ORG_USERS} and to
94leave all other settings unchanged.
95
96 HEADLESS_X_ORG_CONFIGURATION_FOLDER
97 The folder where the X server configuration files are to be created.
98
99 HEADLESS_X_ORG_LOG_FOLDER
100 The folder where log files will be saved.
101
102 HEADLESS_X_ORG_LOG_FILE
103 The main log file name.
104
105 HEADLESS_X_ORG_RUN_FOLDER
106 The folder to store run-time data in.
107
108 HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES
109 Command to execute to wait until all dependencies for the X servers are
110 available. The default command waits until the udev event queue has
111 settled. The command may return failure to signal that it has given up.
112 No arguments may be passsed.
113
114 HEADLESS_X_ORG_USERS
115 List of users who will have access to the X servers started and for whom we
116 will provide the configuration details via VirtualBox extra data. This
117 variable is only used by the commands in the default configuration
118 (\${HEADLESS_X_ORG_SERVER_PRE_COMMAND} and
119 \${HEADLESS_X_ORG_SERVER_POST_COMMAND}), and not by the service itself.
120
121 HEADLESS_X_ORG_FIRST_DISPLAY
122 The first display number which will be used for a started X server. The
123 others will use the following numbers.
124
125 HEADLESS_X_ORG_SERVER_PRE_COMMAND
126 Command to execute once to perform any set-up needed before starting the
127 X servers, such as setting up the X server authentication. The default
128 command creates an authority file for each of the users in the list
129 \${HEADLESS_X_ORG_USERS} and generates server configuration files for all
130 detected graphics cards. No arguments may be passed.
131
132 HEADLESS_X_ORG_SERVER_COMMAND
133 The default X server start-up command. It will be passed three parameters
134 - in order, the screen number to use, the path of the X.Org configuration
135 file to use and the path of the X server log file to create.
136
137 HEADLESS_X_ORG_SERVER_POST_COMMAND
138 Command to execute once the X servers have been successfully started. It
139 will be passed a single parameter which is a space-separated list of the
140 X server screen numbers. By default this stores the service configuration
141 information to VirtualBox extra data for each of the users in the list
142 from the variable HEADLESS_X_ORG_USERS: the list of displays is set to the
143 key "${EXTRA_DATA_KEY_DISPLAYS}" and the path of the authority file to
144 "${EXTRA_DATA_KEY_AUTH}".
145EOF
146}
147
148# Default configuration.
149HEADLESS_X_ORG_CONFIGURATION_FOLDER="${DEFAULT_CONFIGURATION_FOLDER}"
150HEADLESS_X_ORG_LOG_FOLDER="/var/log/${SERVICE_NAME}"
151HEADLESS_X_ORG_LOG_FILE="${SERVICE_NAME}.log"
152HEADLESS_X_ORG_RUN_FOLDER="/var/run/${SERVICE_NAME}"
153HEADLESS_X_ORG_USERS=""
154HEADLESS_X_ORG_FIRST_DISPLAY=40
155X_AUTH_FILE="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
156
157default_wait_for_prerequisites()
158{
159 udevadm settle || udevsettle # Fails if no udevadm.
160}
161HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES="default_wait_for_prerequisites"
162
163default_pre_command()
164{
165 # Create new authority file.
166 echo > "${X_AUTH_FILE}"
167 # Create the xorg.conf files.
168 mkdir -p "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}" || return 1
169 display="${HEADLESS_X_ORG_FIRST_DISPLAY}"
170 for i in /sys/bus/pci/devices/*; do
171 read class < "${i}/class"
172 case "${class}" in *03????)
173 address="${i##*/}"
174 address="${address%%:*}${address#*:}"
175 address="PCI:${address%%.*}:${address#*.}"
176 read vendor < "${i}/vendor"
177 case "${vendor}" in *10de|*10DE) # NVIDIA
178 cat > "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/xorg.conf.${display}" << EOF
179Section "Module"
180 Load "glx"
181EndSection
182Section "Device"
183 Identifier "Device${display}"
184 Driver "nvidia"
185 Option "UseDisplayDevice" "none"
186EndSection
187Section "Screen"
188 Identifier "Screen${display}"
189 Device "Device${display}"
190EndSection
191Section "ServerLayout"
192 Identifier "Layout${display}"
193 Screen "Screen${display}"
194 Option "AllowMouseOpenFail" "true"
195 Option "AutoAddDevices" "false"
196 Option "AutoAddGPU" "false"
197 Option "AutoEnableDevices" "false"
198 Option "IsolateDevice" "${address}"
199EndSection
200EOF
201 esac
202 # Add key to the authority file.
203 key="$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | od -An -x)"
204 xauth -f "${X_AUTH_FILE}" add :${display} . "${key}"
205 display=`expr ${display} + 1`
206 esac
207 done
208 # Duplicate the authority file.
209 for i in ${HEADLESS_X_ORG_USERS}; do
210 cp "${X_AUTH_FILE}" "${X_AUTH_FILE}.${i}"
211 chown "${i}" "${X_AUTH_FILE}.${i}"
212 done
213}
214HEADLESS_X_ORG_SERVER_PRE_COMMAND="default_pre_command"
215
216default_command()
217{
218 auth="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
219 # screen=$1
220 # conf_file=$2
221 # log_file=$3
222 trap "kill \${PID}; sleep 5; kill -KILL \${PID} 2>/dev/null" ${EXIT_SIGNALS}
223 Xorg :"${1}" -auth "${auth}" -config "${2}" -logverbose 0 -logfile /dev/null -verbose 7 > "${3}" 2>&1 &
224 PID="$!"
225 wait
226 exit
227}
228HEADLESS_X_ORG_SERVER_COMMAND="default_command"
229
230default_post_command()
231{
232 # screens=$1
233 for i in ${HEADLESS_X_ORG_USERS}; do
234 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_DISPLAYS} \"${1}\""
235 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_AUTH} \"${HEADLESS_X_ORG_RUN_FOLDER}/xauth\""
236 done
237}
238HEADLESS_X_ORG_SERVER_POST_COMMAND="default_post_command"
239
240## The function definition at the start of every non-trivial shell script!
241abort() {
242 ## $@, ... Error text to output to standard error in printf format.
243 printf "$@" >&2
244 exit 1
245}
246
247## Milder version of abort, when we can't continue because of a valid condition.
248abandon() {
249 ## $@, ... Text to output to standard error in printf format.
250 printf "$@" >&2
251 exit 0
252}
253
254abort_usage() {
255 usage >&2
256 abort "$@"
257}
258
259# Print a banner message
260banner() {
261 cat << EOF
262${VBOX_PRODUCT} VBoxHeadless X Server start-up service Version ${VBOX_VERSION_STRING}
263(C) 2005-${VBOX_C_YEAR} ${VBOX_VENDOR}
264All rights reserved.
265
266EOF
267}
268
269# Get the directory where the script is located.
270SCRIPT_FOLDER=$(dirname "${SCRIPT_NAME}")"/"
271[ -r "${SCRIPT_FOLDER}generated.sh" ] ||
272 abort "${LOG_FILE}" "Failed to find installation information.\n"
273. "${SCRIPT_FOLDER}generated.sh"
274
275# Parse our arguments.
276do_install=""
277while [ "$#" -gt 0 ]; do
278 case $1 in
279 -c|--conf-file)
280 [ "$#" -gt 1 ] ||
281 {
282 banner
283 abort "%s requires at least one argument.\n" "$1"
284 }
285 CONFIGURATION_FILE="$2"
286 shift
287 ;;
288 --help|--usage)
289 banner
290 usage
291 exit 0
292 ;;
293 --install)
294 do_install="install"
295 ;;
296 --uninstall)
297 do_install="uninstall"
298 ;;
299 *)
300 banner
301 abort_usage "Unknown argument $1.\n"
302 ;;
303 esac
304 shift
305done
306
307[ -r "${CONFIGURATION_FILE}" ] && . "${CONFIGURATION_FILE}"
308
309if [ -n "${do_install}" ]; then
310 SCRIPT_FOLDER=$(cd "${SCRIPT_FOLDER}" && pwd)"/"
311 CONFIGURATION_FILE_ESCAPED=$(echo "${CONFIGURATION_FILE}" | sed 's/\([ \%]\)/\\\1/g')
312 if [ "x${do_install}" = "xinstall" ]; then
313 ${SCRIPT_FOLDER}install_service --enable -- --command "${SCRIPT_FOLDER}"$(basename "${SCRIPT_NAME}") --arguments "--conf-file ${CONFIGURATION_FILE_ESCAPED}" --service-name "${SERVICE_NAME}" --description "${SERVICE_DESCRIPTION}"
314 else
315 ${SCRIPT_FOLDER}install_service --remove -- --service-name "${SERVICE_NAME}"
316 fi
317 exit 0
318fi
319
320# Change to the root directory so we don't hold any other open.
321cd /
322
323# If something fails here we will catch it when we create the directory.
324[ -e "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
325 [ -d "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
326 rm -rf "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null &&
327mv "${HEADLESS_X_ORG_LOG_FOLDER}" "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null
328mkdir -p "${HEADLESS_X_ORG_LOG_FOLDER}" 2>/dev/null ||
329{
330 banner
331 abort "Failed to create log folder \"${HEADLESS_X_ORG_LOG_FOLDER}\".\n"
332}
333mkdir -p "${HEADLESS_X_ORG_RUN_FOLDER}" 2>/dev/null ||
334{
335 banner
336 abort "Failed to create run folder \"${HEADLESS_X_ORG_RUN_FOLDER}\".\n"
337}
338exec > "${HEADLESS_X_ORG_LOG_FOLDER}/${HEADLESS_X_ORG_LOG_FILE}" 2>&1
339
340banner
341
342# Wait for our dependencies to become available.
343if [ -n "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ]; then
344 "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ||
345 abort "Service prerequisites not available.\n"
346fi
347
348# Do any pre-start setup.
349if [ -n "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ]; then
350 "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ||
351 abort "Pre-requisite failed.\n"
352fi
353
354X_SERVER_PIDS=""
355X_SERVER_SCREENS=""
356trap "kill \${X_SERVER_PIDS} 2>/dev/null" ${EXIT_SIGNALS}
357space="" # Hack to put spaces between the pids but not before or after.
358for conf_file in "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}"/*; do
359 [ x"${conf_file}" = x"${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/*" ] &&
360 ! [ -e "${conf_file}" ] &&
361 abort "No configuration files found.\n"
362 filename="$(basename "${conf_file}")"
363 screen="$(expr "${filename}" : "xorg\.conf\.\(.*\)")"
364 [ 0 -le "${screen}" ] 2>/dev/null ||
365 abort "Badly formed file name \"${conf_file}\".\n"
366 log_file="${HEADLESS_X_ORG_LOG_FOLDER}/Xorg.${screen}.log"
367 "${HEADLESS_X_ORG_SERVER_COMMAND}" "${screen}" "${conf_file}" "${log_file}" &
368 X_SERVER_PIDS="${X_SERVER_PIDS}${space}$!"
369 X_SERVER_SCREENS="${X_SERVER_SCREENS}${space}${screen}"
370 space=" "
371done
372
373# Do any post-start work.
374if [ -n "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" ]; then
375 "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" "${X_SERVER_SCREENS}" ||
376 abort "Post-command failed.\n"
377fi
378
379wait
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