/*
* Copyright (C), 2000-2007 by the monit project group.
* All Rights Reserved.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#ifdef HAVE_STDIO_H
#include
#endif
#ifdef HAVE_STRING_H
#include
#endif
#ifdef HAVE_SYS_TYPES_H
#include
#endif
#ifdef HAVE_SYS_SOCKET_H
#include
#endif
#ifdef HAVE_ERRNO_H
#include
#endif
#include "monitor.h"
#include "event.h"
#include "process.h"
/**
* XML routines for status and event notification message handling.
*
* @author Martin Pala,
*
* @version \$Id: xml.c,v 1.29 2007/07/25 12:54:30 hauk Exp $
*
* @file
*/
/* ------------------------------------------------------------- Definitions */
/** Defines an output buffer object */
typedef struct mybuffer {
char *buf; /**< Output buffer */
size_t bufsize; /**< Output buffer size */
size_t bufused; /**< Output buffer usage */
} Buffer_T;
/* -------------------------------------------------------------- Prototypes */
static void document_head(Buffer_T *);
static void document_foot(Buffer_T *);
static void status_service(Service_T, Buffer_T *, short);
static void status_event(Event_T, Buffer_T *);
static void buf_print(Buffer_T *, const char *, ...);
/* ------------------------------------------------------------------ Public */
/**
* Return XML formated message for event notification or general status
* of monitored services and resources.
* @param E An event object or NULL for general status
* @param L Status information level
* @return XML document or NULL in the case of error. The caller must free
* the memory.
*/
char *status_xml(Event_T E, short L) {
Buffer_T B;
Service_T S;
memset(&B, 0, sizeof(Buffer_T));
document_head(&B);
if(E)
{
/* there is no use for status level in the event (at least now) */
status_event(E, &B);
}
else
{
for(S = servicelist_conf; S; S = S->next_conf)
{
status_service(S, &B, L);
}
}
document_foot(&B);
return B.buf;
}
/* ----------------------------------------------------------------- Private */
/**
* Prints a document header into the given buffer.
* @param B Buffer object
*/
static void document_head(Buffer_T *B) {
buf_print(B,
"\r\n"
"\r\n"
"\t\r\n"
"\t\t%ld\r\n"
"\t\t%s\r\n"
"\t\t%ld\r\n"
"\t\t%d\r\n",
Run.incarnation,
VERSION,
(long)Util_getProcessUptime(Run.pidfile),
Run.polltime);
if(Run.dohttpd)
{
buf_print(B,
"\t\t\r\n"
"\t\t\t%s\r\n"
"\t\t\t%d\r\n"
"\t\t\t%d\r\n"
"\t\t\r\n",
Run.bind_addr?Run.bind_addr:"",
Run.httpdport,
Run.httpdssl);
}
buf_print(B,
"\t\r\n");
}
/**
* Prints a document footer into the given buffer.
* @param B Buffer object
*/
static void document_foot(Buffer_T *B) {
buf_print(B, "\r\n");
}
/**
* Prints a service status into the given buffer.
* @param S Service object
* @param B Buffer object
* @param L Status information level
*/
static void status_service(Service_T S, Buffer_T *B, short L) {
buf_print(B,
"\t\r\n"
"\t\t%ld\r\n"
"\t\t%s\r\n"
"\t\t%llu\r\n"
"\t\t%d\r\n"
"\t\t%d\r\n"
"\t\t%s\r\n",
S->type,
S->collected,
S->name?S->name:"",
S->error,
S->monitor,
S->doaction,
S->group?S->group:"");
if(L == LEVEL_FULL)
{
if(Util_hasServiceStatus(S)) {
if(S->type == TYPE_FILE ||
S->type == TYPE_DIRECTORY ||
S->type == TYPE_FIFO ||
S->type == TYPE_DEVICE) {
buf_print(B,
"\t\t%o\r\n"
"\t\t%d\r\n"
"\t\t%d\r\n",
S->inf->st_mode & 07777,
(int)S->inf->st_uid,
(int)S->inf->st_gid);
}
if(S->type == TYPE_FILE ||
S->type == TYPE_FIFO ||
S->type == TYPE_DIRECTORY) {
buf_print(B,
"\t\t%ld\r\n",
(long)S->inf->timestamp);
}
if(S->type == TYPE_FILE) {
buf_print(B,
"\t\t%llu\r\n",
(unsigned long long) S->inf->st_size);
if(S->checksum) {
buf_print(B,
"\t\t%s\r\n",
checksumnames[S->checksum->type], S->inf->cs_sum);
}
}
if(S->type == TYPE_DEVICE) {
buf_print(B,
"\t\t%ld\r\n"
"\t\t\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%ld\r\n"
"\t\t\r\n",
S->inf->flags,
S->inf->f_bsize,
S->inf->f_blocks,
S->inf->f_blocksfree,
S->inf->f_blocksfreetotal);
if(S->inf->f_files > 0) {
buf_print(B,
"\t\t\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%ld\r\n"
"\t\t\r\n",
S->inf->f_files,
S->inf->f_filesfree);
}
}
if(S->type == TYPE_PROCESS) {
buf_print(B,
"\t\t%d\r\n"
"\t\t%d\r\n"
"\t\t%ld\r\n",
S->inf->pid,
S->inf->ppid,
(long)S->inf->uptime);
if(Run.doprocess) {
buf_print(B,
"\t\t%d\r\n"
"\t\t\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%.1f\r\n"
"\t\t\t%.1f\r\n"
"\t\t\r\n"
"\t\t\r\n"
"\t\t\t%.1f\r\n"
"\t\t\t%.1f\r\n"
"\t\t\r\n",
S->inf->children,
S->inf->mem_kbyte,
S->inf->total_mem_kbyte,
S->inf->mem_percent/10.0,
S->inf->total_mem_percent/10.0,
S->inf->cpu_percent/10.0,
S->inf->total_cpu_percent/10.0);
}
}
if(S->type == TYPE_HOST && S->icmplist) {
Icmp_T i;
for(i= S->icmplist; i; i= i->next) {
buf_print(B,
"\t\t\r\n"
"\t\t\t%s\r\n"
"\t\t\t%.3f\r\n"
"\t\t\r\n",
icmpnames[i->type],
i->is_available?i->response:-1.);
}
}
if((S->type == TYPE_HOST || S->type == TYPE_PROCESS) && S-> portlist) {
Port_T p;
for(p= S->portlist; p; p= p->next) {
if(p->family == AF_INET) {
buf_print(B,
"\t\t\r\n"
"\t\t\t%s\r\n"
"\t\t\t%d\r\n"
"\t\t\t%s\r\n"
"\t\t\t%s\r\n"
"\t\t\t%s\r\n"
"\t\t\t%.3f\r\n"
"\t\t\r\n",
p->hostname?p->hostname:"",
p->port,
p->request?p->request:"",
Util_portTypeDescription(p),
p->protocol->name?p->protocol->name:"",
p->is_available?p->response:-1.);
} else if(p->family == AF_UNIX) {
buf_print(B,
"\t\t\r\n"
"\t\t\t%s\r\n"
"\t\t\t%s\r\n"
"\t\t\t%.3f\r\n"
"\t\t\r\n",
p->pathname?p->pathname:"",
p->protocol->name?p->protocol->name:"",
p->is_available?p->response:-1.);
}
}
}
if(S->type == TYPE_SYSTEM && Run.doprocess) {
buf_print(B,
"\t\t\r\n"
"\t\t\t%.2f\r\n"
"\t\t\t%.2f\r\n"
"\t\t\t%.2f\r\n"
"\t\t\r\n"
"\t\t\r\n"
"\t\t\t%.1f\r\n"
"\t\t\t%.1f\r\n"
#ifdef HAVE_CPU_WAIT
"\t\t\t%.1f\r\n"
#endif
"\t\t\r\n"
"\t\t\r\n"
"\t\t\t%ld\r\n"
"\t\t\t%.1f\r\n"
"\t\t\r\n",
systeminfo.loadavg[0],
systeminfo.loadavg[1],
systeminfo.loadavg[2],
systeminfo.total_cpu_user_percent/10.,
systeminfo.total_cpu_syst_percent/10.,
#ifdef HAVE_CPU_WAIT
systeminfo.total_cpu_wait_percent/10.,
#endif
systeminfo.total_mem_kbyte,
systeminfo.total_mem_percent/10.);
}
}
}
buf_print(B, "\t\r\n");
}
/**
* Prints a event description into the given buffer.
* @param E Event object
* @param B Buffer object
*/
static void status_event(Event_T E, Buffer_T *B) {
ASSERT(E);
buf_print(B,
"\t\r\n"
"\t\t%ld\r\n"
"\t\t%s\r\n"
"\t\t%d\r\n"
"\t\t%s\r\n"
"\t\t%d\r\n"
"\t\t%d\r\n"
"\t\t%d\r\n"
"\t\t%s\r\n"
"\t\r\n",
Event_get_collected(E),
Event_get_source_name(E),
Event_get_source_type(E),
Event_get_source_group(E),
Event_get_id(E),
Event_get_state(E),
Event_get_action(E),
Event_get_message(E));
}
/**
* Prints a string into the given buffer.
* @param B Buffer object
* @param m A formated string to be written to the buffer
*/
static void buf_print(Buffer_T *B, const char *m, ...) {
if(m)
{
va_list ap;
char *buf;
long need= 0;
ssize_t have= 0;
va_start(ap, m);
buf = Util_formatString(m, ap, &need);
va_end(ap);
have = (*B).bufsize - (*B).bufused;
if(have <= need)
{
(*B).bufsize += (need + STRLEN);
(*B).buf = xresize((*B).buf, (*B).bufsize);
if(!(*B).bufused)
{
memset((*B).buf, 0, (*B).bufsize);
}
}
memcpy(&(*B).buf[(*B).bufused], buf, need);
(*B).bufused += need;
(*B).buf[(*B).bufused]= 0;
FREE(buf);
}
}