mirror of https://github.com/nocturn9x/nimd.git
110 lines
4.0 KiB
Nim
110 lines
4.0 KiB
Nim
# 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.
|
|
|
|
## Default signal handlers, exit procedures and helpers
|
|
## to allow a clean shutdown of NimD
|
|
import os
|
|
import strutils
|
|
import syscall
|
|
import strformat
|
|
import posix
|
|
|
|
|
|
import logging
|
|
import ../core/shutdown
|
|
|
|
|
|
proc sleepSeconds*(amount: SomeNumber) = sleep(int(amount * 1000))
|
|
proc dummySigHandler(x: cint) {.noconv.} = discard
|
|
|
|
|
|
|
|
proc doSync*(logger: Logger) =
|
|
## Performs a sync() system call
|
|
logger.debug(&"Calling sync() syscall has returned {syscall(SYNC)}")
|
|
|
|
|
|
proc blockSignals*(logger: Logger) =
|
|
## Temporarily blocks all signals
|
|
## for critical sections of code
|
|
var tmp: Sigset
|
|
var sigaction: Sigaction
|
|
sigaction.sa_handler = dummySigHandler
|
|
sigaction.sa_flags = SA_RESTART
|
|
if posix.sigfillset(sigaction.sa_mask) == -1:
|
|
logger.fatal(&"Could not initialize signal lock (code {posix.errno}, {posix.strerror(posix.errno)}): environment is not safe, exiting now!")
|
|
nimDExit(logger, 131)
|
|
if posix.sigprocmask(SIG_SETMASK, sigaction.sa_mask, tmp) == -1:
|
|
logger.fatal(&"Could not apply signal mask to process (code {posix.errno}, {posix.strerror(posix.errno)}): environment is not safe, exiting now!")
|
|
nimDExit(logger, 131)
|
|
|
|
|
|
proc unblockSignals*(logger: Logger) =
|
|
## Unblocks all signals
|
|
var tmp: Sigset
|
|
var sigaction: Sigaction
|
|
sigaction.sa_flags = SA_RESTART
|
|
if posix.sigemptyset(sigaction.sa_mask) == -1:
|
|
logger.fatal(&"Could not initialize signal unlock (code {posix.errno}, {posix.strerror(posix.errno)}): environment is not safe, exiting now!")
|
|
nimDExit(logger, 131)
|
|
if posix.sigprocmask(SIG_SETMASK, sigaction.sa_mask, tmp) == -1:
|
|
logger.fatal(&"Could not apply signal mask to process (code {posix.errno}, {posix.strerror(posix.errno)}): environment is not safe, exiting now!")
|
|
nimDExit(logger, 131)
|
|
|
|
|
|
proc reapProcess*(logger: Logger) =
|
|
## Reaps zombie processes. Note: This does not
|
|
## handle restarting crashed service processes,
|
|
## it simply makes sure that there's no dead
|
|
## process entries in the kernel's ptable.
|
|
## When (supervised) services are started,
|
|
## they are spawned by a controlling subprocess
|
|
## of PID 1 which listens for changes in them
|
|
## and restarts them as needed
|
|
logger.debug("Handling SIGCHLD")
|
|
var status: cint
|
|
logger.trace("Calling waitpid() on -1")
|
|
var returnCode = posix.waitPid(-1, status, WNOHANG) # This doesn't hang, which is what we want
|
|
logger.trace(&"Call to waitpid() set status to {status} and returned {returnCode}")
|
|
|
|
|
|
|
|
proc setHostname*(logger: Logger): string =
|
|
## Sets the machine's hostname. Returns
|
|
## the hostname that has been set or an
|
|
## empty string if an error occurs. If
|
|
## /etc/hostname doesn't exist, the hostname
|
|
## defaults to localhost
|
|
var hostname: string
|
|
try:
|
|
if not fileExists("/etc/hostname"):
|
|
logger.warning("/etc/hostname doesn't exist, defaulting to 'localhost'")
|
|
hostname = "localhost"
|
|
else:
|
|
hostname = readFile("/etc/hostname").strip(chars={'\n'})
|
|
writeFile("/proc/sys/kernel/hostname", hostname)
|
|
except:
|
|
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 |