You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

113 lines
3.4 KiB

package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
)
func isAutoStartEnabled(appPath string) bool {
serviceFile := autoStartServiceFile(appPath)
kioskInfof("autostart check begin service=%s expectedExec=%s expectedWorkdir=%s", serviceFile, appPath, filepath.Dir(appPath))
content, err := os.ReadFile(serviceFile)
if err != nil {
kioskWarnf("autostart service read failed service=%s err=%v", serviceFile, err)
return false
}
matches := autoStartServiceMatches(string(content), appPath)
kioskInfof("autostart service match result service=%s matches=%v", serviceFile, matches)
return matches
}
func enableAutoStart(appPath string) error {
serviceFile := autoStartServiceFile(appPath)
kioskInfof("autostart setup begin service=%s exec=%s workdir=%s", serviceFile, appPath, filepath.Dir(appPath))
content := autoStartServiceContent(appPath)
kioskDebugf("autostart service content:\n%s", content)
cmd := exec.Command("sudo", "bash", "-c",
fmt.Sprintf("echo '%s' > %s", content, serviceFile))
if err := cmd.Run(); err != nil {
kioskErrorf("write autostart service failed service=%s err=%v", serviceFile, err)
return err
}
kioskInfof("write autostart service success service=%s", serviceFile)
cmd = exec.Command("sudo", "systemctl", "daemon-reload")
if err := cmd.Run(); err != nil {
kioskErrorf("systemctl daemon-reload failed err=%v", err)
return err
}
kioskInfof("systemctl daemon-reload success")
cmd = exec.Command("sudo", "systemctl", "enable", autoStartServiceName(appPath))
if err := cmd.Run(); err != nil {
kioskErrorf("systemctl enable failed service=%s err=%v", autoStartServiceName(appPath), err)
return err
}
kioskInfof("systemctl enable success service=%s", autoStartServiceName(appPath))
return nil
}
func autoStartServiceName(appPath string) string {
return strings.TrimSuffix(filepath.Base(appPath), filepath.Ext(appPath)) + ".service"
}
func autoStartServiceFile(appPath string) string {
return filepath.Join("/etc/systemd/system", autoStartServiceName(appPath))
}
func autoStartServiceContent(appPath string) string {
appName := strings.TrimSuffix(filepath.Base(appPath), filepath.Ext(appPath))
return fmt.Sprintf(`[Unit]
Description=%s Background Service
After=network.target
[Service]
Type=simple
ExecStart=%s
Restart=on-failure
RestartSec=10
User=root
WorkingDirectory=%s
[Install]
WantedBy=multi-user.target
`,
appName,
appPath,
filepath.Dir(appPath))
}
func autoStartServiceMatches(content string, appPath string) bool {
execStart := normalizeSystemdValue(systemdUnitValue(content, "ExecStart"))
workingDirectory := normalizeSystemdValue(systemdUnitValue(content, "WorkingDirectory"))
expectedWorkdir := filepath.Dir(appPath)
matches := execStart == appPath && workingDirectory == expectedWorkdir
kioskInfof("autostart service fields execStart=%s expectedExec=%s workingDirectory=%s expectedWorkdir=%s matches=%v", execStart, appPath, workingDirectory, expectedWorkdir, matches)
return matches
}
func systemdUnitValue(content string, key string) string {
for _, line := range strings.Split(content, "\n") {
line = strings.TrimSpace(line)
if line == "" || strings.HasPrefix(line, "#") || strings.HasPrefix(line, ";") {
continue
}
name, value, ok := strings.Cut(line, "=")
if !ok || strings.TrimSpace(name) != key {
continue
}
return strings.TrimSpace(value)
}
return ""
}
func normalizeSystemdValue(value string) string {
return strings.Trim(strings.TrimSpace(value), `"'`)
}