commit e0a8cb56f82349216c602ff656e461067a179526
parent d0fd3d05d45b84643313070715d94cfe248a520f
Author: Cem Keylan <cem@ckyln.com>
Date: Fri, 9 Oct 2020 14:30:35 +0300
sysmgr: fully works now, time for cleanup
Diffstat:
11 files changed, 263 insertions(+), 32 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -1,7 +1,12 @@
+# -*- mode: gitignore; -*-
+# Emacs editor files
+*~
+\#*\#
+.\#*
# C Objects/binaries
*.a
*.o
config.h
sysmgr
runsyssv
-svctl-
\ No newline at end of file
+svctl
diff --git a/LICENSE b/LICENSE
@@ -1,3 +1,18 @@
+Some of the utility functions here are taken from other places, here are their
+licenses. See the files for more information. Most of those are from sbase, but
+some of the ones from sbase are taken from other places as well.
+
+enprintf.c, mkdirp.c
+ Taken from https://core.suckless.org/sbase. MIT/X Consortium License
+rm.c
+ Taken from https://stackoverflow.com/a/5467788. CC BY-SA 2.5
+strlcpy.c
+ Taken from sbase. Copyright (c) 1998 Todd C. Miller. ISC License
+strtonum.c
+ Taken from sbase. Copyright (c) 2004 Ted Unangst and Todd Miller. ISC License
+
+--------------------------------------------------------------------------------
+
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
diff --git a/Makefile b/Makefile
@@ -1,3 +1,6 @@
+PREFIX = /usr/local
+BINDIR = ${PREFIX}/bin
+
include config.mk
.SUFFIXES:
@@ -20,7 +23,8 @@ LIBUTILSRC = \
BIN = \
sysmgr \
- runsyssv
+ runsyssv \
+ svctl
SRC = ${BIN:=.c}
BINOBJ = ${SRC:.c=.o}
@@ -54,4 +58,12 @@ config.h:
clean:
rm -f ${BIN} ${OBJ} ${LIBUTIL}
-.PHONY: all clean
+install: all
+ mkdir -p ${DESTDIR}${BINDIR}
+ cp ${BIN} ${DESTDIR}${BINDIR}
+ for bin in ${BIN}; do chmod 755 ${DESTDIR}${BINDIR}/$${bin}; done
+
+uninstall:
+ for bin in ${BIN}; do rm -f ${DESTDIR}${BINDIR}/$${bin}; done
+
+.PHONY: all clean install uninstall
diff --git a/config.mk b/config.mk
@@ -1,8 +1,9 @@
+VERSION = git
+
CC = cc
AR = ar
RANLIB = ranlib
-CPPFLAGS = -D_XOPEN_SOURCE=700 -D_GNU_SOURCE
+CPPFLAGS = -D_XOPEN_SOURCE=700 -DVERSION=\"${VERSION}\"
CFLAGS = -std=c99 -Wpedantic -Wall -Wextra
LDFLAGS = -static
-
diff --git a/libutil/proc.c b/libutil/proc.c
@@ -29,8 +29,10 @@ getsyspid(service *sv)
{
pid_t pid;
- if (access(sv->syspidfile, R_OK) == -1)
+ if (access(sv->syspidfile, R_OK) == -1) {
+ perror(sv->syspidfile);
return -1;
+ }
FILE *pidfile;
pidfile = fopen(sv->syspidfile, "r");
@@ -49,10 +51,10 @@ writesvpid(char *file, pid_t pid)
FILE *pidfile;
pidfile = fopen(file, "w");
- if (pidfile == NULL)
- /* perror(file); */
- return -2;
-
+ if (pidfile == NULL) {
+ perror(file);
+ return -1;
+ }
fprintf(pidfile, "%d\n", pid);
fclose(pidfile);
diff --git a/libutil/rm.c b/libutil/rm.c
@@ -1,7 +1,5 @@
/* Remove directories
*
- * This file is part of sysmgr.
- *
* Function mostly taken from:
* https://stackoverflow.com/a/5467788
* Licensed under CC BY-SA 2.5
diff --git a/libutil/service.c b/libutil/service.c
@@ -20,17 +20,19 @@
#include <sys/stat.h>
#include "../util.h"
+#include "../config.h"
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->sysdir, "%s", getenv_fallback("SYSDIR", sysdir_default));
+ sprintf(sv->rundir, "%s", getenv_fallback("RUNDIR", rundir_default));
sprintf(sv->pidfile, "%s/%s/pid", sv->rundir, sv->name);
sprintf(sv->syspidfile, "%s/%s/syspid", sv->rundir, sv->name);
sprintf(sv->svfile, "%s/%s", sv->sysdir, sv_name);
sprintf(sv->svrundir, "%s/%s", sv->rundir, sv_name);
+ sprintf(sv->lockfile, "%s/%s/lock", sv->rundir, sv->name);
return sv;
}
@@ -50,18 +52,21 @@ void sv_start(service *sv)
}
}
-int sv_check(service *sv)
+int sv_check(service *sv, int force)
{
+ /* If force is specified '1', this will return the actual service status
+ * regardless of the lockfile. The lockfile serves the purpose of
+ * stopping services and making sure they are not restarted.
+ */
pid_t pid;
struct stat sb;
- char lockfile[PATH_MAX + sizeof("/lock")];
- /* If a lockfile exists, we will assume that the service was stopped by
- * the user. */
- sprintf(lockfile, "%s/lock", sv->svrundir);
-
- if (lstat(lockfile, &sb) == 0)
- return 0;
+ if (lstat(sv->lockfile, &sb) == 0) {
+ if (force == 1)
+ return -1;
+ else
+ return 0;
+ }
pid = getsyspid(sv);
@@ -70,3 +75,18 @@ int sv_check(service *sv)
return 0;
}
+
+int sv_writelock(char *file, int sig)
+{
+ FILE *lockfile;
+
+ lockfile = fopen(file, "w");
+ if (lockfile == NULL) {
+ perror(file);
+ return -1;
+ }
+ fprintf(lockfile, "%d\n", sig);
+ fclose(lockfile);
+
+ return 0;
+}
diff --git a/runsyssv.c b/runsyssv.c
@@ -1,15 +1,20 @@
#include <sys/types.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
+#include <libgen.h>
#include <string.h>
+#include <dirent.h>
#include "util.h"
#include "config.h"
-static char *argv0;
+static char *argv0, *lockfile, *svrundir;
+static pid_t syspid, svpid;
+static struct service sv;
void
usage(int exitnum)
@@ -18,6 +23,23 @@ usage(int exitnum)
exit(exitnum);
}
+void
+term(int sig)
+{
+ switch(sig) {
+ case SIGUSR1:
+ kill(svpid, SIGKILL);
+ break;
+ default:
+ kill(svpid, SIGTERM);
+ break;
+ }
+ if (sv_writelock(lockfile, sig) != 0)
+ rm_rf(svrundir);
+ exit(0);
+}
+
+
int
main(int argc, char *argv[])
{
@@ -32,8 +54,41 @@ main(int argc, char *argv[])
} else
usage(1);
+ syspid = getpid();
+
struct service sv;
- sv_init(&sv, argv[1]);
+ sv_init(&sv, basename(argv[1]));
+
+ DIR *dir;
+ if ((dir = opendir(sv.svrundir)) != NULL) {
+ closedir(dir);
+ return 1;
+ }
+
mkdirp(sv.svrundir);
+ int sv_signals[] = {SIGTERM, SIGINT, SIGHUP, SIGQUIT, SIGABRT};
+ lockfile = sv.lockfile;
+ svrundir = sv.svrundir;
+
+ svpid = fork();
+ switch(svpid) {
+ case -1:
+ die("fork:");
+ break;
+ case 0:
+ execvp(sv.svfile, argv);
+ perror(sv.svfile);
+ break;
+ default:
+ writesvpid(sv.syspidfile, syspid);
+ writesvpid(sv.pidfile, svpid);
+ for (long unsigned int i=0; i < sizeof(sv_signals); i++)
+ signal(sv_signals[i], term);
+ wait(NULL);
+ if (rm_rf(sv.svrundir) != 0)
+ return 1;
+ break;
+ }
+ return 0;
}
diff --git a/svctl.c b/svctl.c
@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <dirent.h>
+#include <libgen.h>
+
+#include "util.h"
+#include "config.h"
+
+static char *argv0;
+
+void
+usage(int exitnum)
+{
+ printf("usage: %s [operation] [service...]\n\n", argv0);
+ fputs(" Operations:\n"
+ " start/stop/restart Start/stop/restart services\n"
+ " once Start services once\n"
+ " status Check service statuses\n"
+ " up/down Same as start/stop\n\n", stdout);
+ exit(exitnum);
+}
+
+int check_rundir(char *dir)
+{
+ DIR *rundirectory;
+ rundirectory = opendir(dir);
+ if (rundirectory == NULL)
+ return -1;
+ closedir(rundirectory);
+ return 0;
+}
+
+int handle_service(char *operation, char *name)
+{
+ struct service sv;
+ sv_init(&sv, basename(name));
+ pid_t pid;
+
+ if (strcmp(operation, "start") == 0 || strcmp(operation, "up") == 0) {
+ if(sv_check(&sv, 1) == 0)
+ return 0;
+ return rm_rf(sv.svrundir);
+ } else if (strcmp(operation, "stop") == 0 || strcmp(operation, "down") == 0) {
+ pid = getsyspid(&sv);
+ switch (pid) {
+ case -1:
+ perror(NULL);
+ return 1;
+ default:
+ sv_writelock(sv.lockfile, SIGTERM);
+ kill(pid, SIGTERM);
+ unlink(sv.syspidfile);
+ unlink(sv.pidfile);
+ }
+ } else if (strcmp(operation, "kill") == 0) {
+ pid = getsyspid(&sv);
+ switch (pid) {
+ case -1:
+ perror(NULL);
+ return 1;
+ default:
+ sv_writelock(sv.lockfile, SIGKILL);
+ kill(pid, SIGUSR1);
+ unlink(sv.syspidfile);
+ unlink(sv.pidfile);
+ }
+ } else if (strcmp(operation, "once") == 0) {
+ if(sv_check(&sv, 1) == 0) {
+ if (sv_writelock(sv.lockfile, 0) != 0) {
+ perror(sv.lockfile);
+ die("Failed to write lock.");
+ }
+ } else {
+ rm_rf(sv.svrundir);
+ sleep(1);
+ return sv_writelock(sv.lockfile, 0);
+ }
+ } else if (strcmp(operation, "restart") == 0) {
+ handle_service("stop", name);
+ while (1) {
+ if (sv_check(&sv, 1) != 0)
+ break;
+ }
+ handle_service("start", name);
+
+ } else if (strcmp(operation, "stat") == 0 || strcmp(operation, "status") == 0) {
+ if (sv_check(&sv, 1) < 0) {
+ fprintf(stderr, "%s: DOWN\n", name);
+ exit(1);
+ } else
+ fprintf(stderr, "%s: UP\n", name);
+ } else
+ die("Unknown operation: %s", operation);
+ return 0;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *rundir;
+ argv0 = argv[0];
+ int i;
+
+ if (argc < 2 || strncmp(argv[1], "-", 1) == 0)
+ usage(0);
+ else if (argc < 3)
+ usage(1);
+
+ char **sv = argv + 1;
+
+ /* Check if the RUNDIR exists */
+ rundir = getenv_fallback("RUNDIR", rundir_default);
+ if (check_rundir(rundir) != 0)
+ die("%s could not be found, are you sure sysmgr is running?", rundir);
+
+ for (i=2; i < argc; i++)
+ if (handle_service(argv[1], argv[i]) != 0)
+ die("Couldn't %s %s", argv[1], argv[i]);
+
+ return 0;
+}
diff --git a/sysmgr.c b/sysmgr.c
@@ -91,13 +91,12 @@ int main(int argc, char *argv[])
mkdirp(rundir);
/* Trap signals */
- int signals[] = {SIGTERM, SIGINT, SIGHUP, SIGQUIT, SIGABRT};
- for (long unsigned int i=0; i < sizeof(signals); i++)
- signal(signals[i], term);
+ int sv_signals[] = {SIGTERM, SIGINT, SIGHUP, SIGQUIT, SIGABRT};
+ for (long unsigned int i=0; i < sizeof(sv_signals); i++)
+ signal(sv_signals[i], term);
pid_t pid = getpid();
- printf("RUNDIR: %s\nSYSDIR: %s\nselfpid: %d\n", rundir, sysdir, pid);
if (writesvpid(sysmgr_pidfile, pid) != 0)
die("%s:", sysmgr_pidfile);
@@ -112,8 +111,7 @@ int main(int argc, char *argv[])
continue;
struct service sv;
sv_init(&sv, ent->d_name);
- if (sv_check(&sv) != 0) {
- printf("%s\n", ent->d_name);
+ if (sv_check(&sv, 0) != 0) {
sv_start(&sv);
}
}
diff --git a/util.h b/util.h
@@ -22,12 +22,14 @@ typedef struct service {
char syspidfile[PATH_MAX];
char svfile[PATH_MAX];
char svrundir[PATH_MAX];
+ char lockfile[PATH_MAX];
} service;
/* service.c */
service *sv_init(service *sv, char *sv_name);
void sv_start(service *sv);
-int sv_check(service *sv);
+int sv_check(service *sv, int force);
+int sv_writelock(char *file, int sig);
/* proc.c */
int getsvpid(service *sv);