/* * 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); } }