xvfb-run 5.3 KB

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