3 Commits
2 changed files with 61 additions and 13 deletions
+1 -2
View File
@@ -1,7 +1,6 @@
name: lo-interface name: lo-interface
description: Enable loopback interface on boot description: Enable loopback interface on boot
dependencies: ["/usr/sbin/ip"]
type: simple type: simple
start_cmd: ip link set lo up start_cmd: ip link set lo up
exit_method: kill exit_method: kill
restart: false restart: false
+60 -11
View File
@@ -6,8 +6,10 @@ import (
"io" "io"
"os" "os"
"os/exec" "os/exec"
"os/user"
"path" "path"
"slices" "slices"
"strconv"
"strings" "strings"
"syscall" "syscall"
"time" "time"
@@ -42,9 +44,9 @@ type EnitService struct {
Description string `yaml:"description,omitempty"` Description string `yaml:"description,omitempty"`
Type string `yaml:"type"` Type string `yaml:"type"`
StartCmd string `yaml:"start_cmd"` StartCmd string `yaml:"start_cmd"`
ExitMethod string `yaml:"exit_method"`
CrashOnSafeExit bool `yaml:"crash_on_safe_exit"` CrashOnSafeExit bool `yaml:"crash_on_safe_exit"`
StopCmd string `yaml:"stop_cmd,omitempty"` StopCmd string `yaml:"stop_cmd,omitempty"`
User string `yaml:"user,omitempty"`
Restart string `yaml:"restart,omitempty"` Restart string `yaml:"restart,omitempty"`
ReadyFd int `yaml:"ready_fd"` ReadyFd int `yaml:"ready_fd"`
Setpgid bool `yaml:"setpgid"` Setpgid bool `yaml:"setpgid"`
@@ -154,8 +156,8 @@ func LoadService(filepath string) {
Description: "", Description: "",
Type: "", Type: "",
StartCmd: "", StartCmd: "",
ExitMethod: "",
StopCmd: "", StopCmd: "",
User: "",
Restart: "", Restart: "",
Setpgid: true, Setpgid: true,
CrashOnSafeExit: true, CrashOnSafeExit: true,
@@ -190,13 +192,6 @@ func LoadService(filepath string) {
return return
} }
switch newService.ExitMethod {
case "stop_command", "kill":
default:
logger.Printf("Error: unknown exit method (%s)\n", newService.ExitMethod)
return
}
switch newService.Restart { switch newService.Restart {
case "true", "always": case "true", "always":
default: default:
@@ -236,10 +231,38 @@ func (service *EnitService) StartService() (err error) {
cmd := exec.Command("/bin/sh", "-c", "exec "+service.StartCmd) cmd := exec.Command("/bin/sh", "-c", "exec "+service.StartCmd)
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: service.Setpgid, Pgid: 0} cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: service.Setpgid, Pgid: 0}
// Setup service log file
if logFile != nil { if logFile != nil {
cmd.Stdout = logFile cmd.Stdout = logFile
cmd.Stderr = logFile cmd.Stderr = logFile
} }
// Setup command credentials
if service.User != "" && service.User != "root" {
// Lookup user in /etc/passwd
u, err := user.Lookup(service.User)
if err != nil {
return err
}
// Get user id and group id
uid, err := strconv.Atoi(u.Uid)
if err != nil {
return err
}
gid, err := strconv.Atoi(u.Gid)
if err != nil {
return err
}
cmd.SysProcAttr.Credential = &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
}
}
// Setup command pipes
var pipeReader, pipeWriter *os.File var pipeReader, pipeWriter *os.File
if service.ReadyFd > 2 { if service.ReadyFd > 2 {
pipeReader, pipeWriter, err = os.Pipe() pipeReader, pipeWriter, err = os.Pipe()
@@ -267,6 +290,7 @@ func (service *EnitService) StartService() (err error) {
} }
cmd.ExtraFiles = append(cmd.ExtraFiles, pipeWriter) cmd.ExtraFiles = append(cmd.ExtraFiles, pipeWriter)
} }
if err := cmd.Start(); err != nil { if err := cmd.Start(); err != nil {
// Close log file if not nil // Close log file if not nil
if logFile != nil { if logFile != nil {
@@ -319,7 +343,7 @@ func (service *EnitService) StartService() (err error) {
if service.Type == "simple" && err == nil { if service.Type == "simple" && err == nil {
service.restartCount = 0 service.restartCount = 0
if service.ExitMethod != "stop_command" { if strings.TrimSpace(service.StopCmd) == "" {
service.state = EnitServiceCompleted service.state = EnitServiceCompleted
// Reload service if needed // Reload service if needed
@@ -395,7 +419,7 @@ func (service *EnitService) StopService() error {
} }
}() }()
if service.ExitMethod == "kill" { if strings.TrimSpace(service.StopCmd) == "" {
if err := service.GetProcess().Signal(syscall.Signal(0)); err != nil { if err := service.GetProcess().Signal(syscall.Signal(0)); err != nil {
newServiceStatus = EnitServiceStopped newServiceStatus = EnitServiceStopped
logger.Printf("Service (%s) has stopped (Process already dead)", service.Name) logger.Printf("Service (%s) has stopped (Process already dead)", service.Name)
@@ -413,6 +437,31 @@ func (service *EnitService) StopService() error {
go func() { service.stopChannel <- true }() go func() { service.stopChannel <- true }()
cmd := exec.Command("/bin/sh", "-c", service.StopCmd) cmd := exec.Command("/bin/sh", "-c", service.StopCmd)
// Setup command credentials
if service.User != "" && service.User != "root" {
// Lookup user in /etc/passwd
u, err := user.Lookup(service.User)
if err != nil {
return err
}
// Get user id and group id
uid, err := strconv.Atoi(u.Uid)
if err != nil {
return err
}
gid, err := strconv.Atoi(u.Gid)
if err != nil {
return err
}
cmd.SysProcAttr.Credential = &syscall.Credential{
Uid: uint32(uid),
Gid: uint32(gid),
}
}
if err := cmd.Run(); err != nil { if err := cmd.Run(); err != nil {
return err return err
} }