2 Commits
4 changed files with 135 additions and 108 deletions
+6 -2
View File
@@ -195,7 +195,8 @@ func killProcesses() {
return
}
for _, process := range processes {
if process.Pid() == 1 {
sid, _, _ := syscall.Syscall(syscall.SYS_GETSID, uintptr(process.Pid()), 0, 0)
if process.Pid() == 1 || sid == 1 {
continue
}
@@ -210,7 +211,8 @@ func killProcesses() {
return
}
for _, process := range processes {
if process.Pid() == 1 {
sid, _, _ := syscall.Syscall(syscall.SYS_GETSID, uintptr(process.Pid()), 0, 0)
if process.Pid() == 1 || sid == 1 {
continue
}
@@ -270,6 +272,7 @@ func shutdownSystem() {
stopServiceManager()
killProcesses()
unmountFilesystems()
remountRootReadonly()
fmt.Print("Syncing disks... ")
syscall.Sync()
@@ -288,6 +291,7 @@ func rebootSystem() {
stopServiceManager()
killProcesses()
unmountFilesystems()
remountRootReadonly()
fmt.Print("Syncing disks... ")
syscall.Sync()
+44 -16
View File
@@ -241,11 +241,6 @@ func unmountFilesystems() {
log.Fatal(err)
}
// Reserve variables for root filesytem
rootSource := ""
rootFilesystem := ""
rootData := ""
// Unmount filesystems
entries := strings.Split(string(data), "\n")
slices.Reverse(entries)
@@ -259,17 +254,18 @@ func unmountFilesystems() {
fields := strings.Fields(entry)
mountpoint := fields[4]
filesystem := ""
source := ""
data := ""
for i := 6; i < len(fields); i++ {
if fields[i] == "-" {
filesystem = fields[i+1]
source = fields[i+2]
data = fields[i+3]
break
}
}
// Skip root filesystem
if mountpoint == "/" {
continue
}
// Skip root and ignored filesystems
ignoredFilesystems := []string{
"devtmpfs",
@@ -277,12 +273,6 @@ func unmountFilesystems() {
"sysfs",
"tmpfs",
}
if mountpoint == "/" {
rootSource = source
rootFilesystem = filesystem
_, rootData, _ = convertMountOptions(data)
continue
}
if slices.Contains(ignoredFilesystems, filesystem) {
continue
@@ -311,11 +301,49 @@ func unmountFilesystems() {
}
}
}
}
func remountRootReadonly() {
fmt.Print("Remounting root as read-only...")
data, err := os.ReadFile("/proc/self/mountinfo")
if err != nil {
log.Fatal(err)
}
filesystem := ""
source := ""
fsData := ""
// Get root filesystems
entries := strings.Split(string(data), "\n")
slices.Reverse(entries)
for _, entry := range entries {
entry = strings.TrimSpace(entry)
if len(entry) == 0 {
continue
}
// Get entry fields
fields := strings.Fields(entry)
mountpoint := fields[4]
for i := 6; i < len(fields); i++ {
if fields[i] == "-" {
filesystem = fields[i+1]
source = fields[i+2]
fsData = fields[i+3]
break
}
}
if mountpoint == "/" {
break
}
}
tries := 0
for {
err = unix.Mount(rootSource, "/", rootFilesystem, syscall.MS_RDONLY|syscall.MS_REMOUNT, rootData)
err := unix.Mount(source, "/", filesystem, syscall.MS_RDONLY|syscall.MS_REMOUNT, fsData)
if errors.Is(err, syscall.EBUSY) {
fmt.Print(".")
tries++
+22 -63
View File
@@ -1,7 +1,6 @@
package main
import (
"crypto/sha256"
"flag"
"fmt"
"io"
@@ -15,8 +14,6 @@ import (
"strings"
"syscall"
"time"
"gopkg.in/yaml.v3"
)
// Build-time variables
@@ -136,64 +133,8 @@ func Init() {
// Read and initialize service files
for _, entry := range dirEntries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".esv") {
logger.Printf("Initializing service (%s)...\n", entry.Name())
bytes, err := os.ReadFile(path.Join(serviceConfigDir, "services", entry.Name()))
if err != nil {
logger.Printf("Error: Could not read service file (%s)", path.Join(serviceConfigDir, "services", entry.Name()))
continue
}
service := EnitService{
Name: "",
Description: "",
Type: "",
StartCmd: "",
ExitMethod: "",
StopCmd: "",
Restart: "",
Setpgid: true,
CrashOnSafeExit: true,
LogOutput: true,
Filepath: path.Join(serviceConfigDir, "services", entry.Name()),
filepathChecksum: sha256.Sum256(bytes),
restartCount: 0,
stopChannel: make(chan bool),
state: EnitServiceUnloaded,
}
if err := yaml.Unmarshal(bytes, &service); err != nil {
logger.Printf("Error: could not read service file %s", path.Join(serviceConfigDir, "services", entry.Name()))
continue
}
for _, sv := range Services {
if sv.Name == service.Name {
logger.Printf("Error: service with name (%s) has already been initialized", service.Name)
}
}
switch service.Type {
case "simple", "background":
default:
logger.Printf("Error: unknown service type (%s)", service.Type)
continue
}
switch service.ExitMethod {
case "stop_command", "kill":
default:
logger.Printf("Error: unknown exit method (%s)\n", service.ExitMethod)
continue
}
switch service.Restart {
case "true", "always":
default:
service.Restart = "false"
}
Services = append(Services, &service)
logger.Printf("Service (%s) has been initialized!\n", service.Name)
filepath := path.Join(serviceConfigDir, "services", entry.Name())
LoadService(filepath)
}
}
@@ -231,8 +172,26 @@ func Init() {
func Reload() {
logger.Println("Reloading all ESVM services...")
for _, service := range Services {
service.ReloadService()
dirEntries, err := os.ReadDir(path.Join(serviceConfigDir, "services"))
if err != nil {
logger.Fatalf("Error: Could not initialize ESVM: %s", err)
}
// Read and load service files
servicesToRemove := slices.Clone(Services)
for _, entry := range dirEntries {
if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".esv") {
filepath := path.Join(serviceConfigDir, "services", entry.Name())
LoadService(filepath)
servicesToRemove = slices.DeleteFunc(servicesToRemove, func(sv *EnitService) bool {
return sv.Filepath == filepath
})
}
}
// Reload services that had their esv file removed
for _, service := range servicesToRemove {
LoadService(service.Filepath)
}
logger.Println("All ESVM services have been reloaded!")
+55 -19
View File
@@ -101,9 +101,18 @@ func (service *EnitService) GetLogFile() (file *os.File, err error) {
return file, nil
}
func (service *EnitService) ReloadService() {
bytes, err := os.ReadFile(service.Filepath)
func LoadService(filepath string) {
bytes, err := os.ReadFile(filepath)
checksum := sha256.Sum256(bytes)
var serviceToReload *EnitService
// Check if service is already loaded
for _, service := range Services {
if service.Filepath != filepath {
continue
}
if slices.Equal(checksum[:], service.filepathChecksum[:]) {
return
}
@@ -114,17 +123,29 @@ func (service *EnitService) ReloadService() {
return
}
service.shouldReload = false
serviceToReload = service
logger.Printf("Reloading service (%s)...\n", service.Filepath)
break
}
if serviceToReload == nil {
logger.Printf("Loading service (%s)...\n", filepath)
} else {
logger.Printf("Reloading service (%s)...\n", filepath)
}
if os.IsNotExist(err) {
Services = slices.DeleteFunc(Services, func(sv *EnitService) bool {
return sv == service
if sv.Filepath == filepath {
logger.Printf("Service (%s) has been removed\n", sv.Name)
return true
}
return false
})
logger.Printf("Service (%s) has been removed\n", service.Name)
return
} else if err != nil {
logger.Printf("Error: Could not read service file (%s)", service.Filepath)
logger.Printf("Error: Could not read service file (%s)", filepath)
return
}
@@ -139,20 +160,26 @@ func (service *EnitService) ReloadService() {
Setpgid: true,
CrashOnSafeExit: true,
LogOutput: true,
Filepath: service.Filepath,
filepathChecksum: checksum,
restartCount: service.restartCount,
stopChannel: service.stopChannel,
state: service.state,
Filepath: filepath,
filepathChecksum: sha256.Sum256(bytes),
restartCount: 0,
stopChannel: make(chan bool),
state: EnitServiceUnloaded,
}
if serviceToReload != nil {
newService.restartCount = serviceToReload.restartCount
newService.stopChannel = serviceToReload.stopChannel
newService.state = serviceToReload.state
}
if err := yaml.Unmarshal(bytes, &newService); err != nil {
logger.Printf("Error: could not read service file %s", service.Filepath)
logger.Printf("Error: could not read service file %s", filepath)
return
}
for _, sv := range Services {
if sv.Name == newService.Name && sv != service {
logger.Printf("Error: service with name (%s) has already been initialized", service.Name)
if sv.Name == newService.Name && sv != serviceToReload {
logger.Printf("Error: service with name (%s) has already been loaded", newService.Name)
return
}
}
@@ -177,12 +204,15 @@ func (service *EnitService) ReloadService() {
}
for i, sv := range Services {
if sv == service {
if sv == serviceToReload {
Services[i] = &newService
logger.Printf("Service (%s) has been reloaded!\n", newService.Name)
return
}
}
logger.Printf("Service (%s) has been reloaded!\n", newService.Name)
Services = append(Services, &newService)
logger.Printf("Service (%s) has been loaded!\n", newService.Name)
}
func (service *EnitService) StartService() (err error) {
@@ -294,7 +324,7 @@ func (service *EnitService) StartService() (err error) {
// Reload service if needed
if service.shouldReload {
service.ReloadService()
LoadService(service.Filepath)
if GetServiceByName(service.Name) == nil {
return
}
@@ -314,7 +344,7 @@ func (service *EnitService) StartService() (err error) {
// Reload service if needed
if service.shouldReload {
service.ReloadService()
LoadService(service.Filepath)
if GetServiceByName(service.Name) == nil {
return
}
@@ -362,7 +392,7 @@ func (service *EnitService) StopService() error {
// Reload service if needed
if service.shouldReload {
service.ReloadService()
LoadService(service.Filepath)
if GetServiceByName(service.Name) == nil {
return
}
@@ -422,6 +452,12 @@ func (service *EnitService) RestartService() error {
return err
}
// Get service from list in case of a reload
if GetServiceByName(service.Name) == nil {
return fmt.Errorf("service was removed")
}
service = GetServiceByName(service.Name)
if err := service.StartService(); err != nil {
return err
}