Fixed issues with fcntl and replaced file locking with a duplicate of stderr in O_APPEND mode. Added basic utilities for shutdown/reboot/halt

This commit is contained in:
nocturn9x 2022-01-04 12:00:18 +01:00
parent a93c3c6fd0
commit d41e67f413
6 changed files with 114 additions and 66 deletions

View File

@ -23,12 +23,13 @@ import shutdown
proc mainLoop*(logger: Logger, workers: int = 1) =
proc mainLoop*(logger: Logger, workers: int = 1, startServices: bool = true) =
## NimD's main execution loop
logger.info("Processing default runlevel")
startServices(logger, workers=workers, level=Default)
logger.debug(&"Unblocking signals")
unblockSignals(logger)
if startServices:
logger.info("Processing default runlevel")
startServices(logger, workers=workers, level=Default)
logger.debug(&"Unblocking signals")
unblockSignals(logger)
logger.info("System initialization complete, idling on control socket")
var opType: string
try:
@ -37,10 +38,12 @@ proc mainLoop*(logger: Logger, workers: int = 1) =
serverSocket.listen(5)
var clientSocket = newSocket(AF_INET, SOCK_STREAM, IPPROTO_TCP)
logger.switchToFile()
logger.debug("Entering accept() loop")
while true:
serverSocket.accept(clientSocket)
logger.debug(&"Received connection on control socket")
if clientSocket.recv(opType, size=1) == 0:
logger.debug(&"Client has disconnected, waiting for new connection")
logger.debug(&"Client has disconnected, waiting for new connections")
continue
logger.debug(&"Received operation type '{opType}' via control socket")
# The operation type is a single byte:
@ -68,4 +71,4 @@ proc mainLoop*(logger: Logger, workers: int = 1) =
logger.critical(&"A critical error has occurred while running, restarting the mainloop in 30 seconds! Error -> {getCurrentExceptionMsg()}")
sleepSeconds(30)
# We *absolutely* cannot die
mainLoop(logger)
mainLoop(logger, startServices=false)

View File

@ -31,7 +31,7 @@ type ShutdownHandler* = ref object
body*: proc (logger: Logger, code: int)
const reboot_codes = {"poweroff": 0x4321fedc'i64, "restart": 0x01234567'i64, "halt": 0xcdef0123}.toTable()
const reboot_codes = {"poweroff": 0x4321fedc'i64, "reboot": 0x01234567'i64, "halt": 0xcdef0123}.toTable()
proc newShutdownHandler*(body: proc (logger: Logger, code: int)): ShutdownHandler =

25
src/programs/halt.nim Normal file
View File

@ -0,0 +1,25 @@
# 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 net
when isMainModule:
var sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
try:
sock.connectUnix("/var/run/nimd.sock")
except OSError:
echo getCurrentExceptionMsg()
quit(-1)
echo sock.trySend("r")
sock.close()

25
src/programs/poweroff.nim Normal file
View File

@ -0,0 +1,25 @@
# 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 net
when isMainModule:
var sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
try:
sock.connectUnix("/var/run/nimd.sock")
except OSError:
echo getCurrentExceptionMsg()
quit(-1)
echo sock.trySend("p")
sock.close()

25
src/programs/reboot.nim Normal file
View File

@ -0,0 +1,25 @@
# 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 net
when isMainModule:
var sock = newSocket(AF_UNIX, SOCK_STREAM, IPPROTO_IP)
try:
sock.connectUnix("/var/run/nimd.sock")
except OSError:
echo getCurrentExceptionMsg()
quit(-1)
echo sock.trySend("r")
sock.close()

View File

@ -38,10 +38,21 @@ type
level*: LogLevel
handlers*: seq[LogHandler]
proc dup3(a1, a2, a3: cint): cint {.importc.}
var defaultLevel = LogLevel.Info
var logFile = "/var/log/nimd"
var logToFileOnly: bool = false
## This mess is needed to make sure stderr writes are mostly atomic. Sort of
## No error handling yet. Deal with it
var customStderrFd = dup(stderr.getFileHandle())
discard dup3(stderr.getFileHandle(), customStderrFd, O_APPEND)
var customStderr: File
discard open(customStderr, customStderrFd, fmAppend)
proc log(self: Logger, level: LogLevel = defaultLevel, message: string) # Forward declaration
@ -79,132 +90,91 @@ proc log(self: Logger, level: LogLevel = defaultLevel, message: string) =
# Do NOT touch the alignment offsets or your console output and logs will look like trash
proc lockFile(logger: Logger, handle: File) =
## Locks the given file across the whole system for writing using fcntl()
if fcntl(handle.getFileHandle(), F_WRLCK) == -1:
setForegroundColor(fgRed)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} ERROR {"-":>3} ({posix.getpid():03})] Error while locking handle (code {posix.errno}, {posix.strerror(posix.errno)}): output may be mangled""")
setForegroundColor(fgDefault)
proc unlockFile(logger: Logger, handle: File) =
## Unlocks the given file across the whole system for writing using fcntl()
if fcntl(handle.getFileHandle(), F_UNLCK) == -1:
setForegroundColor(fgRed)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} ERROR {"-":>3} ({posix.getpid():03})] Error while unlocking handle (code {posix.errno}, {posix.strerror(posix.errno)}): output may be missing""")
setForegroundColor(fgDefault)
proc logTraceStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgMagenta)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} TRACE {"-":>3} ({posix.getpid():03})] {message}""")
customStderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} TRACE {"-":>3} ({posix.getpid():03})] {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logDebugStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgCyan)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} DEBUG {"-":>3} ({posix.getpid():03})] {message}""")
customStderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} DEBUG {"-":>3} ({posix.getpid():03})] {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logInfoStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgGreen)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} INFO {"-":>4} ({posix.getpid():03})] {message}""")
customStderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} INFO {"-":>4} ({posix.getpid():03})] {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logWarningStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgYellow)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} WARNING {"-":>1} ({posix.getpid():03})] {message}""")
customStderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} WARNING {"-":>1} ({posix.getpid():03})] {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logErrorStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgRed)
stderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} ERROR {"-":>3} ({posix.getpid():03})] {message}""")
customStderr.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} ERROR {"-":>3} ({posix.getpid():03})] {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logCriticalStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgYellow)
setBackgroundColor(bgRed)
stderr.write(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<4} {"-":>1} CRITICAL {"-":>2} ({posix.getpid():03})]""")
customStderr.write(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<4} {"-":>1} CRITICAL {"-":>2} ({posix.getpid():03})]""")
setBackgroundColor(bgDefault)
stderr.writeLine(&""" {message}""")
customStderr.writeLine(&""" {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logFatalStderr(self: LogHandler, logger: Logger, message: string) =
logger.lockFile(stderr)
setForegroundColor(fgBlack)
setBackgroundColor(bgRed)
stderr.write(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<5} {"-":>1} {"":>1} FATAL {"-":>3} ({posix.getpid():03})]""")
customStderr.write(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<5} {"-":>1} {"":>1} FATAL {"-":>3} ({posix.getpid():03})]""")
setForegroundColor(fgRed)
setBackgroundColor(bgDefault)
stderr.writeline(&""" {message}""")
customStderr.writeline(&""" {message}""")
setForegroundColor(fgDefault)
logger.unlockFile(stderr)
proc logTraceFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} TRACE {"-":>3} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logDebugFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} DEBUG {"-":>3} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logInfoFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} INFO {"-":>4} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logWarningFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} WARNING {"-":>1} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logErrorFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<10} {"-":>1} {"":>1} ERROR {"-":>3} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logCriticalFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<4} {"-":>1} CRITICAL {"-":>2} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc logFatalFile(self: LogHandler, logger: Logger, message: string) =
var self = StreamHandler(self)
logger.lockFile(self.file)
self.file.writeLine(&"""[{fromUnix(getTime().toUnixFloat().int).format("d/M/yyyy HH:mm:ss"):<5} {"-":>1} {"":>1} FATAL {"-":>3} ({posix.getpid():03})] {message}""")
logger.unlockFile(self.file)
proc switchToFile*(self: Logger) =