95 lines
2.2 KiB
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
|
|
}
|