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