Ctrl K
ComunidadGuías…

svcopts_other.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
//go:build !windows

package main

import (
	"runtime"
	"strings"

	"github.com/kardianos/service"
)

// applyServiceOpts sets non-Windows service ordering. Only systemd has a clean
// network-ready gate; launchd on macOS has no equivalent, so there we lean on the
// existing DownAfter debounce to swallow a brief boot-time blip rather than
// confirm a false outage (and fire a reconnect speedtest).
func applyServiceOpts(sc *service.Config) {
	if p := servicePath(runtime.GOOS); p != "" {
		if sc.EnvVars == nil {
			sc.EnvVars = map[string]string{}
		}
		sc.EnvVars["PATH"] = p
	}
	// Start after the network is up, else a boot where DHCP/WiFi comes up late
	// records a false outage. These strings go into the unit's [Unit] section
	// verbatim, so only systemd gets them - other init systems expect service
	// names here.
	if service.Platform() == "linux-systemd" {
		sc.Dependencies = []string{"After=network-online.target", "Wants=network-online.target"}
		// ExecReload=/bin/kill -HUP: lets `systemctl reload pingularity` drive the
		// SIGHUP settings reload (see the reload goroutine in main.go).
		if sc.Option == nil {
			sc.Option = service.KeyValue{}
		}
		sc.Option["ReloadSignal"] = "HUP"
		// Replace kardianos's stock unit so the self-install service tracks the
		// operational behaviour of the deb/rpm one (packaging/pingularity.service):
		// $PINGULARITY_OPTS from /etc/default, a 5s restart delay, a bounded restart
		// loop, and the root-compatible subset of that unit's sandboxing. It is NOT
		// full parity - this path installs as root (kardianos emits no User=), so it
		// keeps neither the de-rooting nor ProtectSystem=strict; see the template
		// comment for exactly what is and isn't carried over. The stock default reads
		// /etc/sysconfig (an RPM-ism), has no $PINGULARITY_OPTS in ExecStart, and uses
		// RestartSec=120 - so a self-install user could never add daemon flags
		// post-install, and a crash kept the monitor down for 2 minutes instead of 5
		// seconds.
		sc.Option["SystemdScript"] = systemdScript
		// The template writes each install argument through kardianos's cmd,
		// which double-quotes it and escapes only the quote. systemd then reads
		// ExecStart by its own rules, quotes or not: %x is a specifier (%t the
		// runtime directory, %h the home), $VAR and ${VAR} substitute the
		// environment, and a backslash starts a C escape. So a -metrics-token
		// with a % in it reached the daemon as a different token and the
		// scraper's 401s said nothing about why, a %-mangled -db planted the
		// database at a path nobody named, and an unknown specifier or a
		// trailing backslash left a unit systemd refuses to load. Escape here,
		// on the unit path only: launchd's plist and the Windows SCM expand
		// nothing and must see the bytes as typed.
		sc.Arguments = systemdArgs(sc.Arguments)
	}
}

// systemdArgs escapes install arguments for the unit's ExecStart line per
// systemd.unit(5) and systemd.service(5): a literal percent is written %%, a
// literal dollar $$, and every backslash doubled (inside double quotes systemd
// unescapes C sequences, so a lone one eats the closing quote or turns into a
// newline). The double quote itself stays kardianos's cmd's job. Backslashes
// first, so the doubling never touches what the other two produce.
func systemdArgs(args []string) []string {
	if args == nil {
		return nil
	}
	out := make([]string, len(args))
	for i, a := range args {
		a = strings.ReplaceAll(a, `\`, `\\`)
		a = strings.ReplaceAll(a, "%", "%%")
		out[i] = strings.ReplaceAll(a, "$", "$$")
	}
	return out
}

// systemdScript tracks packaging/pingularity.service for the self-install path:
// flags from /etc/default/pingularity via $PINGULARITY_OPTS, a 5s restart delay, a
// bounded restart loop so a wedged binary reaches the 'failed' state, and the
// root-compatible hardening directives (see the [Service] block). It is NOT a
// line-for-line copy: this unit runs as root, so it drops the packaged unit's
// User=/ambient CAP_NET_RAW/StateDirectory de-rooting and uses ProtectSystem=full
// rather than =strict. The cmd/cmdEscape funcs and the template fields come from
// kardianos's systemd backend; the Dependencies range emits the After=/Wants= lines
// set above.
const systemdScript = `[Unit]
Description={{.Description}}
ConditionFileIsExecutable={{.Path|cmdEscape}}
{{range $i, $dep := .Dependencies}}
{{$dep}} {{end}}
StartLimitIntervalSec=60
StartLimitBurst=5

[Service]
EnvironmentFile=-/etc/default/{{.Name}}
ExecStart={{.Path|cmdEscape}}{{range .Arguments}} {{.|cmd}}{{end}} $PINGULARITY_OPTS
{{if .WorkingDirectory}}WorkingDirectory={{.WorkingDirectory|cmdEscape}}{{end}}
{{if .ReloadSignal}}ExecReload=/bin/kill -{{.ReloadSignal}} "$MAINPID"{{end}}
{{if .Restart}}Restart={{.Restart}}{{end}}
RestartSec=5
# Defence-in-depth hardening. This self-install unit runs as ROOT (kardianos
# installs with no User=), so it deliberately drops the packaged unit's de-rooting
# (User=/Group=/AmbientCapabilities/CapabilityBoundingSet/StateDirectory) and uses
# ProtectSystem=full rather than =strict - a root daemon writes its DB under /var,
# which strict would render read-only. The directives below still hold under root:
# forbid privilege escalation, keep /usr,/boot,/etc read-only, hide home dirs, give
# a private /tmp, and lock down kernel tunables, SUID/SGID and personality.
NoNewPrivileges=yes
ProtectSystem=full
ProtectHome=yes
PrivateTmp=yes
ProtectKernelTunables=yes
RestrictSUIDSGID=yes
LockPersonality=yes

[Install]
WantedBy=multi-user.target
`