sm

sysmgr implemented in C
git clone git://git.ckyln.com/sm
Log | Files | Refs | README | LICENSE

commit d0fd3d05d45b84643313070715d94cfe248a520f
parent e1f433927a0ca2e71ffdf6502c15ef09b3a6bfe8
Author: Cem Keylan <cem@ckyln.com>
Date:   Wed,  7 Oct 2020 21:38:04 +0300

sysmgr.c: somewhat works with the shell parts (runsyssv, svctl)

While the implementation is not good right now, it works with the shell
counterparts. I will now clean this mess up and implement runsyssv and svctl.

Diffstat:
MMakefile | 1+
Mlibutil/proc.c | 21++++++++++++++++++++-
Mlibutil/service.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msysmgr.c | 92+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------
Mutil.h | 7+++++++
5 files changed, 163 insertions(+), 14 deletions(-)

diff --git a/Makefile b/Makefile @@ -12,6 +12,7 @@ LIBUTILSRC = \ libutil/io.c \ libutil/mkdirp.c \ libutil/proc.c \ + libutil/rm.c \ libutil/service.c \ libutil/strlcpy.c \ libutil/strtonum.c \ diff --git a/libutil/proc.c b/libutil/proc.c @@ -16,7 +16,26 @@ getsvpid(service *sv) pidfile = fopen(sv->pidfile, "r"); if (pidfile == NULL) - return -2; + return -1; + + fscanf(pidfile, "%d", &pid); + fclose(pidfile); + + return pid; +} + +pid_t +getsyspid(service *sv) +{ + pid_t pid; + + if (access(sv->syspidfile, R_OK) == -1) + return -1; + FILE *pidfile; + + pidfile = fopen(sv->syspidfile, "r"); + if (pidfile == NULL) + return -1; fscanf(pidfile, "%d", &pid); fclose(pidfile); diff --git a/libutil/service.c b/libutil/service.c @@ -1,4 +1,23 @@ +/* Service related operations + * + * Copyright (C) 2020 Cem Keylan <cem@ckyln.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ #include <stdio.h> +#include <unistd.h> +#include <sys/stat.h> #include "../util.h" @@ -9,8 +28,45 @@ sv_init(service *sv, char *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->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); return sv; } + +void sv_start(service *sv) +{ + char *arg_list[] = {"runsyssv", sv->svfile, NULL}; + switch(fork()) { + case 0: + setsid(); + execvp("runsyssv", arg_list); + perror("execvp"); + break; + case -1: + perror("fork"); + break; + } +} + +int sv_check(service *sv) +{ + 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; + + pid = getsyspid(sv); + + if (pid < 0 || checkprocess(pid) != 0) + return -1; + + return 0; +} diff --git a/sysmgr.c b/sysmgr.c @@ -1,5 +1,23 @@ +/* sysmgr -- A simplistic service supervisor. + * + * Copyright (C) 2020 Cem Keylan <cem@ckyln.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ #include <sys/types.h> #include <sys/stat.h> +#include <sys/wait.h> #include <unistd.h> #include <stdio.h> @@ -10,7 +28,45 @@ #include "util.h" #include "config.h" -static char *argv0; +static char *argv0, *rundir, *sysdir; + +void +term(int sig) +{ + /* We are ignoring the sig variable */ + (void)(sig); + + DIR *dir; + struct dirent *ent; + + if ((dir = opendir(rundir)) == NULL) + die("%s:", rundir); + + while ((ent = readdir(dir)) != NULL) { + char realfile[PATH_MAX]; + sprintf(realfile, "%s/%s", rundir, ent->d_name); + + printf("%s\n", ent->d_name); + + if (strncmp(ent->d_name, ".", 1) == 0 || + strcmp(ent->d_name, "pid") == 0) + continue; + + printf("%s\n", ent->d_name); + struct service sv; + sv_init(&sv, ent->d_name); + pid_t pid = getsyspid(&sv); + if (pid == -1) { + perror(sv.name); + continue; + } + if (kill(pid, SIGTERM) != 0) + perror("kill"); + } + sleep(1); + rm_rf(rundir); + exit(0); +} void usage(void) @@ -23,7 +79,6 @@ usage(void) int main(int argc, char *argv[]) { argv0 = argv[0]; - char *sysdir, *rundir; char sysmgr_pidfile[PATH_MAX]; if (argc > 1) @@ -35,6 +90,11 @@ 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); + pid_t pid = getpid(); printf("RUNDIR: %s\nSYSDIR: %s\nselfpid: %d\n", rundir, sysdir, pid); @@ -44,18 +104,24 @@ int main(int argc, char *argv[]) /* Go to the service directory and get all the service entries. */ DIR *dir; struct dirent *ent; - if ((dir = opendir(sysdir)) == NULL) - die("%s:", sysdir); - while ((ent = readdir(dir)) != NULL) { - if (strncmp(ent->d_name, ".", 1) == 0) - continue; - printf("%s\n", ent->d_name); - - struct service sv; - sv_init(&sv, ent->d_name); - + while(1) { + if ((dir = opendir(sysdir)) == NULL) + die("%s:", sysdir); + while ((ent = readdir(dir)) != NULL) { + if (strncmp(ent->d_name, ".", 1) == 0) + continue; + struct service sv; + sv_init(&sv, ent->d_name); + if (sv_check(&sv) != 0) { + printf("%s\n", ent->d_name); + sv_start(&sv); + } + } + closedir(dir); + sleep(1); } - closedir(dir); + wait(NULL); + term(SIGTERM); return 0; } diff --git a/util.h b/util.h @@ -19,15 +19,19 @@ typedef struct service { char sysdir[PATH_MAX]; char rundir[PATH_MAX]; char pidfile[PATH_MAX]; + char syspidfile[PATH_MAX]; char svfile[PATH_MAX]; char svrundir[PATH_MAX]; } service; /* service.c */ service *sv_init(service *sv, char *sv_name); +void sv_start(service *sv); +int sv_check(service *sv); /* proc.c */ int getsvpid(service *sv); +int getsyspid(service *sv); int checkprocess(int pid); int writesvpid(char *file, pid_t pid); @@ -56,4 +60,7 @@ int mkdirp(const char *path); size_t strlcpy(char *, const char *, size_t); size_t estrlcpy(char *, const char *, size_t); +/* rm.c */ +int rm_rf(char *path); + #endif