From 7b7b675fef3fa823a0bb8f812eac66d0c46fde09 Mon Sep 17 00:00:00 2001 From: Nocturn9x Date: Tue, 18 Oct 2022 09:32:44 +0200 Subject: [PATCH] Minor changes and additions --- scripts/boot.sh | 4 ++-- scripts/start.sh | 19 ++++++++++++++++++- src/core/control.nim | 15 +++++++++++---- src/core/fs.nim | 17 +---------------- src/core/mainloop.nim | 6 +++--- src/core/services.nim | 3 +-- src/main.nim | 2 +- src/programs/halt.nim | 11 ++++++++--- src/programs/poweroff.nim | 11 ++++++++--- src/programs/reboot.nim | 11 ++++++++--- src/programs/reload.nim | 30 ++++++++++++++++++++++++++++++ src/util/cffi.nim | 30 ++++++++++++++++++++++++++++++ src/util/logging.nim | 7 +++---- src/util/misc.nim | 20 ++++++++++---------- 14 files changed, 134 insertions(+), 52 deletions(-) create mode 100644 src/programs/reload.nim create mode 100644 src/util/cffi.nim diff --git a/scripts/boot.sh b/scripts/boot.sh index fc9ede1..6d7e253 100755 --- a/scripts/boot.sh +++ b/scripts/boot.sh @@ -107,9 +107,9 @@ then fi qemumem='' -if ! [[ $memory -eq "" ]] +if ! [[ ${memory::-1} -eq "" ]] then qemumem="-m ${memory}" fi -qemu-system-x86_64 -net nic,model=virtio,netdev=user.0 -netdev user,id=user.0 -drive file=vm.qcow2,if=virtio -enable-kvm -kernel ${kernel} -initrd ${initrd} ${qemumem} -append 'root=/dev/vda1 rw quiet modules=ext4 console=ttyS0 init=/bin/nimd' +qemu-system-x86_64 -net nic,model=virtio,netdev=user.0 -netdev user,id=user.0 -drive file=vm.qcow2,if=virtio -enable-kvm -kernel ${kernel} -initrd ${initrd} ${qemumem} -append 'root=/dev/vda1 rw quiet modules=ext4 init=/sbin/nimd console=ttyS0 -- -X' diff --git a/scripts/start.sh b/scripts/start.sh index 4bb6653..235df0e 100755 --- a/scripts/start.sh +++ b/scripts/start.sh @@ -1 +1,18 @@ -./scripts/boot.sh --kernel vmlinuz-linux --initrd initrd-linux.img --memory 1G +trap 'catch' ERR + +catch() { + echo "Build failed" + exit +} +echo "Compiling NimD" +nim -d:release -d:danger --passC:"-O3 -flto" --opt:size --hints:off --gc:orc --passL:"-static" -o:rootfs/sbin/nimd c src/main +echo "Compiling NimD subprograms" +nim -d:release -d:danger --passC:"-O3 -flto" --opt:size --hints:off --gc:orc --passL:"-static" -o:rootfs/sbin/poweroff c src/programs/poweroff +nim -d:release -d:danger --passC:"-O3 -flto" --opt:size --hints:off --gc:orc --passL:"-static" -o:rootfs/sbin/halt c src/programs/halt +nim -d:release -d:danger --passC:"-O3 -flto" --opt:size --hints:off --gc:orc --passL:"-static" -o:rootfs/sbin/reboot c src/programs/reboot +nim -d:release -d:danger --passC:"-O3 -flto" --opt:size --hints:off --gc:orc --passL:"-static" -o:rootfs/sbin/nimd-reload c src/programs/reload +echo "Setting up directory structure" +mkdir -p rootfs/etc/nimd +cp nimd.conf rootfs/etc/nimd +echo "Building and starting VM" +./boot.sh --memory 1G --kernel vmlinuz-linux --initrd initramfs-linux.img --build \ No newline at end of file diff --git a/src/core/control.nim b/src/core/control.nim index 3e17a2c..068909c 100644 --- a/src/core/control.nim +++ b/src/core/control.nim @@ -13,24 +13,31 @@ # limitations under the License. import os import net +import posix import strformat import shutdown import ../util/logging -import ../util/misc proc initControlSocket*(logger: Logger, path: string = "/var/run/nimd.sock"): Socket = ## Initializes NimD's control socket (an unbuffered ## TCP Unix Domain Socket) binding it to the given - ## path (defaults to /var/run/nimd.sock) + ## path (defaults to /var/run/nimd.sock). The socket's + ## permissions are set to 700 so that only root can read + ## from it try: logger.info(&"Initializing control socket at '{path}'") - if exists(path): + if fileExists(path): removeFile(path) - result = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP, buffered=false) + elif dirExists(path): + removeDir(path) + result = newSocket(net.AF_UNIX, net.SOCK_STREAM, net.IPPROTO_IP, buffered=false) bindUnix(result, path) + if posix.chmod(cstring(splitPath(path).head), 700) == -1: + logger.error(&"Could not restrict access to unix socket at '{path}: {posix.strerror(posix.errno)}'") + nimDExit(logger, code=int(posix.errno)) except OSError: logger.error(&"Error when binding unix socket at '{path}': {getCurrentExceptionMsg()}") nimDExit(logger, code=int(osLastError())) \ No newline at end of file diff --git a/src/core/fs.nim b/src/core/fs.nim index 9350c5d..5dbf970 100644 --- a/src/core/fs.nim +++ b/src/core/fs.nim @@ -17,25 +17,10 @@ import strformat import posix import os -import ../util/[logging, misc] +import ../util/[logging, misc, cffi] import shutdown -# Nim wrappers around C functionality in sys/mount.h on Linux -proc mount*(source: cstring, target: cstring, fstype: cstring, - mountflags: culong, data: pointer): cint {.header: "sys/mount.h", importc.} -# Since cstrings are weak references, we need to convert nim strings to cstrings only -# when we're ready to use them and only when we're sure the underlying nim string is -# in scope, otherwise garbage collection madness happens -proc mount*(source, target, fstype: string, mountflags: uint64, data: string): int = int(mount(cstring(source), cstring(target), cstring(fstype), culong(mountflags), cstring(data))) - -proc umount*(target: cstring): cint {.header: "sys/mount.h", importc.} -proc umount2*(target: cstring, flags: cint): cint {.header: "sys/mount.h", importc.} -# These 2 wrappers silent the CStringConv warning -# (implicit conversion to 'cstring' from a non-const location) -proc umount*(target: string): int = int(umount(cstring(target))) -proc umount2*(target: string, flags: int): int = int(umount2(cstring(target), cint(flags))) - ## Our Nim API type diff --git a/src/core/mainloop.nim b/src/core/mainloop.nim index 764b4f9..00c64f1 100644 --- a/src/core/mainloop.nim +++ b/src/core/mainloop.nim @@ -28,9 +28,9 @@ 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.info("System initialization complete, idling on control socket") + logger.debug(&"Unblocking signals") + unblockSignals(logger) + logger.info("System initialization complete, idling on control socket") var opType: string try: logger.trace("Calling initControlSocket()") diff --git a/src/core/services.nim b/src/core/services.nim index a4a9db6..24ada05 100644 --- a/src/core/services.nim +++ b/src/core/services.nim @@ -22,10 +22,9 @@ import shlex import os -proc strsignal(sig: cint): cstring {.header: "string.h", importc.} - import ../util/logging +import ../util/cffi type diff --git a/src/main.nim b/src/main.nim index 06bb731..da941d8 100644 --- a/src/main.nim +++ b/src/main.nim @@ -18,7 +18,7 @@ import net import os # NimD's own stuff -import util/[logging, constants, misc, config] +import util/[logging, constants, misc, config, cffi] import core/[mainloop, fs, shutdown, services] diff --git a/src/programs/halt.nim b/src/programs/halt.nim index 2e9c211..542110d 100644 --- a/src/programs/halt.nim +++ b/src/programs/halt.nim @@ -11,7 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import os import net +import strformat when isMainModule: @@ -19,7 +21,10 @@ when isMainModule: try: sock.connectUnix("/var/run/nimd.sock") except OSError: - echo getCurrentExceptionMsg() - quit(-1) - echo sock.trySend("r") + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" + quit(int(osLastError())) + if sock.trySend("h"): + echo "Halting" + else: + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" sock.close() diff --git a/src/programs/poweroff.nim b/src/programs/poweroff.nim index 16f4ec6..4be542e 100644 --- a/src/programs/poweroff.nim +++ b/src/programs/poweroff.nim @@ -11,7 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import os import net +import strformat when isMainModule: @@ -19,7 +21,10 @@ when isMainModule: try: sock.connectUnix("/var/run/nimd.sock") except OSError: - echo getCurrentExceptionMsg() - quit(-1) - echo sock.trySend("p") + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" + quit(int(osLastError())) + if sock.trySend("p"): + echo "Shutting down" + else: + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" sock.close() diff --git a/src/programs/reboot.nim b/src/programs/reboot.nim index 2e9c211..3848f44 100644 --- a/src/programs/reboot.nim +++ b/src/programs/reboot.nim @@ -11,7 +11,9 @@ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. +import os import net +import strformat when isMainModule: @@ -19,7 +21,10 @@ when isMainModule: try: sock.connectUnix("/var/run/nimd.sock") except OSError: - echo getCurrentExceptionMsg() - quit(-1) - echo sock.trySend("r") + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" + quit(int(osLastError())) + if sock.trySend("r"): + echo "Rebooting" + else: + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" sock.close() diff --git a/src/programs/reload.nim b/src/programs/reload.nim new file mode 100644 index 0000000..4633031 --- /dev/null +++ b/src/programs/reload.nim @@ -0,0 +1,30 @@ +# Copyright 2021 Mattia Giambirtone & All Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import net +import strformat + + +when isMainModule: + var sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP) + try: + sock.connectUnix("/var/run/nimd.sock") + except OSError: + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" + quit(int(osLastError())) + if sock.trySend("l"): + echo "Reloading" + else: + echo &"Communication with NimD control socket failed: {osErrorMsg(osLastError())}" + sock.close() \ No newline at end of file diff --git a/src/util/cffi.nim b/src/util/cffi.nim new file mode 100644 index 0000000..a795c37 --- /dev/null +++ b/src/util/cffi.nim @@ -0,0 +1,30 @@ +# Copyright 2021 Mattia Giambirtone & All Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +proc strsignal*(sig: cint): cstring {.header: "string.h", importc.} +proc dup3*(a1, a2, a3: cint): cint {.importc.} +# Nim wrappers around C functionality in sys/mount.h on Linux +proc mount*(source: cstring, target: cstring, fstype: cstring, + mountflags: culong, data: pointer): cint {.header: "sys/mount.h", importc.} +# Since cstrings are weak references, we need to convert nim strings to cstrings only +# when we're ready to use them and only when we're sure the underlying nim string is +# in scope, otherwise garbage collection madness happens +proc mount*(source, target, fstype: string, mountflags: uint64, data: string): int = int(mount(cstring(source), cstring(target), cstring(fstype), culong(mountflags), cstring(data))) + +proc umount*(target: cstring): cint {.header: "sys/mount.h", importc.} +proc umount2*(target: cstring, flags: cint): cint {.header: "sys/mount.h", importc.} +# These 2 wrappers silent the CStringConv warning +# (implicit conversion to 'cstring' from a non-const location) +proc umount*(target: string): int = int(umount(cstring(target))) +proc umount2*(target: string, flags: int): int = int(umount2(cstring(target), cint(flags))) diff --git a/src/util/logging.nim b/src/util/logging.nim index a53667b..9f3b52e 100644 --- a/src/util/logging.nim +++ b/src/util/logging.nim @@ -19,6 +19,8 @@ import posix import times +import cffi + type LogLevel* = enum Trace = 0, @@ -39,9 +41,6 @@ type handlers*: seq[LogHandler] -proc dup3(a1, a2, a3: cint): cint {.importc.} - - var defaultLevel = LogLevel.Info var logFile = "/var/log/nimd" var logToFileOnly: bool = false @@ -215,7 +214,7 @@ proc switchToConsole*(self: Logger) = self.addHandler(createHandler(logFatalStderr, LogLevel.Fatal)) -proc getDefaultLogger*(): Logger = +proc getDefaultLogger*: Logger = ## Gets a simple logger with level set ## to LogLevel.Info and one handler per ## level that writes the given message to the diff --git a/src/util/misc.nim b/src/util/misc.nim index f433fdb..2ab4f21 100644 --- a/src/util/misc.nim +++ b/src/util/misc.nim @@ -26,7 +26,6 @@ import ../core/shutdown proc sleepSeconds*(amount: SomeNumber) = sleep(int(amount * 1000)) -proc strsignal*(sig: cint): cstring {.header: "string.h", importc.} proc dummySigHandler(x: cint) {.noconv.} = discard @@ -80,15 +79,6 @@ proc reapProcess*(logger: Logger) = logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}") -proc exists*(p: string): bool = - ## Returns true if a path exists, - ## false otherwise - try: - discard getFileInfo(p) - result = true - except OSError: - result = false - proc setHostname*(logger: Logger): string = ## Sets the machine's hostname. Returns @@ -108,3 +98,13 @@ proc setHostname*(logger: Logger): string = logger.error(&"An error occurred while setting hostname -> {getCurrentExceptionMsg()}") return "" return hostname + + +proc exists*(p: string): bool = + ## Returns true if a path exists, + ## false otherwise + try: + discard getFileInfo(p) + result = true + except OSError: + result = false \ No newline at end of file