#!/bin/sh -e # xvfb-run - run the specified command in a virtual X server # This script starts an instance of Xvfb, the "fake" X server, runs a # command with that server available, and kills the X server when # done. The return value of the command becomes the return value of # this script. PROGNAME=xvfb-run SERVERNUM=99 XVFB_RUN_TMPDIR= AUTHFILE= ERRORFILE= STARTWAIT=3 XVFBARGS='-extension GLX -screen 0 640x480x8' LISTENTCP='-nolisten tcp' XAUTHPROTO=. fatal() { echo "$PROGNAME: $*" >&2 exit 1 } # display a usage message usage () { [ "$1" = 0 ] || exec >&2 cat << EOF $PROGNAME - run COMMAND (usually an X client) in a virtual X server environment Usage: $PROGNAME [OPTIONS] COMMAND Valid options are: -a --auto-servernum try to get a free server number -e FILE --error-file=FILE file used to store xauth errors and Xvfb output (by default is no redirection) -f FILE --auth-file=FILE file used to store auth cookie (default is to create temporary file) -n NUM --server-num=NUM server number to use (default: $SERVERNUM) -l --listen-tcp enable TCP port listening in the X server -p PROTO --xauth-protocol=PROTO X authority protocol name to use (defaults to xauth default) -s ARGS --server-args=ARGS arguments (other than server number and -nolisten tcp) to pass to the Xvfb server (default: $XVFBARGS) -w DELAY --wait=DELAY delay in seconds to wait for Xvfb to start (default: $STARTWAIT) -h --help display this text and exit EOF [ -n "$1" ] && exit "$1" || exit } # find free server number by looking at .X*-lock files in /tmp find_free_servernum() { local last_display last_display=`find /tmp/ -maxdepth 1 -type f -name '.X*-lock' | sed -ne 's,^/tmp/\.X\([[:digit:]]\+\)-lock$,\1,p' | sort -n | tail -1` [ -z "$last_display" ] && echo 0 || echo "$((1+last_display))" } XVFBPID= kill_xvfb() { if [ -n "$XVFBPID" ]; then kill "$XVFBPID" XVFBPID= fi } # parse command line ARGS=$(getopt --options +ae:f:hn:lp:s:w: \ --long auto-servernum,error-file:,auth-file:,help,server-num:,listen-tcp,xauth-protocol:,server-args:,wait: \ --name "$PROGNAME" -- "$@") || usage eval set -- "$ARGS" while :; do case "$1" in -a|--auto-servernum) SERVERNUM=$(find_free_servernum) ;; -e|--error-file) shift; ERRORFILE="$1" ;; -f|--auth-file) shift; AUTHFILE="$1" ;; -n|--server-num) shift; SERVERNUM="$1" ;; -l|--listen-tcp) LISTENTCP="" ;; -p|--xauth-protocol) shift; XAUTHPROTO="$1" ;; -s|--server-args) shift; XVFBARGS="$1" ;; -w|--wait) shift; STARTWAIT="$1" ;; -h|--help) usage 0 ;; --) shift; break ;; *) fatal "unrecognized option: $1" ;; esac shift done [ -n "$*" ] || fatal "need a command to run" cleanup() { trap - EXIT set +e if [ -n "$XVFB_RUN_TMPDIR" ]; then rm -rf -- "$XVFB_RUN_TMPDIR" elif [ -s "$AUTHFILE" ]; then if [ -z "$ERRORFILE" ]; then XAUTHORITY="$AUTHFILE" xauth remove ":$SERVERNUM" else XAUTHORITY="$AUTHFILE" xauth remove ":$SERVERNUM" >>"$ERRORFILE" 2>&1 fi fi kill_xvfb exit "$@" } exit_handler() { cleanup $? } signal_handler() { cleanup 1 } trap exit_handler EXIT trap signal_handler HUP INT QUIT TERM # check whether fakeroot is requires if [ -d "/tmp/.X11-unix" -o "$(id -u)" = 0 ]; then FAKEROOT= else FAKEROOT='fakeroot --' fi # if the user did not specify an X authorization file to use, # set up a temporary directory to house one if [ -z "$AUTHFILE" ]; then XVFB_RUN_TMPDIR="$(mktemp -d -t "$PROGNAME.XXXXXX")" AUTHFILE="$XVFB_RUN_TMPDIR/Xauthority" >"$AUTHFILE" fi # start Xvfb MCOOKIE="$(mcookie)" if [ -z "$ERRORFILE" ]; then XAUTHORITY="$AUTHFILE" xauth source - <<__EOF__ add :$SERVERNUM $XAUTHPROTO $MCOOKIE __EOF__ XAUTHORITY="$AUTHFILE" $FAKEROOT Xvfb :"$SERVERNUM" $XVFBARGS $LISTENTCP & else XAUTHORITY="$AUTHFILE" xauth source - <<__EOF__ >>"$ERRORFILE" 2>&1 add :$SERVERNUM $XAUTHPROTO $MCOOKIE __EOF__ XAUTHORITY="$AUTHFILE" $FAKEROOT Xvfb :"$SERVERNUM" $XVFBARGS $LISTENTCP >"$ERRORFILE" 2>&1 & fi XVFBPID=$! sleep $STARTWAIT # start the command and save its exit status set +e DISPLAY=:"$SERVERNUM" XAUTHORITY="$AUTHFILE" "$@" RETVAL=$? kill_xvfb # return the executed command's exit status exit $RETVAL # vim:set ai et sts=4 sw=4 tw=0: