commit 3abfdb4bb044b6b0176ff987e92ca005810e25c7
Author: Cem Keylan <cem@ckyln.com>
Date: Sun, 23 Feb 2020 15:17:33 +0300
initial commit
Diffstat:
A | LICENSE | | | 21 | +++++++++++++++++++++ |
A | Makefile | | | 16 | ++++++++++++++++ |
A | sysmgr | | | 196 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 233 insertions(+), 0 deletions(-)
diff --git a/LICENSE b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2020 Cem Keylan
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Makefile b/Makefile
@@ -0,0 +1,16 @@
+# See LICENSE for copyright information
+VERSION = 0.01.0
+
+PREFIX = /usr/local
+BINDIR = ${PREFIX}/bin
+SHAREDIR = ${PREFIX}/share
+
+LINK = runsyssv svctl
+
+install:
+ install -Dm755 sysmgr ${DESTDIR}${BINDIR}/sysmgr
+ for link in ${LINK} ; do ln -sf sysmgr ${DESTDIR}${BINDIR}/$$link ; done
+
+uninstall:
+ rm -rf ${DESTDIR}${BINDIR}/sysmgr
+ for link in ${LINK} ; do unlink ${DESTDIR}${BINDIR}/$$link ; done
diff --git a/sysmgr b/sysmgr
@@ -0,0 +1,196 @@
+#!/bin/sh -e
+
+###########################################################
+# A modular system-supervisor written in POSIX shell #
+# written with Carbs Linux[1] in mind. #
+# #
+# [1]: https://carbslinux.org #
+# #
+# Copyright (c) 2020 - Cem Keylan #
+# See LICENSE for copyright information #
+# #
+# Please report bugs to <cem at ckyln dot com> #
+###########################################################
+
+
+# Shellcheck gives an error telling us that 'printf ->' is
+# undefined, but since we do want to print '->' this can
+# be safely ignored.
+# shellcheck disable=SC2039
+out() { printf '-> %s\n' "$@" ;}
+error() { printf '-> error: %s\n' "$@" ;}
+die() { printf '-> error: %s\n' "$@" "exiting..." ; exit 1 ;}
+
+RUNDIR="${RUNDIR:-/run/sysmgr}"
+SYSDIR="${SYSDIR:-/var/sysmgr}"
+
+cleanup() {
+
+ # Clean the service run directory so that it can be
+ # restarted. Do not remove the run directory if lock
+ # file exists.
+
+ [ -e "${RUNDIR:?}/${service##*/}/lock" ] && return 0
+ rm -rf "${RUNDIR:?}/${service##*/}"
+
+}
+
+term() {
+
+ # This function is executed when the sysmgr receives an
+ # interrupt or a hangup signal. It enters the termination
+ # state where it forwards SIGTERM to every other runsyssv
+ # process that have their process ids in the RUNDIR
+
+ for process in "${RUNDIR:?}"/*/syspid ; do
+ kill -SIGTERM "$(cat "$process")" 2>/dev/null
+ done
+
+ # Wait for the redirections to happen
+ sleep 1
+
+ # Remove the RUNDIR so we can do a fresh start when we
+ # are re-initiating the program.
+ rm -rf "${RUNDIR}"
+
+ exit 0
+}
+
+redirectsignal() {
+
+ # We redirect signal that was sent to runsyssv so that
+ # those programs are stopped with the exact kill command.
+ # Adding a lock file ensures that the directory is not
+ # cleaned up.
+ sig="$1"
+
+ printf '%s\n' "${sig:-15}" > "${RUNDIR:?}/${service##*/}/lock"
+ kill "-${sig:-15}" "$svpid"
+
+}
+
+fn_sysmgr() {
+ [ "$1" ] && {
+ printf 'Usage: %s\n\nStarts a sysmgr instance.\n' "${0##*/}"
+ exit 0
+ }
+
+ # Start sanity checks. We first check that we have
+ # the "$SYSDIR" variable. We then check whether the
+ # given SYSDIR exists, and has service files installed.
+ [ "$SYSDIR" ] || die "Please specify service directory"
+ [ -d "$SYSDIR" ] || die "$SYSDIR does not exist."
+ [ "$(find "$SYSDIR" -type f)" ] || die "No service file is found"
+ mkdir -p "$RUNDIR" || die
+
+ # Add pid to $RUNDIR before starting loops
+ printf '%s\n' "$$" > "$RUNDIR/pid"
+
+ # We redirect hangup and interrupt signals to the
+ # 'term' function so that we send kill signals to
+ # all sysmgr processes
+ for sig in 1 2 ; do
+ trap term "$sig"
+ done
+
+ # Lots of loops here. The first while loop is to
+ # make sure that the sysmgr does not exist. The
+ # for loop is to run every single service on the
+ # $SYSDIR. We then fork the runsyssv function to
+ # the background. This ensures that we don't have
+ # to wait until runsyssv has finished, which is a
+ # program that is not supposed to exit.
+ while sleep 1 ; do
+ for service in "$SYSDIR"/* ; do
+ [ -x "$service" ] || error "$service is not an executable file"
+ ! [ -d "$RUNDIR/${service##*/}" ] && runsyssv "$service" &
+ done
+ done
+}
+
+fn_runsyssv() {
+
+ # This is a really hacky way to handle '--help'
+ # I just do not want to add 'usage' functions nor
+ # call the same command twice. Just remove the $1
+ # if it is the typical help flag.
+ case "$1" in -h|--help|help) shift ;; esac
+ [ "$1" ] || { printf 'Usage: %s <service-file>\n\nRuns the given service script.\n' "${0##*/}" ; exit 0 ;}
+
+ # Record service name in a variable
+ service="$1"
+
+ # This is the simplest way of checking whether a
+ # service is running (or killed by the user with
+ # ctl, so that it does not run again).
+ [ -e "/run/sysmgr/${service##*/}" ] && exit 1
+
+ # Create the run directory for the service where
+ # we will be adding the pid value when we start
+ # the process.
+ mkdir -p "$RUNDIR/${service##*/}"
+
+ # Start the service script. If the service fails
+ # exit with failure code 1. If the service exits
+ # without a failure (which it probably shouldn't)
+ # exit with code 0
+ "$service" &
+ svpid="$!"
+ printf '%s\n' "$svpid" > "$RUNDIR/${service##*/}/pid"
+ printf '%s\n' "$$" > "$RUNDIR/${service##*/}/syspid"
+
+ for sig in 1 2 3 6 15 ; do
+ # We want to trap every signal with their own
+ # value so that we kill the service with the
+ # requested signal.
+ # shellcheck disable=SC2064
+ trap "redirectsignal $sig" $sig
+ done
+
+ # check whether services are alive
+ while kill -0 "$svpid" >/dev/null 2>&1 ; do sleep 1 ; done
+
+ # Do a cleanup when the service is killed
+ cleanup
+}
+
+fn_svctl() {
+ [ "$2" ] || {
+ printf 'usage: %s <kill|restart|stop|start> <service>\n' "${0##*/}"
+ exit 0
+ }
+ [ -d "${RUNDIR:?}/$2" ] || die "service $2 could not be found."
+ case "$1" in
+ restart)
+ fn_svctl kill "$2"
+ fn_svctl start "$2"
+ ;;
+ kill)
+ printf '9\n' > "${RUNDIR:?}/$2/lock"
+ kill -9 "$(cat "${RUNDIR:?}/$2/pid")" 2>/dev/null
+ ;;
+ stop)
+ printf '15\n' > "${RUNDIR:?}/$2/lock"
+ kill -15 "$(cat "${RUNDIR:?}/$2/pid")" 2>/dev/null
+ ;;
+ start)
+ rm -rf "${RUNDIR:?}/${2}"
+ ;;
+ *)
+ exit 1
+ ;;
+ esac
+}
+
+main() {
+ # Call the appropriate function depending on the
+ # name of the program.
+ case "${0##*/}" in
+ sysmgr) fn_sysmgr "$@" ;;
+ runsyssv) fn_runsyssv "$@" ;;
+ svctl) fn_svctl "$@" ;;
+ *) printf '%s is not a function\n' "${0##*/}" ; exit 1 ;;
+ esac
+}
+
+main "$@"