#!/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 AUTHFILE="$(pwd)/.Xauthority" ERRORFILE= STARTWAIT=3 XVFBARGS="-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: $AUTHFILE) -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" rm -f "$AUTHFILE" exit_handler() { local rc=$? trap - EXIT rm -f -- "$AUTHFILE" kill_xvfb exit $rc } trap exit_handler EXIT HUP INT QUIT TERM # check whether fakeroot is requires if [ -d "/tmp/.X11-unix" -o "$(id -u)" = 0 ]; then FAKEROOT= else FAKEROOT='fakeroot --' fi # start Xvfb MCOOKIE="$(mcookie)" if [ -z "$ERRORFILE" ]; then XAUTHORITY="$AUTHFILE" xauth add :"$SERVERNUM" "$XAUTHPROTO" "$MCOOKIE" XAUTHORITY="$AUTHFILE" $FAKEROOT Xvfb :"$SERVERNUM" $XVFBARGS $LISTENTCP & else XAUTHORITY="$AUTHFILE" xauth add :"$SERVERNUM" "$XAUTHPROTO" "$MCOOKIE" >"$ERRORFILE" 2>&1 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: