usb-server/internal/service/service_linux.go

95 lines
2.2 KiB
Go

//go:build linux
package service
import (
"fmt"
"os"
"os/exec"
"path/filepath"
)
const systemdUnitTemplate = `[Unit]
Description=USB Client (%s mode)
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=%s %s --config %s
Restart=always
RestartSec=5
User=root
[Install]
WantedBy=multi-user.target
`
const serviceName = "usb-client"
// Install creates and enables a systemd service
func Install(mode, configPath string) error {
// Find the executable
exePath, err := os.Executable()
if err != nil {
return fmt.Errorf("finding executable: %w", err)
}
exePath, err = filepath.Abs(exePath)
if err != nil {
return fmt.Errorf("resolving path: %w", err)
}
absConfigPath, err := filepath.Abs(configPath)
if err != nil {
return fmt.Errorf("resolving config path: %w", err)
}
unitContent := fmt.Sprintf(systemdUnitTemplate, mode, exePath, mode, absConfigPath)
unitPath := fmt.Sprintf("/etc/systemd/system/%s.service", serviceName)
if err := os.WriteFile(unitPath, []byte(unitContent), 0644); err != nil {
return fmt.Errorf("writing unit file: %w (need root?)", err)
}
// Reload systemd
if err := exec.Command("systemctl", "daemon-reload").Run(); err != nil {
return fmt.Errorf("daemon-reload: %w", err)
}
// Enable and start
if err := exec.Command("systemctl", "enable", serviceName).Run(); err != nil {
return fmt.Errorf("enable: %w", err)
}
if err := exec.Command("systemctl", "start", serviceName).Run(); err != nil {
return fmt.Errorf("start: %w", err)
}
return nil
}
// Uninstall stops and removes the systemd service
func Uninstall() error {
// Stop and disable
exec.Command("systemctl", "stop", serviceName).Run()
exec.Command("systemctl", "disable", serviceName).Run()
// Remove unit file
unitPath := fmt.Sprintf("/etc/systemd/system/%s.service", serviceName)
os.Remove(unitPath)
// Reload
exec.Command("systemctl", "daemon-reload").Run()
return nil
}
// Status returns the systemd service status
func Status() (string, error) {
out, err := exec.Command("systemctl", "status", serviceName).CombinedOutput()
if err != nil {
return string(out), nil // status returns non-zero for inactive services
}
return string(out), nil
}