Extract init-neutral unit resolution into service/, add initsys.Init with systemd, openrc and runit backends, selected by 'init:' config or autodetect. OpenRC and runit are root only; rootless units run as system services as that user. Add docs and generated examples for all three.
78 lines
2.2 KiB
Go
78 lines
2.2 KiB
Go
// Package initsys selects the init system backend that installs and controls
|
|
// unitdore services.
|
|
package initsys
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/warkanum/unitdore/config"
|
|
"github.com/warkanum/unitdore/openrc"
|
|
"github.com/warkanum/unitdore/runit"
|
|
"github.com/warkanum/unitdore/systemd"
|
|
)
|
|
|
|
// Backend names.
|
|
const (
|
|
Systemd = "systemd"
|
|
OpenRC = "openrc"
|
|
Runit = "runit"
|
|
)
|
|
|
|
// Init is implemented by every init system backend. u.User selects the scope;
|
|
// backends that cannot do per-user managers run user units as system services.
|
|
type Init interface {
|
|
Name() string
|
|
ServiceName(u config.Unit, prefix, suffix string) string
|
|
UnitPath(u config.Unit, prefix, suffix string) (string, error)
|
|
Generate(u config.Unit, prefix, suffix string) (string, error)
|
|
Install(u config.Unit, prefix, suffix string) error
|
|
Uninstall(u config.Unit, prefix, suffix string) error
|
|
Enable(u config.Unit, prefix, suffix string) error
|
|
Disable(u config.Unit, prefix, suffix string) error
|
|
Start(u config.Unit, prefix, suffix string) error
|
|
Stop(u config.Unit, prefix, suffix string) error
|
|
// Status returns active | inactive | failed | activating | deactivating | unknown.
|
|
Status(u config.Unit, prefix, suffix string) string
|
|
IsInstalled(u config.Unit, prefix, suffix string) bool
|
|
// SupportsLinger reports whether user units need systemd-style linger.
|
|
SupportsLinger() bool
|
|
}
|
|
|
|
// New returns the backend named in cfg.Init, or the detected one.
|
|
func New(cfg *config.Config) (Init, error) {
|
|
name := cfg.Init
|
|
if name == "" {
|
|
name = Detect("/")
|
|
}
|
|
switch name {
|
|
case Systemd:
|
|
return systemd.Backend{}, nil
|
|
case OpenRC:
|
|
return openrc.Backend{}, nil
|
|
case Runit:
|
|
return runit.Backend{ServiceDir: cfg.ServiceDir}, nil
|
|
default:
|
|
return nil, fmt.Errorf("unknown init %q (want systemd, openrc or runit)", name)
|
|
}
|
|
}
|
|
|
|
// Detect guesses the running init system below root. Falls back to systemd.
|
|
func Detect(root string) string {
|
|
has := func(p string) bool {
|
|
_, err := os.Stat(filepath.Join(root, p))
|
|
return err == nil
|
|
}
|
|
switch {
|
|
case has("run/systemd/system"):
|
|
return Systemd
|
|
case has("run/openrc"), has("sbin/openrc-run"):
|
|
return OpenRC
|
|
case has("run/runit"), has("etc/runit"):
|
|
return Runit
|
|
default:
|
|
return Systemd
|
|
}
|
|
}
|