From b68b6f5e747b3481742c6bc9364b9ed8a89e6244 Mon Sep 17 00:00:00 2001 From: nocturn9x Date: Mon, 27 Dec 2021 15:08:57 +0100 Subject: [PATCH] Failed attempts to fix missing stderr from supervised processes --- src/core/mainloop.nim | 4 +- src/core/services.nim | 120 +++++++++++++++++++++--------------------- src/main.nim | 27 ++++------ 3 files changed, 72 insertions(+), 79 deletions(-) diff --git a/src/core/mainloop.nim b/src/core/mainloop.nim index 91482cb..601e6c8 100644 --- a/src/core/mainloop.nim +++ b/src/core/mainloop.nim @@ -23,10 +23,10 @@ import shutdown -proc mainLoop*(logger: Logger) = +proc mainLoop*(logger: Logger, workers: int = 1) = ## NimD's main execution loop logger.info("Processing default runlevel") - startServices(logger, workers=1, level=Default) + startServices(logger, workers=workers, level=Default) logger.debug(&"Unblocking signals") unblockSignals(logger) logger.info("System initialization complete, idling on control socket") diff --git a/src/core/services.nim b/src/core/services.nim index cd3fb07..610e693 100644 --- a/src/core/services.nim +++ b/src/core/services.nim @@ -219,14 +219,13 @@ proc removeService*(service: Service) = break -proc loggerWorker(logger: Logger, service: Service, process: Process) = +proc streamLoggerWorker(logger: Logger, service: Service, stream: Stream) = ## Captures the output of a given process and relays it ## in a formatted manner into our logging system try: logger.debug("Switching logs to file") - logger.switchToFile() + # logger.switchToFile() var line: string = "" - var stream = process.outputStream while stream.readLine(line): logger.info(&"{service.name}: {line}") except: @@ -244,63 +243,62 @@ proc supervisorWorker(logger: Logger, service: Service, process: Process) = logger.error(&"Error, cannot fork: {posix.strerror(posix.errno)}") elif p == 0: logger.trace(&"New child has been spawned") - loggerWorker(logger, service, process) - else: - var pid = process.processID - var status: cint - var returnCode: int - var sig: int - var process: Process - logger.debug("Switching logs to file") - logger.switchToFile() - while true: - logger.trace(&"Calling waitpid() on {pid}") - returnCode = posix.waitPid(cint(pid), status, WUNTRACED) - if WIFEXITED(status): - sig = 0 - elif WIFSIGNALED(status): - sig = WTERMSIG(status) - else: - sig = -1 - logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}, setting sig to {sig}") - case service.restart: - of Never: - logger.info(&"Service '{service.name}' ({returnCode}) has exited, shutting down controlling process") + streamLoggerWorker(logger, service, process.outputStream) + var pid = process.processID + var status: cint + var returnCode: int + var sig: int + var process: Process + logger.debug("Switching logs to file") + logger.switchToFile() + while true: + logger.trace(&"Calling waitpid() on {pid}") + returnCode = posix.waitPid(cint(pid), status, WUNTRACED) + if WIFEXITED(status): + sig = 0 + elif WIFSIGNALED(status): + sig = WTERMSIG(status) + else: + sig = -1 + logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}, setting sig to {sig}") + case service.restart: + of Never: + logger.info(&"Service '{service.name}' ({returnCode}) has exited, shutting down controlling process") + break + of Always: + if sig > 0: + logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") + elif sig == 0: + logger.info(&"Service '{service.name}' has exited gracefully, sleeping {service.restartDelay} seconds before restarting it") + else: + logger.info(&"Service '{service.name}' has exited, sleeping {service.restartDelay} seconds before restarting it") + removeManagedProcess(pid) + sleep(service.restartDelay * 1000) + var split = shlex(service.exec) + if split.error: + logger.error(&"Error while restarting service '{service.name}': invalid exec syntax") break - of Always: - if sig > 0: - logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") - elif sig == 0: - logger.info(&"Service '{service.name}' has exited gracefully, sleeping {service.restartDelay} seconds before restarting it") - else: - logger.info(&"Service '{service.name}' has exited, sleeping {service.restartDelay} seconds before restarting it") - removeManagedProcess(pid) - sleep(service.restartDelay * 1000) - var split = shlex(service.exec) - if split.error: - logger.error(&"Error while restarting service '{service.name}': invalid exec syntax") - break - var arguments = split.words - let progName = arguments[0] - arguments = arguments[1..^1] - process = startProcess(progName, workingDir=service.workDir, args=arguments) - pid = process.processID() - of OnFailure: - if sig > 0: - logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") - removeManagedProcess(pid) - sleep(service.restartDelay * 1000) - var split = shlex(service.exec) - if split.error: - logger.error(&"Error while restarting service '{service.name}': invalid exec syntax") - break - var arguments = split.words - let progName = arguments[0] - arguments = arguments[1..^1] - process = startProcess(progName, workingDir=service.workDir, args=arguments) - pid = process.processID() - if process != nil: - process.close() + var arguments = split.words + let progName = arguments[0] + arguments = arguments[1..^1] + process = startProcess(progName, workingDir=service.workDir, args=arguments) + pid = process.processID() + of OnFailure: + if sig > 0: + logger.info(&"Service '{service.name}' ({returnCode}) has crashed (terminated by signal {sig}: {strsignal(cint(sig))}), sleeping {service.restartDelay} seconds before restarting it") + removeManagedProcess(pid) + sleep(service.restartDelay * 1000) + var split = shlex(service.exec) + if split.error: + logger.error(&"Error while restarting service '{service.name}': invalid exec syntax") + break + var arguments = split.words + let progName = arguments[0] + arguments = arguments[1..^1] + process = startProcess(progName, workingDir=service.workDir, args=arguments) + pid = process.processID() + if process != nil: + process.close() proc startService(logger: Logger, service: Service) = @@ -319,7 +317,7 @@ proc startService(logger: Logger, service: Service) = var arguments = split.words let progName = arguments[0] arguments = arguments[1..^1] - process = startProcess(progName, workingDir=service.workDir, args=arguments, options=if service.useParentStreams: {poParentStreams} else: {poUsePath, poDaemon, poStdErrToStdOut}) + process = startProcess(progName, workingDir=service.workDir, args=arguments, options=if service.useParentStreams: {poParentStreams, poStdErrToStdOut} else: {poUsePath, poDaemon, poStdErrToStdOut}) if service.supervised or service.kind != Oneshot: var pid = posix.fork() if pid == -1: @@ -329,7 +327,7 @@ proc startService(logger: Logger, service: Service) = supervisorWorker(logger, service, process) # If the service is unsupervised we just spawn the logger worker (assuming it doesn't use poParentStreams) if not service.useParentStreams: - loggerWorker(logger, service, process) + streamLoggerWorker(logger, service, process.outputStream) except: logger.error(&"Error while starting service '{service.name}': {getCurrentExceptionMsg()}") diff --git a/src/main.nim b/src/main.nim index ce0685d..4c9d980 100644 --- a/src/main.nim +++ b/src/main.nim @@ -44,30 +44,25 @@ proc addStuff = addShutdownHandler(newShutdownHandler(unmountAllDisks)) # Adds test services var echoer = newService(name="echoer", description="prints owo", exec="/bin/echo owoooooooooo", - runlevel=Boot, kind=Oneshot, workDir=getCurrentDir(), - supervised=false, restart=Never, restartDelay=0, + runlevel=Boot, kind=Simple, workDir=getCurrentDir(), + supervised=false, restart=Always, restartDelay=5, depends=(@[]), provides=(@[])) var errorer = newService(name="errorer", description="la mamma di gavd", - exec="/bin/false", supervised=true, restart=OnFailure, - restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, - depends=(@[newDependency(Other, echoer)]), provides=(@[])) - var test = newService(name="broken", description="", exec="/bin/echo owo", - runlevel=Boot, kind=Oneshot, workDir=getCurrentDir(), - supervised=false, restart=Never, restartDelay=0, - depends=(@[newDependency(Other, echoer)]), provides=(@[])) + exec="/bin/false", supervised=true, restart=OnFailure, + restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, + depends=(@[]), provides=(@[])) var exiter = newService(name="exiter", description="la mamma di licenziat", - exec="/bin/true", supervised=true, restart=Always, - restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, - depends=(@[newDependency(Other, errorer)]), provides=(@[])) + exec="/bin/true", supervised=true, restart=Always, + restartDelay=5, runlevel=Boot, workDir="/", kind=Simple, + depends=(@[newDependency(Other, errorer)]), provides=(@[])) var shell = newService(name="login", description="A simple login shell", kind=Simple, - getCurrentDir(), runlevel=Boot, exec="/bin/login -f root", - supervised=true, restart=Always, restartDelay=0, depends=(@[]), provides=(@[]), + getCurrentDir(), runlevel=Default, exec="/bin/login -f root", + supervised=true, restart=Always, restartDelay=5, depends=(@[]), provides=(@[]), useParentStreams=true ) addService(errorer) addService(echoer) addService(exiter) - addService(test) addService(shell) @@ -126,7 +121,7 @@ proc main(logger: Logger, mountDisks: bool = true, fstab: string = "/etc/fstab", logger.info("Processing boot runlevel") startServices(logger, workers=workerCount, level=Boot) logger.debug("Starting main loop") - mainLoop(logger) + mainLoop(logger, workers=workerCount) when isMainModule: