fix(freebsd): make the rc.d scripts start their services

Merged
SE
8d ago
+298-43

Problem

The contrib/freebsd rc.d scripts shipped in v2.2.0 could not start either service. There were three independent blockers, each confirmed by driving the scripts through the official FreeBSD 14.3 rc.subr with command execution intercepted:

  1. -t ${desc} was unquoted. desc="Heliograph hub" became -t Heliograph after rc.subr's eval, and hub became daemon(8)'s child program.
  2. ${name}_flags is rc.subr's reserved rc_flags, which is inserted between $command and $command_args. The hub's default smoked_flags=-downsample therefore went to /usr/sbin/daemon itself (illegal option -- d).
  3. ${name}_user=smoke makes rc.subr wrap the start in su -m smoke, so daemon(8) ran as smoke and could not create /var/run/<name>.pid, while the script also passed -u smoke.

There was also a fourth bug: : ${smoke_agent_spool:="…"} replaces an empty value too, so the documented smoke_agent_spool="" never disabled the spool.

The existing CI only ran sh -n, which cannot catch any of these.

Fix

This follows the ports convention used by sysutils/node_exporter and net-mgmt/prometheus2:

  • rc.subr's standard ${name}_user runs daemon(8) and the child unprivileged; there is no -u.
  • The supervisor pidfile (-P) lives in /var/run/<name>/, owned by the service user and created in start_precmd. The supervisor can create it and remove it on exit, and service stop signals the supervisor rather than the child, which -r would otherwise restart.
  • The process title and the syslog tag (-t/-T) are the single word ${name}. The default procname (/usr/sbin/daemon) matches the daemon: <name>[pid] title for status/stop.
  • Extra flags move to ${name}_args. A leftover ${name}_flags value from v2.2.0 is migrated to _args with a warning, so it no longer reaches daemon(8).
  • smoke_agent_spool="" and smoked_args="" now take effect: they use = rather than :=.
  • Unchanged: the DSN is passed via the SMOKED_DSN environment variable, never argv; the agent always gets an explicit -spool-dir=; the spool dir is created in precmd.

Emitted start line, before and after (rc.subr harness):

before: su -m smoke -c 'sh -c " /usr/sbin/daemon -downsample -r -S -P /var/run/smoked.pid -t Heliograph hub -u smoke /usr/local/bin/smoked ..."'
after:  su -m smoke -c 'sh -c " /usr/sbin/daemon  -r -T smoked -t smoked -P /var/run/smoked/smoked.pid /usr/local/bin/smoked -serve -addr 127.0.0.1:8087 -webdir /usr/local/share/heliograph/web -downsample"'

Real verification in CI

freebsd-test now also runs .github/scripts/freebsd-rc-test.sh inside the FreeBSD VM. It installs the binaries and rc.d scripts as the README describes, creates the smoke user, and checks through service(8):

  • smoked: onestart brings up /api/targets with the demo targets, and onestatus passes. The supervisor and the child both run as smoke, the child's argv is exact, and its output reaches syslog under the tag smoked.
  • Restart on crash: killing the child brings back a new one.
  • Leftover smoked_flags: onerestart with it set gives a new supervisor, the warning, and the flag on smoked.
  • DSN stays off argv: with a DSN set, procstat -e shows SMOKED_DSN in the child's environment and pgrep -f finds it on no command line.
  • smoked stop: after onestop, onestatus fails, no process is left, and the pidfile is gone.
  • smoke_agent: with a throwaway cert and an unreachable hub, the supervisor and child run as smoke, spool.lock is owned by smoke, argv and the syslog tag are right, smoke_agent_spool="" yields -spool-dir=, and onestop cleans up.