Skip to content
This repository
branch: master
Jordan Sissel October 21, 2010
file 187 lines (162 sloc) 4.223 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
#!/bin/sh
# Start an ephemeral X server.
#
# This is useful for when you want to lauch an X server for a specific
# process. When that process exits, the X server will be killed.
#

XSERVER=Xvfb
WINMGR=

prog=$0
usage() {
  echo "Usage: $prog [-x XSERVER] [-w WINDOWMANAGER] [-q] [-h] <command>"
  echo "-h this help"
  echo "-q quiet"
  echo "-w window manager process to start once Xserver is up"
  echo " (default: '$WINMGR')"
  echo "-x Xserver (and args) to run"
  echo " (default: '$XSERVER')"
  echo
echo "This tool will pick an unused DISPLAY value (:0, :1, etc) and"
  echo "start an Xserver on that display, then run your command."
  echo
echo "Examples:"
  echo " $prog -x 'Xephyr -screen 1280x720' xterm"
  echo " $prog -x 'Xvnc -httpd /usr/share/vnc/classes -geometry 1024x768 -depth 24' -w "gnome-session" firefox"
}

quiet() {
  [ "0$QUIET" -eq 1 ]
}

test_x_available() {
  xsocket=$1
  ! test -S $xsocket
}

test_x_healthy() {
  xpid=$1
  xsocket=$2
  displaynum=$3

  # Try xterm to see if X is up.
  if which xterm > /dev/null 2>&1 ; then
DISPLAY=:$displaynum xterm -e 'true'
    return $?
  fi

  # Try xdotool if available, if xterm is not.
  if which xdotool > /dev/null 2>&1 ; then
DISPLAY=:$displaynum xdotool getmouselocation > /dev/null 2>&1
    return $?
  fi

  # Try lsof if no X clients (above) are available
  if which lsof > /dev/null 2>&1 ; then
lsof -p $xpid | grep -qF $xsocket
    return $?
  fi

echo "Unable to determine if X is healthy (no tools available)"
  return false
}

cleanup() {
  if [ ! -z "$winmgrpid" ] ; then
kill -TERM "$winmgrpid" || true
fi
kill -TERM "$xpid" || true

pkill -KILL -P $$ || true
}

eval "set -- $( (POSIXLY_CORRECT=1 getopt -s sh +x:w:qh "$@" || echo " "FAIL) | tr -d '\n' )"

while [ "0$#" -gt 0 ] ; do
case $1 in
    -x) XSERVER="$2"; shift ;;
    -w) WINMGR="$2"; shift ;;
    -q) QUIET=1 ;;
    -h) usage; exit ;;
    --) shift; break ;;
  esac
shift
done

if [ "$1" = "FAIL" ] ; then
usage
  exit 1
fi

num=-1
XSERVERNAME=${XSERVER%% *}
if ! which "$XSERVERNAME" > /dev/null 2>&1 ; then
echo "Unable to find $XSERVERNAME. Aborting."
  cleanup
  exit 1
fi

while true; do
num=$(expr $num + 1)
  xsocket=/tmp/.X11-unix/X$num
  quiet || echo "Trying :$num"
  test_x_available $xsocket || continue
  (
    if quiet ; then
exec > /dev/null
      exec 2> /dev/null
    fi
echo set -- $XSERVER
    set -- $XSERVER
    cmd=$1
    shift
exec $cmd :$num "$@"
  ) &
  xpid=$!

  healthy=0
  for i in 1 2 3 4 5 6 7 8 9 ; do
    # Break early if the xserver died
    #ps -p $xpid > /dev/null 2>&1 || break
    kill -0 $xpid > /dev/null 2>&1 || break

    # See if the xserver got a hold of the display socket.
    # If so, the server is up and healthy.
    sleep 1
    if test_x_healthy $xpid $xsocket $num ; then
quiet || echo "$XSERVERNAME looks healthy. Moving on."
      healthy=1
      break
fi
sleep 0.2 || sleep 1 # In case your sleep doesn't take subsecond values
  done

if [ "0$healthy" -eq 1 ] ; then
break
fi
done

export DISPLAY=:$num
quiet || echo "Using display: $DISPLAY"

if [ ! -z "$WINMGR" -a "$WINMGR" != "none" ] ; then
if ! which $WINMGR > /dev/null 2>&1 ; then
echo "Cannot find $WINMGR. Aborting."
    cleanup
    exit 1
  fi
WINMGRNAME=${WINMGR%% *}
  quiet || echo "Starting window manager: $WINMGRNAME"
  (
    if quiet ; then
exec > /dev/null
      exec 2> /dev/null
    fi
    $WINMGR
  ) &
  winmgrpid=$!

  # Wait for the window manager to startup
  quiet || echo "Waiting for window manager '$WINMGRNAME' to be healthy."
  # Wait for the window manager to start.
  for i in 1 2 3 4 5 6 7 8 9 10 ABORT ; do
    # A good signal that the WM has started is that the WM_STATE property is
    # set or that any NETWM/ICCCM property is set.
    if xprop -root | egrep -q 'WM_STATE|^_NET' ; then
quiet || echo "$WINMGRNAME looks healthy. Moving on."
      break;
    fi
sleep .5

    if [ "$i" = "ABORT" ] ; then
quiet || echo "Window manager ($WINMGRNAME) seems to have failed starting up."
      cleanup
      exit 1
    fi
done
fi

quiet || echo "Running: $@"
(
  "$@"
)
exitcode=$?
cleanup
exit $exitcode
Something went wrong with that request. Please try again.