NimD now checks if another instance is running before starting up

This commit is contained in:
Mattia Giambirtone 2022-03-12 17:22:40 +01:00
parent e34e48f87c
commit 99fd4171ed
6 changed files with 61 additions and 13 deletions

View File

@ -121,4 +121,5 @@ sigtermDelay = 90 # Delay (seconds) that nimd will wa
## Testing NimD
NimD is not quite ready for production yet, but in the `scripts` folder you can find a few simple bash scripts to test NimD
in a minimal Alpine Linux VM using QEMU.
in a minimal Alpine Linux VM using QEMU. Note that due to weirdness in how stdout is handled on the VGA port, the VM will use
the serial port (ttyS0) as output by default (you can change this in the kernel parameters)

View File

@ -1,7 +1,10 @@
nim -o:rootfs/bin/nimd -d:release --gc:orc --opt:size --passL:"-static" compile src/main.nim
nim -o:rootfs/bin/nimdown -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/poweroff.nim
nim -o:rootfs/bin/nimhalt -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/halt.nim
nim -o:rootfs/bin/nimreboot -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/reboot.nim
# Build the environment
mkdir -p rootfs/etc/nimd
cp nimd.conf rootfs/etc/nimd/nimd.conf
./boot.sh --kernel vmlinuz-linux --initrd initrd-linux.img --memory 1G --build
nim -o:rootfs/bin/nimd -d:release --gc:orc --opt:size --passL:"-static" compile src/main.nim
nim -o:rootfs/bin/halt -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/halt.nim
nim -o:rootfs/bin/reboot -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/reboot.nim
nim -o:rootfs/bin/poweroff -d:release --gc:orc --opt:size --passL:"-static" compile src/programs/poweroff.nim
# Start the VM
./scripts/boot.sh --kernel vmlinuz-linux --initrd initrd-linux.img --memory 1G --build

View File

@ -1 +1 @@
./boot.sh --kernel vmlinuz-linux --initrd initrd-linux.img --memory 1G
./scripts/boot.sh --kernel vmlinuz-linux --initrd initrd-linux.img --memory 1G

View File

@ -52,6 +52,7 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
# - 'h' -> halt
# - 's' -> Services-related operations (start, stop, get status, etc.)
# - 'l' -> Reload in-memory configuration
# - 'c' -> Check NimD status (returns "1" if up)
case opType:
of "p":
logger.info("Received shutdown request")
@ -63,11 +64,14 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
logger.info("Received halt request")
halt(logger)
of "s":
logger.info("Received service request")
logger.info("Received service-related request")
# TODO: Operate on services
of "l":
logger.info("Received reload request")
mainLoop(logger, parseConfig(logger, "/etc/nimd/nimd.conf"), startServices=false)
of "c":
logger.info("Received check request, responding")
clientSocket.send("1")
else:
logger.warning(&"Received unknown operation type '{opType}' via control socket, ignoring it")
discard

View File

@ -119,7 +119,6 @@ proc nimDExit*(logger: Logger, code: int, emerg: bool = true) =
logger.info("Terminating child processes with SIGKILL")
discard posix.kill(-1, SIGKILL)
logger.warning("Shutdown procedure complete, NimD is exiting")
quit(-1)
proc reboot*(logger: Logger) =

View File

@ -14,6 +14,7 @@
import parseopt
import strformat
import posix
import net
import os
# NimD's own stuff
@ -68,10 +69,51 @@ proc addStuff =
addService(shell)
proc checkControlSocket(logger: Logger, config: NimDConfig): bool =
## Performs some startup checks on nim's control
## socket
result = true
var stat_result: Stat
if posix.stat(cstring(config.sock), stat_result) == -1:
logger.warning(&"Could not stat() {config.sock}, assuming NimD instance isn't running")
# I stole this from /usr/lib/python3.10/stat.py
elif (int(stat_result.st_mode) and 0o170000) != 0o140000:
logger.fatal(&"{config.sock} exists and is not a socket")
result = false
elif dirExists(config.sock):
logger.info("Control socket path is a directory, appending nimd.sock to it")
config.sock = config.sock.joinPath("nimd.sock")
else:
logger.debug("Trying to reach current NimD instance")
var sock = newSocket(Domain.AF_UNIX, SockType.SOCK_STREAM, Protocol.IPPROTO_IP)
try:
sock.connectUnix(config.sock)
logger.info("Control socket already exists, trying to reach current NimD instance")
except OSError:
logger.warning(&"Could not connect to control socket at {config.sock} ({getCurrentExceptionMsg()}), assuming NimD instance isn't running")
try:
removeFile(config.sock)
except OSError:
logger.warning(&"Could not delete dangling control socket at {config.sock} ({getCurrentExceptionMsg()})")
if sock.trySend("c"):
try:
if sock.recv(1, timeout=5) == "1":
logger.error("Another NimD instance is running! Exiting")
result = false
except OSError:
logger.warning(&"Could not read from control socket at {config.sock} ({getCurrentExceptionMsg()}), assuming NimD instance isn't running")
except TimeoutError:
logger.warning(&"Could not read from control socket at {config.sock} ({getCurrentExceptionMsg()}), assuming NimD instance isn't running")
else:
logger.fatal(&"Could not write on control socket at {config.sock}")
result = false
proc main(logger: Logger, config: NimDConfig) =
## NimD's entry point and setup
## function
if not checkControlSocket(logger, config):
return
logger.debug(&"Setting log file to '{config.logFile}'")
setLogFile(file=config.logFile)
logger.debug("Starting NimD: A minimal, self-contained, dependency-based Linux init system written in Nim")
@ -174,7 +216,6 @@ when isMainModule:
else:
echo "Usage: nimd [options]"
quit(EINVAL) # EINVAL - Invalid argument
setStdIoUnbuffered() # Colors don't work otherwise!
try:
main(logger, parseConfig(logger, "/etc/nimd/nimd.conf"))