|
ali@38
|
1 |
#!/bin/sh
|
|
ali@38
|
2 |
|
|
ali@38
|
3 |
# This script starts an instance of Xvfb, the "fake" X server, runs a command
|
|
ali@38
|
4 |
# with that server available, and kills the X server when done. The return
|
|
ali@38
|
5 |
# value of the command becomes the return value of this script.
|
|
ali@38
|
6 |
#
|
|
ali@38
|
7 |
# If anyone is using this to build a Debian package, make sure the package
|
|
ali@38
|
8 |
# Build-Depends on xvfb and xauth.
|
|
ali@38
|
9 |
|
|
ali@38
|
10 |
set -e
|
|
ali@38
|
11 |
|
|
ali@38
|
12 |
PROGNAME=xvfb-run
|
|
ali@38
|
13 |
SERVERNUM=99
|
|
ali@38
|
14 |
AUTHFILE=
|
|
ali@38
|
15 |
ERRORFILE=/dev/null
|
|
ali@38
|
16 |
XVFBARGS="-screen 0 640x480x8"
|
|
ali@38
|
17 |
LISTENTCP="-nolisten tcp"
|
|
ali@38
|
18 |
XAUTHPROTO=.
|
|
ali@38
|
19 |
|
|
ali@38
|
20 |
# Query the terminal to establish a default number of columns to use for
|
|
ali@38
|
21 |
# displaying messages to the user. This is used only as a fallback in the event
|
|
ali@38
|
22 |
# the COLUMNS variable is not set. ($COLUMNS can react to SIGWINCH while the
|
|
ali@38
|
23 |
# script is running, and this cannot, only being calculated once.)
|
|
ali@38
|
24 |
DEFCOLUMNS=$(stty size 2>/dev/null | awk '{print $2}') || true
|
|
ali@38
|
25 |
if ! expr "$DEFCOLUMNS" : "[[:digit:]]\+$" >/dev/null 2>&1; then
|
|
ali@38
|
26 |
DEFCOLUMNS=80
|
|
ali@38
|
27 |
fi
|
|
ali@38
|
28 |
|
|
ali@38
|
29 |
# Display a message, wrapping lines at the terminal width.
|
|
ali@38
|
30 |
message () {
|
|
ali@38
|
31 |
echo "$PROGNAME: $*" | fmt -t -w ${COLUMNS:-$DEFCOLUMNS}
|
|
ali@38
|
32 |
}
|
|
ali@38
|
33 |
|
|
ali@38
|
34 |
# Display an error message.
|
|
ali@38
|
35 |
error () {
|
|
ali@38
|
36 |
message "error: $*" >&2
|
|
ali@38
|
37 |
}
|
|
ali@38
|
38 |
|
|
ali@38
|
39 |
# Display a usage message.
|
|
ali@38
|
40 |
usage () {
|
|
ali@38
|
41 |
if [ -n "$*" ]; then
|
|
ali@38
|
42 |
message "usage error: $*"
|
|
ali@38
|
43 |
fi
|
|
ali@38
|
44 |
cat <<EOF
|
|
ali@38
|
45 |
Usage: $PROGNAME [OPTION ...] COMMAND
|
|
ali@38
|
46 |
Run COMMAND (usually an X client) in a virtual X server environment.
|
|
ali@38
|
47 |
Options:
|
|
ali@38
|
48 |
-a --auto-servernum try to get a free server number, starting at
|
|
ali@38
|
49 |
--server-num
|
|
ali@38
|
50 |
-e FILE --error-file=FILE file used to store xauth errors and Xvfb
|
|
ali@38
|
51 |
output (default: $ERRORFILE)
|
|
ali@38
|
52 |
-f FILE --auth-file=FILE file used to store auth cookie
|
|
ali@38
|
53 |
(default: ./.Xauthority)
|
|
ali@38
|
54 |
-h --help display this usage message and exit
|
|
ali@38
|
55 |
-n NUM --server-num=NUM server number to use (default: $SERVERNUM)
|
|
ali@38
|
56 |
-l --listen-tcp enable TCP port listening in the X server
|
|
ali@38
|
57 |
-p PROTO --xauth-protocol=PROTO X authority protocol name to use
|
|
ali@38
|
58 |
(default: xauth command's default)
|
|
ali@38
|
59 |
-s ARGS --server-args=ARGS arguments (other than server number and
|
|
ali@38
|
60 |
"-nolisten tcp") to pass to the Xvfb server
|
|
ali@38
|
61 |
(default: "$XVFBARGS")
|
|
ali@38
|
62 |
EOF
|
|
ali@38
|
63 |
}
|
|
ali@38
|
64 |
|
|
ali@38
|
65 |
# Find a free server number by looking at .X*-lock files in /tmp.
|
|
ali@38
|
66 |
find_free_servernum() {
|
|
ali@38
|
67 |
# Sadly, the "local" keyword is not POSIX. Leave the next line commented in
|
|
ali@38
|
68 |
# the hope Debian Policy eventually changes to allow it in /bin/sh scripts
|
|
ali@38
|
69 |
# anyway.
|
|
ali@38
|
70 |
#local i
|
|
ali@38
|
71 |
|
|
ali@38
|
72 |
i=$SERVERNUM
|
|
ali@38
|
73 |
while [ -f /tmp/.X$i-lock ]; do
|
|
ali@38
|
74 |
i=$(($i + 1))
|
|
ali@38
|
75 |
done
|
|
ali@38
|
76 |
echo $i
|
|
ali@38
|
77 |
}
|
|
ali@38
|
78 |
|
|
ali@38
|
79 |
# Clean up files
|
|
ali@38
|
80 |
clean_up() {
|
|
ali@38
|
81 |
if [ -e "$AUTHFILE" ]; then
|
|
ali@38
|
82 |
XAUTHORITY=$AUTHFILE xauth remove ":$SERVERNUM" >>"$ERRORFILE" 2>&1
|
|
ali@38
|
83 |
fi
|
|
ali@38
|
84 |
if [ -n "$XVFB_RUN_TMPDIR" ]; then
|
|
ali@38
|
85 |
if ! rm -r "$XVFB_RUN_TMPDIR"; then
|
|
ali@38
|
86 |
error "problem while cleaning up temporary directory"
|
|
ali@38
|
87 |
exit 5
|
|
ali@38
|
88 |
fi
|
|
ali@38
|
89 |
fi
|
|
ali@38
|
90 |
if [ -n "$XVFBPID" ]; then
|
|
ali@38
|
91 |
kill "$XVFBPID" >>"$ERRORFILE" 2>&1
|
|
ali@38
|
92 |
fi
|
|
ali@38
|
93 |
}
|
|
ali@38
|
94 |
|
|
ali@38
|
95 |
# Parse the command line.
|
|
ali@38
|
96 |
ARGS=$(getopt --options +ae:f:hn:lp:s:w: \
|
|
ali@38
|
97 |
--long auto-servernum,error-file:,auth-file:,help,server-num:,listen-tcp,xauth-protocol:,server-args:,wait: \
|
|
ali@38
|
98 |
--name "$PROGNAME" -- "$@")
|
|
ali@38
|
99 |
GETOPT_STATUS=$?
|
|
ali@38
|
100 |
|
|
ali@38
|
101 |
if [ $GETOPT_STATUS -ne 0 ]; then
|
|
ali@38
|
102 |
error "internal error; getopt exited with status $GETOPT_STATUS"
|
|
ali@38
|
103 |
exit 6
|
|
ali@38
|
104 |
fi
|
|
ali@38
|
105 |
|
|
ali@38
|
106 |
eval set -- "$ARGS"
|
|
ali@38
|
107 |
|
|
ali@38
|
108 |
while :; do
|
|
ali@38
|
109 |
case "$1" in
|
|
ali@38
|
110 |
-a|--auto-servernum) SERVERNUM=$(find_free_servernum); AUTONUM="yes" ;;
|
|
ali@38
|
111 |
-e|--error-file) ERRORFILE="$2"; shift ;;
|
|
ali@38
|
112 |
-f|--auth-file) AUTHFILE="$2"; shift ;;
|
|
ali@38
|
113 |
-h|--help) SHOWHELP="yes" ;;
|
|
ali@38
|
114 |
-n|--server-num) SERVERNUM="$2"; shift ;;
|
|
ali@38
|
115 |
-l|--listen-tcp) LISTENTCP="" ;;
|
|
ali@38
|
116 |
-p|--xauth-protocol) XAUTHPROTO="$2"; shift ;;
|
|
ali@38
|
117 |
-s|--server-args) XVFBARGS="$2"; shift ;;
|
|
ali@38
|
118 |
-w|--wait) shift ;;
|
|
ali@38
|
119 |
--) shift; break ;;
|
|
ali@38
|
120 |
*) error "internal error; getopt permitted \"$1\" unexpectedly"
|
|
ali@38
|
121 |
exit 6
|
|
ali@38
|
122 |
;;
|
|
ali@38
|
123 |
esac
|
|
ali@38
|
124 |
shift
|
|
ali@38
|
125 |
done
|
|
ali@38
|
126 |
|
|
ali@38
|
127 |
if [ "$SHOWHELP" ]; then
|
|
ali@38
|
128 |
usage
|
|
ali@38
|
129 |
exit 0
|
|
ali@38
|
130 |
fi
|
|
ali@38
|
131 |
|
|
ali@38
|
132 |
if [ -z "$*" ]; then
|
|
ali@38
|
133 |
usage "need a command to run" >&2
|
|
ali@38
|
134 |
exit 2
|
|
ali@38
|
135 |
fi
|
|
ali@38
|
136 |
|
|
ali@38
|
137 |
if ! which xauth >/dev/null; then
|
|
ali@38
|
138 |
error "xauth command not found"
|
|
ali@38
|
139 |
exit 3
|
|
ali@38
|
140 |
fi
|
|
ali@38
|
141 |
|
|
ali@38
|
142 |
# tidy up after ourselves
|
|
ali@38
|
143 |
trap clean_up EXIT
|
|
ali@38
|
144 |
|
|
ali@38
|
145 |
# If the user did not specify an X authorization file to use, set up a temporary
|
|
ali@38
|
146 |
# directory to house one.
|
|
ali@38
|
147 |
if [ -z "$AUTHFILE" ]; then
|
|
ali@38
|
148 |
XVFB_RUN_TMPDIR="$(mktemp -d -t $PROGNAME.XXXXXX)"
|
|
ali@38
|
149 |
# Create empty file to avoid xauth warning
|
|
ali@38
|
150 |
AUTHFILE=$(tempfile -n "$XVFB_RUN_TMPDIR/Xauthority")
|
|
ali@38
|
151 |
fi
|
|
ali@38
|
152 |
|
|
ali@38
|
153 |
# Start Xvfb.
|
|
ali@38
|
154 |
MCOOKIE=$(mcookie)
|
|
ali@38
|
155 |
tries=10
|
|
ali@38
|
156 |
while [ $tries -gt 0 ]; do
|
|
ali@38
|
157 |
tries=$(( $tries - 1 ))
|
|
ali@38
|
158 |
XAUTHORITY=$AUTHFILE xauth source - << EOF >>"$ERRORFILE" 2>&1
|
|
ali@38
|
159 |
add :$SERVERNUM $XAUTHPROTO $MCOOKIE
|
|
ali@38
|
160 |
EOF
|
|
ali@38
|
161 |
# handle SIGUSR1 so Xvfb knows to send a signal when it's ready to accept
|
|
ali@38
|
162 |
# connections
|
|
ali@38
|
163 |
trap : USR1
|
|
ali@38
|
164 |
(trap '' USR1; exec Xvfb ":$SERVERNUM" $XVFBARGS $LISTENTCP -auth $AUTHFILE >>"$ERRORFILE" 2>&1) &
|
|
ali@38
|
165 |
XVFBPID=$!
|
|
ali@38
|
166 |
|
|
ali@38
|
167 |
wait || :
|
|
ali@38
|
168 |
if kill -0 $XVFBPID 2>/dev/null; then
|
|
ali@38
|
169 |
break
|
|
ali@38
|
170 |
elif [ -n "$AUTONUM" ]; then
|
|
ali@38
|
171 |
# The display is in use so try another one (if '-a' was specified).
|
|
ali@38
|
172 |
SERVERNUM=$((SERVERNUM + 1))
|
|
ali@38
|
173 |
SERVERNUM=$(find_free_servernum)
|
|
ali@38
|
174 |
continue
|
|
ali@38
|
175 |
fi
|
|
ali@38
|
176 |
error "Xvfb failed to start" >&2
|
|
ali@38
|
177 |
XVFBPID=
|
|
ali@38
|
178 |
exit 1
|
|
ali@38
|
179 |
done
|
|
ali@38
|
180 |
|
|
ali@38
|
181 |
# Start the command and save its exit status.
|
|
ali@38
|
182 |
set +e
|
|
ali@38
|
183 |
DISPLAY=:$SERVERNUM XAUTHORITY=$AUTHFILE "$@" 2>&1
|
|
ali@38
|
184 |
RETVAL=$?
|
|
ali@38
|
185 |
set -e
|
|
ali@38
|
186 |
|
|
ali@38
|
187 |
# Return the executed command's exit status.
|
|
ali@38
|
188 |
exit $RETVAL
|
|
ali@38
|
189 |
|
|
ali@38
|
190 |
# vim:set ai et sts=4 sw=4 tw=80:
|