#!/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"