3 # This script starts an instance of Xvfb, the "fake" X server, runs a command
4 # with that server available, and kills the X server when done. The return
5 # value of the command becomes the return value of this script, except in cases
6 # where this script encounters an error.
8 # If anyone is using this to build a Debian package, make sure the package
9 # Build-Depends on xvfb and xauth.
17 XVFBARGS
="-screen 0 640x480x8"
18 LISTENTCP
="-nolisten tcp"
21 # Query the terminal to establish a default number of columns to use for
22 # displaying messages to the user. This is used only as a fallback in the event
23 # the COLUMNS variable is not set. ($COLUMNS can react to SIGWINCH while the
24 # script is running, and this cannot, only being calculated once.)
25 DEFCOLUMNS
=$
(stty size
2>/dev
/null |
awk '{print $2}') || true
26 if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" >/dev
/null
2>&1; then
30 # Display a message, wrapping lines at the terminal width.
32 echo "$PROGNAME: $*" |
fmt -t -w ${COLUMNS:-$DEFCOLUMNS}
35 # Display an error message.
37 message
"error: $*" >&2
40 # Display a usage message.
43 message
"usage error: $*"
46 Usage: $PROGNAME [OPTION ...] COMMAND
47 Run COMMAND (usually an X client) in a virtual X server environment.
49 -a --auto-servernum try to get a free server number, starting at
51 -e FILE --error-file=FILE file used to store xauth errors and Xvfb
52 output (default: $ERRORFILE)
53 -f FILE --auth-file=FILE file used to store auth cookie
54 (default: ./.Xauthority)
55 -h --help display this usage message and exit
56 -n NUM --server-num=NUM server number to use (default: $SERVERNUM)
57 -l --listen-tcp enable TCP port listening in the X server
58 -p PROTO --xauth-protocol=PROTO X authority protocol name to use
59 (default: xauth command's default)
60 -s ARGS --server-args=ARGS arguments (other than server number and
61 "-nolisten tcp") to pass to the Xvfb server
62 (default: "$XVFBARGS")
66 # Find a free server number by looking at .X*-lock files in /tmp.
67 find_free_servernum
() {
68 # Sadly, the "local" keyword is not POSIX. Leave the next line commented in
69 # the hope Debian Policy eventually changes to allow it in /bin/sh scripts
74 while [ -f /tmp
/.X
$i-lock ]; do
82 if [ -e "$AUTHFILE" ]; then
83 XAUTHORITY
=$AUTHFILE xauth remove
":$SERVERNUM" >>"$ERRORFILE" 2>&1
85 if [ -n "$XVFB_RUN_TMPDIR" ]; then
86 if ! rm -r "$XVFB_RUN_TMPDIR"; then
87 error
"problem while cleaning up temporary directory"
91 if [ -n "$XVFBPID" ]; then
92 kill "$XVFBPID" >>"$ERRORFILE" 2>&1
96 # Parse the command line.
97 ARGS
=$
(getopt
--options +ae
:f
:hn
:lp:s
:w
: \
98 --long auto-servernum
,error-file
:,auth-file
:,help,server-num
:,listen-tcp
,xauth-protocol
:,server-args
:,wait: \
99 --name "$PROGNAME" -- "$@")
102 if [ $GETOPT_STATUS -ne 0 ]; then
103 error
"internal error; getopt exited with status $GETOPT_STATUS"
111 -a|
--auto-servernum) SERVERNUM
=$
(find_free_servernum
); AUTONUM
="yes" ;;
112 -e|
--error-file) ERRORFILE
="$2"; shift ;;
113 -f|
--auth-file) AUTHFILE
="$2"; shift ;;
114 -h|
--help) SHOWHELP
="yes" ;;
115 -n|
--server-num) SERVERNUM
="$2"; shift ;;
116 -l|
--listen-tcp) LISTENTCP
="" ;;
117 -p|
--xauth-protocol) XAUTHPROTO
="$2"; shift ;;
118 -s|
--server-args) XVFBARGS
="$2"; shift ;;
121 *) error
"internal error; getopt permitted \"$1\" unexpectedly"
128 if [ "$SHOWHELP" ]; then
134 usage
"need a command to run" >&2
138 if ! which xauth
>/dev
/null
; then
139 error
"xauth command not found"
143 # tidy up after ourselves
146 # If the user did not specify an X authorization file to use, set up a temporary
147 # directory to house one.
148 if [ -z "$AUTHFILE" ]; then
149 XVFB_RUN_TMPDIR
="$(mktemp -d -t $PROGNAME.XXXXXX)"
150 # Create empty file to avoid xauth warning
151 AUTHFILE
=$
(tempfile
-n "$XVFB_RUN_TMPDIR/Xauthority")
157 while [ $tries -gt 0 ]; do
158 tries
=$
(( $tries - 1 ))
159 XAUTHORITY
=$AUTHFILE xauth
source - << EOF >>"$ERRORFILE" 2>&1
160 add :$SERVERNUM $XAUTHPROTO $MCOOKIE
162 # handle SIGUSR1 so Xvfb knows to send a signal when it's ready to accept
165 (trap '' USR1
; exec Xvfb
":$SERVERNUM" $XVFBARGS $LISTENTCP -auth $AUTHFILE >>"$ERRORFILE" 2>&1) &
169 if kill -0 $XVFBPID 2>/dev
/null
; then
171 elif [ -n "$AUTONUM" ]; then
172 # The display is in use so try another one (if '-a' was specified).
173 SERVERNUM
=$
((SERVERNUM
+ 1))
174 SERVERNUM
=$
(find_free_servernum
)
177 error
"Xvfb failed to start" >&2
182 # Start the command and save its exit status.
184 DISPLAY
=:$SERVERNUM XAUTHORITY
=$AUTHFILE "$@" 2>&1
188 # Return the executed command's exit status.
191 # vim:set ai et sts=4 sw=4 tw=80: