From bd7d4e19744ee0178b491a38644c674b26ad92fa Mon Sep 17 00:00:00 2001 From: Nocturn9x Date: Thu, 2 Dec 2021 23:16:16 +0100 Subject: [PATCH] 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 --- .dockerignore | 3 +++ Dockerfile | 1 + src/core/mainloop.nim | 7 +++--- src/main.nim | 5 +++- src/util/disks.nim | 16 +++--------- src/util/misc.nim | 57 +++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 70 insertions(+), 19 deletions(-) diff --git a/.dockerignore b/.dockerignore index e69de29..ee5add9 100644 --- a/.dockerignore +++ b/.dockerignore @@ -0,0 +1,3 @@ +.git +nimd +src/main diff --git a/Dockerfile b/Dockerfile index eec50ad..15fd7a9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -6,6 +6,7 @@ WORKDIR /code # Removes any already existing binary so that when compilation fails the container stops RUN rm -f /code/nimd 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 cp /code/nimd /sbin/nimd diff --git a/src/core/mainloop.nim b/src/core/mainloop.nim index 5a60237..63b3d48 100644 --- a/src/core/mainloop.nim +++ b/src/core/mainloop.nim @@ -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()}") nimDExit(logger, 131) logger.info("Disks mounted") + logger.debug("Calling sync() just in case") + doSync(logger) logger.info("Setting hostname") logger.debug(&"Hostname was set to '{setHostname(logger)}'") + logger.info("Creating symlinks") + createSymlinks(logger) logger.info("Processing boot runlevel") # TODO logger.info("Processing default runlevel") @@ -46,9 +50,6 @@ proc mainLoop*(logger: Logger, mountDisks: bool = true, fstab: string = "/etc/fs try: # TODO 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: logger.critical(&"A critical error has occurred while running, restarting the mainloop! Error -> {getCurrentExceptionMsg()}") # We *absolutely* cannot die diff --git a/src/main.nim b/src/main.nim index e75d120..bdd969d 100644 --- a/src/main.nim +++ b/src/main.nim @@ -37,11 +37,14 @@ proc main(logger: Logger) = logger.fatal(&"NimD must run as root, but current user id is {uid}") quit(EPERM) # EPERM - Operation not permitted 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 # Can't capture local variables because this implicitly generates # a noconv procedure 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") mainLoop(logger) diff --git a/src/util/disks.nim b/src/util/disks.nim index 97a20d0..88f5036 100644 --- a/src/util/disks.nim +++ b/src/util/disks.nim @@ -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 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 = ## Returns true if a disk is already mounted. If expand is true, ## 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") continue logger.debug(&"Unmounting filesystem {entry.source} ({entry.filesystemtype}) from {entry.target}") - logger.trace(&"Calling umount2('{entry.target}', MNT_DETACH)") - retcode = umount2(entry.target, 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(&"Calling umount2('{entry.source}', MNT_DETACH)") + retcode = umount2(entry.source, 2) # 2 = MNT_DETACH - Since we're shutting down, we need the disks to be *gone*! + logger.trace(&"umount2('{entry.source}', MNT_DETACH) returned {retcode}") if retcode == -1: logger.error(&"Unmounting disk {entry.source} from {entry.target} has failed with error {posix.errno}: {posix.strerror(posix.errno)}") # Resets the error code diff --git a/src/util/misc.nim b/src/util/misc.nim index 2e1dc9d..02f51b8 100644 --- a/src/util/misc.nim +++ b/src/util/misc.nim @@ -17,16 +17,45 @@ import os import strformat import strutils +import syscall 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)] = @[] +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) = shutdownHandlers.add(handler) @@ -83,7 +112,31 @@ proc setHostname*(logger: Logger): string = 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 strsignal*(sig: cint): cstring {.header:"string.h", importc.} +proc strsignal*(sig: cint): cstring {.header: "string.h", importc.}