327 lines
7.4 KiB
Bash
Executable File
327 lines
7.4 KiB
Bash
Executable File
#!/bin/sh
|
|
|
|
cd "$(dirname "$0")" || exit 1
|
|
root=$(pwd -P) || exit 1
|
|
uid=$(id -u) || exit 1
|
|
|
|
if test "$#" -eq 0; then
|
|
set --
|
|
for font in \
|
|
/usr/share/fonts/TTF/DejaVuSans.ttf \
|
|
/usr/share/fonts/TTF/Jigmo.ttf \
|
|
/usr/share/fonts/TTF/Jigmo2.ttf \
|
|
/usr/share/fonts/noto/NotoSansCJK-Regular.ttc
|
|
do
|
|
if test -f "$font"; then
|
|
set -- "$@" "$font"
|
|
fi
|
|
done
|
|
if test "$#" -eq 0; then
|
|
echo "run.sh: no default font found; pass a font file" >&2
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
if ! test -x ./strans; then
|
|
echo "run.sh: ./strans is not executable; run make first" >&2
|
|
exit 1
|
|
fi
|
|
if test -n "${DISPLAY-}" && ! test -x xim/strans-xim; then
|
|
echo "run.sh: xim/strans-xim is not executable; run make first" >&2
|
|
exit 1
|
|
fi
|
|
|
|
case ${XDG_RUNTIME_DIR-} in
|
|
/) ipc=/strans.sock ;;
|
|
/*/) ipc=${XDG_RUNTIME_DIR}strans.sock ;;
|
|
/*) ipc=${XDG_RUNTIME_DIR}/strans.sock ;;
|
|
*) ipc=/tmp/strans.$(id -u) ;;
|
|
esac
|
|
if test -n "${XDG_CONFIG_HOME-}"; then
|
|
busdir=$XDG_CONFIG_HOME/ibus/bus
|
|
elif test "${HOME+x}" = x; then
|
|
busdir=$HOME/.config/ibus/bus
|
|
else
|
|
echo "run.sh: HOME or XDG_CONFIG_HOME is required for IBus discovery" >&2
|
|
exit 1
|
|
fi
|
|
|
|
strans_pid=
|
|
xim_pid=
|
|
old_daemon_pid=
|
|
old_daemon_start=
|
|
old_launcher_pid=
|
|
old_launcher_start=
|
|
|
|
cleanup()
|
|
{
|
|
status=$?
|
|
trap - 0 1 2 15
|
|
if test -n "$xim_pid"; then
|
|
kill "$xim_pid" 2>/dev/null || :
|
|
wait "$xim_pid" 2>/dev/null || :
|
|
xim_pid=
|
|
fi
|
|
if test -n "$strans_pid"; then
|
|
kill "$strans_pid" 2>/dev/null || :
|
|
wait "$strans_pid" 2>/dev/null || :
|
|
strans_pid=
|
|
fi
|
|
exit "$status"
|
|
}
|
|
|
|
ibusready()
|
|
{
|
|
for address in "$busdir"/*; do
|
|
test -f "$address" || continue
|
|
foundpid=
|
|
foundaddress=
|
|
while IFS= read -r line; do
|
|
case $line in
|
|
IBUS_DAEMON_PID="$strans_pid") foundpid=1 ;;
|
|
IBUS_ADDRESS=unix:abstract=strans-"$strans_pid",*) foundaddress=1 ;;
|
|
esac
|
|
done <"$address"
|
|
if test -n "$foundpid" && test -n "$foundaddress"; then
|
|
return 0
|
|
fi
|
|
done
|
|
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 'exit 129' 1
|
|
trap 'exit 130' 2
|
|
trap 'exit 143' 15
|
|
|
|
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=$!
|
|
|
|
attempt=0
|
|
while test "$attempt" -lt 10; do
|
|
if test -S "$ipc" && ibusready; then
|
|
break
|
|
fi
|
|
if ! kill -0 "$strans_pid" 2>/dev/null; then
|
|
wait "$strans_pid"
|
|
status=$?
|
|
strans_pid=
|
|
if test "$status" -eq 0; then
|
|
status=1
|
|
fi
|
|
echo "run.sh: daemon exited before publishing IPC and IBus endpoints" >&2
|
|
exit "$status"
|
|
fi
|
|
attempt=$((attempt + 1))
|
|
if test "$attempt" -lt 10; then
|
|
sleep 1
|
|
fi
|
|
done
|
|
if test "$attempt" -eq 10; then
|
|
echo "run.sh: daemon did not publish IPC and IBus endpoints within 10 seconds" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "run.sh: daemon $strans_pid is ready"
|
|
if test -z "${DISPLAY-}"; then
|
|
echo "run.sh: DISPLAY is unset; XIM will not be started"
|
|
wait "$strans_pid"
|
|
status=$?
|
|
strans_pid=
|
|
exit "$status"
|
|
fi
|
|
|
|
xim/strans-xim &
|
|
xim_pid=$!
|
|
echo "run.sh: started XIM $xim_pid; press Ctrl-C to stop both processes"
|
|
wait "$xim_pid"
|
|
status=$?
|
|
xim_pid=
|
|
exit "$status"
|