Added sync() system call for testing purposes. Added SIGSTP signal handler. Removed CtrlCException. Added dummy SIGCHLD handler for future process reaping. NimD now creates some symlinks at startup so Linux ports of BSD software don't crash. Moved exists procedure to misc module. UnmountAllDisks now unmounts the source instead of the target. Other minor fixes and typos

This commit is contained in:
Nocturn9x 2021-12-02 23:16:16 +01:00
parent 6ef157baa0
commit bd7d4e1974
6 changed files with 70 additions and 19 deletions

View File

@ -0,0 +1,3 @@
.git
nimd
src/main

View File

@ -6,6 +6,7 @@ WORKDIR /code
# Removes any already existing binary so that when compilation fails the container stops # Removes any already existing binary so that when compilation fails the container stops
RUN rm -f /code/nimd RUN rm -f /code/nimd
RUN rm -f /code/main RUN rm -f /code/main
RUN nimble install syscall -y
RUN nim -d:release --opt:size --passL:"-static" --gc:orc -d:useMalloc c -o:nimd src/main RUN nim -d:release --opt:size --passL:"-static" --gc:orc -d:useMalloc c -o:nimd src/main
RUN cp /code/nimd /sbin/nimd RUN cp /code/nimd /sbin/nimd

View File

@ -35,8 +35,12 @@ proc mainLoop*(logger: Logger, mountDisks: bool = true, fstab: string = "/etc/fs
logger.fatal(&"A fatal error has occurred while preparing filesystem, booting cannot continue. Error -> {getCurrentExceptionMsg()}") logger.fatal(&"A fatal error has occurred while preparing filesystem, booting cannot continue. Error -> {getCurrentExceptionMsg()}")
nimDExit(logger, 131) nimDExit(logger, 131)
logger.info("Disks mounted") logger.info("Disks mounted")
logger.debug("Calling sync() just in case")
doSync(logger)
logger.info("Setting hostname") logger.info("Setting hostname")
logger.debug(&"Hostname was set to '{setHostname(logger)}'") logger.debug(&"Hostname was set to '{setHostname(logger)}'")
logger.info("Creating symlinks")
createSymlinks(logger)
logger.info("Processing boot runlevel") logger.info("Processing boot runlevel")
# TODO # TODO
logger.info("Processing default runlevel") logger.info("Processing default runlevel")
@ -46,9 +50,6 @@ proc mainLoop*(logger: Logger, mountDisks: bool = true, fstab: string = "/etc/fs
try: try:
# TODO # TODO
sleepSeconds(5) sleepSeconds(5)
except CtrlCException:
logger.warning("Main process received SIGINT: exiting") # TODO: Ignore this once we stop testing on our local machines lol
nimDExit(logger, 130, emerg=false) # 130 - Interrupted by SIGINT
except: except:
logger.critical(&"A critical error has occurred while running, restarting the mainloop! Error -> {getCurrentExceptionMsg()}") logger.critical(&"A critical error has occurred while running, restarting the mainloop! Error -> {getCurrentExceptionMsg()}")
# We *absolutely* cannot die # We *absolutely* cannot die

View File

@ -37,11 +37,14 @@ proc main(logger: Logger) =
logger.fatal(&"NimD must run as root, but current user id is {uid}") logger.fatal(&"NimD must run as root, but current user id is {uid}")
quit(EPERM) # EPERM - Operation not permitted quit(EPERM) # EPERM - Operation not permitted
logger.debug("Setting up dummy signal handlers") logger.debug("Setting up dummy signal handlers")
onSignal(SIGABRT, SIGALRM, SIGHUP, SIGILL, SIGKILL, SIGQUIT, SIGSTOP, SIGSEGV, onSignal(SIGABRT, SIGALRM, SIGHUP, SIGILL, SIGKILL, SIGQUIT, SIGSTOP, SIGSEGV, SIGTSTP,
SIGTRAP, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, 6, SIGFPE, SIGBUS, SIGURG, SIGINT): # 6 is SIGIOT SIGTRAP, SIGTERM, SIGPIPE, SIGUSR1, SIGUSR2, 6, SIGFPE, SIGBUS, SIGURG, SIGINT): # 6 is SIGIOT
# Can't capture local variables because this implicitly generates # Can't capture local variables because this implicitly generates
# a noconv procedure # a noconv procedure
getDefaultLogger().warning(&"Ignoring signal {sig} ({strsignal(sig)})") # Nim injects the variable "sig" into the scope. Gotta love those macros getDefaultLogger().warning(&"Ignoring signal {sig} ({strsignal(sig)})") # Nim injects the variable "sig" into the scope. Gotta love those macros
logger.debug("Setting up SIGCHLD signal handler")
onSignal(SIGCHLD):
reapProcess(getDefaultLogger())
logger.debug("Starting uninterruptible mainloop") logger.debug("Starting uninterruptible mainloop")
mainLoop(logger) mainLoop(logger)

View File

@ -115,16 +115,6 @@ proc umount*(target: string): int = int(umount(cstring(target)))
proc umount2*(target: string, flags: int): int = int(umount2(cstring(target), cint(flags))) proc umount2*(target: string, flags: int): int = int(umount2(cstring(target), cint(flags)))
proc exists(p: string): bool =
# Checks if a path exists. Thanks
# araq :)
try:
discard getFileInfo(p)
result = true
except OSError:
result = false
proc checkDisksIsMounted(search: tuple[source, target, filesystemtype: string, mountflags: uint64, data: string, dump, pass: uint8], expand: bool = false): bool = proc checkDisksIsMounted(search: tuple[source, target, filesystemtype: string, mountflags: uint64, data: string, dump, pass: uint8], expand: bool = false): bool =
## Returns true if a disk is already mounted. If expand is true, ## Returns true if a disk is already mounted. If expand is true,
## symlinks are expanded and checked instead of doing a simple ## symlinks are expanded and checked instead of doing a simple
@ -211,9 +201,9 @@ proc unmountAllDisks*(logger: Logger, code: int) =
logger.debug(&"Skipping unmounting filesystem {entry.source} ({entry.filesystemtype}) from {entry.target}: not mounted") logger.debug(&"Skipping unmounting filesystem {entry.source} ({entry.filesystemtype}) from {entry.target}: not mounted")
continue continue
logger.debug(&"Unmounting filesystem {entry.source} ({entry.filesystemtype}) from {entry.target}") logger.debug(&"Unmounting filesystem {entry.source} ({entry.filesystemtype}) from {entry.target}")
logger.trace(&"Calling umount2('{entry.target}', MNT_DETACH)") logger.trace(&"Calling umount2('{entry.source}', MNT_DETACH)")
retcode = umount2(entry.target, 2) # 2 = MNT_DETACH - Since we're shutting down, we need the disks to be *gone*! retcode = umount2(entry.source, 2) # 2 = MNT_DETACH - Since we're shutting down, we need the disks to be *gone*!
logger.trace(&"umount2('{entry.target}', MNT_DETACH) returned {retcode}") logger.trace(&"umount2('{entry.source}', MNT_DETACH) returned {retcode}")
if retcode == -1: if retcode == -1:
logger.error(&"Unmounting disk {entry.source} from {entry.target} has failed with error {posix.errno}: {posix.strerror(posix.errno)}") logger.error(&"Unmounting disk {entry.source} from {entry.target} has failed with error {posix.errno}: {posix.strerror(posix.errno)}")
# Resets the error code # Resets the error code

View File

@ -17,16 +17,45 @@
import os import os
import strformat import strformat
import strutils import strutils
import syscall
import logging import logging
type CtrlCException* = object of CatchableError # Note: This will work reliably only with absolute paths. Use with care
const symlinks: array[7, tuple[dest, source: string]] = [
(dest: "/dev/fd", source: "/proc/self/fd"),
(dest: "/dev/fd/0", source: "/proc/self/fd/0"),
(dest: "/dev/fd/1", source: "/proc/self/fd/1"),
(dest: "/dev/fd/2", source: "/proc/self/fd/2"),
(dest: "/dev/std/in", source: "/proc/self/fd/0"),
(dest: "/dev/std/out", source: "/proc/self/fd/1"),
(dest: "/dev/std/err", source: "/proc/self/fd/2"),
]
var shutdownHandlers: seq[proc (logger: Logger, code: int)] = @[] var shutdownHandlers: seq[proc (logger: Logger, code: int)] = @[]
proc doSync*(logger: Logger) =
logger.debug(&"Calling sync() syscall has returned {syscall(SYNC)}")
proc reapProcess*(logger: Logger) =
logger.debug("Handling SIGCHLD")
# TODO
proc exists*(p: string): bool =
# Checks if a path exists. Thanks
# araq :)
try:
discard getFileInfo(p)
result = true
except OSError:
result = false
proc addShutdownHandler*(handler: proc (logger: Logger, code: int), logger: Logger) = proc addShutdownHandler*(handler: proc (logger: Logger, code: int), logger: Logger) =
shutdownHandlers.add(handler) shutdownHandlers.add(handler)
@ -83,7 +112,31 @@ proc setHostname*(logger: Logger): string =
return hostname return hostname
proc createSymlinks*(logger: Logger) =
## Creates a set of symlinks needed
## by stuff like Linux ports of BSD
## software
for sym in symlinks:
try:
if not exists(sym.source):
logger.warning(&"Skipping creation of symbolic link from {sym.dest} to {sym.source}: destination does not exist")
continue
elif exists(sym.dest):
if symlinkExists(sym.dest) and sameFile(expandSymlink(sym.dest), sym.source):
logger.debug(&"Skipping creation of symbolic link from {sym.dest} to {sym.source}: link already exists")
elif symlinkExists(sym.dest) and not sameFile(expandSymlink(sym.dest), sym.source):
logger.warning(&"Attempted to create symbolic link from {sym.dest} to {sym.source}, but link already exists and points to {expandSymlink(sym.dest)}")
continue
logger.debug(&"Creating symbolic link from {sym.source} to {sym.dest}")
createSymlink(sym.dest, sym.source)
except:
logger.error(&"Failed to create symbolic link from {sym.dest} to {sym.source}: {getCurrentExceptionMsg()}")
proc createDirectories*(logger: Logger) =
## Creates
proc sleepSeconds*(amount: SomeInteger) = sleep(amount * 1000) proc sleepSeconds*(amount: SomeInteger) = sleep(amount * 1000)
proc strsignal*(sig: cint): cstring {.header:"string.h", importc.} proc strsignal*(sig: cint): cstring {.header: "string.h", importc.}