aboutsummaryrefslogtreecommitdiffstats
path: root/rsplayer.rc
blob: ccc2bc97dfb88684d33194034fb89ab1858c2c98 (plain) (blame)
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
#!/bin/sh

# This file is a part of RSPlayer
# Licensed under the GPL-3.0 License
# Copyright (C) 2026 Salmonik @ salmonik@tuta.io
# https://codeberg.org/salmonik/RSPlayer
#
# FreeBSD rc.d service for RSPlayer.
#
# Add the following to /etc/rc.conf to enable the service:
#
#   rsplayer_enable="YES"
#   rsplayer_user="salmon"     # user to run the daemon as (NOT root)
#   rsplayer_group="wheel"     # group of that user
#
# rsplayer_user must be a regular user: the daemon socket and PID file live
# in that user's XDG state directory (~/.local/state/rsplayer) and the `rsp`
# CLI connects to that socket, so the daemon and the CLI must run as the
# same user. This also means the socket path no longer depends on the
# environment (XDG_RUNTIME_DIR), so the service and manual runs agree.

# PROVIDE: rsplayer
# REQUIRE: LOGIN dbus
# KEYWORD: shutdown

. /etc/rc.subr

name="rsplayer"
rcvar=rsplayer_enable

load_rc_config $name

: ${rsplayer_user:="root"}
: ${rsplayer_group:="wheel"}

# daemon(8) does not set HOME when dropping privileges, and rsp derives its
# config and runtime paths from it, so resolve the user's home explicitly.
rsplayer_home=$(pw usershow "${rsplayer_user}" 2>/dev/null | awk -F: '{print $9}')
if [ -z "${rsplayer_home}" ]; then
    echo "Cannot determine home directory for user '${rsplayer_user}'."
    echo "Set rsplayer_user in /etc/rc.conf."
    exit 1
fi

command="/usr/local/bin/rsp"
procname="${command}"
state_dir="${rsplayer_home}/.local/state/rsplayer"
pidfile="${state_dir}/rsplayer.pid"
socket="${state_dir}/daemon.sock"

start_cmd="rsplayer_start"
stop_cmd="rsplayer_stop"

rsplayer_start()
{
    if [ -s "${pidfile}" ] && kill -0 "$(cat "${pidfile}")" 2>/dev/null; then
        echo "rsplayer is already running (PID $(cat "${pidfile}"))."
        return 0
    fi

    if [ "${rsplayer_user}" = "root" ]; then
        echo "WARNING: rsplayer_user is \"root\"; the rsp CLI will not be able to"
        echo "         connect to the daemon socket. Set rsplayer_user in rc.conf."
    fi

    # daemon(8) opens the log file (-o) before exec'ing rsp and before
    # dropping privileges, but the state dir is only created by rsp itself —
    # create both up front so the log can open and stays user-owned/readable.
    install -d -o "${rsplayer_user}" -g "${rsplayer_group}" -m 700 "${state_dir}"
    if [ ! -e "${state_dir}/rsplayer.log" ]; then
        install -o "${rsplayer_user}" -g "${rsplayer_group}" -m 600 /dev/null "${state_dir}/rsplayer.log"
    fi

    echo "Starting rsplayer as ${rsplayer_user} (HOME=${rsplayer_home})."
    /usr/bin/env HOME="${rsplayer_home}" \
        /usr/sbin/daemon -u "${rsplayer_user}" -o "${state_dir}/rsplayer.log" \
        "${command}" start-daemon
}

rsplayer_stop()
{
    echo "Stopping rsplayer."
    if ! su -m "${rsplayer_user}" -c "env HOME='${rsplayer_home}' ${command} stop-daemon"; then
        # stop-daemon could not reach the daemon (stale/missing PID file or
        # socket, e.g. a daemon started under an older runtime dir): kill any
        # leftover rsp start-daemon processes for this user.
        echo "Graceful stop failed; killing leftover daemons."
        pkill -u "${rsplayer_user}" -f "${command} start-daemon" 2>/dev/null || true
    fi
    rm -f "${pidfile}" "${socket}"
}

run_rc_command "$1"