| 1 | #!/bin/sh |
| 2 | # Stand up the parts a Linux login session would have provided, then hand off. |
| 3 | # |
| 4 | # Display :0 is the "host" desktop. The parity engine samples it through |
| 5 | # hostProbe() to measure whether a run disturbed the user's session, and the |
| 6 | # isolated route's claim ("0px, no active-window change") is only worth |
| 7 | # anything if something real is being sampled — a missing :0 would report |
| 8 | # zeroes because the probe failed, not because nothing moved. The isolated |
| 9 | # route's own Xvfb :99 is started by the driver, not here. |
| 10 | set -eu |
| 11 | |
| 12 | HOST_DISPLAY="${CU_HOST_DISPLAY:-:0}" |
| 13 | HOST_GEOMETRY="${CU_HOST_GEOMETRY:-1600x1200x24}" |
| 14 | |
| 15 | # Reap the display before PID 1 exits, so a normal container restart does |
| 16 | # not inherit an Xvfb lock for the previous container's process IDs. |
| 17 | xvfb_pid= wm_pid= session_pid= |
| 18 | cleanup() { |
| 19 | trap - EXIT INT TERM |
| 20 | for child_pid in $session_pid $wm_pid $xvfb_pid; do |
| 21 | kill -TERM "$child_pid" 2>/dev/null || true |
| 22 | done |
| 23 | for child_pid in $session_pid $wm_pid $xvfb_pid; do |
| 24 | wait "$child_pid" 2>/dev/null || true |
| 25 | done |
| 26 | } |
| 27 | trap cleanup EXIT |
| 28 | trap 'exit 130' INT |
| 29 | trap 'exit 143' TERM |
| 30 | |
| 31 | Xvfb "$HOST_DISPLAY" -screen 0 "$HOST_GEOMETRY" -nolisten tcp >/tmp/xvfb-host.log 2>&1 & |
| 32 | xvfb_pid=$! |
| 33 | i=0 |
| 34 | until DISPLAY="$HOST_DISPLAY" xdotool getdisplaygeometry >/dev/null 2>&1; do |
| 35 | i=$((i + 1)) |
| 36 | if [ "$i" -gt 60 ]; then |
| 37 | echo "entrypoint: Xvfb $HOST_DISPLAY did not come up" >&2 |
| 38 | cat /tmp/xvfb-host.log >&2 || true |
| 39 | exit 1 |
| 40 | fi |
| 41 | sleep 0.25 |
| 42 | done |
| 43 | |
| 44 | DISPLAY="$HOST_DISPLAY" openbox >/tmp/openbox-host.log 2>&1 & |
| 45 | wm_pid=$! |
| 46 | sleep 0.5 |
| 47 | |
| 48 | export DISPLAY="$HOST_DISPLAY" |
| 49 | |
| 50 | # AT-SPI rides the session bus, and at-spi-bus-launcher is activated from it on |
| 51 | # demand. Without a session bus every semantic tool fails at the accessibility |
| 52 | # tree, so wrap the whole command rather than starting a daemon and hoping the |
| 53 | # address is inherited. The inner sh also records the session env for |
| 54 | # docker/agent-exec.sh, so `docker exec`'d agents join this same display+bus |
| 55 | # instead of starting blind. |
| 56 | dbus-run-session -- sh -c 'printf "DISPLAY=%s\nDBUS_SESSION_BUS_ADDRESS=%s\n" "$DISPLAY" "$DBUS_SESSION_BUS_ADDRESS" > /tmp/cu-session.env; exec "$@"' sh "$@" & |
| 57 | session_pid=$! |
| 58 | wait "$session_pid" |
| 59 |