Initial Commit

This commit is contained in:
EnumDev 2025-02-22 18:09:08 +02:00
commit a31c319627
12 changed files with 883 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
# Ignore build directory
build/
# Ignore IDE directories
.idea

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 EnumDev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

40
Makefile Normal file
View File

@ -0,0 +1,40 @@
SHELL := /bin/bash
PREFIX ?= /usr/local
SBINDIR ?= $(PREFIX)/sbin
SYSCONFDIR ?= $(PREFIX)/etc
LOCALSTATEDIR ?= $(PREFIX)/var
RUNSTATEDIR ?= $(LOCALSTATEDIR)/run
GO ?= $(shell type -a -P go | head -n 1)
# Set version variable
ifeq ($(VERSION),)
COMMIT := $(shell git rev-parse --short HEAD)
TAG_COMMIT := $(shell git rev-list --abbrev-commit --tags --max-count=1)
TAG := $(shell git describe --abbrev=0 --tags ${TAG_COMMIT} 2>/dev/null || true)
VERSION := $(COMMIT)
ifeq ($(COMMIT), $(TAG_COMMIT))
VERSION := $(TAG)
endif
ifneq ($(shell git status --porcelain),)
VERSION := $(VERSION)-dirty
endif
endif
build:
mkdir -p build
cd cmd/enit; $(GO) build -ldflags "-w -X main.version=$(VERSION)" -o ../../build/enit enit
cd cmd/esvm; $(GO) build -ldflags "-w -X main.version=$(VERSION)" -o ../../build/esvm esvm
cd cmd/ectl; $(GO) build -ldflags "-w -X main.version=$(VERSION) -X main.sysconfdir=$(SYSCONFDIR) -X main.runstatedir=$(RUNSTATEDIR)" -o ../../build/ectl ectl
install: build/enit build/ectl
mkdir -p $(DESTDIR)$(SBINDIR)
mkdir -p $(DESTDIR)$(SYSCONFDIR)/esvm/services
cp build/enit $(DESTDIR)$(SBINDIR)/enit
cp build/enit $(DESTDIR)$(SBINDIR)/esvm
cp build/ectl $(DESTDIR)$(SBINDIR)/ectl
clean:
rm -r build/
.PHONY: build

5
cmd/ectl/go.mod Normal file
View File

@ -0,0 +1,5 @@
module ectl
go 1.23.4
require rsc.io/getopt v0.0.0-20170811000552-20be20937449 // indirect

2
cmd/ectl/go.sum Normal file
View File

@ -0,0 +1,2 @@
rsc.io/getopt v0.0.0-20170811000552-20be20937449 h1:UukjJOsjQH0DIuyyrcod6CXHS6cdaMMuJmrt+SN1j4A=
rsc.io/getopt v0.0.0-20170811000552-20be20937449/go.mod h1:dhCdeqAxkyt5u3/sKRkUXuHaMXUu1Pt13GTQAM2xnig=

192
cmd/ectl/main.go Normal file
View File

@ -0,0 +1,192 @@
package main
import (
"flag"
"fmt"
"log"
"net"
"os"
"path"
"strconv"
"strings"
"syscall"
"time"
)
// Build-time variables
var version = "dev"
var sysconfdir = "/etc/"
var runstatedir = "/var/run/"
var socket net.Conn
func main() {
// Set and parse flags
printVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
// Dial esvm socket
dialSocket()
defer socket.Close()
if flag.NArg() < 1 {
printUsage()
os.Exit(1)
}
if *printVersion || flag.Args()[0] == "version" {
fmt.Printf("Enit Control version %s\n", version)
return
} else if flag.Args()[0] == "help" {
printUsage()
return
} else if flag.Args()[0] == "shutdown" || flag.Args()[0] == "poweroff" || flag.Args()[0] == "halt" {
err := syscall.Kill(1, syscall.SIGUSR1)
if err != nil {
log.Fatalf("Could not send shutdown signal! Error: %s\n", err)
}
return
} else if flag.Args()[0] == "reboot" || flag.Args()[0] == "restart" || flag.Args()[0] == "reset" {
err := syscall.Kill(1, syscall.SIGTERM)
if err != nil {
log.Fatalf("Could not send shutdown signal! Error: %s\n", err)
}
return
} else if flag.Args()[0] == "service" || flag.Args()[0] == "sv" {
if len(flag.Args()) <= 1 {
fmt.Println("Usage: ectl service <start/stop/enable/disable/status/list> [service]")
return
} else if flag.Args()[1] == "list" {
fmt.Println("list")
return
} else if len(flag.Args()) <= 2 {
fmt.Printf("Usage: ectl service %s <service>\n", flag.Args()[1])
return
} else if flag.Args()[1] == "start" {
flag.Args()[2] = strings.TrimSuffix(flag.Args()[2], ".esv")
if _, err := os.Stat(path.Join(sysconfdir, "esvm/services/", flag.Args()[2]+".esv")); err != nil {
log.Fatalf("Could not start service! Error: %s\n", err)
}
_, err := socket.Write([]byte("start " + flag.Args()[2]))
if err != nil {
log.Fatalf("Could not start service! Error: %s\n", err)
}
buf := make([]byte, 1024)
n, err := socket.Read(buf)
if err != nil {
log.Fatalf("Could not start service! Error: %s\n", err)
}
if string(buf[:n]) != "ok" {
log.Fatalf("Could not start service! Error: expcted 'ok' got '%s'\n", string(buf))
}
fmt.Println("Service started successfully!")
return
} else if flag.Args()[1] == "stop" {
flag.Args()[2] = strings.TrimSuffix(flag.Args()[2], ".esv")
if _, err := os.Stat(path.Join(sysconfdir, "esvm/services/", flag.Args()[2]+".esv")); err != nil {
log.Fatalf("Could not stop service! Error: %s\n", err)
}
_, err := socket.Write([]byte("stop " + flag.Args()[2]))
if err != nil {
log.Fatalf("Could not stop service! Error: %s\n", err)
}
buf := make([]byte, 1024)
n, err := socket.Read(buf)
if err != nil {
log.Fatalf("Could not stop service! Error: %s\n", err)
}
if string(buf[:n]) != "ok" {
log.Fatalf("Could not stop service! Error: expcted 'ok' got '%s'\n", string(buf))
}
fmt.Println("Service stopped successfully!")
return
} else if flag.Args()[1] == "restart" || flag.Args()[1] == "reload" {
flag.Args()[2] = strings.TrimSuffix(flag.Args()[2], ".esv")
if _, err := os.Stat(path.Join(sysconfdir, "esvm/services/", flag.Args()[2]+".esv")); err != nil {
log.Fatalf("Could not stop service! Error: %s\n", err)
}
_, err := socket.Write([]byte("restart " + flag.Args()[2]))
if err != nil {
log.Fatalf("Could not restart service! Error: %s\n", err)
}
buf := make([]byte, 1024)
n, err := socket.Read(buf)
if err != nil {
log.Fatalf("Could not restart service! Error: %s\n", err)
}
if string(buf[:n]) != "ok" {
log.Fatalf("Could not restart service! Error: expcted 'ok' got '%s'\n", string(buf))
}
fmt.Println("Service restarted successfully!")
return
} else if flag.Args()[1] == "status" {
flag.Args()[2] = strings.TrimSuffix(flag.Args()[2], ".esv")
if _, err := os.Stat(path.Join(sysconfdir, "esvm/services/", flag.Args()[2]+".esv")); err != nil {
log.Fatalf("Could not stop service! Error: %s\n", err)
}
var state uint64
bytes, err := os.ReadFile(path.Join(runstatedir, "esvm", flag.Args()[2], "state"))
if err != nil {
state = 0
}
state, err = strconv.ParseUint(string(bytes), 10, 8)
fmt.Println("Service name: " + flag.Args()[2])
switch state {
case 0:
fmt.Println("Service state: Unknown")
case 1:
fmt.Println("Service state: Unloaded")
case 2:
fmt.Println("Service state: Running")
case 3:
fmt.Println("Service state: Stopped")
case 4:
fmt.Println("Service state: Crashed")
}
return
}
}
printUsage()
os.Exit(1)
}
func printUsage() {
fmt.Println("Available sucommands:")
fmt.Println("ectl version | Show enit version")
fmt.Println("ectl shutdown/poweroff/halt | Shutdown the system")
fmt.Println("ectl reboot/restart | Reboot the system")
fmt.Println("ectl help | Show command explanations")
fmt.Println("ectl sv/service start <service> | Start a service")
fmt.Println("ectl sv/service stop <service> | Stop a service")
fmt.Println("ectl sv/service enable <service> | Enable a service at startup")
fmt.Println("ectl sv/service disable <service> | Disable a service at startup")
fmt.Println("ectl sv/service status <service> | Show service status")
fmt.Println("ectl sv/service list | Show all enabled services")
}
func dialSocket() {
if _, err := os.Stat(path.Join(runstatedir, "esvm/esvm.sock")); err != nil {
log.Fatalf("Could not find esvm.sock! Error: %s\n", err)
}
var err error
socket, err = net.Dial("unix", path.Join(runstatedir, "esvm/esvm.sock"))
if err != nil {
log.Fatalf("Failed to connect to esvm.sock! Error: %s\n", err)
}
if err := socket.SetDeadline(time.Now().Add(5 * time.Second)); err != nil {
log.Fatalf("Failed to set write deadline! Error: %s\n", err)
}
}

3
cmd/enit/go.mod Normal file
View File

@ -0,0 +1,3 @@
module enit
go 1.23.4

4
cmd/enit/go.sum Normal file
View File

@ -0,0 +1,4 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

177
cmd/enit/main.go Normal file
View File

@ -0,0 +1,177 @@
package main
import (
"flag"
"fmt"
"log"
"os"
"os/exec"
"os/signal"
"path"
"strconv"
"syscall"
)
// Build-time variables
var version = "dev"
var sysconfdir = "/etc/"
var runstatedir = "/var/run/"
var serviceManagerPid int
func main() {
// Parse flags
printVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
if *printVersion {
fmt.Printf("Enit version %s\n", version)
os.Exit(0)
}
if os.Getpid() != 1 {
fmt.Println("Enit must be run as PID 1!")
os.Exit(1)
}
fmt.Println("Starting Enit...")
// Mount virtual filesystems
mountVirtualFilesystems()
// Mount filesystems in fstab
mountFilesystems()
// Start service manager
startServiceManager()
// Run function once to wait zombie processes created by initcpio
waitZombieProcesses()
fmt.Println()
startTerminal()
// Catch signals
catchSignals()
}
func mountVirtualFilesystems() {
fmt.Print("Mounting virtual filesystems... ")
if err := os.Mkdir("/dev/pts", 0755); err != nil {
panic(err)
}
if err := syscall.Mount("none", "/dev/pts", "devpts", syscall.MS_NOSUID|syscall.MS_NOEXEC, ""); err != nil {
panic(err)
}
fmt.Println("Done.")
}
func mountFilesystems() {
fmt.Print("Mounting filesystems... ")
cmd := exec.Command("/bin/mount", "-a")
err := cmd.Run()
if err != nil {
log.Println("Could not mount fstab entries!")
panic(err)
}
fmt.Println("Done.")
}
func startServiceManager() {
fmt.Print("Initializing service manager... ")
cmd := exec.Command("/sbin/esvm", path.Join(runstatedir, "esvm"), path.Join(sysconfdir, "esvm"))
err := cmd.Start()
if err != nil {
log.Println("Could not initialize service manager!")
panic(err)
}
serviceManagerPid = cmd.Process.Pid
fmt.Println("Done")
}
func waitZombieProcesses() {
for {
if wpid, _ := syscall.Wait4(-1, nil, syscall.WNOHANG, nil); wpid <= 0 {
break
}
}
}
func startTerminal() {
for i := 1; i < 6; i++ {
cmd := exec.Command("/sbin/agetty", "--noclear", "tty"+strconv.Itoa(i))
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Start()
if err != nil {
log.Println("Could not start agetty terminal on tty" + strconv.Itoa(i) + "!")
panic(err)
}
}
}
func catchSignals() {
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGUSR1, syscall.SIGTERM, syscall.SIGINT, syscall.SIGCHLD)
defer close(sigc)
defer signal.Stop(sigc)
for {
switch <-sigc {
case syscall.SIGUSR1:
close(sigc)
signal.Stop(sigc)
shutdownSystem()
case syscall.SIGTERM, syscall.SIGINT:
close(sigc)
signal.Stop(sigc)
rebootSystem()
case syscall.SIGCHLD:
waitZombieProcesses()
}
}
}
func shutdownSystem() {
fmt.Println("Shutting down...")
fmt.Println("Stopping services... ")
err := syscall.Kill(serviceManagerPid, syscall.SIGTERM)
if err != nil {
log.Println("Could not stop service manager!")
panic(err)
}
fmt.Print("Done.")
fmt.Println("Sending shutdown syscall...")
syscall.Sync()
err = syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
if err != nil {
panic(err)
}
}
func rebootSystem() {
fmt.Println("Rebooting...")
fmt.Println("Stopping service manager... ")
err := syscall.Kill(serviceManagerPid, syscall.SIGTERM)
if err != nil {
log.Println("Could not stop service manager!")
panic(err)
}
fmt.Print("Done.")
fmt.Println("Sending reboot syscall...")
syscall.Sync()
err = syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
if err != nil {
panic(err)
}
}

5
cmd/esvm/go.mod Normal file
View File

@ -0,0 +1,5 @@
module esvm
go 1.23.4
require gopkg.in/yaml.v3 v3.0.1 // indirect

3
cmd/esvm/go.sum Normal file
View File

@ -0,0 +1,3 @@
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

426
cmd/esvm/main.go Normal file
View File

@ -0,0 +1,426 @@
package main
import (
"flag"
"fmt"
"gopkg.in/yaml.v3"
"io"
"log"
"net"
"os"
"os/exec"
"os/signal"
"path"
"strconv"
"strings"
"syscall"
)
type EnitServiceState uint8
const (
EnitServiceUnknown EnitServiceState = iota
EnitServiceUnloaded
EnitServiceRunning
EnitServiceStopped
EnitServiceCrashed
EnitServiceCompleted
)
type EnitService struct {
Name string `yaml:"name"`
Description string `yaml:"description,omitempty"`
Type string `yaml:"type"`
StartCmd string `yaml:"start_cmd"`
ExitMethod string `yaml:"exit_method"`
StopCmd string `yaml:"stop_cmd,omitempty"`
ServiceRunPath string
stopChannel chan bool
}
// Build-time variables
var version = "dev"
var runtimeServiceDir string
var serviceConfigDir string
var Services = make([]EnitService, 0)
var socket net.Listener
func main() {
// Parse flags
printVersion := flag.Bool("version", false, "print version and exit")
flag.Parse()
if *printVersion || flag.NArg() != 2 {
fmt.Printf("Enit Service Manager version %s\n", version)
os.Exit(0)
}
// Set directory variables
runtimeServiceDir = flag.Arg(0)
serviceConfigDir = flag.Arg(1)
if os.Getppid() != 1 {
fmt.Println("Enit must be run by PID 1!")
os.Exit(1)
}
err := Init()
if err != nil {
log.Fatalf("Could not initialize esvm! Error: %s", err)
}
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigc
Destroy()
os.Exit(0)
}()
for {
listenToSocket()
}
}
func Init() error {
if _, err := os.Stat(runtimeServiceDir); err == nil {
return fmt.Errorf("runtime service directory %s already exists", runtimeServiceDir)
}
err := os.MkdirAll(runtimeServiceDir, 0755)
if err != nil {
return err
}
socket, err = net.Listen("unix", path.Join(runtimeServiceDir, "esvm.sock"))
if err != nil {
return err
}
if stat, err := os.Stat(serviceConfigDir); err != nil || !stat.IsDir() {
return nil
}
dirEntries, err := os.ReadDir(path.Join(serviceConfigDir, "services"))
if err != nil {
return err
}
for _, entry := range dirEntries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".esv") {
bytes, err := os.ReadFile(path.Join(serviceConfigDir, "services", entry.Name()))
if err != nil {
log.Printf("Could not read service file at %s!", path.Join(serviceConfigDir, "services", entry.Name()))
}
service := EnitService{
StopCmd: "",
stopChannel: make(chan bool),
}
if err := yaml.Unmarshal(bytes, &service); err != nil {
log.Printf("Could not read service file at %s!", path.Join(serviceConfigDir, "services", entry.Name()))
}
switch service.Type {
case "simple", "background":
default:
return fmt.Errorf("unknown service type: %s", service.Type)
}
switch service.ExitMethod {
case "stop_command", "kill":
default:
return fmt.Errorf("unknown exit method: %s", service.ExitMethod)
}
service.ServiceRunPath = path.Join(runtimeServiceDir, service.Name)
err = os.MkdirAll(path.Join(service.ServiceRunPath), 0755)
if err != nil {
return err
}
err = service.setCurrentState(EnitServiceUnloaded)
if err != nil {
return err
}
Services = append(Services, service)
if err := service.StartService(); err != nil {
log.Printf("Could not start service %s: %s\n", service.Name, err)
}
}
}
return nil
}
func Destroy() {
for _, service := range Services {
if err := service.StopService(); err != nil {
log.Printf("Error stopping service %s: %s\n", service.Name, err)
}
}
}
func GetServiceByName(name string) *EnitService {
for _, service := range Services {
if service.Name == name {
return &service
}
}
return nil
}
func (service *EnitService) GetProcess() *os.Process {
bytes, err := os.ReadFile(path.Join(service.ServiceRunPath, "process"))
if err != nil {
return nil
}
pid, err := strconv.Atoi(strings.TrimSpace(string(bytes)))
if err != nil {
return nil
}
process, err := os.FindProcess(pid)
if err != nil {
return nil
}
return process
}
func (service *EnitService) setProcessID(pid int) error {
if err := os.WriteFile(path.Join(service.ServiceRunPath, "process"), []byte(strconv.Itoa(pid)), 0644); err != nil {
return err
}
return nil
}
func (service *EnitService) GetCurrentState() EnitServiceState {
bytes, err := os.ReadFile(path.Join(service.ServiceRunPath, "state"))
if err != nil {
return EnitServiceUnknown
}
state, err := strconv.Atoi(strings.TrimSpace(string(bytes)))
if err != nil {
return EnitServiceUnknown
}
return EnitServiceState(state)
}
func (service *EnitService) setCurrentState(state EnitServiceState) error {
if err := os.WriteFile(path.Join(service.ServiceRunPath, "state"), []byte(strconv.Itoa(int(state))), 0644); err != nil {
return err
}
return nil
}
func (service *EnitService) StartService() error {
if service == nil {
return nil
}
if service.GetCurrentState() == EnitServiceRunning {
return nil
}
cmd := exec.Command("/bin/sh", "-c", service.StartCmd)
if err := cmd.Start(); err != nil {
return err
}
go func() {
err := cmd.Wait()
select {
case <-service.stopChannel:
_ = service.setCurrentState(EnitServiceStopped)
default:
if service.Type == "simple" && err == nil {
_ = service.setCurrentState(EnitServiceCompleted)
}
_ = service.setCurrentState(EnitServiceCrashed)
}
}()
err := service.setProcessID(cmd.Process.Pid)
if err != nil {
return err
}
err = service.setCurrentState(EnitServiceRunning)
if err != nil {
return err
}
return nil
}
func (service *EnitService) StopService() error {
if service.GetCurrentState() != EnitServiceRunning {
return nil
}
if service.ExitMethod == "kill" {
if service.GetProcess() == nil {
return nil
}
go func() { service.stopChannel <- true }()
err := service.GetProcess().Kill()
if err != nil {
return err
}
} else {
cmd := exec.Command("/bin/sh", "-c", service.StopCmd)
if err := cmd.Run(); err != nil {
return err
}
}
err := service.setCurrentState(EnitServiceStopped)
if err != nil {
return err
}
err = service.setProcessID(0)
if err != nil {
return err
}
return nil
}
func (service *EnitService) RestartService() error {
if err := service.StopService(); err != nil {
return err
}
if err := service.StartService(); err != nil {
return err
}
return nil
}
func checkForServiceCommand() {
for _, service := range Services {
if _, err := os.Stat(path.Join(service.ServiceRunPath, "start")); err == nil {
err := service.StartService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "start"))
if err != nil {
return
}
} else if _, err := os.Stat(path.Join(service.ServiceRunPath, "stop")); err == nil {
err := service.StopService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "stop"))
if err != nil {
return
}
} else if _, err := os.Stat(path.Join(service.ServiceRunPath, "restart")); err == nil {
err := service.RestartService()
if err != nil {
return
}
err = os.Remove(path.Join(service.ServiceRunPath, "restart"))
if err != nil {
return
}
}
}
}
func listenToSocket() {
conn, err := socket.Accept()
if err != nil {
log.Println("Could not accept socket connection!")
panic(err)
}
// Handle the connection in a separate goroutine.
go func(conn net.Conn) {
defer conn.Close()
// Create a buffer for incoming data.
buf := make([]byte, 4096)
// Read data from the connection.
n, err := conn.Read(buf)
if err == io.EOF {
return
}
if err != nil {
log.Fatal(err)
}
command := string(buf[:n])
commandSplit := strings.Split(command, " ")
if len(commandSplit) >= 2 {
if commandSplit[0] == "start" {
service := GetServiceByName(commandSplit[1])
if service == nil {
_, err := conn.Write([]byte("service not found"))
if err != nil {
return
}
}
if err := service.StartService(); err != nil {
_, err := conn.Write([]byte("could not start service"))
if err != nil {
return
}
}
_, err := conn.Write([]byte("ok"))
if err != nil {
return
}
} else if commandSplit[0] == "stop" {
service := GetServiceByName(commandSplit[1])
if service == nil {
_, err := conn.Write([]byte("service not found"))
if err != nil {
return
}
}
if err := service.StopService(); err != nil {
_, err := conn.Write([]byte("could not stop service"))
if err != nil {
return
}
}
_, err := conn.Write([]byte("ok"))
if err != nil {
return
}
} else if commandSplit[0] == "restart" {
service := GetServiceByName(commandSplit[1])
if service == nil {
_, err := conn.Write([]byte("service not found"))
if err != nil {
return
}
}
if err := service.RestartService(); err != nil {
_, err := conn.Write([]byte("could not restart service"))
if err != nil {
return
}
}
_, err := conn.Write([]byte("ok"))
if err != nil {
return
}
}
}
}(conn)
}