Skip to content

Instantly share code, notes, and snippets.

@ManonStripes
Last active November 21, 2019 10:32
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ManonStripes/e6c6709e5fa4a99c330371e0fdf90277 to your computer and use it in GitHub Desktop.
Save ManonStripes/e6c6709e5fa4a99c330371e0fdf90277 to your computer and use it in GitHub Desktop.
monit-5.20.0 Dark Theme
/*
* Copyright (C) Tildeslash Ltd. All rights reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3.
*
* 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 Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
*
* You must obey the GNU Affero General Public License in all respects
* for all of the code used other than OpenSSL.
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
// libmonit
#include "system/Time.h"
#include "util/List.h"
#include "monit.h"
#include "cervlet.h"
#include "engine.h"
#include "processor.h"
#include "base64.h"
#include "event.h"
#include "alert.h"
#include "ProcessTree.h"
#include "device.h"
#include "protocol.h"
#include "Color.h"
#include "Box.h"
#define ACTION(c) ! strncasecmp(req->url, c, sizeof(c))
/* URL Commands supported */
#define HOME "/"
#define TEST "/_monit"
#define ABOUT "/_about"
#define PING "/_ping"
#define GETID "/_getid"
#define STATUS "/_status"
#define STATUS2 "/_status2"
#define SUMMARY "/_summary"
#define REPORT "/_report"
#define RUNTIME "/_runtime"
#define VIEWLOG "/_viewlog"
#define DOACTION "/_doaction"
#define FAVICON "/favicon.ico"
typedef enum {
TXT = 0,
HTML
} __attribute__((__packed__)) Output_Type;
/* Private prototypes */
static boolean_t is_readonly(HttpRequest);
static void printFavicon(HttpResponse);
static void doGet(HttpRequest, HttpResponse);
static void doPost(HttpRequest, HttpResponse);
static void do_head(HttpResponse res, const char *path, const char *name, int refresh);
static void do_foot(HttpResponse res);
static void do_home(HttpResponse);
static void do_home_system(HttpResponse);
static void do_home_filesystem(HttpResponse);
static void do_home_directory(HttpResponse);
static void do_home_file(HttpResponse);
static void do_home_fifo(HttpResponse);
static void do_home_net(HttpResponse);
static void do_home_process(HttpResponse);
static void do_home_program(HttpResponse);
static void do_home_host(HttpResponse);
static void do_about(HttpResponse);
static void do_ping(HttpResponse);
static void do_getid(HttpResponse);
static void do_runtime(HttpRequest, HttpResponse);
static void do_viewlog(HttpRequest, HttpResponse);
static void handle_service(HttpRequest, HttpResponse);
static void handle_service_action(HttpRequest, HttpResponse);
static void handle_doaction(HttpRequest, HttpResponse);
static void handle_runtime(HttpRequest, HttpResponse);
static void handle_runtime_action(HttpRequest, HttpResponse);
static void is_monit_running(HttpResponse);
static void do_service(HttpRequest, HttpResponse, Service_T);
static void print_alerts(HttpResponse, Mail_T);
static void print_buttons(HttpRequest, HttpResponse, Service_T);
static void print_service_rules_timeout(HttpResponse, Service_T);
static void print_service_rules_existence(HttpResponse, Service_T);
static void print_service_rules_port(HttpResponse, Service_T);
static void print_service_rules_socket(HttpResponse, Service_T);
static void print_service_rules_icmp(HttpResponse, Service_T);
static void print_service_rules_perm(HttpResponse, Service_T);
static void print_service_rules_uid(HttpResponse, Service_T);
static void print_service_rules_euid(HttpResponse, Service_T);
static void print_service_rules_gid(HttpResponse, Service_T);
static void print_service_rules_timestamp(HttpResponse, Service_T);
static void print_service_rules_fsflags(HttpResponse, Service_T);
static void print_service_rules_filesystem(HttpResponse, Service_T);
static void print_service_rules_size(HttpResponse, Service_T);
static void print_service_rules_linkstatus(HttpResponse, Service_T);
static void print_service_rules_linkspeed(HttpResponse, Service_T);
static void print_service_rules_linksaturation(HttpResponse, Service_T);
static void print_service_rules_uploadbytes(HttpResponse, Service_T);
static void print_service_rules_uploadpackets(HttpResponse, Service_T);
static void print_service_rules_downloadbytes(HttpResponse, Service_T);
static void print_service_rules_downloadpackets(HttpResponse, Service_T);
static void print_service_rules_uptime(HttpResponse, Service_T);
static void print_service_rules_content(HttpResponse, Service_T);
static void print_service_rules_checksum(HttpResponse, Service_T);
static void print_service_rules_pid(HttpResponse, Service_T);
static void print_service_rules_ppid(HttpResponse, Service_T);
static void print_service_rules_program(HttpResponse, Service_T);
static void print_service_rules_resource(HttpResponse, Service_T);
static void print_status(HttpRequest, HttpResponse, int);
static void print_summary(HttpRequest, HttpResponse);
static void _printReport(HttpRequest req, HttpResponse res);
static void status_service_txt(Service_T, HttpResponse);
static char *get_monitoring_status(Output_Type, Service_T s, char *, int);
static char *get_service_status(Output_Type, Service_T, char *, int);
/**
* Implementation of doGet and doPost routines used by the cervlet
* processor module. This particilary cervlet will provide
* information about the monit deamon and programs monitored by
* monit.
*
* @file
*/
/* ------------------------------------------------------------------ Public */
/**
* Callback hook to the Processor module for registering this modules
* doGet and doPost methods.
*/
void init_service() {
add_Impl(doGet, doPost);
}
/* ----------------------------------------------------------------- Private */
static char *_getUptime(time_t delta, char s[256]) {
static int min = 60;
static int hour = 3600;
static int day = 86400;
long rest_d;
long rest_h;
long rest_m;
char *p = s;
if (delta < 0) {
*s = 0;
} else {
if ((rest_d = delta / day) > 0) {
p += snprintf(p, 256 - (p - s), "%ldd ", rest_d);
delta -= rest_d * day;
}
if ((rest_h = delta / hour) > 0 || (rest_d > 0)) {
p += snprintf(p, 256 - (p - s), "%ldh ", rest_h);
delta -= rest_h * hour;
}
rest_m = delta / min;
snprintf(p, 256 - (p - s), "%ldm", rest_m);
}
return s;
}
static void _formatStatus(const char *name, Event_Type errorType, Output_Type type, HttpResponse res, Service_T s, boolean_t validValue, const char *value, ...) {
if (type == HTML) {
StringBuffer_append(res->outputbuffer, "<tr><td>%c%s</td>", toupper(name[0]), name + 1);
} else {
StringBuffer_append(res->outputbuffer, " %-28s ", name);
}
if (! validValue) {
StringBuffer_append(res->outputbuffer, type == HTML ? "<td class='gray-text'>-</td>" : COLOR_DARKGRAY "-" COLOR_RESET);
} else {
va_list ap;
va_start(ap, value);
char *_value = Str_vcat(value, ap);
va_end(ap);
if (errorType != Event_Null && s->error & errorType)
StringBuffer_append(res->outputbuffer, type == HTML ? "<td class='red-text'>" : COLOR_LIGHTRED);
else
StringBuffer_append(res->outputbuffer, type == HTML ? "<td>" : COLOR_DEFAULT);
if (type == HTML) {
// If the output contains multiple line, wrap use <pre>, otherwise keep as is
int multiline = strrchr(_value, '\n') > 0;
if (multiline)
StringBuffer_append(res->outputbuffer, "<pre>");
escapeHTML(res->outputbuffer, _value);
StringBuffer_append(res->outputbuffer, "%s</td>", multiline ? "</pre>" : "");
} else {
int column = 0;
for (int i = 0; _value[i]; i++) {
if (_value[i] == '\r') {
// Discard CR
continue;
} else if (_value[i] == '\n') {
// Indent 2nd+ line
if (_value[i + 1])
StringBuffer_append(res->outputbuffer, "\n ");
column = 0;
continue;
} else if (column <= 200) {
StringBuffer_append(res->outputbuffer, "%c", _value[i]);
column++;
}
}
StringBuffer_append(res->outputbuffer, COLOR_RESET);
}
FREE(_value);
}
StringBuffer_append(res->outputbuffer, type == HTML ? "</tr>" : "\n");
}
static void _printStatus(Output_Type type, HttpResponse res, Service_T s) {
if (Util_hasServiceStatus(s)) {
switch (s->type) {
case Service_System:
_formatStatus("load average", Event_Resource, type, res, s, true, "[%.2f] [%.2f] [%.2f]", systeminfo.loadavg[0], systeminfo.loadavg[1], systeminfo.loadavg[2]);
_formatStatus("cpu", Event_Resource, type, res, s, true, "%.1f%%us %.1f%%sy"
#ifdef HAVE_CPU_WAIT
" %.1f%%wa"
#endif
, systeminfo.total_cpu_user_percent > 0. ? systeminfo.total_cpu_user_percent : 0., systeminfo.total_cpu_syst_percent > 0. ? systeminfo.total_cpu_syst_percent : 0.
#ifdef HAVE_CPU_WAIT
, systeminfo.total_cpu_wait_percent > 0. ? systeminfo.total_cpu_wait_percent : 0.
#endif
);
_formatStatus("memory usage", Event_Resource, type, res, s, true, "%s [%.1f%%]", Str_bytesToSize(systeminfo.total_mem, (char[10]){}), systeminfo.total_mem_percent);
_formatStatus("swap usage", Event_Resource, type, res, s, true, "%s [%.1f%%]", Str_bytesToSize(systeminfo.total_swap, (char[10]){}), systeminfo.total_swap_percent);
_formatStatus("uptime", Event_Uptime, type, res, s, systeminfo.booted > 0, "%s", _getUptime(Time_now() - systeminfo.booted, (char[256]){}));
_formatStatus("boot time", Event_Null, type, res, s, true, "%s", Time_string(systeminfo.booted, (char[32]){}));
break;
case Service_File:
_formatStatus("permission", Event_Permission, type, res, s, s->inf->priv.file.mode >= 0, "%o", s->inf->priv.file.mode & 07777);
_formatStatus("uid", Event_Uid, type, res, s, s->inf->priv.file.uid >= 0, "%d", s->inf->priv.file.uid);
_formatStatus("gid", Event_Gid, type, res, s, s->inf->priv.file.gid >= 0, "%d", s->inf->priv.file.gid);
_formatStatus("size", Event_Size, type, res, s, s->inf->priv.file.size >= 0, "%s", Str_bytesToSize(s->inf->priv.file.size, (char[10]){}));
_formatStatus("timestamp", Event_Timestamp, type, res, s, s->inf->priv.file.timestamp > 0, "%s", Time_string(s->inf->priv.file.timestamp, (char[32]){}));
if (s->matchlist)
_formatStatus("content match", Event_Content, type, res, s, true, "%s", (s->error & Event_Content) ? "yes" : "no");
if (s->checksum)
_formatStatus("checksum", Event_Checksum, type, res, s, *s->inf->priv.file.cs_sum, "%s (%s)", s->inf->priv.file.cs_sum, checksumnames[s->checksum->type]);
break;
case Service_Directory:
_formatStatus("permission", Event_Permission, type, res, s, s->inf->priv.directory.mode >= 0, "%o", s->inf->priv.directory.mode & 07777);
_formatStatus("uid", Event_Uid, type, res, s, s->inf->priv.directory.uid >= 0, "%d", s->inf->priv.directory.uid);
_formatStatus("gid", Event_Gid, type, res, s, s->inf->priv.directory.gid >= 0, "%d", s->inf->priv.directory.gid);
_formatStatus("timestamp", Event_Timestamp, type, res, s, s->inf->priv.directory.timestamp > 0, "%s", Time_string(s->inf->priv.directory.timestamp, (char[32]){}));
break;
case Service_Fifo:
_formatStatus("permission", Event_Permission, type, res, s, s->inf->priv.fifo.mode >= 0, "%o", s->inf->priv.fifo.mode & 07777);
_formatStatus("uid", Event_Uid, type, res, s, s->inf->priv.fifo.uid >= 0, "%d", s->inf->priv.fifo.uid);
_formatStatus("gid", Event_Gid, type, res, s, s->inf->priv.fifo.gid >= 0, "%d", s->inf->priv.fifo.gid);
_formatStatus("timestamp", Event_Timestamp, type, res, s, s->inf->priv.fifo.timestamp > 0, "%s", Time_string(s->inf->priv.fifo.timestamp, (char[32]){}));
break;
case Service_Net:
{
long long speed = Link_getSpeed(s->inf->priv.net.stats);
long long ibytes = Link_getBytesInPerSecond(s->inf->priv.net.stats);
long long obytes = Link_getBytesOutPerSecond(s->inf->priv.net.stats);
_formatStatus("link", Event_Link, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%d errors", Link_getErrorsInPerSecond(s->inf->priv.net.stats) + Link_getErrorsOutPerSecond(s->inf->priv.net.stats));
if (speed > 0) {
_formatStatus("capacity", Event_Speed, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%.0lf Mb/s %s-duplex", (double)speed / 1000000., Link_getDuplex(s->inf->priv.net.stats) == 1 ? "full" : "half");
_formatStatus("download bytes", Event_ByteIn, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%s/s (%.1f%% link saturation)", Str_bytesToSize(ibytes, (char[10]){}), 100. * ibytes * 8 / (double)speed);
_formatStatus("upload bytes", Event_ByteOut, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%s/s (%.1f%% link saturation)", Str_bytesToSize(obytes, (char[10]){}), 100. * obytes * 8 / (double)speed);
} else {
_formatStatus("download bytes", Event_ByteIn, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%s/s", Str_bytesToSize(ibytes, (char[10]){}));
_formatStatus("upload bytes", Event_ByteOut, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%s/s", Str_bytesToSize(obytes, (char[10]){}));
}
_formatStatus("download packets", Event_PacketIn, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%lld per second", Link_getPacketsInPerSecond(s->inf->priv.net.stats));
_formatStatus("upload packets", Event_PacketOut, type, res, s, Link_getState(s->inf->priv.net.stats) == 1, "%lld per second", Link_getPacketsOutPerSecond(s->inf->priv.net.stats));
}
break;
case Service_Filesystem:
_formatStatus("permission", Event_Permission, type, res, s, s->inf->priv.filesystem.mode >= 0, "%o", s->inf->priv.filesystem.mode & 07777);
_formatStatus("uid", Event_Uid, type, res, s, s->inf->priv.filesystem.uid >= 0, "%d", s->inf->priv.filesystem.uid);
_formatStatus("gid", Event_Gid, type, res, s, s->inf->priv.filesystem.gid >= 0, "%d", s->inf->priv.filesystem.gid);
_formatStatus("filesystem flags", Event_Fsflag, type, res, s, true, "0x%x", s->inf->priv.filesystem.flags);
_formatStatus("block size", Event_Null, type, res, s, true, "%s", Str_bytesToSize(s->inf->priv.filesystem.f_bsize, (char[10]){}));
_formatStatus("space total", Event_Null, type, res, s, true, "%s (of which %.1f%% is reserved for root user)",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocks * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)(s->inf->priv.filesystem.f_blocksfreetotal - s->inf->priv.filesystem.f_blocksfree) / (float)s->inf->priv.filesystem.f_blocks) : 0);
_formatStatus("space free for non superuser", Event_Null, type, res, s, true, "%s [%.1f%%]",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfree * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfree / (float)s->inf->priv.filesystem.f_blocks) : 0);
_formatStatus("space free total", Event_Resource, type, res, s, true, "%s [%.1f%%]",
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.f_blocksfreetotal * s->inf->priv.filesystem.f_bsize, (char[10]){}) : "0 MB",
s->inf->priv.filesystem.f_blocks > 0 ? ((float)100 * (float)s->inf->priv.filesystem.f_blocksfreetotal / (float)s->inf->priv.filesystem.f_blocks) : 0);
if (s->inf->priv.filesystem.f_files > 0) {
_formatStatus("inodes total", Event_Null, type, res, s, true, "%lld", s->inf->priv.filesystem.f_files);
_formatStatus("inodes free", Event_Resource, type, res, s, true, "%lld [%.1f%%]", s->inf->priv.filesystem.f_filesfree, (float)100 * (float)s->inf->priv.filesystem.f_filesfree / (float)s->inf->priv.filesystem.f_files);
}
break;
case Service_Process:
_formatStatus("pid", Event_Pid, type, res, s, s->inf->priv.process.pid >= 0, "%d", s->inf->priv.process.pid);
_formatStatus("parent pid", Event_PPid, type, res, s, s->inf->priv.process.ppid >= 0, "%d", s->inf->priv.process.ppid);
_formatStatus("uid", Event_Uid, type, res, s, s->inf->priv.process.uid >= 0, "%d", s->inf->priv.process.uid);
_formatStatus("effective uid", Event_Uid, type, res, s, s->inf->priv.process.euid >= 0, "%d", s->inf->priv.process.euid);
_formatStatus("gid", Event_Gid, type, res, s, s->inf->priv.process.gid >= 0, "%d", s->inf->priv.process.gid);
_formatStatus("uptime", Event_Uptime, type, res, s, s->inf->priv.process.uptime >= 0, "%s", _getUptime(s->inf->priv.process.uptime, (char[256]){}));
if (Run.flags & Run_ProcessEngineEnabled) {
_formatStatus("threads", Event_Resource, type, res, s, s->inf->priv.process.threads >= 0, "%d", s->inf->priv.process.threads);
_formatStatus("children", Event_Resource, type, res, s, s->inf->priv.process.children >= 0, "%d", s->inf->priv.process.children);
_formatStatus("cpu", Event_Resource, type, res, s, s->inf->priv.process.cpu_percent >= 0, "%.1f%%", s->inf->priv.process.cpu_percent);
_formatStatus("cpu total", Event_Resource, type, res, s, s->inf->priv.process.total_cpu_percent >= 0, "%.1f%%", s->inf->priv.process.total_cpu_percent);
_formatStatus("memory", Event_Resource, type, res, s, s->inf->priv.process.mem_percent >= 0, "%.1f%% [%s]", s->inf->priv.process.mem_percent, Str_bytesToSize(s->inf->priv.process.mem, (char[10]){}));
_formatStatus("memory total", Event_Resource, type, res, s, s->inf->priv.process.total_mem_percent >= 0, "%.1f%% [%s]", s->inf->priv.process.total_mem_percent, Str_bytesToSize(s->inf->priv.process.total_mem, (char[10]){}));
}
break;
case Service_Program:
if (s->program->started) {
_formatStatus("last exit value", Event_Status, type, res, s, true, "%d", s->program->exitStatus);
_formatStatus("last output", Event_Status, type, res, s, StringBuffer_length(s->program->output), "%s", StringBuffer_toString(s->program->output));
}
break;
default:
break;
}
for (Icmp_T i = s->icmplist; i; i = i->next) {
if (i->is_available == Connection_Failed)
_formatStatus("ping response time", Event_Icmp, type, res, s, true, "connection failed");
else
_formatStatus("ping response time", Event_Null, type, res, s, i->is_available != Connection_Init && i->response >= 0., "%s", Str_milliToTime(i->response, (char[23]){}));
}
for (Port_T p = s->portlist; p; p = p->next) {
if (p->is_available == Connection_Failed) {
_formatStatus("port response time", Event_Connection, type, res, s, true, "FAILED to [%s]:%d%s type %s/%s %sprotocol %s", p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.flags ? "using SSL/TLS " : "", p->protocol->name);
} else {
_formatStatus("port response time", Event_Null, type, res, s, p->is_available != Connection_Init, "%s to %s:%d%s type %s/%s %s protocol %s", Str_milliToTime(p->response, (char[23]){}), p->hostname, p->target.net.port, Util_portRequestDescription(p), Util_portTypeDescription(p), Util_portIpDescription(p), p->target.net.ssl.flags ? "using SSL/TLS " : "", p->protocol->name);
}
}
for (Port_T p = s->socketlist; p; p = p->next) {
if (p->is_available == Connection_Failed) {
_formatStatus("unix socket response time", Event_Connection, type, res, s, true, "FAILED to %s type %s protocol %s", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
} else {
_formatStatus("unix socket response time", Event_Null, type, res, s, p->is_available != Connection_Init, "%s to %s type %s protocol %s", Str_milliToTime(p->response, (char[23]){}), p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name);
}
}
}
_formatStatus("data collected", Event_Null, type, res, s, true, "%s", Time_string(s->collected.tv_sec, (char[32]){}));
}
/**
* Called by the Processor (via the service method)
* to handle a POST request.
*/
static void doPost(HttpRequest req, HttpResponse res) {
set_content_type(res, "text/html");
if (ACTION(RUNTIME))
handle_runtime_action(req, res);
else if (ACTION(VIEWLOG))
do_viewlog(req, res);
else if (ACTION(STATUS))
print_status(req, res, 1);
else if (ACTION(STATUS2))
print_status(req, res, 2);
else if (ACTION(SUMMARY))
print_summary(req, res);
else if (ACTION(REPORT))
_printReport(req, res);
else if (ACTION(DOACTION))
handle_doaction(req, res);
else
handle_service_action(req, res);
}
/**
* Called by the Processor (via the service method)
* to handle a GET request.
*/
static void doGet(HttpRequest req, HttpResponse res) {
set_content_type(res, "text/html");
if (ACTION(HOME)) {
LOCK(Run.mutex)
do_home(res);
END_LOCK;
} else if (ACTION(RUNTIME)) {
handle_runtime(req, res);
} else if (ACTION(TEST)) {
is_monit_running(res);
} else if (ACTION(ABOUT)) {
do_about(res);
} else if (ACTION(FAVICON)) {
printFavicon(res);
} else if (ACTION(PING)) {
do_ping(res);
} else if (ACTION(GETID)) {
do_getid(res);
} else if (ACTION(STATUS)) {
print_status(req, res, 1);
} else if (ACTION(STATUS2)) {
print_status(req, res, 2);
} else if (ACTION(SUMMARY)) {
print_summary(req, res);
} else if (ACTION(REPORT)) {
_printReport(req, res);
} else {
handle_service(req, res);
}
}
/* ----------------------------------------------------------------- Helpers */
static void is_monit_running(HttpResponse res) {
set_status(res, exist_daemon() ? SC_OK : SC_GONE);
}
static void printFavicon(HttpResponse res) {
static size_t l;
Socket_T S = res->S;
static unsigned char *favicon = NULL;
if (! favicon) {
favicon = CALLOC(sizeof(unsigned char), strlen(FAVICON_ICO));
l = decode_base64(favicon, FAVICON_ICO);
}
if (l) {
res->is_committed = true;
Socket_print(S, "HTTP/1.0 200 OK\r\n");
Socket_print(S, "Content-length: %lu\r\n", (unsigned long)l);
Socket_print(S, "Content-Type: image/x-icon\r\n");
Socket_print(S, "Connection: close\r\n\r\n");
Socket_write(S, favicon, l);
}
}
static void do_head(HttpResponse res, const char *path, const char *name, int refresh) {
StringBuffer_append(res->outputbuffer,
"<!DOCTYPE html>"\
"<html>"\
"<head>"\
"<title>Monit: %s</title> "\
"<style type=\"text/css\"> "\
" @import url('https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,600');"\
" html, body {height: 100%%;margin: 0;} "\
" body {background-color: #29292d;font: 18px 'Open Sans', Helvetica, Arial, sans-serif; color:#d0d0d0; font-weight:300;} "\
" h1 {padding:80px 0 0 0; margin: 0; text-align:left;color:#fff;font-size:36px; font-weight:300;} "\
" h2 {margin:0 0 0 140px; padding:80px 0 40px 0; text-align:left;color:#fff;font-size:36px; font-weight:300;} "\
" p {margin:0;text-align:left;} "\
" a:hover {text-decoration: none;} "\
" a {text-decoration: none;color:#d0d0d0; font-weight:600;} "\
" table {border-collapse:collapse; border:0;} "\
" .stripe {background:#434347} "\
" .rule {background:#434347} "\
" .red-text {color:#ad3355;} "\
" .green-text {color:#73ddc8;} "\
" .gray-text {color:#b1b1b1;} "\
" .blue-text {color:#36b9b8;} "\
" .yellow-text {color:#f9a582;} "\
" .orange-text {color:#f95944;} "\
" .short {overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 350px;}"\
" #wrap {min-height:92%%;} "\
" #main {overflow:auto; padding-bottom:50px;} "\
" /*Opera Fix*/body:before {content:\"\";height:100%%;float:left;width:0;margin-top:-32767px;/} "\
" #footer {margin-left:140px; position: relative; height: 50px; clear:both; font-size:11px;color:#777;text-align:left;} "\
" #footer a {color:#fff;} #footer a:hover {text-decoration: none;} "\
" nav {height:100%%; position:fixed; box-shadow: 0 0 32px #000; background:#2c2c31;font:18px 'Open Sans', Helvetica; width:80px; float:left; display:inline; margin:0; padding:0;} "\
" nav td {padding:0; height:80px; width:80px; text-align:center;} "\
" nav a {text-decoration:none;} "\
" nav .active {background-color:#36b9b8; color:#fff; height:80px; width:80px;} "\
" nav .active a {color:#fff;} "\
" nav .hidden {display:none;} "\
" #header {margin-left:140px; margin-bottom:30px;background:#29292d} "\
" #header-row {margin-left:140px; width:85%%;} "\
" #header-row th {padding:30px 10px 10px 10px;font-size:18px; font-weight:300; color:#fff;} "\
" #header-row td {padding:3px 10px; line-height: 18px;} "\
" #header-row .first {min-width:200px;width:200px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:24px; font-weight:300;color:#fff;} "\
" #status-table {margin-left:140px; width:85%%;} "\
" #status-table th {text-align:left;background:#434347;font-weight:300;font-size:18px;color:#fff;} "\
" #status-table th, #status-table td, #status-table tr {border:1px solid #4c4c54;padding:5px 5px 5px 10px;} "\
" #status-table td, #status-table tr {font-size:16px;} "\
" #buttons {font-size:20px; margin:40px auto 20px;} "\
" #buttons td {padding-right:50px;} "\
" #buttons input {font-size:18px;padding:5px;} "\
"</style>"\
"<meta HTTP-EQUIV='REFRESH' CONTENT=%d> "\
"<meta HTTP-EQUIV='Expires' Content=0> "\
"<meta HTTP-EQUIV='Pragma' CONTENT='no-cache'> "\
"<meta charset='UTF-8'>" \
"<link rel='shortcut icon' href='favicon.ico'>"\
"<script src=\"https://use.fontawesome.com/ebdc252e31.js\"></script>"\
"<script type=\"text/javascript\">function setActive() {"\
" aObj = document.getElementById('nav').getElementsByTagName('a');"\
" tdObj = document.getElementById('nav').getElementsByTagName('td');"\
" for(i=0;i<aObj.length;i++) { "\
" if(document.location.href == aObj[i].href) {"\
" if(i == 0) {"\
" document.getElementById('nav').getElementsByTagName('tr')[aObj.length - 1].className='hidden';"\
" }"\
" tdObj[i].className='active';"\
" }"\
" }"\
"}"\
"window.onload = setActive;</script>"\
"</head>"\
"<body><div id='wrap'><div id='main'>" \
"<nav id=\"nav\">"\
"<table>"\
" <tr>"\
" <td>"\
" <a href='.'>"\
" <i class=\"fa fa-home\" aria-hidden=\"true\"></i>"\
" </a>"\
" </td>"\
" </tr>"\
" <tr>"\
" <td>"\
" <a href='%s'>"\
" <i class=\"fa fa-sliders\" aria-hidden=\"true\"></i>"\
" </a>"\
" </td>"\
" </tr>"\
"</table>"\
"</nav>",
Run.system->name, refresh, path, name, VERSION);
}
static void do_foot(HttpResponse res) {
StringBuffer_append(res->outputbuffer,
"</div></div>"
"<div id='footer'>"
"Copyright &copy; 2001-2016 <a href=\"http://tildeslash.com/\">Tildeslash</a>. All rights reserved. Dark Theme by <a href=\"https://github.com/ManonStripes\">Manon Stripes</a>."
"<span style='margin-left:5px;'></span>"
"<a href=\"http://mmonit.com/monit/\">Monit web site</a> | "
"<a href=\"http://mmonit.com/wiki/\">Monit Wiki</a> | "
"<a href=\"http://mmonit.com/\">M/Monit</a>"
"</div></body></html>");
}
static void do_home(HttpResponse res) {
do_head(res, "", "", Run.polltime);
StringBuffer_append(res->outputbuffer,
"<table id='header'>"
" <tr>"
" <td colspan=2 valign='top' align='left' width='100%%'>"
" <h1>Monit Service Manager</h1>"
" <p align='left'>Monit is <a href='_runtime'>running</a> on %s and monitoring:</p><br>"
" </td>"
" </tr>"
"</table>", Run.system->name);
do_home_system(res);
do_home_process(res);
do_home_program(res);
do_home_filesystem(res);
do_home_file(res);
do_home_fifo(res);
do_home_directory(res);
do_home_net(res);
do_home_host(res);
do_foot(res);
}
static void do_about(HttpResponse res) {
StringBuffer_append(res->outputbuffer,
"<html><head><title>about monit</title></head><body bgcolor=white>"
"<br><h1><center><a href='http://mmonit.com/monit/'>"
"monit " VERSION "</a></center></h1>");
StringBuffer_append(res->outputbuffer,
"<ul>"
"<li style='padding-bottom:10px;'>Copyright &copy; 2001-2016 <a "
"href='http://tildeslash.com/'>Tildeslash Ltd"
"</a>. All Rights Reserved.</li></ul>");
StringBuffer_append(res->outputbuffer, "<hr size='1'>");
StringBuffer_append(res->outputbuffer,
"<p>This program is free software; you can redistribute it and/or "
"modify it under the terms of the GNU Affero General Public License version 3</p>"
"<p>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 "
"<a href='http://www.gnu.org/licenses/agpl.html'>"
"GNU AFFERO GENERAL PUBLIC LICENSE</a> for more details.</p>");
StringBuffer_append(res->outputbuffer,
"<center><p style='padding-top:20px;'>[<a href='.'>Back to Monit</a>]</p></body></html>");
}
static void do_ping(HttpResponse res) {
StringBuffer_append(res->outputbuffer, "pong");
}
static void do_getid(HttpResponse res) {
StringBuffer_append(res->outputbuffer, "%s", Run.id);
}
static void do_runtime(HttpRequest req, HttpResponse res) {
int pid = exist_daemon();
char buf[STRLEN];
do_head(res, "_runtime", "Runtime", 1000);
StringBuffer_append(res->outputbuffer,
"<h2>Monit runtime status</h2>");
StringBuffer_append(res->outputbuffer, "<table id='status-table'><tr>"
"<th width='40%%'>Parameter</th>"
"<th width='60%%'>Value</th></tr>");
StringBuffer_append(res->outputbuffer, "<tr><td>Monit ID</td><td>%s</td></tr>", Run.id);
StringBuffer_append(res->outputbuffer, "<tr><td>Host</td><td>%s</td></tr>", Run.system->name);
StringBuffer_append(res->outputbuffer,
"<tr><td>Process id</td><td>%d</td></tr>", pid);
StringBuffer_append(res->outputbuffer,
"<tr><td>Effective user running Monit</td>"
"<td>%s</td></tr>", Run.Env.user);
StringBuffer_append(res->outputbuffer,
"<tr><td>Controlfile</td><td>%s</td></tr>", Run.files.control);
if (Run.files.log)
StringBuffer_append(res->outputbuffer,
"<tr><td>Logfile</td><td>%s</td></tr>", Run.files.log);
StringBuffer_append(res->outputbuffer,
"<tr><td>Pidfile</td><td>%s</td></tr>", Run.files.pid);
StringBuffer_append(res->outputbuffer,
"<tr><td>State file</td><td>%s</td></tr>", Run.files.state);
StringBuffer_append(res->outputbuffer,
"<tr><td>Debug</td><td>%s</td></tr>",
Run.debug ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"<tr><td>Log</td><td>%s</td></tr>", (Run.flags & Run_Log) ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"<tr><td>Use syslog</td><td>%s</td></tr>",
(Run.flags & Run_UseSyslog) ? "True" : "False");
if (Run.eventlist_dir) {
if (Run.eventlist_slots < 0)
snprintf(buf, STRLEN, "unlimited");
else
snprintf(buf, STRLEN, "%d", Run.eventlist_slots);
StringBuffer_append(res->outputbuffer,
"<tr><td>Event queue</td>"
"<td>base directory %s with %d slots</td></tr>",
Run.eventlist_dir, Run.eventlist_slots);
}
#ifdef HAVE_OPENSSL
{
const char *options = Ssl_printOptions(&(Run.ssl), (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer,
"<tr><td>SSL options</td><td>%s</td></tr>", options);
}
#endif
if (Run.mmonits) {
StringBuffer_append(res->outputbuffer, "<tr><td>M/Monit server(s)</td><td>");
for (Mmonit_T c = Run.mmonits; c; c = c->next)
{
StringBuffer_append(res->outputbuffer, "%s with timeout %s", c->url->url, Str_milliToTime(c->timeout, (char[23]){}));
#ifdef HAVE_OPENSSL
if (c->ssl.flags) {
StringBuffer_append(res->outputbuffer, " using SSL/TLS");
const char *options = Ssl_printOptions(&c->ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer, " with options {%s}", options);
if (c->ssl.checksum)
StringBuffer_append(res->outputbuffer, " and certificate checksum %s equal to '%s'", checksumnames[c->ssl.checksumType], c->ssl.checksum);
}
#endif
if (c->url->user)
StringBuffer_append(res->outputbuffer, " using credentials");
if (c->next)
StringBuffer_append(res->outputbuffer, "</td></tr><tr><td>&nbsp;</td><td>");
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (Run.mailservers) {
StringBuffer_append(res->outputbuffer, "<tr><td>Mail server(s)</td><td>");
for (MailServer_T mta = Run.mailservers; mta; mta = mta->next) {
StringBuffer_append(res->outputbuffer, "%s:%d", mta->host, mta->port);
#ifdef HAVE_OPENSSL
if (mta->ssl.flags) {
StringBuffer_append(res->outputbuffer, " using SSL/TLS");
const char *options = Ssl_printOptions(&mta->ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(res->outputbuffer, " with options {%s}", options);
if (mta->ssl.checksum)
StringBuffer_append(res->outputbuffer, " and certificate checksum %s equal to '%s'", checksumnames[mta->ssl.checksumType], mta->ssl.checksum);
}
#endif
if (mta->next)
StringBuffer_append(res->outputbuffer, "</td></tr><tr><td>&nbsp;</td><td>");
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (Run.MailFormat.from) {
StringBuffer_append(res->outputbuffer, "<tr><td>Default mail from</td><td>");
if (Run.MailFormat.from->name)
StringBuffer_append(res->outputbuffer, "%s &lt;%s&gt;", Run.MailFormat.from->name, Run.MailFormat.from->address);
else
StringBuffer_append(res->outputbuffer, "%s", Run.MailFormat.from->address);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (Run.MailFormat.replyto) {
StringBuffer_append(res->outputbuffer, "<tr><td>Default mail reply to</td><td>");
if (Run.MailFormat.replyto->name)
StringBuffer_append(res->outputbuffer, "%s &lt;%s&gt;", Run.MailFormat.replyto->name, Run.MailFormat.replyto->address);
else
StringBuffer_append(res->outputbuffer, "%s", Run.MailFormat.replyto->address);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (Run.MailFormat.subject)
StringBuffer_append(res->outputbuffer, "<tr><td>Default mail subject</td><td>%s</td></tr>", Run.MailFormat.subject);
if (Run.MailFormat.message)
StringBuffer_append(res->outputbuffer, "<tr><td>Default mail message</td><td>%s</td></tr>", Run.MailFormat.message);
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for Send/Expect buffer</td><td>%s</td></tr>", Str_bytesToSize(Run.limits.sendExpectBuffer, buf));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for file content buffer</td><td>%s</td></tr>", Str_bytesToSize(Run.limits.fileContentBuffer, buf));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for HTTP content buffer</td><td>%s</td></tr>", Str_bytesToSize(Run.limits.httpContentBuffer, buf));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for program output</td><td>%s</td></tr>", Str_bytesToSize(Run.limits.programOutput, buf));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for network timeout</td><td>%s</td></tr>", Str_milliToTime(Run.limits.networkTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for check program timeout</td><td>%s</td></tr>", Str_milliToTime(Run.limits.programTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for service stop timeout</td><td>%s</td></tr>", Str_milliToTime(Run.limits.stopTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for service start timeout</td><td>%s</td></tr>", Str_milliToTime(Run.limits.startTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "<tr><td>Limit for service restart timeout</td><td>%s</td></tr>", Str_milliToTime(Run.limits.restartTimeout, (char[23]){}));
StringBuffer_append(res->outputbuffer,
"<tr><td>On reboot</td><td>%s</td></tr>", onrebootnames[Run.onreboot]);
StringBuffer_append(res->outputbuffer,
"<tr><td>Poll time</td><td>%d seconds with start delay %d seconds</td></tr>",
Run.polltime, Run.startdelay);
if (Run.httpd.flags & Httpd_Net) {
StringBuffer_append(res->outputbuffer,
"<tr><td>httpd bind address</td><td>%s</td></tr>",
Run.httpd.socket.net.address ? Run.httpd.socket.net.address : "Any/All");
StringBuffer_append(res->outputbuffer,
"<tr><td>httpd portnumber</td><td>%d</td></tr>", Run.httpd.socket.net.port);
} else if (Run.httpd.flags & Httpd_Unix) {
StringBuffer_append(res->outputbuffer,
"<tr><td>httpd unix socket</td><td>%s</td></tr>",
Run.httpd.socket.unix.path);
}
StringBuffer_append(res->outputbuffer,
"<tr><td>httpd signature</td><td>%s</td></tr>",
Run.httpd.flags & Httpd_Signature ? "True" : "False");
StringBuffer_append(res->outputbuffer,
"<tr><td>Use ssl encryption</td><td>%s</td></tr>",
Run.httpd.flags & Httpd_Ssl ? "True" : "False");
if (Run.httpd.flags & Httpd_Ssl) {
StringBuffer_append(res->outputbuffer,
"<tr><td>PEM key/certificate file</td><td>%s</td></tr>",
Run.httpd.socket.net.ssl.pem);
if (Run.httpd.socket.net.ssl.clientpem != NULL) {
StringBuffer_append(res->outputbuffer,
"<tr><td>Client PEM key/certification"
"</td><td>%s</td></tr>", "Enabled");
StringBuffer_append(res->outputbuffer,
"<tr><td>Client PEM key/certificate file"
"</td><td>%s</td></tr>", Run.httpd.socket.net.ssl.clientpem);
} else {
StringBuffer_append(res->outputbuffer,
"<tr><td>Client PEM key/certification"
"</td><td>%s</td></tr>", "Disabled");
}
StringBuffer_append(res->outputbuffer,
"<tr><td>Allow self certified certificates "
"</td><td>%s</td></tr>", Run.httpd.flags & Httpd_AllowSelfSignedCertificates ? "True" : "False");
}
StringBuffer_append(res->outputbuffer,
"<tr><td>httpd auth. style</td><td>%s</td></tr>",
Run.httpd.credentials && Engine_hasAllow() ? "Basic Authentication and Host/Net allow list" : Run.httpd.credentials ? "Basic Authentication" : Engine_hasAllow() ? "Host/Net allow list" : "No authentication");
print_alerts(res, Run.maillist);
StringBuffer_append(res->outputbuffer, "</table>");
if (! is_readonly(req)) {
StringBuffer_append(res->outputbuffer,
"<table id='buttons'><tr>");
StringBuffer_append(res->outputbuffer,
"<td style='color:red;'>"
"<form method=POST action='_runtime'>Stop Monit http server? "
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden name='action' value='stop'>"
"<input type=submit value='Go'>"
"</form>"
"</td>",
res->token);
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action='_runtime'>Force validate now? "
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden name='action' value='validate'>"
"<input type=submit value='Go'>"
"</form>"
"</td>",
res->token);
if ((Run.flags & Run_Log) && ! (Run.flags & Run_UseSyslog)) {
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action='_viewlog'>View Monit logfile? "
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=submit value='Go'>"
"</form>"
"</td>",
res->token);
}
StringBuffer_append(res->outputbuffer,
"</tr></table>");
}
do_foot(res);
}
static void do_viewlog(HttpRequest req, HttpResponse res) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficient privileges to access this page");
return;
}
do_head(res, "_viewlog", "View log", 100);
if ((Run.flags & Run_Log) && ! (Run.flags & Run_UseSyslog)) {
struct stat sb;
if (! stat(Run.files.log, &sb)) {
FILE *f = fopen(Run.files.log, "r");
if (f) {
#define BUFSIZE 512
size_t n;
char buf[BUFSIZE+1];
StringBuffer_append(res->outputbuffer, "<br><p><form><textarea cols=120 rows=30 readonly>");
while ((n = fread(buf, sizeof(char), BUFSIZE, f)) > 0) {
buf[n] = 0;
StringBuffer_append(res->outputbuffer, "%s", buf);
}
fclose(f);
StringBuffer_append(res->outputbuffer, "</textarea></form>");
} else {
StringBuffer_append(res->outputbuffer, "Error opening logfile: %s", STRERROR);
}
} else {
StringBuffer_append(res->outputbuffer, "Error stating logfile: %s", STRERROR);
}
} else {
StringBuffer_append(res->outputbuffer,
"<b>Cannot view logfile:</b><br>");
if (! (Run.flags & Run_Log))
StringBuffer_append(res->outputbuffer, "Monit was started without logging");
else
StringBuffer_append(res->outputbuffer, "Monit uses syslog");
}
do_foot(res);
}
static void handle_service(HttpRequest req, HttpResponse res) {
char *name = req->url;
Service_T s = Util_getService(++name);
if (! s) {
send_error(req, res, SC_NOT_FOUND, "There is no service named \"%s\"", name ? name : "");
return;
}
do_service(req, res, s);
}
static void handle_service_action(HttpRequest req, HttpResponse res) {
char *name = req->url;
Service_T s = Util_getService(++name);
if (! s) {
send_error(req, res, SC_NOT_FOUND, "There is no service named \"%s\"", name ? name : "");
return;
}
const char *action = get_parameter(req, "action");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficient privileges to access this page");
return;
}
Action_Type doaction = Util_getAction(action);
if (doaction == Action_Ignored) {
send_error(req, res, SC_BAD_REQUEST, "Invalid action \"%s\"", action);
return;
}
s->doaction = doaction;
const char *token = get_parameter(req, "token");
if (token) {
FREE(s->token);
s->token = Str_dup(token);
}
LogInfo("'%s' %s on user request\n", s->name, action);
Run.flags |= Run_ActionPending; /* set the global flag */
do_wakeupcall();
}
do_service(req, res, s);
}
static void handle_doaction(HttpRequest req, HttpResponse res) {
Service_T s;
Action_Type doaction = Action_Ignored;
const char *action = get_parameter(req, "action");
const char *token = get_parameter(req, "token");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficient privileges to access this page");
return;
}
if ((doaction = Util_getAction(action)) == Action_Ignored) {
send_error(req, res, SC_BAD_REQUEST, "Invalid action \"%s\"", action);
return;
}
for (HttpParameter p = req->params; p; p = p->next) {
if (IS(p->name, "service")) {
s = Util_getService(p->value);
if (! s) {
send_error(req, res, SC_BAD_REQUEST, "There is no service named \"%s\"", p->value ? p->value : "");
return;
}
s->doaction = doaction;
LogInfo("'%s' %s on user request\n", s->name, action);
}
}
/* Set token for last service only so we'll get it back after all services were handled */
if (token) {
Service_T q = NULL;
for (s = servicelist; s; s = s->next)
if (s->doaction == doaction)
q = s;
if (q) {
FREE(q->token);
q->token = Str_dup(token);
}
}
Run.flags |= Run_ActionPending;
do_wakeupcall();
}
}
static void handle_runtime(HttpRequest req, HttpResponse res) {
LOCK(Run.mutex)
do_runtime(req, res);
END_LOCK;
}
static void handle_runtime_action(HttpRequest req, HttpResponse res) {
const char *action = get_parameter(req, "action");
if (action) {
if (is_readonly(req)) {
send_error(req, res, SC_FORBIDDEN, "You do not have sufficient privileges to access this page");
return;
}
if (IS(action, "validate")) {
LogInfo("The Monit http server woke up on user request\n");
do_wakeupcall();
} else if (IS(action, "stop")) {
LogInfo("The Monit http server stopped on user request\n");
send_error(req, res, SC_SERVICE_UNAVAILABLE, "The Monit http server is stopped");
Engine_stop();
return;
}
}
handle_runtime(req, res);
}
static void do_service(HttpRequest req, HttpResponse res, Service_T s) {
char buf[STRLEN];
ASSERT(s);
do_head(res, s->name, s->name, Run.polltime);
StringBuffer_append(res->outputbuffer,
"<h2>%s status</h2>"
"<table id='status-table'>"
"<tr>"
"<th width='30%%'>Parameter</th>"
"<th width='70%%'>Value</th>"
"</tr>"
"<tr>"
"<td>Name</td>"
"<td>%s</td>"
"</tr>",
servicetypes[s->type],
s->name);
if (s->type == Service_Process)
StringBuffer_append(res->outputbuffer, "<tr><td>%s</td><td>%s</td></tr>", s->matchlist ? "Match" : "Pid file", s->path);
else if (s->type == Service_Host)
StringBuffer_append(res->outputbuffer, "<tr><td>Address</td><td>%s</td></tr>", s->path);
else if (s->type == Service_Net)
StringBuffer_append(res->outputbuffer, "<tr><td>Interface</td><td>%s</td></tr>", s->path);
else if (s->type != Service_System)
StringBuffer_append(res->outputbuffer, "<tr><td>Path</td><td>%s</td></tr>", s->path);
StringBuffer_append(res->outputbuffer, "<tr><td>Status</td><td>%s</td></tr>", get_service_status(HTML, s, buf, sizeof(buf)));
for (ServiceGroup_T sg = servicegrouplist; sg; sg = sg->next)
for (list_t m = sg->members->head; m; m = m->next)
if (m->e == s)
StringBuffer_append(res->outputbuffer, "<tr><td>Group</td><td class='blue-text'>%s</td></tr>", sg->name);
StringBuffer_append(res->outputbuffer,
"<tr><td>Monitoring status</td><td>%s</td></tr>", get_monitoring_status(HTML, s, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer,
"<tr><td>Monitoring mode</td><td>%s</td></tr>", modenames[s->mode]);
StringBuffer_append(res->outputbuffer,
"<tr><td>On reboot</td><td>%s</td></tr>", onrebootnames[s->onreboot]);
for (Dependant_T d = s->dependantlist; d; d = d->next) {
if (d->dependant != NULL) {
StringBuffer_append(res->outputbuffer,
"<tr><td>Depends on service </td><td> <a href=%s> %s </a></td></tr>",
d->dependant, d->dependant);
}
}
if (s->start) {
StringBuffer_append(res->outputbuffer, "<tr><td>Start program</td><td>'%s'", Util_commandDescription(s->start, (char[STRLEN]){}));
if (s->start->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->start->uid);
if (s->start->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->start->gid);
StringBuffer_append(res->outputbuffer, " timeout %s", Str_milliToTime(s->start->timeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (s->stop) {
StringBuffer_append(res->outputbuffer, "<tr><td>Stop program</td><td>'%s'", Util_commandDescription(s->stop, (char[STRLEN]){}));
if (s->stop->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->stop->uid);
if (s->stop->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->stop->gid);
StringBuffer_append(res->outputbuffer, " timeout %s", Str_milliToTime(s->stop->timeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (s->restart) {
StringBuffer_append(res->outputbuffer, "<tr><td>Restart program</td><td>'%s'", Util_commandDescription(s->restart, (char[STRLEN]){}));
if (s->restart->has_uid)
StringBuffer_append(res->outputbuffer, " as uid %d", s->restart->uid);
if (s->restart->has_gid)
StringBuffer_append(res->outputbuffer, " as gid %d", s->restart->gid);
StringBuffer_append(res->outputbuffer, " timeout %s", Str_milliToTime(s->restart->timeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
if (s->every.type != Every_Cycle) {
StringBuffer_append(res->outputbuffer, "<tr><td>Check service</td><td>");
if (s->every.type == Every_SkipCycles)
StringBuffer_append(res->outputbuffer, "every %d cycle", s->every.spec.cycle.number);
else if (s->every.type == Every_Cron)
StringBuffer_append(res->outputbuffer, "every <code>\"%s\"</code>", s->every.spec.cron);
else if (s->every.type == Every_NotInCron)
StringBuffer_append(res->outputbuffer, "not every <code>\"%s\"</code>", s->every.spec.cron);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
_printStatus(HTML, res, s);
// Rules
print_service_rules_timeout(res, s);
print_service_rules_existence(res, s);
print_service_rules_icmp(res, s);
print_service_rules_port(res, s);
print_service_rules_socket(res, s);
print_service_rules_perm(res, s);
print_service_rules_uid(res, s);
print_service_rules_euid(res, s);
print_service_rules_gid(res, s);
print_service_rules_timestamp(res, s);
print_service_rules_fsflags(res, s);
print_service_rules_filesystem(res, s);
print_service_rules_size(res, s);
print_service_rules_linkstatus(res, s);
print_service_rules_linkspeed(res, s);
print_service_rules_linksaturation(res, s);
print_service_rules_uploadbytes(res, s);
print_service_rules_uploadpackets(res, s);
print_service_rules_downloadbytes(res, s);
print_service_rules_downloadpackets(res, s);
print_service_rules_uptime(res, s);
print_service_rules_content(res, s);
print_service_rules_checksum(res, s);
print_service_rules_pid(res, s);
print_service_rules_ppid(res, s);
print_service_rules_program(res, s);
print_service_rules_resource(res, s);
print_alerts(res, s->maillist);
StringBuffer_append(res->outputbuffer, "</table>");
print_buttons(req, res, s);
do_foot(res);
}
static void do_home_system(HttpResponse res) {
Service_T s = Run.system;
char buf[STRLEN];
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>System</th>"
"<th align='left'>Status</th>");
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer,
"<th align='right'>Load</th>"
"<th align='right'>CPU</th>"
"<th align='right'>Memory</th>"
"<th align='right'>Swap</th>");
}
StringBuffer_append(res->outputbuffer,
"</tr>"
"<tr class='stripe'>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer,
"<td align='right'>[%.2f]&nbsp;[%.2f]&nbsp;[%.2f]</td>"
"<td align='right'>"
"%.1f%%us,&nbsp;%.1f%%sy"
#ifdef HAVE_CPU_WAIT
",&nbsp;%.1f%%wa"
#endif
"</td>",
systeminfo.loadavg[0], systeminfo.loadavg[1], systeminfo.loadavg[2],
systeminfo.total_cpu_user_percent > 0. ? systeminfo.total_cpu_user_percent : 0.,
systeminfo.total_cpu_syst_percent > 0. ? systeminfo.total_cpu_syst_percent : 0.
#ifdef HAVE_CPU_WAIT
, systeminfo.total_cpu_wait_percent > 0. ? systeminfo.total_cpu_wait_percent : 0.
#endif
);
StringBuffer_append(res->outputbuffer,
"<td align='right'>%.1f%% [%s]</td>",
systeminfo.total_mem_percent, Str_bytesToSize(systeminfo.total_mem, buf));
StringBuffer_append(res->outputbuffer,
"<td align='right'>%.1f%% [%s]</td>",
systeminfo.total_swap_percent, Str_bytesToSize(systeminfo.total_swap, buf));
}
StringBuffer_append(res->outputbuffer,
"</tr>"
"</table>");
}
static void do_home_process(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Process)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Process</th>"
"<th align='left'>Status</th>"
"<th align='right'>Uptime</th>");
if (Run.flags & Run_ProcessEngineEnabled) {
StringBuffer_append(res->outputbuffer,
"<th align='right'>CPU Total</b></th>"
"<th align='right'>Memory Total</th>");
}
StringBuffer_append(res->outputbuffer, "</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s) || s->inf->priv.process.uptime < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%s</td>", _getUptime(s->inf->priv.process.uptime, (char[256]){}));
if (Run.flags & Run_ProcessEngineEnabled) {
if (! Util_hasServiceStatus(s) || s->inf->priv.process.total_cpu_percent < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right' class='%s'>%.1f%%</td>", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.total_cpu_percent);
if (! Util_hasServiceStatus(s) || s->inf->priv.process.total_mem_percent < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right' class='%s'>%.1f%% [%s]</td>", (s->error & Event_Resource) ? "red-text" : "", s->inf->priv.process.total_mem_percent, Str_bytesToSize(s->inf->priv.process.total_mem, buf));
}
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_program(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Program)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Program</th>"
"<th align='left'>Status</th>"
"<th align='left'>Output</th>"
"<th align='right'>Last started</th>"
"<th align='right'>Exit value</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer, "<td align='left'>-</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
} else {
if (s->program->started) {
StringBuffer_append(res->outputbuffer, "<td align='left' class='short'>");
if (StringBuffer_length(s->program->output)) {
// Print first line only (escape HTML characters if any)
const char *output = StringBuffer_toString(s->program->output);
for (int i = 0; output[i]; i++) {
if (output[i] == '<')
StringBuffer_append(res->outputbuffer, "&lt;");
else if (output[i] == '>')
StringBuffer_append(res->outputbuffer, "&gt;");
else if (output[i] == '&')
StringBuffer_append(res->outputbuffer, "&amp;");
else if (output[i] == '\r' || output[i] == '\n')
break;
else
StringBuffer_append(res->outputbuffer, "%c", output[i]);
}
} else {
StringBuffer_append(res->outputbuffer, "no output");
}
StringBuffer_append(res->outputbuffer, "</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>%s</td>", Time_fmt((char[32]){}, 32, "%d %b %Y %H:%M:%S", s->program->started));
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->program->exitStatus);
} else {
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>Not yet started</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
}
}
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_net(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Net)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Net</th>"
"<th align='left'>Status</th>"
"<th align='right'>Upload</th>"
"<th align='right'>Download</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s) || Link_getState(s->inf->priv.net.stats) != 1) {
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
} else {
StringBuffer_append(res->outputbuffer, "<td align='right'>%s&#47;s</td>", Str_bytesToSize(Link_getBytesOutPerSecond(s->inf->priv.net.stats), buf));
StringBuffer_append(res->outputbuffer, "<td align='right'>%s&#47;s</td>", Str_bytesToSize(Link_getBytesInPerSecond(s->inf->priv.net.stats), buf));
}
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_filesystem(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Filesystem)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Filesystem</th>"
"<th align='left'>Status</th>"
"<th align='right'>Space usage</th>"
"<th align='right'>Inodes usage</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer,
"<td align='right'>- [-]</td>"
"<td align='right'>- [-]</td>");
} else {
StringBuffer_append(res->outputbuffer,
"<td align='right'>%.1f%% [%s]</td>",
s->inf->priv.filesystem.space_percent,
s->inf->priv.filesystem.f_bsize > 0 ? Str_bytesToSize(s->inf->priv.filesystem.space_total * s->inf->priv.filesystem.f_bsize, buf) : "0 MB");
if (s->inf->priv.filesystem.f_files > 0) {
StringBuffer_append(res->outputbuffer,
"<td align='right'>%.1f%% [%lld objects]</td>",
s->inf->priv.filesystem.inode_percent,
s->inf->priv.filesystem.inode_total);
} else {
StringBuffer_append(res->outputbuffer,
"<td align='right'>not supported by filesystem</td>");
}
}
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_file(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_File)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>File</th>"
"<th align='left'>Status</th>"
"<th align='right'>Size</th>"
"<th align='right'>Permission</th>"
"<th align='right'>UID</th>"
"<th align='right'>GID</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s) || s->inf->priv.file.size < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%s</td>", Str_bytesToSize(s->inf->priv.file.size, (char[10]){}));
if (! Util_hasServiceStatus(s) || s->inf->priv.file.mode < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%04o</td>", s->inf->priv.file.mode & 07777);
if (! Util_hasServiceStatus(s) || s->inf->priv.file.uid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.file.uid);
if (! Util_hasServiceStatus(s) || s->inf->priv.file.gid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.file.gid);
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_fifo(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Fifo)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Fifo</th>"
"<th align='left'>Status</th>"
"<th align='right'>Permission</th>"
"<th align='right'>UID</th>"
"<th align='right'>GID</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s) || s->inf->priv.fifo.mode < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%04o</td>", s->inf->priv.fifo.mode & 07777);
if (! Util_hasServiceStatus(s) || s->inf->priv.fifo.uid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.fifo.uid);
if (! Util_hasServiceStatus(s) || s->inf->priv.fifo.gid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.fifo.gid);
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_directory(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Directory)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Directory</th>"
"<th align='left'>Status</th>"
"<th align='right'>Permission</th>"
"<th align='right'>UID</th>"
"<th align='right'>GID</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s) || s->inf->priv.directory.mode < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%04o</td>", s->inf->priv.directory.mode & 07777);
if (! Util_hasServiceStatus(s) || s->inf->priv.directory.uid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.directory.uid);
if (! Util_hasServiceStatus(s) || s->inf->priv.directory.gid < 0)
StringBuffer_append(res->outputbuffer, "<td align='right'>-</td>");
else
StringBuffer_append(res->outputbuffer, "<td align='right'>%d</td>", s->inf->priv.directory.gid);
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
static void do_home_host(HttpResponse res) {
char buf[STRLEN];
boolean_t on = true;
boolean_t header = true;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type != Service_Host)
continue;
if (header) {
StringBuffer_append(res->outputbuffer,
"<table id='header-row'>"
"<tr>"
"<th align='left' class='first'>Host</th>"
"<th align='left'>Status</th>"
"<th align='right'>Protocol(s)</th>"
"</tr>");
header = false;
}
StringBuffer_append(res->outputbuffer,
"<tr %s>"
"<td align='left'><a href='%s'>%s</a></td>"
"<td align='left'>%s</td>",
on ? "class='stripe'" : "",
s->name, s->name,
get_service_status(HTML, s, buf, sizeof(buf)));
if (! Util_hasServiceStatus(s)) {
StringBuffer_append(res->outputbuffer,
"<td align='right'>-</td>");
} else {
StringBuffer_append(res->outputbuffer,
"<td align='right'>");
for (Icmp_T icmp = s->icmplist; icmp; icmp = icmp->next) {
if (icmp != s->icmplist)
StringBuffer_append(res->outputbuffer, "&nbsp;&nbsp;<b>|</b>&nbsp;&nbsp;");
switch (icmp->is_available) {
case Connection_Init:
StringBuffer_append(res->outputbuffer, "<span class='gray-text'>[Ping]</span>");
break;
case Connection_Failed:
StringBuffer_append(res->outputbuffer, "<span class='red-text'>[Ping]</span>");
break;
default:
StringBuffer_append(res->outputbuffer, "<span>[Ping]</span>");
break;
}
}
if (s->icmplist && s->portlist)
StringBuffer_append(res->outputbuffer, "&nbsp;&nbsp;<b>|</b>&nbsp;&nbsp;");
for (Port_T port = s->portlist; port; port = port->next) {
if (port != s->portlist)
StringBuffer_append(res->outputbuffer, "&nbsp;&nbsp;<b>|</b>&nbsp;&nbsp;");
switch (port->is_available) {
case Connection_Init:
StringBuffer_append(res->outputbuffer, "<span class='gray-text'>[%s] at port %d</span>", port->protocol->name, port->target.net.port);
break;
case Connection_Failed:
StringBuffer_append(res->outputbuffer, "<span class='red-text'>[%s] at port %d</span>", port->protocol->name, port->target.net.port);
break;
default:
StringBuffer_append(res->outputbuffer, "<span>[%s] at port %d</span>", port->protocol->name, port->target.net.port);
break;
}
}
StringBuffer_append(res->outputbuffer, "</td>");
}
StringBuffer_append(res->outputbuffer, "</tr>");
on = ! on;
}
if (! header)
StringBuffer_append(res->outputbuffer, "</table>");
}
/* ------------------------------------------------------------------------- */
static void print_alerts(HttpResponse res, Mail_T s) {
for (Mail_T r = s; r; r = r->next) {
StringBuffer_append(res->outputbuffer,
"<tr class='stripe'><td>Alert mail to</td>"
"<td>%s</td></tr>", r->to ? r->to : "");
StringBuffer_append(res->outputbuffer, "<tr><td>Alert on</td><td>");
if (r->events == Event_Null) {
StringBuffer_append(res->outputbuffer, "No events");
} else if (r->events == Event_All) {
StringBuffer_append(res->outputbuffer, "All events");
} else {
if (IS_EVENT_SET(r->events, Event_Action))
StringBuffer_append(res->outputbuffer, "Action ");
if (IS_EVENT_SET(r->events, Event_ByteIn))
StringBuffer_append(res->outputbuffer, "ByteIn ");
if (IS_EVENT_SET(r->events, Event_ByteOut))
StringBuffer_append(res->outputbuffer, "ByteOut ");
if (IS_EVENT_SET(r->events, Event_Checksum))
StringBuffer_append(res->outputbuffer, "Checksum ");
if (IS_EVENT_SET(r->events, Event_Connection))
StringBuffer_append(res->outputbuffer, "Connection ");
if (IS_EVENT_SET(r->events, Event_Content))
StringBuffer_append(res->outputbuffer, "Content ");
if (IS_EVENT_SET(r->events, Event_Data))
StringBuffer_append(res->outputbuffer, "Data ");
if (IS_EVENT_SET(r->events, Event_Exec))
StringBuffer_append(res->outputbuffer, "Exec ");
if (IS_EVENT_SET(r->events, Event_Fsflag))
StringBuffer_append(res->outputbuffer, "Fsflags ");
if (IS_EVENT_SET(r->events, Event_Gid))
StringBuffer_append(res->outputbuffer, "Gid ");
if (IS_EVENT_SET(r->events, Event_Instance))
StringBuffer_append(res->outputbuffer, "Instance ");
if (IS_EVENT_SET(r->events, Event_Invalid))
StringBuffer_append(res->outputbuffer, "Invalid ");
if (IS_EVENT_SET(r->events, Event_Link))
StringBuffer_append(res->outputbuffer, "Link ");
if (IS_EVENT_SET(r->events, Event_Nonexist))
StringBuffer_append(res->outputbuffer, "Nonexist ");
if (IS_EVENT_SET(r->events, Event_Permission))
StringBuffer_append(res->outputbuffer, "Permission ");
if (IS_EVENT_SET(r->events, Event_PacketIn))
StringBuffer_append(res->outputbuffer, "PacketIn ");
if (IS_EVENT_SET(r->events, Event_PacketOut))
StringBuffer_append(res->outputbuffer, "PacketOut ");
if (IS_EVENT_SET(r->events, Event_Pid))
StringBuffer_append(res->outputbuffer, "PID ");
if (IS_EVENT_SET(r->events, Event_Icmp))
StringBuffer_append(res->outputbuffer, "Ping ");
if (IS_EVENT_SET(r->events, Event_PPid))
StringBuffer_append(res->outputbuffer, "PPID ");
if (IS_EVENT_SET(r->events, Event_Resource))
StringBuffer_append(res->outputbuffer, "Resource ");
if (IS_EVENT_SET(r->events, Event_Saturation))
StringBuffer_append(res->outputbuffer, "Saturation ");
if (IS_EVENT_SET(r->events, Event_Size))
StringBuffer_append(res->outputbuffer, "Size ");
if (IS_EVENT_SET(r->events, Event_Speed))
StringBuffer_append(res->outputbuffer, "Speed ");
if (IS_EVENT_SET(r->events, Event_Status))
StringBuffer_append(res->outputbuffer, "Status ");
if (IS_EVENT_SET(r->events, Event_Timeout))
StringBuffer_append(res->outputbuffer, "Timeout ");
if (IS_EVENT_SET(r->events, Event_Timestamp))
StringBuffer_append(res->outputbuffer, "Timestamp ");
if (IS_EVENT_SET(r->events, Event_Uid))
StringBuffer_append(res->outputbuffer, "Uid ");
if (IS_EVENT_SET(r->events, Event_Uptime))
StringBuffer_append(res->outputbuffer, "Uptime ");
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
if (r->reminder) {
StringBuffer_append(res->outputbuffer,
"<tr><td>Alert reminder</td><td>%u cycles</td></tr>",
r->reminder);
}
}
}
static void print_buttons(HttpRequest req, HttpResponse res, Service_T s) {
if (is_readonly(req)) {
// A read-only REMOTE_USER does not get access to these buttons
return;
}
StringBuffer_append(res->outputbuffer, "<table id='buttons'><tr>");
/* Start program */
if (s->start)
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action=%s>"
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden value='start' name=action>"
"<input type=submit value='Start service'>"
"</form>"
"</td>", s->name, res->token);
/* Stop program */
if (s->stop)
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action=%s>"
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden value='stop' name=action>"
"<input type=submit value='Stop service'>"
"</form>"
"</td>", s->name, res->token);
/* Restart program */
if ((s->start && s->stop) || s->restart)
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action=%s>"
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden value='restart' name=action>"
"<input type=submit value='Restart service'>"
"</form>"
"</td>", s->name, res->token);
/* (un)monitor */
StringBuffer_append(res->outputbuffer,
"<td>"
"<form method=POST action=%s>"
"<input type=hidden name='securitytoken' value='%s'>"
"<input type=hidden value='%s' name=action>"
"<input type=submit value='%s'>"
"</form>"
"</td>",
s->name,
res->token,
s->monitor ? "unmonitor" : "monitor",
s->monitor ? "Disable monitoring" : "Enable monitoring");
StringBuffer_append(res->outputbuffer, "</tr></table>");
}
static void print_service_rules_timeout(HttpResponse res, Service_T s) {
for (ActionRate_T ar = s->actionratelist; ar; ar = ar->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Timeout</td><td>If restarted %d times within %d cycle(s) then ", ar->count, ar->cycle);
Util_printAction(ar->action->failed, res->outputbuffer);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_existence(HttpResponse res, Service_T s) {
for (Nonexist_T l = s->nonexistlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Existence</td><td>");
Util_printRule(res->outputbuffer, l->action, "If doesn't exist");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_port(HttpResponse res, Service_T s) {
for (Port_T p = s->portlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Port</td><td>");
StringBuffer_T buf = StringBuffer_create(64);
StringBuffer_append(buf, "If failed [%s]:%d%s",
p->hostname, p->target.net.port, Util_portRequestDescription(p));
if (p->outgoing.ip)
StringBuffer_append(buf, " via address %s", p->outgoing.ip);
StringBuffer_append(buf, " type %s/%s protocol %s with timeout %s",
Util_portTypeDescription(p), Util_portIpDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}));
if (p->retry > 1)
StringBuffer_append(buf, " and retry %d times", p->retry);
#ifdef HAVE_OPENSSL
if (p->target.net.ssl.flags) {
StringBuffer_append(buf, " using SSL/TLS");
const char *options = Ssl_printOptions(&p->target.net.ssl, (char[STRLEN]){}, STRLEN);
if (options && *options)
StringBuffer_append(buf, " with options {%s}", options);
if (p->target.net.ssl.minimumValidDays > 0)
StringBuffer_append(buf, " and certificate expires in more than %d days", p->target.net.ssl.minimumValidDays);
if (p->target.net.ssl.checksum)
StringBuffer_append(buf, " and certificate checksum %s equal to '%s'", checksumnames[p->target.net.ssl.checksumType], p->target.net.ssl.checksum);
}
#endif
Util_printRule(res->outputbuffer, p->action, "%s", StringBuffer_toString(buf));
StringBuffer_free(&buf);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_socket(HttpResponse res, Service_T s) {
for (Port_T p = s->socketlist; p; p = p->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Unix Socket</td><td>");
if (p->retry > 1)
Util_printRule(res->outputbuffer, p->action, "If failed %s type %s protocol %s with timeout %s and retry %d time(s)", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}), p->retry);
else
Util_printRule(res->outputbuffer, p->action, "If failed %s type %s protocol %s with timeout %s", p->target.unix.pathname, Util_portTypeDescription(p), p->protocol->name, Str_milliToTime(p->timeout, (char[23]){}));
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_icmp(HttpResponse res, Service_T s) {
for (Icmp_T i = s->icmplist; i; i = i->next) {
switch (i->family) {
case Socket_Ip4:
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Ping4</td><td>");
break;
case Socket_Ip6:
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Ping6</td><td>");
break;
default:
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Ping</td><td>");
break;
}
Util_printRule(res->outputbuffer, i->action, "If failed [count %d size %d with timeout %s%s%s]", i->count, i->size, Str_milliToTime(i->timeout, (char[23]){}), i->outgoing.ip ? " via address " : "", i->outgoing.ip ? i->outgoing.ip : "");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_perm(HttpResponse res, Service_T s) {
if (s->perm) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Permissions</td><td>");
if (s->perm->test_changes)
Util_printRule(res->outputbuffer, s->perm->action, "If changed");
else
Util_printRule(res->outputbuffer, s->perm->action, "If failed %o", s->perm->perm);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_uid(HttpResponse res, Service_T s) {
if (s->uid) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>UID</td><td>");
Util_printRule(res->outputbuffer, s->uid->action, "If failed %d", s->uid->uid);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_euid(HttpResponse res, Service_T s) {
if (s->euid) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>EUID</td><td>");
Util_printRule(res->outputbuffer, s->euid->action, "If failed %d", s->euid->uid);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_gid(HttpResponse res, Service_T s) {
if (s->gid) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>GID</td><td>");
Util_printRule(res->outputbuffer, s->gid->action, "If failed %d", s->gid->gid);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_timestamp(HttpResponse res, Service_T s) {
for (Timestamp_T t = s->timestamplist; t; t = t->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Timestamp</td><td>");
if (t->test_changes)
Util_printRule(res->outputbuffer, t->action, "If changed");
else
Util_printRule(res->outputbuffer, t->action, "If %s %d second(s)", operatornames[t->operator], t->time);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_fsflags(HttpResponse res, Service_T s) {
for (Fsflag_T l = s->fsflaglist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Filesystem flags</td><td>");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_filesystem(HttpResponse res, Service_T s) {
for (Filesystem_T dl = s->filesystemlist; dl; dl = dl->next) {
if (dl->resource == Resource_Inode) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Inodes usage limit</td><td>");
if (dl->limit_absolute > -1)
Util_printRule(res->outputbuffer, dl->action, "If %s %lld", operatornames[dl->operator], dl->limit_absolute);
else
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
StringBuffer_append(res->outputbuffer, "</td></tr>");
} else if (dl->resource == Resource_InodeFree) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Inodes free limit</td><td>");
if (dl->limit_absolute > -1)
Util_printRule(res->outputbuffer, dl->action, "If %s %lld", operatornames[dl->operator], dl->limit_absolute);
else
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
StringBuffer_append(res->outputbuffer, "</td></tr>");
} else if (dl->resource == Resource_Space) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Space usage limit</td><td>");
if (dl->limit_absolute > -1) {
if (s->inf->priv.filesystem.f_bsize > 0)
Util_printRule(res->outputbuffer, dl->action, "If %s %s", operatornames[dl->operator], Str_bytesToSize(dl->limit_absolute * s->inf->priv.filesystem.f_bsize, (char[10]){}));
else
Util_printRule(res->outputbuffer, dl->action, "If %s %lld blocks", operatornames[dl->operator], dl->limit_absolute);
} else {
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
} else if (dl->resource == Resource_SpaceFree) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Space free limit</td><td>");
if (dl->limit_absolute > -1) {
if (s->inf->priv.filesystem.f_bsize > 0)
Util_printRule(res->outputbuffer, dl->action, "If %s %s", operatornames[dl->operator], Str_bytesToSize(dl->limit_absolute * s->inf->priv.filesystem.f_bsize, (char[10]){}));
else
Util_printRule(res->outputbuffer, dl->action, "If %s %lld blocks", operatornames[dl->operator], dl->limit_absolute);
} else {
Util_printRule(res->outputbuffer, dl->action, "If %s %.1f%%", operatornames[dl->operator], dl->limit_percent);
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
}
static void print_service_rules_size(HttpResponse res, Service_T s) {
for (Size_T sl = s->sizelist; sl; sl = sl->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Size</td><td>");
if (sl->test_changes)
Util_printRule(res->outputbuffer, sl->action, "If changed");
else
Util_printRule(res->outputbuffer, sl->action, "If %s %llu byte(s)", operatornames[sl->operator], sl->size);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_linkstatus(HttpResponse res, Service_T s) {
for (LinkStatus_T l = s->linkstatuslist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Link status</td><td>");
Util_printRule(res->outputbuffer, l->action, "If failed");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_linkspeed(HttpResponse res, Service_T s) {
for (LinkSpeed_T l = s->linkspeedlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Link capacity</td><td>");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_linksaturation(HttpResponse res, Service_T s) {
for (LinkSaturation_T l = s->linksaturationlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Link saturation</td><td>");
Util_printRule(res->outputbuffer, l->action, "If %s %.1f%%", operatornames[l->operator], l->limit);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_uploadbytes(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->uploadbyteslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Upload bytes</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %s/s", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}));
} else {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Total upload bytes</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %s in last %d %s(s)", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}), bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_uploadpackets(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->uploadpacketslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Upload packets</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets/s", operatornames[bl->operator], bl->limit);
} else {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Total upload packets</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets in last %d %s(s)", operatornames[bl->operator], bl->limit, bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_downloadbytes(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->downloadbyteslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Download bytes</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %s/s", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}));
} else {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Total download bytes</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %s in last %d %s(s)", operatornames[bl->operator], Str_bytesToSize(bl->limit, (char[10]){}), bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_downloadpackets(HttpResponse res, Service_T s) {
for (Bandwidth_T bl = s->downloadpacketslist; bl; bl = bl->next) {
if (bl->range == Time_Second) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Download packets</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets/s", operatornames[bl->operator], bl->limit);
} else {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Total download packets</td><td>");
Util_printRule(res->outputbuffer, bl->action, "If %s %lld packets in last %d %s(s)", operatornames[bl->operator], bl->limit, bl->rangecount, Util_timestr(bl->range));
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_uptime(HttpResponse res, Service_T s) {
for (Uptime_T ul = s->uptimelist; ul; ul = ul->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Uptime</td><td>");
Util_printRule(res->outputbuffer, ul->action, "If %s %s", operatornames[ul->operator], _getUptime(ul->uptime, (char[256]){}));
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_content(HttpResponse res, Service_T s) {
if (s->type != Service_Process) {
for (Match_T ml = s->matchignorelist; ml; ml = ml->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Ignore content</td><td>");
Util_printRule(res->outputbuffer, ml->action, "If content %s \"%s\"", ml->not ? "!=" : "=", ml->match_string);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
for (Match_T ml = s->matchlist; ml; ml = ml->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Content match</td><td>");
Util_printRule(res->outputbuffer, ml->action, "If content %s \"%s\"", ml->not ? "!=" : "=", ml->match_string);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
}
static void print_service_rules_checksum(HttpResponse res, Service_T s) {
if (s->checksum) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Checksum</td><td>");
if (s->checksum->test_changes)
Util_printRule(res->outputbuffer, s->checksum->action, "If changed %s", checksumnames[s->checksum->type]);
else
Util_printRule(res->outputbuffer, s->checksum->action, "If failed %s(%s)", s->checksum->hash, checksumnames[s->checksum->type]);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_pid(HttpResponse res, Service_T s) {
for (Pid_T l = s->pidlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>PID</td><td>");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_ppid(HttpResponse res, Service_T s) {
for (Pid_T l = s->ppidlist; l; l = l->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>PPID</td><td>");
Util_printRule(res->outputbuffer, l->action, "If changed");
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static void print_service_rules_program(HttpResponse res, Service_T s) {
if (s->type == Service_Program) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Program timeout</td><td>Terminate the program if not finished within %s</td></tr>", Str_milliToTime(s->program->timeout, (char[23]){}));
for (Status_T status = s->statuslist; status; status = status->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>Test Exit value</td><td>");
if (status->operator == Operator_Changed)
Util_printRule(res->outputbuffer, status->action, "If exit value changed");
else
Util_printRule(res->outputbuffer, status->action, "If exit value %s %d", operatorshortnames[status->operator], status->return_value);
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
}
static void print_service_rules_resource(HttpResponse res, Service_T s) {
char buf[STRLEN];
for (Resource_T q = s->resourcelist; q; q = q->next) {
StringBuffer_append(res->outputbuffer, "<tr class='rule'><td>");
switch (q->resource_id) {
case Resource_CpuPercent:
StringBuffer_append(res->outputbuffer, "CPU usage limit");
break;
case Resource_CpuPercentTotal:
StringBuffer_append(res->outputbuffer, "CPU usage limit (incl. children)");
break;
case Resource_CpuUser:
StringBuffer_append(res->outputbuffer, "CPU user limit");
break;
case Resource_CpuSystem:
StringBuffer_append(res->outputbuffer, "CPU system limit");
break;
case Resource_CpuWait:
StringBuffer_append(res->outputbuffer, "CPU wait limit");
break;
case Resource_MemoryPercent:
StringBuffer_append(res->outputbuffer, "Memory usage limit");
break;
case Resource_MemoryKbyte:
StringBuffer_append(res->outputbuffer, "Memory amount limit");
break;
case Resource_SwapPercent:
StringBuffer_append(res->outputbuffer, "Swap usage limit");
break;
case Resource_SwapKbyte:
StringBuffer_append(res->outputbuffer, "Swap amount limit");
break;
case Resource_LoadAverage1m:
StringBuffer_append(res->outputbuffer, "Load average (1min)");
break;
case Resource_LoadAverage5m:
StringBuffer_append(res->outputbuffer, "Load average (5min)");
break;
case Resource_LoadAverage15m:
StringBuffer_append(res->outputbuffer, "Load average (15min)");
break;
case Resource_Threads:
StringBuffer_append(res->outputbuffer, "Threads");
break;
case Resource_Children:
StringBuffer_append(res->outputbuffer, "Children");
break;
case Resource_MemoryKbyteTotal:
StringBuffer_append(res->outputbuffer, "Memory amount limit (incl. children)");
break;
case Resource_MemoryPercentTotal:
StringBuffer_append(res->outputbuffer, "Memory usage limit (incl. children)");
break;
default:
break;
}
StringBuffer_append(res->outputbuffer, "</td><td>");
switch (q->resource_id) {
case Resource_CpuPercent:
case Resource_CpuPercentTotal:
case Resource_MemoryPercentTotal:
case Resource_CpuUser:
case Resource_CpuSystem:
case Resource_CpuWait:
case Resource_MemoryPercent:
case Resource_SwapPercent:
Util_printRule(res->outputbuffer, q->action, "If %s %.1f%%", operatornames[q->operator], q->limit);
break;
case Resource_MemoryKbyte:
case Resource_SwapKbyte:
case Resource_MemoryKbyteTotal:
Util_printRule(res->outputbuffer, q->action, "If %s %s", operatornames[q->operator], Str_bytesToSize(q->limit, buf));
break;
case Resource_LoadAverage1m:
case Resource_LoadAverage5m:
case Resource_LoadAverage15m:
Util_printRule(res->outputbuffer, q->action, "If %s %.1f", operatornames[q->operator], q->limit);
break;
case Resource_Threads:
case Resource_Children:
Util_printRule(res->outputbuffer, q->action, "If %s %.0f", operatornames[q->operator], q->limit);
break;
default:
break;
}
StringBuffer_append(res->outputbuffer, "</td></tr>");
}
}
static boolean_t is_readonly(HttpRequest req) {
if (req->remote_user) {
Auth_T user_creds = Util_getUserCredentials(req->remote_user);
return (user_creds ? user_creds->is_readonly : true);
}
return false;
}
/* ----------------------------------------------------------- Status output */
/* Print status in the given format. Text status is default. */
static void print_status(HttpRequest req, HttpResponse res, int version) {
const char *stringFormat = get_parameter(req, "format");
if (stringFormat && Str_startsWith(stringFormat, "xml")) {
char buf[STRLEN];
StringBuffer_T sb = StringBuffer_create(256);
status_xml(sb, NULL, version, Socket_getLocalHost(req->S, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer, "%s", StringBuffer_toString(sb));
StringBuffer_free(&sb);
set_content_type(res, "text/xml");
} else {
set_content_type(res, "text/plain");
StringBuffer_append(res->outputbuffer, "Monit %s uptime: %s\n\n", VERSION, _getUptime(ProcessTree_getProcessUptime(getpid()), (char[256]){}));
int found = 0;
const char *stringGroup = Util_urlDecode((char *)get_parameter(req, "group"));
const char *stringService = Util_urlDecode((char *)get_parameter(req, "service"));
if (stringGroup) {
for (ServiceGroup_T sg = servicegrouplist; sg; sg = sg->next) {
if (IS(stringGroup, sg->name)) {
for (list_t m = sg->members->head; m; m = m->next) {
status_service_txt(m->e, res);
found++;
}
break;
}
}
} else {
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (! stringService || IS(stringService, s->name)) {
status_service_txt(s, res);
found++;
}
}
}
if (found == 0) {
if (stringGroup)
send_error(req, res, SC_BAD_REQUEST, "Service group '%s' not found", stringGroup);
else if (stringService)
send_error(req, res, SC_BAD_REQUEST, "Service '%s' not found", stringService);
else
send_error(req, res, SC_BAD_REQUEST, "No service found");
}
}
}
static void _printServiceSummary(Box_T t, Service_T s) {
Box_setColumn(t, 1, "%s", s->name);
Box_setColumn(t, 2, "%s", get_service_status(TXT, s, (char[STRLEN]){}, STRLEN));
Box_setColumn(t, 3, "%s", servicetypes[s->type]);
Box_printRow(t);
}
static int _printServiceSummaryByType(Box_T t, Service_Type type) {
int found = 0;
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (s->type == type) {
_printServiceSummary(t, s);
found++;
}
}
return found;
}
static void print_summary(HttpRequest req, HttpResponse res) {
set_content_type(res, "text/plain");
StringBuffer_append(res->outputbuffer, "Monit %s uptime: %s\n", VERSION, _getUptime(ProcessTree_getProcessUptime(getpid()), (char[256]){}));
int found = 0;
const char *stringGroup = Util_urlDecode((char *)get_parameter(req, "group"));
const char *stringService = Util_urlDecode((char *)get_parameter(req, "service"));
Box_T t = Box_new(res->outputbuffer, 3, (BoxColumn_T []){
{.name = "Service Name", .width = 31, .wrap = false, .align = BoxAlign_Left},
{.name = "Status", .width = 26, .wrap = false, .align = BoxAlign_Left},
{.name = "Type", .width = 13, .wrap = false, .align = BoxAlign_Left}
}, true);
if (stringGroup) {
for (ServiceGroup_T sg = servicegrouplist; sg; sg = sg->next) {
if (IS(stringGroup, sg->name)) {
for (list_t m = sg->members->head; m; m = m->next) {
_printServiceSummary(t, m->e);
found++;
}
break;
}
}
} else if (stringService) {
for (Service_T s = servicelist_conf; s; s = s->next_conf) {
if (IS(stringService, s->name)) {
_printServiceSummary(t, s);
found++;
}
}
} else {
found += _printServiceSummaryByType(t, Service_System);
found += _printServiceSummaryByType(t, Service_Process);
found += _printServiceSummaryByType(t, Service_File);
found += _printServiceSummaryByType(t, Service_Fifo);
found += _printServiceSummaryByType(t, Service_Directory);
found += _printServiceSummaryByType(t, Service_Filesystem);
found += _printServiceSummaryByType(t, Service_Host);
found += _printServiceSummaryByType(t, Service_Net);
found += _printServiceSummaryByType(t, Service_Program);
}
Box_free(&t);
if (found == 0) {
if (stringGroup)
send_error(req, res, SC_BAD_REQUEST, "Service group '%s' not found", stringGroup);
else if (stringService)
send_error(req, res, SC_BAD_REQUEST, "Service '%s' not found", stringService);
else
send_error(req, res, SC_BAD_REQUEST, "No service found");
}
}
static void _printReport(HttpRequest req, HttpResponse res) {
set_content_type(res, "text/plain");
const char *type = get_parameter(req, "type");
int count = 0;
if (! type) {
float up = 0, down = 0, init = 0, unmonitored = 0, total = 0;
for (Service_T s = servicelist; s; s = s->next) {
if (s->monitor == Monitor_Not)
unmonitored++;
else if (s->monitor & Monitor_Init)
init++;
else if (s->error)
down++;
else
up++;
total++;
}
StringBuffer_append(res->outputbuffer,
"up: %*.0f (%.1f%%)\n"
"down: %*.0f (%.1f%%)\n"
"initialising: %*.0f (%.1f%%)\n"
"unmonitored: %*.0f (%.1f%%)\n"
"total: %*.0f services\n",
3, up, 100. * up / total,
3, down, 100. * down / total,
3, init, 100. * init / total,
3, unmonitored, 100. * unmonitored / total,
3, total);
} else if (Str_isEqual(type, "up")) {
for (Service_T s = servicelist; s; s = s->next)
if (s->monitor != Monitor_Not && ! (s->monitor & Monitor_Init) && ! s->error)
count++;
StringBuffer_append(res->outputbuffer, "%d\n", count);
} else if (Str_isEqual(type, "down")) {
for (Service_T s = servicelist; s; s = s->next)
if (s->monitor != Monitor_Not && ! (s->monitor & Monitor_Init) && s->error)
count++;
StringBuffer_append(res->outputbuffer, "%d\n", count);
} else if (Str_startsWith(type, "initiali")) { // allow 'initiali(s|z)ing'
for (Service_T s = servicelist; s; s = s->next)
if (s->monitor & Monitor_Init)
count++;
StringBuffer_append(res->outputbuffer, "%d\n", count);
} else if (Str_isEqual(type, "unmonitored")) {
for (Service_T s = servicelist; s; s = s->next)
if (s->monitor == Monitor_Not)
count++;
StringBuffer_append(res->outputbuffer, "%d\n", count);
} else if (Str_isEqual(type, "total")) {
for (Service_T s = servicelist; s; s = s->next)
count++;
StringBuffer_append(res->outputbuffer, "%d\n", count);
} else {
send_error(req, res, SC_BAD_REQUEST, "Invalid report type: '%s'", type);
}
}
static void status_service_txt(Service_T s, HttpResponse res) {
char buf[STRLEN];
StringBuffer_append(res->outputbuffer,
COLOR_BOLDCYAN "%s '%s'" COLOR_RESET "\n"
" %-28s %s\n",
servicetypes[s->type], s->name,
"status", get_service_status(TXT, s, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer,
" %-28s %s\n",
"monitoring status", get_monitoring_status(TXT, s, buf, sizeof(buf)));
StringBuffer_append(res->outputbuffer,
" %-28s %s\n",
"monitoring mode", modenames[s->mode]);
StringBuffer_append(res->outputbuffer,
" %-28s %s\n",
"on reboot", onrebootnames[s->onreboot]);
_printStatus(TXT, res, s);
StringBuffer_append(res->outputbuffer, "\n");
}
static char *get_monitoring_status(Output_Type type, Service_T s, char *buf, int buflen) {
ASSERT(s);
ASSERT(buf);
if (s->monitor == Monitor_Not) {
if (type == HTML)
snprintf(buf, buflen, "<span class='gray-text'>Not monitored</span>");
else
snprintf(buf, buflen, Color_lightYellow("Not monitored"));
} else if (s->monitor & Monitor_Waiting) {
if (type == HTML)
snprintf(buf, buflen, "<span>Waiting</span>");
else
snprintf(buf, buflen, Color_white("Waiting"));
} else if (s->monitor & Monitor_Init) {
if (type == HTML)
snprintf(buf, buflen, "<span class='blue-text'>Initializing</span>");
else
snprintf(buf, buflen, Color_lightBlue("Initializing"));
} else if (s->monitor & Monitor_Yes) {
if (type == HTML)
snprintf(buf, buflen, "<span>Monitored</span>");
else
snprintf(buf, buflen, "Monitored");
}
return buf;
}
static char *get_service_status(Output_Type type, Service_T s, char *buf, int buflen) {
ASSERT(s);
ASSERT(buf);
if (s->monitor == Monitor_Not || s->monitor & Monitor_Init) {
get_monitoring_status(type, s, buf, buflen);
} else if (s->error == 0) {
if (type == HTML)
snprintf(buf, buflen, "<span class='green-text'><i style=\"font-size:11px;\" class=\"fa fa-circle\" aria-hidden=\"true\"></i> %s</span>", statusnames[s->type]);
else
snprintf(buf, buflen, Color_lightGreen("%s", statusnames[s->type]));
} else {
// In the case that the service has actualy some failure, the error bitmap will be non zero
char *p = buf;
EventTable_T *et = Event_Table;
while ((*et).id) {
if (s->error & (*et).id) {
if (p > buf)
p += snprintf(p, buflen - (p - buf), " | ");
if (s->error_hint & (*et).id) {
if (type == HTML)
p += snprintf(p, buflen - (p - buf), "<span class='orange-text'><i style=\"font-size:11px;\" class=\"fa fa-circle\" aria-hidden=\"true\"></i>&nbsp; %s</span>", (*et).description_changed);
else
p += snprintf(p, buflen - (p - buf), Color_lightYellow("%s", (*et).description_changed));
} else {
if (type == HTML)
p += snprintf(p, buflen - (p - buf), "<span class='red-text'><i style=\"font-size:11px;\" class=\"fa fa-circle\" aria-hidden=\"true\"></i>&nbsp; %s</span>", (*et).description_failed);
else
p += snprintf(p, buflen - (p - buf), Color_lightRed("%s", (*et).description_failed));
}
}
et++;
}
}
if (s->doaction)
snprintf(buf + strlen(buf), buflen - strlen(buf) - 1, " - %s pending", actionnames[s->doaction]);
return buf;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment