sysmgr

a simplistic service supervisor
git clone git://git.ckyln.com/~cem/sysmgr.git
Log | Files | Refs | README | LICENSE

commit d8b95146b561057b70b5e1af91274f47c2de29d3
parent 04c1126e0d9b11896948a4716500292f03e04dcf
Author: Cem Keylan <cem@ckyln.com>
Date:   Sat,  4 Jul 2020 00:31:19 +0300

utils: remove sysmgr-needs script and add C programs

The previous shell script implementation had too much CPU overhead
because of the 'while true'. It also didn't exit properly. I have
decided to replace it with this small C program.

'util.c' is also added to make way for possible new programs to make
use of it. Perhaps a library could be created from this.

Diffstat:
Autils/Makefile | 19+++++++++++++++++++
Dutils/sysmgr-needs | 29-----------------------------
Autils/sysmgr-needs.c | 45+++++++++++++++++++++++++++++++++++++++++++++
Autils/util.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Autils/util.h | 34++++++++++++++++++++++++++++++++++
5 files changed, 166 insertions(+), 29 deletions(-)

diff --git a/utils/Makefile b/utils/Makefile @@ -0,0 +1,19 @@ +CC = cc + +HDR = util.h +SRC = util.c sysmgr-needs.c +OBJ = ${SRC:.c=.o} +BIN = sysmgr-needs + +all: ${BIN} + +.c.o: + ${CC} ${CFLAGS} -c -o $@ $< + +${BIN}: ${HDR} ${OBJ} + ${CC} ${LDFLAGS} -o $@ ${@:=.o} util.o + +clean: + rm -f ${OBJ} ${BIN} + +.PHONY: all clean diff --git a/utils/sysmgr-needs b/utils/sysmgr-needs @@ -1,29 +0,0 @@ -#!/bin/sh - -# A simple utility for dependency tracking with sysmgr. - -[ "$1" ] || { cat <<EOF -usage: ${0##*/} [dep1] [dep2] [dep...] - -sysmgr utility for service dependency tracking. -This program waits until all dependencies are -started with sysmgr. -EOF - exit 1 ;} - -checkprocess() { - # This is quite similar to the function with the - # same name on sysmgr, except it gets the pid itself. - read -r pid < "$RUNDIR/$1/pid" - [ -d /proc ] || { - kill -0 "$pid" || return 1 - return 0 - } - [ -d "/proc/$pid" ] || return 1 - return 0 -} - -for service in "$@" ; do - # We parallelize and wait for all checks to pass. - while :; do [ -r "${RUNDIR:=/run/sysmgr}/${service}/pid" ] && checkprocess "$service" && break ; done & -done; wait diff --git a/utils/sysmgr-needs.c b/utils/sysmgr-needs.c @@ -0,0 +1,45 @@ +/* See LICENSE for copyright information + * sysmgr-needs -- tool to check service dependencies. + */ +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> + +#include "util.h" + +int main(int argc, char *argv[]) { + if (argc < 2) { + printf("usage: %s [service...]\n", argv[0]); + return 1; + } + + int i; + struct service sv; + + /* We are doing two iterations, because we want to exit as soon as possible if + * any of the given services do not exist. + */ + for (i = 1; i < argc; i++) { + sv_init(&sv, argv[i]); + if (access(sv.svfile, R_OK) == -1) + die("sysmgr: service file for '%s' doesn't exist.", sv.name); + } + + for (i = 1; i < argc; i++) { + while(1) { + int pid; + + sv_init(&sv, argv[i]); + FILE *pidfile; + + pidfile = fopen(sv.pidfile, "r"); + if (pidfile != NULL) { + fscanf(pidfile, "%d", &pid); + fclose(pidfile); + + if (checkprocess(pid) == 0) break; + } + sleep(1); + } + } +} diff --git a/utils/util.c b/utils/util.c @@ -0,0 +1,68 @@ +/* See LICENSE for copyright information + * + * These are shared functions for utility programs. This may be used for a + * library in the future. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <stdarg.h> +#include <errno.h> + +#include "util.h" + +extern int errno; + +char *getenv_fallback(char *name, char *fallback) { + char *value = getenv(name); + if ( ! value ) value = fallback; + return value; +} + +service *sv_init(service *sv, char *sv_name) { + sprintf(sv->name, "%s", sv_name); + sprintf(sv->sysdir, "%s", getenv_fallback("SYSDIR", "/var/sysmgr")); + sprintf(sv->rundir, "%s", getenv_fallback("RUNDIR", "/run/sysmgr")); + sprintf(sv->pidfile, "%s/%s/pid", sv->rundir, sv->name); + sprintf(sv->svfile, "%s/%s", sv->sysdir, sv_name); + + return sv; +} + +void die(const char *msg, ...) { + va_list ap; + + va_start(ap, msg); + vfprintf(stderr, msg, ap); + va_end(ap); + + if (msg[0] && msg[strlen(msg)-1] == ':') { + fputc(' ', stderr); + perror(NULL); + } else { + fputc('\n', stderr); + } + exit(1); +} + +int checkprocess(int pid) { + if (kill(pid, 0) == 0) return 0; + else { + + switch (errno) { + case 1: + /* + * Instead of a continuous loop, exit the program if we don't have the + * permissions to check the process + */ + die("kill:"); + break; + default: + perror("kill"); + break; + } + + return 1; + } +} diff --git a/utils/util.h b/utils/util.h @@ -0,0 +1,34 @@ +/* See LICENSE for copyright information + * + * Common functions that may be used for future C utilities + */ + +#include <limits.h> + +typedef struct service { + char name[NAME_MAX]; + char sysdir[PATH_MAX]; + char rundir[PATH_MAX]; + char pidfile[PATH_MAX]; + char svfile[PATH_MAX]; +} service; + +/* + * Get information about the service. + */ +service *sv_init(service *sv, char *sv_name); + +/* + * Check whether the given pid exists. + */ +int checkprocess(int pid); + +/* + * Get environment variable while setting a fallback + */ +char *getenv_fallback(char *name, char *fallback); + +/* + * Exit program while printing a message + */ +void die(const char *msg, ...);