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