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.}