Compare commits
3 Commits
3cc35fa7ff
...
74868ab2d3
Author | SHA1 | Date | |
---|---|---|---|
74868ab2d3 | |||
4b37214113 | |||
ce34b7b21a |
@ -2,7 +2,4 @@ module ectl
|
|||||||
|
|
||||||
go 1.23.4
|
go 1.23.4
|
||||||
|
|
||||||
require (
|
require gopkg.in/yaml.v3 v3.0.1
|
||||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
|
||||||
rsc.io/getopt v0.0.0-20170811000552-20be20937449 // indirect
|
|
||||||
)
|
|
||||||
|
@ -1,5 +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/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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
rsc.io/getopt v0.0.0-20170811000552-20be20937449 h1:UukjJOsjQH0DIuyyrcod6CXHS6cdaMMuJmrt+SN1j4A=
|
|
||||||
rsc.io/getopt v0.0.0-20170811000552-20be20937449/go.mod h1:dhCdeqAxkyt5u3/sKRkUXuHaMXUu1Pt13GTQAM2xnig=
|
|
||||||
|
@ -59,7 +59,28 @@ func main() {
|
|||||||
fmt.Println("Usage: ectl service <start/stop/enable/disable/status/list> [service]")
|
fmt.Println("Usage: ectl service <start/stop/enable/disable/status/list> [service]")
|
||||||
return
|
return
|
||||||
} else if flag.Args()[1] == "list" {
|
} else if flag.Args()[1] == "list" {
|
||||||
fmt.Println("list")
|
if _, err := os.Stat(path.Join(runstatedir, "esvm")); err != nil {
|
||||||
|
log.Fatalf("Could not list services! Error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
entries, err := os.ReadDir(path.Join(runstatedir, "esvm"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Could not list services! Error: %s\n", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, entry := range entries {
|
||||||
|
if !entry.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
state := getServiceState(entry.Name())
|
||||||
|
enabled := strconv.FormatBool(isServiceEnabled(entry.Name()))
|
||||||
|
enabled = strings.ToUpper(enabled[:1]) + strings.ToLower(enabled[1:])
|
||||||
|
|
||||||
|
fmt.Println("Service name: " + entry.Name())
|
||||||
|
fmt.Printf(" State: %s\n", state)
|
||||||
|
fmt.Printf(" Enabled: %s\n", enabled)
|
||||||
|
}
|
||||||
return
|
return
|
||||||
} else if len(flag.Args()) <= 2 {
|
} else if len(flag.Args()) <= 2 {
|
||||||
fmt.Printf("Usage: ectl service %s <service>\n", flag.Args()[1])
|
fmt.Printf("Usage: ectl service %s <service>\n", flag.Args()[1])
|
||||||
@ -226,26 +247,13 @@ func main() {
|
|||||||
log.Fatalf("Could not get service status! Error: %s\n", err)
|
log.Fatalf("Could not get service status! Error: %s\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var state uint64
|
state := getServiceState(flag.Args()[2])
|
||||||
bytes, err := os.ReadFile(path.Join(runstatedir, "esvm", flag.Args()[2], "state"))
|
enabled := strconv.FormatBool(isServiceEnabled(flag.Args()[2]))
|
||||||
if err != nil {
|
enabled = strings.ToUpper(enabled[:1]) + strings.ToLower(enabled[1:])
|
||||||
state = 0
|
|
||||||
}
|
|
||||||
state, err = strconv.ParseUint(string(bytes), 10, 8)
|
|
||||||
|
|
||||||
fmt.Println("Service name: " + flag.Args()[2])
|
fmt.Println("Service name: " + flag.Args()[2])
|
||||||
switch state {
|
fmt.Printf(" State: %s\n", state)
|
||||||
case 0:
|
fmt.Printf(" Enabled: %s\n", enabled)
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,6 +262,53 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getServiceState(serviceName string) string {
|
||||||
|
if _, err := os.Stat(path.Join(runstatedir, "esvm", serviceName)); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var state uint64
|
||||||
|
bytes, err := os.ReadFile(path.Join(runstatedir, "esvm", serviceName, "state"))
|
||||||
|
if err != nil {
|
||||||
|
state = 0
|
||||||
|
}
|
||||||
|
state, err = strconv.ParseUint(string(bytes), 10, 8)
|
||||||
|
|
||||||
|
switch state {
|
||||||
|
case 1:
|
||||||
|
return "Unloaded"
|
||||||
|
case 2:
|
||||||
|
return "Running"
|
||||||
|
case 3:
|
||||||
|
return "Stopped"
|
||||||
|
case 4:
|
||||||
|
return "Crashed"
|
||||||
|
case 5:
|
||||||
|
return "Completed"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isServiceEnabled(serviceName string) bool {
|
||||||
|
if _, err := os.Stat(path.Join(sysconfdir, "esvm/enabled_services")); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.ReadFile(path.Join(sysconfdir, "esvm/enabled_services"))
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(file), "\n") {
|
||||||
|
if strings.TrimSpace(line) == serviceName {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func printUsage() {
|
func printUsage() {
|
||||||
fmt.Println("Available sucommands:")
|
fmt.Println("Available sucommands:")
|
||||||
fmt.Println("ectl version | Show enit version")
|
fmt.Println("ectl version | Show enit version")
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
module enit
|
module enit
|
||||||
|
|
||||||
go 1.23.4
|
go 1.23.4
|
||||||
|
|
||||||
|
require golang.org/x/sys v0.31.0
|
||||||
|
@ -1,4 +1,2 @@
|
|||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
@ -75,43 +74,45 @@ func setProcessName() error {
|
|||||||
func mountVirtualFilesystems() {
|
func mountVirtualFilesystems() {
|
||||||
fmt.Print("Mounting virtual filesystems... ")
|
fmt.Print("Mounting virtual filesystems... ")
|
||||||
|
|
||||||
commonFlags := uintptr(0 | syscall.MS_NOSUID | syscall.MS_RELATIME)
|
commonOptions := "rw,nosuid,relatime"
|
||||||
|
|
||||||
// Mount /proc
|
// Mount /proc
|
||||||
if err := syscall.Mount("proc", "/proc", "proc", commonFlags|syscall.MS_NODEV|syscall.MS_NOEXEC|syscall.MS_REMOUNT, ""); err != nil {
|
if err := mount("proc", "/proc", "proc", commonOptions+",nodev,noexec", false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount /sys
|
// Mount /sys
|
||||||
if err := syscall.Mount("sys", "/sys", "sysfs", commonFlags|syscall.MS_NODEV|syscall.MS_NOEXEC|syscall.MS_REMOUNT, ""); err != nil {
|
if err := mount("sys", "/sys", "sysfs", commonOptions+",nodev,noexec", false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount /dev
|
// Mount /dev
|
||||||
if err := syscall.Mount("dev", "/dev", "devtmpfs", commonFlags|syscall.MS_REMOUNT, "mode=755,inode64"); err != nil {
|
if err := mount("dev", "/dev", "devtmpfs", commonOptions+",mode=755,inode64", false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount /run
|
// Mount /run
|
||||||
if err := syscall.Mount("run", "/run", "tmpfs", commonFlags|syscall.MS_NODEV|syscall.MS_REMOUNT, "mode=755,inode64"); err != nil {
|
if err := mount("run", "/run", "tmpfs", commonOptions+",nodev,mode=755,inode64", false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount /dev/pts
|
// Mount /dev/pts
|
||||||
if err := os.Mkdir("/dev/pts", 0755); err != nil && !errors.Is(err, os.ErrExist) {
|
if err := mount("devpts", "/dev/pts", "devpts", commonOptions+",gid=5,mode=620,ptmxmode=000", true); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := syscall.Mount("devpts", "/dev/pts", "devpts", commonFlags, "gid=5,mode=620,ptmxmode=000"); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount /dev/shm
|
// Mount /dev/shm
|
||||||
if err := os.Mkdir("/dev/shm", 0755); err != nil && !errors.Is(err, os.ErrExist) {
|
if err := mount("shm", "/dev/shm", "tmpfs", commonOptions+",nodev,inode64", true); err != nil {
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
if err := syscall.Mount("shm", "/dev/shm", "tmpfs", commonFlags|syscall.MS_NODEV, "inode64"); err != nil {
|
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount securityfs
|
// Mount securityfs
|
||||||
if err := syscall.Mount("securityfs", "/sys/kernel/security", "securityfs", commonFlags, ""); err != nil {
|
if err := mount("securityfs", "/sys/kernel/security", "securityfs", commonOptions, false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount cgroups v2
|
// Mount cgroups v2
|
||||||
if err := syscall.Mount("cgroup2", "/sys/fs/cgroup", "cgroup2", commonFlags|syscall.MS_NOEXEC, ""); err != nil {
|
if err := mount("cgroup2", "/sys/fs/cgroup", "cgroup2", commonOptions+",noexec,nsdelegate,memory_recursiveprot", false); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,12 +120,9 @@ func mountVirtualFilesystems() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mountFilesystems() {
|
func mountFilesystems() {
|
||||||
fmt.Print("Mounting filesystems... ")
|
fmt.Print("Mounting fstab entries... ")
|
||||||
|
|
||||||
cmd := exec.Command("/bin/mount", "-a")
|
if err := mountFstabEntries(); err != nil {
|
||||||
err := cmd.Run()
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Println("Could not mount fstab entries!")
|
log.Println("Could not mount fstab entries!")
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
141
cmd/enit/mount.go
Normal file
141
cmd/enit/mount.go
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
"os"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
var flagsEquivalence = map[string]uintptr{
|
||||||
|
"dirsync": unix.MS_DIRSYNC,
|
||||||
|
"lazytime": unix.MS_LAZYTIME,
|
||||||
|
"noatime": unix.MS_NOATIME,
|
||||||
|
"nodev": unix.MS_NODEV,
|
||||||
|
"nodiratime": unix.MS_NODIRATIME,
|
||||||
|
"noexec": unix.MS_NOEXEC,
|
||||||
|
"nosuid": unix.MS_NOSUID,
|
||||||
|
"ro": unix.MS_RDONLY,
|
||||||
|
"rw": 0,
|
||||||
|
"relatime": unix.MS_RELATIME,
|
||||||
|
"silent": unix.MS_SILENT,
|
||||||
|
"strictatime": unix.MS_STRICTATIME,
|
||||||
|
"sync": unix.MS_SYNCHRONOUS,
|
||||||
|
"defaults": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Split string flags to mount flags and mount data
|
||||||
|
func convertMountOptions(options string) (flags []uintptr, data string) {
|
||||||
|
for _, flag := range strings.Split(options, ",") {
|
||||||
|
if unixFlag, ok := flagsEquivalence[flag]; ok {
|
||||||
|
flags = append(flags, unixFlag)
|
||||||
|
} else {
|
||||||
|
if data == "" {
|
||||||
|
data = flag
|
||||||
|
} else {
|
||||||
|
data += "," + flag
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags, data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Combine a unix flag slice or array into a single uintptr
|
||||||
|
func combineUnixFlags(flagsSlice []uintptr) (flags uintptr) {
|
||||||
|
flags = 0
|
||||||
|
for _, flag := range flagsSlice {
|
||||||
|
flags |= flag
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check whether a certain path is a mountpoint
|
||||||
|
func isMountpoint(mountpoint string) bool {
|
||||||
|
if mountpoint != "/" {
|
||||||
|
mountpoint = strings.TrimRight(mountpoint, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := os.Stat("/proc/mounts"); err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := os.ReadFile("/proc/mounts")
|
||||||
|
if err != nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(bytes), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.Split(line, " ")[1] == mountpoint {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func mount(source, target, fstype string, options string, mkdir bool) error {
|
||||||
|
flags, data := convertMountOptions(options)
|
||||||
|
|
||||||
|
if isMountpoint(target) && !slices.Contains(flags, unix.MS_REMOUNT) {
|
||||||
|
flags = append(flags, unix.MS_REMOUNT)
|
||||||
|
}
|
||||||
|
|
||||||
|
if mkdir {
|
||||||
|
err := os.MkdirAll(target, 0755)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Mount(source, target, fstype, combineUnixFlags(flags), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mountFstabEntries() error {
|
||||||
|
if _, err := os.Stat("/etc/fstab"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := os.ReadFile("/etc/fstab")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, line := range strings.Split(string(bytes), "\n") {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if strings.HasPrefix(line, "#") || line == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
source := strings.Split(line, " ")[0]
|
||||||
|
target := strings.Split(line, " ")[1]
|
||||||
|
fstype := strings.Split(line, " ")[2]
|
||||||
|
options := strings.Split(line, " ")[3]
|
||||||
|
|
||||||
|
flags, data := convertMountOptions(options)
|
||||||
|
|
||||||
|
if slices.Contains(strings.Split(data, ","), "noauto") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isMountpoint(target) && !slices.Contains(flags, unix.MS_REMOUNT) {
|
||||||
|
flags = append(flags, unix.MS_REMOUNT)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := unix.Mount(source, target, fstype, combineUnixFlags(flags), data); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user