run: replace only owned launcher instance
This commit is contained in:
@@ -129,9 +129,12 @@ font-file arguments replace these defaults:
|
|||||||
that it starts. It waits for that daemon's IPC socket and IBus address file
|
that it starts. It waits for that daemon's IPC socket and IBus address file
|
||||||
before reporting success. With `DISPLAY` set it then starts XIM; without a
|
before reporting success. With `DISPLAY` set it then starts XIM; without a
|
||||||
display it keeps the headless daemon in the foreground and does not start
|
display it keeps the headless daemon in the foreground and does not start
|
||||||
XIM. A signal or XIM exit stops and reaps the launcher's daemon. The
|
XIM. A signal or XIM exit stops and reaps the launcher's daemon. On repeated
|
||||||
launcher never replaces an existing daemon: an occupied per-user socket is a
|
invocation, it stops a previous live `run.sh` only after confirming that the
|
||||||
visible startup failure.
|
old launcher directly owns the daemon serving the same IPC and IBus
|
||||||
|
endpoints and that the daemon carries that launcher's PID and process-start
|
||||||
|
identity. A manually started or orphaned daemon is left untouched and
|
||||||
|
reported as a visible startup failure.
|
||||||
|
|
||||||
The IPC socket is placed at `$XDG_RUNTIME_DIR/strans.sock` when
|
The IPC socket is placed at `$XDG_RUNTIME_DIR/strans.sock` when
|
||||||
`XDG_RUNTIME_DIR` is an absolute path. Otherwise strans uses the per-user
|
`XDG_RUNTIME_DIR` is an absolute path. Otherwise strans uses the per-user
|
||||||
|
|||||||
194
run.sh
194
run.sh
@@ -1,6 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
cd "$(dirname "$0")" || exit 1
|
cd "$(dirname "$0")" || exit 1
|
||||||
|
root=$(pwd -P) || exit 1
|
||||||
|
uid=$(id -u) || exit 1
|
||||||
|
|
||||||
if test "$#" -eq 0; then
|
if test "$#" -eq 0; then
|
||||||
set --
|
set --
|
||||||
@@ -46,6 +48,10 @@ fi
|
|||||||
|
|
||||||
strans_pid=
|
strans_pid=
|
||||||
xim_pid=
|
xim_pid=
|
||||||
|
old_daemon_pid=
|
||||||
|
old_daemon_start=
|
||||||
|
old_launcher_pid=
|
||||||
|
old_launcher_start=
|
||||||
|
|
||||||
cleanup()
|
cleanup()
|
||||||
{
|
{
|
||||||
@@ -83,12 +89,198 @@ ibusready()
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
procuid()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
while IFS=' ' read -r key real effective saved filesystem rest; do
|
||||||
|
case $key in
|
||||||
|
Uid:)
|
||||||
|
test "$real" = "$effective" &&
|
||||||
|
test "$real" = "$saved" &&
|
||||||
|
test "$real" = "$filesystem" || return 1
|
||||||
|
printf '%s\n' "$real"
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done <"/proc/$1/status"
|
||||||
|
} 2>/dev/null
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
procparent()
|
||||||
|
{
|
||||||
|
{
|
||||||
|
while IFS=' ' read -r key value rest; do
|
||||||
|
case $key in
|
||||||
|
PPid:) printf '%s\n' "$value"; return 0 ;;
|
||||||
|
esac
|
||||||
|
done <"/proc/$1/status"
|
||||||
|
} 2>/dev/null
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
procstart()
|
||||||
|
{
|
||||||
|
proc_stat=
|
||||||
|
{ IFS= read -r proc_stat <"/proc/$1/stat"; } 2>/dev/null || return 1
|
||||||
|
proc_stat=${proc_stat##*) }
|
||||||
|
set -- $proc_stat
|
||||||
|
test "$#" -ge 20 || return 1
|
||||||
|
test "$1" != Z || return 1
|
||||||
|
printf '%s\n' "${20}"
|
||||||
|
}
|
||||||
|
|
||||||
|
sameproc()
|
||||||
|
{
|
||||||
|
test -n "$2" || return 1
|
||||||
|
proc_now=$(procstart "$1") || return 1
|
||||||
|
test "$proc_now" = "$2"
|
||||||
|
}
|
||||||
|
|
||||||
|
listeninginode()
|
||||||
|
{
|
||||||
|
listener_inode=
|
||||||
|
listener_count=0
|
||||||
|
{
|
||||||
|
while IFS=' ' read -r num ref proto flags type state inode path; do
|
||||||
|
if test "$flags" = 00010000 && test "$type" = 0001 &&
|
||||||
|
test "$state" = 01 && test "$path" = "$1"; then
|
||||||
|
listener_inode=$inode
|
||||||
|
listener_count=$((listener_count + 1))
|
||||||
|
fi
|
||||||
|
done </proc/net/unix
|
||||||
|
} 2>/dev/null
|
||||||
|
test "$listener_count" -eq 1 || return 1
|
||||||
|
printf '%s\n' "$listener_inode"
|
||||||
|
}
|
||||||
|
|
||||||
|
socketowned()
|
||||||
|
{
|
||||||
|
socket_inode=$(listeninginode "$2") || return 1
|
||||||
|
for socket_fd in "/proc/$1/fd"/*; do
|
||||||
|
test "$(readlink "$socket_fd" 2>/dev/null)" = \
|
||||||
|
"socket:[$socket_inode]" && return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
validdaemon()
|
||||||
|
{
|
||||||
|
test "$(procuid "$1")" = "$uid" || return 1
|
||||||
|
test "$(readlink "/proc/$1/cwd" 2>/dev/null)" = "$root" || return 1
|
||||||
|
daemon_exe=$(readlink "/proc/$1/exe" 2>/dev/null) || return 1
|
||||||
|
case $daemon_exe in
|
||||||
|
"$root/strans"|"$root/strans (deleted)") ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
test -S "$ipc" || return 1
|
||||||
|
socketowned "$1" "$ipc" || return 1
|
||||||
|
socketowned "$1" "@strans-$1"
|
||||||
|
}
|
||||||
|
|
||||||
|
finddaemon()
|
||||||
|
{
|
||||||
|
old_daemon_pid=
|
||||||
|
old_daemon_start=
|
||||||
|
for address in "$busdir"/*; do
|
||||||
|
test -f "$address" || continue
|
||||||
|
address_pid=
|
||||||
|
address_ok=
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case $line in
|
||||||
|
IBUS_DAEMON_PID=*) address_pid=${line#IBUS_DAEMON_PID=} ;;
|
||||||
|
esac
|
||||||
|
done <"$address"
|
||||||
|
case $address_pid in
|
||||||
|
''|*[!0-9]*) continue ;;
|
||||||
|
esac
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case $line in
|
||||||
|
IBUS_ADDRESS=unix:abstract=strans-"$address_pid",*)
|
||||||
|
address_ok=1 ;;
|
||||||
|
esac
|
||||||
|
done <"$address"
|
||||||
|
test -n "$address_ok" || continue
|
||||||
|
validdaemon "$address_pid" || continue
|
||||||
|
address_start=$(procstart "$address_pid") || continue
|
||||||
|
validdaemon "$address_pid" || continue
|
||||||
|
old_daemon_pid=$address_pid
|
||||||
|
old_daemon_start=$address_start
|
||||||
|
return 0
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
findlauncher()
|
||||||
|
{
|
||||||
|
launcher_env=$({ tr '\000' '\n' <"/proc/$old_daemon_pid/environ"; } \
|
||||||
|
2>/dev/null) || return 1
|
||||||
|
old_launcher_pid=$(printf '%s\n' "$launcher_env" |
|
||||||
|
sed -n 's/^STRANS_RUN_OWNER_PID=//p')
|
||||||
|
old_launcher_start=$(printf '%s\n' "$launcher_env" |
|
||||||
|
sed -n 's/^STRANS_RUN_OWNER_START=//p')
|
||||||
|
case $old_launcher_pid in
|
||||||
|
''|*[!0-9]*|0|1|"$$") return 1 ;;
|
||||||
|
esac
|
||||||
|
case $old_launcher_start in
|
||||||
|
''|*[!0-9]*) return 1 ;;
|
||||||
|
esac
|
||||||
|
test "$(procuid "$old_launcher_pid")" = "$uid" || return 1
|
||||||
|
test "$(readlink "/proc/$old_launcher_pid/cwd" 2>/dev/null)" = "$root" ||
|
||||||
|
return 1
|
||||||
|
sameproc "$old_launcher_pid" "$old_launcher_start" || return 1
|
||||||
|
sameproc "$old_daemon_pid" "$old_daemon_start" || return 1
|
||||||
|
test "$(procparent "$old_daemon_pid")" = "$old_launcher_pid" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stoplauncher()
|
||||||
|
{
|
||||||
|
sameproc "$old_daemon_pid" "$old_daemon_start" || return 1
|
||||||
|
test "$(procparent "$old_daemon_pid")" = "$old_launcher_pid" || return 1
|
||||||
|
sameproc "$old_launcher_pid" "$old_launcher_start" || return 1
|
||||||
|
kill "$old_launcher_pid" 2>/dev/null || return 1
|
||||||
|
echo "run.sh: stopping previous launcher $old_launcher_pid (daemon $old_daemon_pid)"
|
||||||
|
|
||||||
|
stop_attempt=0
|
||||||
|
while test "$stop_attempt" -lt 10; do
|
||||||
|
if ! sameproc "$old_launcher_pid" "$old_launcher_start" &&
|
||||||
|
! sameproc "$old_daemon_pid" "$old_daemon_start"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
stop_attempt=$((stop_attempt + 1))
|
||||||
|
if test "$stop_attempt" -lt 10; then
|
||||||
|
sleep 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "run.sh: previous launcher did not stop within 10 seconds" >&2
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
trap cleanup 0
|
trap cleanup 0
|
||||||
trap 'exit 129' 1
|
trap 'exit 129' 1
|
||||||
trap 'exit 130' 2
|
trap 'exit 130' 2
|
||||||
trap 'exit 143' 15
|
trap 'exit 143' 15
|
||||||
|
|
||||||
./strans map "$@" &
|
launcher_start=$(procstart "$$") || {
|
||||||
|
echo "run.sh: cannot read launcher process identity from /proc" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if finddaemon; then
|
||||||
|
if ! findlauncher; then
|
||||||
|
echo "run.sh: daemon $old_daemon_pid owns the current endpoints but has no" >&2
|
||||||
|
echo "run.sh: live run.sh owner; leaving it untouched (stop it once, then retry)" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! stoplauncher; then
|
||||||
|
echo "run.sh: previous launcher did not stop cleanly; refusing to start another daemon" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
STRANS_RUN_OWNER_PID=$$ STRANS_RUN_OWNER_START=$launcher_start \
|
||||||
|
./strans map "$@" &
|
||||||
strans_pid=$!
|
strans_pid=$!
|
||||||
|
|
||||||
attempt=0
|
attempt=0
|
||||||
|
|||||||
Reference in New Issue
Block a user