Browse Source

NimD now checks if another instance is running before starting up

main
Mattia Giambirtone 9 months ago
parent
commit
99fd4171ed
  1. 3
      README.md
  2. 13
      scripts/rebuild.sh
  3. 2
      scripts/start.sh
  4. 10
      src/core/mainloop.nim
  5. 1
      src/core/shutdown.nim
  6. 45
      src/main.nim

3
README.md

@ -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)

13
scripts/rebuild.sh

@ -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

2
scripts/start.sh

@ -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

10
src/core/mainloop.nim

@ -28,8 +28,8 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
if startServices:
logger.info("Processing default runlevel")
startServices(logger, workers=config.workers, level=Default)
logger.debug(&"Unblocking signals")
unblockSignals(logger)
logger.debug(&"Unblocking signals")
unblockSignals(logger)
logger.info("System initialization complete, idling on control socket")
var opType: string
try:
@ -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

1
src/core/shutdown.nim

@ -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) =

45
src/main.nim

@ -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")
@ -173,8 +215,7 @@ when isMainModule:
quit(EINVAL) # EINVAL - Invalid argument
else:
echo "Usage: nimd [options]"
quit(EINVAL) # EINVAL - Invalid argument
quit(EINVAL) # EINVAL - Invalid argument
setStdIoUnbuffered() # Colors don't work otherwise!
try:
main(logger, parseConfig(logger, "/etc/nimd/nimd.conf"))

Loading…
Cancel
Save