logo

rc-status-page

Unnamed repository; edit this file 'description' to name the repository.
commit: 0a2550bb0a741c3e7ac34726939564aeab76b71b
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Fri,  1 Apr 2022 20:35:19 +0200

Initial Commit

Diffstat:

A.gitignore2++
ALICENSE23+++++++++++++++++++++++
AMakefile15+++++++++++++++
Arc-status-page.c100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Arc-status-page.css7+++++++
5 files changed, 147 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -0,0 +1 @@ +/rc-status-page +\ No newline at end of file diff --git a/LICENSE b/LICENSE @@ -0,0 +1,23 @@ +Copyright (c) 2022 Haelwenn (lanodan) Monnier <contact+rc-status-page@hacktivis.me> +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/Makefile b/Makefile @@ -0,0 +1,15 @@ +CC ?= cc +CFLAGS ?= -O2 -ggdb -Wall -Wextra +PKG_CONFIG ?= pkg-config + +CFLAGS_openrc = `$(PKG_CONFIG) --cflags openrc` +LIBS_openrc = `$(PKG_CONFIG) --libs openrc` + +all: rc-status-page + +rc-status-page: rc-status-page.c + $(CC) -std=c11 $(CFLAGS) $(CFLAGS_openrc) -o $@ $< $(LDFLAGS) $(LIBS_openrc) + +.PHONY: clean +clean: + rm rc-status-page diff --git a/rc-status-page.c b/rc-status-page.c @@ -0,0 +1,100 @@ +// rc-status-page: Basic HTML status page based on OpenRC +// Copyright © 2022 Haelwenn (lanodan) Monnier <contact+rc-status-page@hacktivis.me> +// SPDX-License-Identifier: BSD-2-Clause + +#include <sys/queue.h> /* TAILQ_FOREACH() */ +#include <rc.h> /* rc_ / RC_ */ +#include <stdlib.h> /* printf */ +#include <errno.h> /* errno */ + +#include <time.h> /* time(), gmtime(), strftime() */ + +static RC_DEPTREE *deptree; +static RC_STRINGLIST *types; +RC_STRINGLIST *levels, *services; + +static void +print_service(const char *service) +{ + RC_SERVICE state = rc_service_state(service); + char *status; + + if(state & RC_SERVICE_STOPPING) { + status = "stopping"; + } else if(state & RC_SERVICE_STARTING) { + status = "starting"; + } else if(state & RC_SERVICE_INACTIVE) { + status = "inactive"; + } else if(state & RC_SERVICE_SCHEDULED) { + status = "scheduled"; + } else if(state & RC_SERVICE_STARTED) { + errno = 0; + if (rc_service_daemons_crashed(service) && errno != EACCES) { + status = "crashed"; + } else { + status = "started"; + } + } else { + status = "stopped"; + } + + printf("\t<li class=\"service service-%s\">%s: %s</li>\n", status, service, status); +} + +static void +print_services(const char *runlevel, RC_STRINGLIST *svcs) +{ + RC_STRINGLIST *l = NULL; + RC_STRING *s; + char *r = NULL; + + if (!svcs) { return; } + if (!deptree) { deptree = rc_deptree_load(); } + if (!types) { + types = rc_stringlist_new(); + rc_stringlist_add(types, "ineed"); + rc_stringlist_add(types, "iuse"); + rc_stringlist_add(types, "iafter"); + } + if (!runlevel) { r = rc_runlevel_get(); } + + l = rc_deptree_depends(deptree, types, svcs, r ? r : runlevel, RC_DEP_STRICT | RC_DEP_TRACE | RC_DEP_START); + free(r); + if (!l) return; + + printf("<ul>\n"); + TAILQ_FOREACH(s, l, entries) { + if (!rc_stringlist_find(svcs, s->value)) continue; + if (!runlevel || rc_service_in_runlevel(s->value, runlevel)) print_service(s->value); + } + rc_stringlist_free(l); + printf("</ul>\n"); +} + +int +main() { + RC_STRING *l; + char timestamp[BUFSIZ]; + time_t now = time(NULL); + struct tm *tm = gmtime(&now); + + strftime(timestamp, sizeof(timestamp), "%FT%TZ", tm); + + levels = rc_stringlist_new(); + rc_stringlist_add(levels, "hacktivism"); + + printf("<html><head><link rel=stylesheet href=\"rc-status-page.css\"/></head><body>"); + printf("<h1>Status page of hacktivis.me</h1>"); + + TAILQ_FOREACH(l, levels, entries) { + services = rc_services_in_runlevel(l->value); + print_services(l->value, services); + } + + printf("<footer>Generated at %s</footer>", timestamp); + + printf("</body></html>\n"); + + rc_stringlist_free(levels); + return 0; +} diff --git a/rc-status-page.css b/rc-status-page.css @@ -0,0 +1,7 @@ +.service-started { color:green; } +.service-stopped { color:red; } +.service-crashed { color:red; } +body { + display: table; + margin: 0 auto; +}