Failed attempts to fix missing stderr from supervised processes

This commit is contained in:
nocturn9x 2021-12-27 15:08:57 +01:00
parent d6c46b3543
commit b68b6f5e74
3 changed files with 72 additions and 79 deletions

View File

@ -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")

View File

@ -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()}")

View File

@ -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: