mirror of https://github.com/nocturn9x/nimd.git
NimD now checks if another instance is running before starting up
This commit is contained in:
parent
e34e48f87c
commit
99fd4171ed
|
@ -121,4 +121,5 @@ sigtermDelay = 90 # Delay (seconds) that nimd will wa
|
||||||
## Testing NimD
|
## 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
|
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)
|
|
@ -1,7 +1,10 @@
|
||||||
nim -o:rootfs/bin/nimd -d:release --gc:orc --opt:size --passL:"-static" compile src/main.nim
|
# Build the environment
|
||||||
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
|
|
||||||
mkdir -p rootfs/etc/nimd
|
mkdir -p rootfs/etc/nimd
|
||||||
cp nimd.conf rootfs/etc/nimd/nimd.conf
|
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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -28,8 +28,8 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
|
||||||
if startServices:
|
if startServices:
|
||||||
logger.info("Processing default runlevel")
|
logger.info("Processing default runlevel")
|
||||||
startServices(logger, workers=config.workers, level=Default)
|
startServices(logger, workers=config.workers, level=Default)
|
||||||
logger.debug(&"Unblocking signals")
|
logger.debug(&"Unblocking signals")
|
||||||
unblockSignals(logger)
|
unblockSignals(logger)
|
||||||
logger.info("System initialization complete, idling on control socket")
|
logger.info("System initialization complete, idling on control socket")
|
||||||
var opType: string
|
var opType: string
|
||||||
try:
|
try:
|
||||||
|
@ -52,6 +52,7 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
|
||||||
# - 'h' -> halt
|
# - 'h' -> halt
|
||||||
# - 's' -> Services-related operations (start, stop, get status, etc.)
|
# - 's' -> Services-related operations (start, stop, get status, etc.)
|
||||||
# - 'l' -> Reload in-memory configuration
|
# - 'l' -> Reload in-memory configuration
|
||||||
|
# - 'c' -> Check NimD status (returns "1" if up)
|
||||||
case opType:
|
case opType:
|
||||||
of "p":
|
of "p":
|
||||||
logger.info("Received shutdown request")
|
logger.info("Received shutdown request")
|
||||||
|
@ -63,11 +64,14 @@ proc mainLoop*(logger: Logger, config: NimDConfig, startServices: bool = true) =
|
||||||
logger.info("Received halt request")
|
logger.info("Received halt request")
|
||||||
halt(logger)
|
halt(logger)
|
||||||
of "s":
|
of "s":
|
||||||
logger.info("Received service request")
|
logger.info("Received service-related request")
|
||||||
# TODO: Operate on services
|
# TODO: Operate on services
|
||||||
of "l":
|
of "l":
|
||||||
logger.info("Received reload request")
|
logger.info("Received reload request")
|
||||||
mainLoop(logger, parseConfig(logger, "/etc/nimd/nimd.conf"), startServices=false)
|
mainLoop(logger, parseConfig(logger, "/etc/nimd/nimd.conf"), startServices=false)
|
||||||
|
of "c":
|
||||||
|
logger.info("Received check request, responding")
|
||||||
|
clientSocket.send("1")
|
||||||
else:
|
else:
|
||||||
logger.warning(&"Received unknown operation type '{opType}' via control socket, ignoring it")
|
logger.warning(&"Received unknown operation type '{opType}' via control socket, ignoring it")
|
||||||
discard
|
discard
|
||||||
|
|
|
@ -119,7 +119,6 @@ proc nimDExit*(logger: Logger, code: int, emerg: bool = true) =
|
||||||
logger.info("Terminating child processes with SIGKILL")
|
logger.info("Terminating child processes with SIGKILL")
|
||||||
discard posix.kill(-1, SIGKILL)
|
discard posix.kill(-1, SIGKILL)
|
||||||
logger.warning("Shutdown procedure complete, NimD is exiting")
|
logger.warning("Shutdown procedure complete, NimD is exiting")
|
||||||
quit(-1)
|
|
||||||
|
|
||||||
|
|
||||||
proc reboot*(logger: Logger) =
|
proc reboot*(logger: Logger) =
|
||||||
|
|
45
src/main.nim
45
src/main.nim
|
@ -14,6 +14,7 @@
|
||||||
import parseopt
|
import parseopt
|
||||||
import strformat
|
import strformat
|
||||||
import posix
|
import posix
|
||||||
|
import net
|
||||||
import os
|
import os
|
||||||
|
|
||||||
# NimD's own stuff
|
# NimD's own stuff
|
||||||
|
@ -68,10 +69,51 @@ proc addStuff =
|
||||||
addService(shell)
|
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) =
|
proc main(logger: Logger, config: NimDConfig) =
|
||||||
## NimD's entry point and setup
|
## NimD's entry point and setup
|
||||||
## function
|
## function
|
||||||
|
if not checkControlSocket(logger, config):
|
||||||
|
return
|
||||||
logger.debug(&"Setting log file to '{config.logFile}'")
|
logger.debug(&"Setting log file to '{config.logFile}'")
|
||||||
setLogFile(file=config.logFile)
|
setLogFile(file=config.logFile)
|
||||||
logger.debug("Starting NimD: A minimal, self-contained, dependency-based Linux init system written in Nim")
|
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
|
quit(EINVAL) # EINVAL - Invalid argument
|
||||||
else:
|
else:
|
||||||
echo "Usage: nimd [options]"
|
echo "Usage: nimd [options]"
|
||||||
quit(EINVAL) # EINVAL - Invalid argument
|
quit(EINVAL) # EINVAL - Invalid argument
|
||||||
|
|
||||||
setStdIoUnbuffered() # Colors don't work otherwise!
|
setStdIoUnbuffered() # Colors don't work otherwise!
|
||||||
try:
|
try:
|
||||||
main(logger, parseConfig(logger, "/etc/nimd/nimd.conf"))
|
main(logger, parseConfig(logger, "/etc/nimd/nimd.conf"))
|
||||||
|
|
Loading…
Reference in New Issue