VirtualBox

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

Last change on this file since 44760 was 44529, checked in by vboxsync, 12 years ago

header (C) fixes

  • Property svn:eol-style set to LF
  • Property svn:executable set to *
  • Property svn:keywords set to Author Date Id Revision
File size: 13.0 KB
Line 
1#!/bin/sh
2# $Id: VBoxHeadlessXOrg.sh 44529 2013-02-04 15:54:15Z 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=10
155X_AUTH_FILE="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
156
157default_wait_for_prerequisites()
158{
159 udevadm settle # Fails if no udevadm.
160}
161HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES="default_wait_for_prerequisites"
162
163default_pre_command()
164{
165 # Create and duplicate the authority file.
166 echo > "${X_AUTH_FILE}"
167 key="$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | od -An -x)"
168 xauth -f "${X_AUTH_FILE}" add :0 . "${key}"
169 for i in ${HEADLESS_X_ORG_USERS}; do
170 cp "${X_AUTH_FILE}" "${X_AUTH_FILE}.${i}"
171 chown "${i}" "${X_AUTH_FILE}.${i}"
172 done
173 # Create the xorg.conf files.
174 mkdir -p "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}" || return 1
175 display="${HEADLESS_X_ORG_FIRST_DISPLAY}"
176 for i in /sys/bus/pci/devices/*; do
177 read class < "${i}/class"
178 case ${class} in *03????)
179 address="${i##*/}"
180 address="${address%%:*}${address#*:}"
181 address="PCI:${address%%.*}:${address#*.}"
182 cat > "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/xorg.conf.${display}" << EOF
183Section "Screen"
184 Identifier "Screen${display}"
185EndSection
186Section "ServerLayout"
187 Identifier "Layout${display}"
188 Screen "Screen${display}"
189 Option "AllowMouseOpenFail" "true"
190 Option "AutoAddDevices" "false"
191 Option "AutoAddGPU" "false"
192 Option "AutoEnableDevices" "false"
193 Option "IsolateDevice" "${address}"
194EndSection
195EOF
196 display=`expr ${display} + 1`
197 esac
198 done
199}
200HEADLESS_X_ORG_SERVER_PRE_COMMAND="default_pre_command"
201
202default_command()
203{
204 auth="${HEADLESS_X_ORG_RUN_FOLDER}/xauth"
205 # screen=$1
206 # conf_file=$2
207 # log_file=$3
208 trap "kill \${PID}; sleep 5; kill -KILL \${PID} 2>/dev/null" ${EXIT_SIGNALS}
209 Xorg :"${1}" -auth "${auth}" -config "${2}" -logverbose 0 -logfile /dev/null -verbose 7 > "${3}" 2>&1 &
210 PID="$!"
211 wait
212 exit
213}
214HEADLESS_X_ORG_SERVER_COMMAND="default_command"
215
216default_post_command()
217{
218 # screens=$1
219 for i in ${HEADLESS_X_ORG_USERS}; do
220 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_DISPLAYS} \"${1}\""
221 su ${i} -c "VBoxManage setextradata global ${EXTRA_DATA_KEY_AUTH} \"${HEADLESS_X_ORG_RUN_FOLDER}/xauth\""
222 done
223}
224HEADLESS_X_ORG_SERVER_POST_COMMAND="default_post_command"
225
226## The function definition at the start of every non-trivial shell script!
227abort() {
228 ## $@, ... Error text to output to standard error in printf format.
229 printf "$@" >&2
230 exit 1
231}
232
233## Milder version of abort, when we can't continue because of a valid condition.
234abandon() {
235 ## $@, ... Text to output to standard error in printf format.
236 printf "$@" >&2
237 exit 0
238}
239
240abort_usage() {
241 usage >&2
242 abort "$@"
243}
244
245# Print a banner message
246banner() {
247 cat << EOF
248${VBOX_PRODUCT} VBoxHeadless X Server start-up service Version ${VBOX_VERSION_STRING}
249(C) 2005-${VBOX_C_YEAR} ${VBOX_VENDOR}
250All rights reserved.
251
252EOF
253}
254
255# Get the directory where the script is located.
256SCRIPT_FOLDER=$(dirname "${SCRIPT_NAME}")"/"
257[ -r "${SCRIPT_FOLDER}generated.sh" ] ||
258 abort "${LOG_FILE}" "Failed to find installation information.\n"
259. "${SCRIPT_FOLDER}generated.sh"
260
261# Parse our arguments.
262do_install=""
263while [ "$#" -gt 0 ]; do
264 case $1 in
265 -c|--conf-file)
266 [ "$#" -gt 1 ] ||
267 {
268 banner
269 abort "%s requires at least one argument.\n" "$1"
270 }
271 CONFIGURATION_FILE="$2"
272 shift
273 ;;
274 --help|--usage)
275 banner
276 usage
277 exit 0
278 ;;
279 --install)
280 do_install="install"
281 ;;
282 --uninstall)
283 do_install="uninstall"
284 ;;
285 *)
286 banner
287 abort_usage "Unknown argument $1.\n"
288 ;;
289 esac
290 shift
291done
292
293[ -r "${CONFIGURATION_FILE}" ] && . "${CONFIGURATION_FILE}"
294
295if [ -n "${do_install}" ]; then
296 SCRIPT_FOLDER=$(cd "${SCRIPT_FOLDER}" && pwd)"/"
297 CONFIGURATION_FILE_ESCAPED=$(echo "${CONFIGURATION_FILE}" | sed 's/\([ \%]\)/\\\1/g')
298 if [ "x${do_install}" = "xinstall" ]; then
299 ${SCRIPT_FOLDER}install_service --enable -- --command "${SCRIPT_FOLDER}"$(basename "${SCRIPT_NAME}") --arguments "--conf-file ${CONFIGURATION_FILE_ESCAPED}" --service-name "${SERVICE_NAME}" --description "${SERVICE_DESCRIPTION}"
300 else
301 ${SCRIPT_FOLDER}install_service --remove -- --service-name "${SERVICE_NAME}"
302 fi
303 exit 0
304fi
305
306# Change to the root directory so we don't hold any other open.
307cd /
308
309# If something fails here we will catch it when we create the directory.
310[ -e "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
311 [ -d "${HEADLESS_X_ORG_LOG_FOLDER}" ] &&
312 rm -rf "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null &&
313mv "${HEADLESS_X_ORG_LOG_FOLDER}" "${HEADLESS_X_ORG_LOG_FOLDER}.old" 2> /dev/null
314mkdir -p "${HEADLESS_X_ORG_LOG_FOLDER}" 2>/dev/null ||
315{
316 banner
317 abort "Failed to create log folder \"${HEADLESS_X_ORG_LOG_FOLDER}\".\n"
318}
319mkdir -p "${HEADLESS_X_ORG_RUN_FOLDER}" 2>/dev/null ||
320{
321 banner
322 abort "Failed to create run folder \"${HEADLESS_X_ORG_RUN_FOLDER}\".\n"
323}
324exec > "${HEADLESS_X_ORG_LOG_FOLDER}/${HEADLESS_X_ORG_LOG_FILE}" 2>&1
325
326banner
327
328# Wait for our dependencies to become available.
329if [ -n "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ]; then
330 "${HEADLESS_X_ORG_WAIT_FOR_PREREQUISITES}" ||
331 abort "Service prerequisites not available.\n"
332fi
333
334# Do any pre-start setup.
335if [ -n "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ]; then
336 "${HEADLESS_X_ORG_SERVER_PRE_COMMAND}" ||
337 abort "Pre-requisite failed.\n"
338fi
339
340X_SERVER_PIDS=""
341X_SERVER_SCREENS=""
342trap "kill \${X_SERVER_PIDS} 2>/dev/null" ${EXIT_SIGNALS}
343space="" # Hack to put spaces between the pids but not before or after.
344for conf_file in "${HEADLESS_X_ORG_CONFIGURATION_FOLDER}"/*; do
345 [ x"${conf_file}" = x"${HEADLESS_X_ORG_CONFIGURATION_FOLDER}/*" ] &&
346 ! [ -e "${conf_file}" ] &&
347 abort "No configuration files found.\n"
348 filename="$(basename "${conf_file}")"
349 screen="$(expr "${filename}" : "xorg\.conf\.\(.*\)")"
350 [ 0 -le "${screen}" ] 2>/dev/null ||
351 abort "Badly formed file name \"${conf_file}\".\n"
352 log_file="${HEADLESS_X_ORG_LOG_FOLDER}/Xorg.${screen}.log"
353 "${HEADLESS_X_ORG_SERVER_COMMAND}" "${screen}" "${conf_file}" "${log_file}" &
354 X_SERVER_PIDS="${X_SERVER_PIDS}${space}$!"
355 X_SERVER_SCREENS="${X_SERVER_SCREENS}${space}${screen}"
356 space=" "
357done
358
359# Do any post-start work.
360if [ -n "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" ]; then
361 "${HEADLESS_X_ORG_SERVER_POST_COMMAND}" "${X_SERVER_SCREENS}" ||
362 abort "Post-command failed.\n"
363fi
364
365wait
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