sx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #!/bin/sh --
  2. set -u
  3. # sx - start an xorg server
  4. # https://github.com/Earnestly/sx
  5. : "${SX_CLIENT_SIGNAL:=TERM}"
  6. : "${SX_CLIENT_STOP_CMD:=:}"
  7. : "${SX_LOCK:=${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}/runtime-${USER:-$(id -un)}}/sx.lock}"
  8. unexport_env() {
  9. unset SX_LOCK
  10. unset SX_CLIENT_SIGNAL
  11. unset SX_CLIENT_STOP_CMD
  12. "${@}"
  13. }
  14. local_kill() {
  15. pid="${1:?}"
  16. shift
  17. kill -0 "${pid}" 2>/dev/null && {
  18. kill "${@}" "${pid}"
  19. wait "${pid}"
  20. local_kill_exit="${?}"
  21. }
  22. }
  23. CLEANUP_DONE=0
  24. cleanup() {
  25. if [ "${CLEANUP_DONE}" -eq 1 ]; then
  26. return
  27. fi
  28. if [ -n "${SX_CLIENT_STOP_CMD}" ] && [ "${SX_CLIENT_STOP_CMD}" != : ]; then
  29. ${SX_CLIENT_STOP_CMD}
  30. else
  31. local_kill "${client}" -s "${SX_CLIENT_SIGNAL}"
  32. fi
  33. local_kill_exit=0
  34. local_kill "${server}"
  35. CLEANUP_DONE=1
  36. if ! stty "${stty}"; then
  37. stty sane
  38. fi
  39. [ -n "${RMDIR:-}" ] && chmod +w -R "${XAUTHORITY%/*}"
  40. xauth remove :"${tty}"
  41. [ -n "${RMDIR:-}" ] && rm -rf "${XAUTHORITY%/*}"
  42. }
  43. usage() {
  44. printf '%s\n' \
  45. "Usage: ${0##*/} [action]" \
  46. ' start <pid> cmd args... - start user services' \
  47. ' stop <pid> - stop user services' \
  48. ' help - show this help'
  49. exit "${1:-0}"
  50. }
  51. exec 3<>"${SX_LOCK}"
  52. cmd="${1:-}"
  53. shift
  54. case "${cmd}" in
  55. start)
  56. flock -n 3 || {
  57. IFS= read -r sx_pid <&3
  58. echo "sx already running (pid=${sx_pid})" 1>&2
  59. exit 1
  60. }
  61. [ "${#}" -gt 0 ] || {
  62. echo "please provide command to start after Xorg is ready" 1>&2
  63. exit 1
  64. }
  65. printf '%d\n' "${$}" 1>&3
  66. ;;
  67. stop)
  68. IFS= read -r sx_pid <&3
  69. rm -f "${SX_LOCK}" || :
  70. exec kill "${sx_pid:?}"
  71. ;;
  72. help | -h) usage 0 ;;
  73. *) usage 1 ;;
  74. esac
  75. server=
  76. client=
  77. stty="$(stty -g)"
  78. tty="${TTY:-$(tty)}"
  79. tty="${tty#/dev/tty}"
  80. RMDIR=
  81. [ -n "${XAUTHORITY:-}" ] || {
  82. XAUTHORITY="$(mktemp --suffix='.Xauthority' -d)/cookie"
  83. RMDIR=1
  84. }
  85. touch -- "${XAUTHORITY}"
  86. export XAUTHORITY
  87. trap 'cleanup; exit "${local_kill_exit:-0}"' EXIT
  88. # shellcheck disable=2016
  89. trap='cleanup; trap - "${signal}"'
  90. for signal in HUP INT QUIT TERM; do
  91. # shellcheck disable=2064
  92. trap "${trap}" "${signal}"
  93. done
  94. # Xorg will return a USR1 signal to the parent process indicating it is ready
  95. # to accept connections if it inherited a USR1 signal with a SIG_IGN
  96. # disposition. Consequently a client may be started directly from a USR1
  97. # signal handler and obviate the need to poll for server readiness.
  98. trap 'DISPLAY=":${tty}" unexport_env "${@}" 3>&- & wait "${!}"' USR1
  99. xauth add ":${tty}" MIT-MAGIC-COOKIE-1 \
  100. "$(od -An -N16 -tx /dev/urandom | tr -d ' ')"
  101. if [ -n "${RMDIR:-}" ]; then
  102. chmod -w -R "${XAUTHORITY%*}"
  103. fi
  104. (
  105. trap '' USR1 &&
  106. exec Xorg ":${tty}" "vt${tty}" \
  107. -auth "${XAUTHORITY}" \
  108. -arinterval 20 \
  109. -nolisten tcp \
  110. -ardelay 200 \
  111. -keeptty \
  112. -noreset
  113. ) &
  114. server="${!}"
  115. wait "${server}"