"Fossies" - the Fresh Open Source Software Archive

Member "monit-5.28.0/src/http/xml.c" (28 Mar 2021, 35132 Bytes) of package /linux/privat/monit-5.28.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "xml.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.27.2_vs_5.28.0.

    1 /*
    2  * Copyright (C) Tildeslash Ltd. All rights reserved.
    3  *
    4  * This program is free software: you can redistribute it and/or modify
    5  * it under the terms of the GNU Affero General Public License version 3.
    6  *
    7  * This program is distributed in the hope that it will be useful,
    8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   10  * GNU General Public License for more details.
   11  *
   12  * You should have received a copy of the GNU Affero General Public License
   13  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   14  *
   15  * In addition, as a special exception, the copyright holders give
   16  * permission to link the code of portions of this program with the
   17  * OpenSSL library under certain conditions as described in each
   18  * individual source file, and distribute linked combinations
   19  * including the two.
   20  *
   21  * You must obey the GNU Affero General Public License in all respects
   22  * for all of the code used other than OpenSSL.
   23  */
   24 
   25 
   26 #include "config.h"
   27 
   28 #ifdef HAVE_STDIO_H
   29 #include <stdio.h>
   30 #endif
   31 
   32 #ifdef HAVE_STRING_H
   33 #include <string.h>
   34 #endif
   35 
   36 #ifdef HAVE_SYS_TYPES_H
   37 #include <sys/types.h>
   38 #endif
   39 
   40 #ifdef HAVE_SYS_SOCKET_H
   41 #include <sys/socket.h>
   42 #endif
   43 
   44 #ifdef HAVE_ERRNO_H
   45 #include <errno.h>
   46 #endif
   47 
   48 #ifdef HAVE_UNISTD_H
   49 #include <unistd.h>
   50 #endif
   51 
   52 // libmonit
   53 #include "util/List.h"
   54 #include "system/Time.h"
   55 
   56 #include "monit.h"
   57 #include "event.h"
   58 #include "ProcessTree.h"
   59 #include "protocol.h"
   60 
   61 
   62 /**
   63  *  XML routines for status and event notification message handling.
   64  *
   65  *  @file
   66  */
   67 
   68 
   69 /* ----------------------------------------------------------------- Private */
   70 
   71 
   72 /**
   73  * Escape the CDATA "]]>" stop sequence in string
   74  * @param B Output StringBuffer object
   75  * @param buf String to escape
   76  */
   77 static void _escapeCDATA(StringBuffer_T B, const char *buf) {
   78         for (int i = 0; buf[i]; i++) {
   79                 if (buf[i] == '>' && i > 1 && (buf[i - 1] == ']' && buf[i - 2] == ']'))
   80                         StringBuffer_append(B, "&gt;");
   81                 else
   82                         StringBuffer_append(B, "%c", buf[i]);
   83         }
   84 }
   85 
   86 
   87 /**
   88  * Prints a document header into the given buffer.
   89  * @param B StringBuffer object
   90  * @param V Format version
   91  * @param myip The client-side IP address
   92  */
   93 static void document_head(StringBuffer_T B, int V, const char *myip) {
   94         StringBuffer_append(B, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>");
   95         if (V == 2)
   96                 StringBuffer_append(B, "<monit id=\"%s\" incarnation=\"%lld\" version=\"%s\"><server>", Run.id, (long long)Run.incarnation, VERSION);
   97         else
   98                 StringBuffer_append(B,
   99                                     "<monit>"
  100                                     "<server>"
  101                                     "<id>%s</id>"
  102                                     "<incarnation>%lld</incarnation>"
  103                                     "<version>%s</version>",
  104                                     Run.id,
  105                                     (long long)Run.incarnation,
  106                                     VERSION);
  107         StringBuffer_append(B,
  108                             "<uptime>%lld</uptime>"
  109                             "<poll>%d</poll>"
  110                             "<startdelay>%d</startdelay>"
  111                             "<localhostname>%s</localhostname>"
  112                             "<controlfile>%s</controlfile>",
  113                             (long long)(Time_now() - Run.incarnation),
  114                             Run.polltime,
  115                             Run.startdelay,
  116                             Run.system->name ? Run.system->name : "",
  117                             Run.files.control ? Run.files.control : "");
  118 
  119         if (Run.httpd.flags & Httpd_Net || Run.httpd.flags & Httpd_Unix) {
  120                 if (Run.httpd.flags & Httpd_Net)
  121                         StringBuffer_append(B, "<httpd><address>%s</address><port>%d</port><ssl>%d</ssl></httpd>", Run.httpd.socket.net.address ? Run.httpd.socket.net.address : myip ? myip : "", Run.httpd.socket.net.port, Run.httpd.socket.net.ssl.flags & SSL_Enabled);
  122                 else if (Run.httpd.flags & Httpd_Unix)
  123                         StringBuffer_append(B, "<httpd><unixsocket>%s</unixsocket></httpd>", Run.httpd.socket.unix.path ? Run.httpd.socket.unix.path : "");
  124 
  125                 if (Run.mmonitcredentials)
  126                         StringBuffer_append(B, "<credentials><username>%s</username><password>%s</password></credentials>", Run.mmonitcredentials->uname, Run.mmonitcredentials->passwd);
  127         }
  128 
  129         StringBuffer_append(B,
  130                             "</server>"
  131                             "<platform>"
  132                             "<name>%s</name>"
  133                             "<release>%s</release>"
  134                             "<version>%s</version>"
  135                             "<machine>%s</machine>"
  136                             "<cpu>%d</cpu>"
  137                             "<memory>%llu</memory>"
  138                             "<swap>%llu</swap>"
  139                             "</platform>",
  140                             systeminfo.uname.sysname,
  141                             systeminfo.uname.release,
  142                             systeminfo.uname.version,
  143                             systeminfo.uname.machine,
  144                             systeminfo.cpu.count,
  145                             (unsigned long long)((double)systeminfo.memory.size / 1024.),   // Send as kB for backward compatibility
  146                             (unsigned long long)((double)systeminfo.swap.size / 1024.)); // Send as kB for backward compatibility
  147 }
  148 
  149 
  150 /**
  151  * Prints a document footer into the given buffer.
  152  * @param B StringBuffer object
  153  */
  154 static void document_foot(StringBuffer_T B) {
  155         StringBuffer_append(B, "</monit>");
  156 }
  157 
  158 
  159 static void _ioStatistics(StringBuffer_T B, const char *name, IOStatistics_T statistics) {
  160         StringBuffer_append(B, "<%s>", name);
  161         if (Statistics_initialized(&(statistics->bytes))) {
  162                 StringBuffer_append(B,
  163                         "<bytesgeneric>"
  164                         "<count>%.0lf</count>"     // bytes per second
  165                         "<total>%llu</total>" // bytes since boot
  166                         "</bytesgeneric>",
  167                         Statistics_deltaNormalize(&(statistics->bytes)),
  168                         Statistics_raw(&(statistics->bytes)));
  169         }
  170         if (Statistics_initialized(&(statistics->bytesPhysical))) {
  171                 StringBuffer_append(B,
  172                         "<bytes>"
  173                         "<count>%.0lf</count>"     // bytes per second
  174                         "<total>%llu</total>" // bytes since boot
  175                         "</bytes>",
  176                         Statistics_deltaNormalize(&(statistics->bytesPhysical)),
  177                         Statistics_raw(&(statistics->bytesPhysical)));
  178         }
  179         if (Statistics_initialized(&(statistics->operations))) {
  180                 StringBuffer_append(B,
  181                         "<operations>"
  182                         "<count>%.0lf</count>"     // operations per second
  183                         "<total>%llu</total>" // operations since boot
  184                         "</operations>",
  185                         Statistics_deltaNormalize(&(statistics->operations)),
  186                         Statistics_raw(&(statistics->operations)));
  187         }
  188         StringBuffer_append(B, "</%s>", name);
  189 }
  190 
  191 
  192 /**
  193  * Prints a service status into the given buffer.
  194  * @param S Service object
  195  * @param B StringBuffer object
  196  * @param V Format version
  197  */
  198 static void status_service(Service_T S, StringBuffer_T B, int V) {
  199         if (V == 2)
  200                 StringBuffer_append(B, "<service name=\"%s\"><type>%d</type>", S->name ? S->name : "", S->type);
  201         else
  202                 StringBuffer_append(B, "<service type=\"%d\"><name>%s</name>", S->type, S->name ? S->name : "");
  203         StringBuffer_append(B,
  204                             "<collected_sec>%lld</collected_sec>"
  205                             "<collected_usec>%ld</collected_usec>"
  206                             "<status>%d</status>"
  207                             "<status_hint>%d</status_hint>"
  208                             "<monitor>%d</monitor>"
  209                             "<monitormode>%d</monitormode>"
  210                             "<onreboot>%d</onreboot>"
  211                             "<pendingaction>%d</pendingaction>",
  212                             (long long)S->collected.tv_sec,
  213                             (long)S->collected.tv_usec,
  214                             S->error,
  215                             S->error_hint,
  216                             S->monitor,
  217                             S->mode,
  218                             S->onreboot,
  219                             S->doaction);
  220         if (S->every.type != Every_Cycle) {
  221                 StringBuffer_append(B, "<every><type>%d</type>", S->every.type);
  222                 if (S->every.type == 1)
  223                         StringBuffer_append(B, "<counter>%d</counter><number>%d</number>", S->every.spec.cycle.counter, S->every.spec.cycle.number);
  224                 else
  225                         StringBuffer_append(B, "<cron>%s</cron>", S->every.spec.cron);
  226                 StringBuffer_append(B, "</every>");
  227         }
  228         if (Util_hasServiceStatus(S)) {
  229                 switch (S->type) {
  230                         case Service_System:
  231                                 StringBuffer_append(B,
  232                                         "<filedescriptors>"
  233                                         "<allocated>%lld</allocated>"
  234                                         "<unused>%lld</unused>"
  235                                         "<maximum>%lld</maximum>"
  236                                         "</filedescriptors>",
  237                                         systeminfo.filedescriptors.allocated,
  238                                         systeminfo.filedescriptors.unused,
  239                                         systeminfo.filedescriptors.maximum);
  240                                 break;
  241 
  242                         case Service_File:
  243                                 StringBuffer_append(B,
  244                                         "<mode>%o</mode>"
  245                                         "<uid>%d</uid>"
  246                                         "<gid>%d</gid>"
  247                                         "<timestamps>"
  248                                         "<access>%llu</access>"
  249                                         "<change>%llu</change>"
  250                                         "<modify>%llu</modify>"
  251                                         "</timestamps>"
  252                                         "<size>%lld</size>",
  253                                         S->inf.file->mode & 07777,
  254                                         (int)S->inf.file->uid,
  255                                         (int)S->inf.file->gid,
  256                                         S->inf.file->timestamp.access,
  257                                         S->inf.file->timestamp.change,
  258                                         S->inf.file->timestamp.modify,
  259                                         (long long)S->inf.file->size);
  260                                 if (S->checksum)
  261                                         StringBuffer_append(B, "<checksum type=\"%s\">%s</checksum>", checksumnames[S->checksum->type], S->inf.file->cs_sum);
  262                                 break;
  263 
  264                         case Service_Directory:
  265                                 StringBuffer_append(B,
  266                                         "<mode>%o</mode>"
  267                                         "<uid>%d</uid>"
  268                                         "<gid>%d</gid>"
  269                                         "<timestamps>"
  270                                         "<access>%llu</access>"
  271                                         "<change>%llu</change>"
  272                                         "<modify>%llu</modify>"
  273                                         "</timestamps>",
  274                                         S->inf.directory->mode & 07777,
  275                                         (int)S->inf.directory->uid,
  276                                         (int)S->inf.directory->gid,
  277                                         S->inf.directory->timestamp.access,
  278                                         S->inf.directory->timestamp.change,
  279                                         S->inf.directory->timestamp.modify);
  280                                 break;
  281 
  282                         case Service_Fifo:
  283                                 StringBuffer_append(B,
  284                                         "<mode>%o</mode>"
  285                                         "<uid>%d</uid>"
  286                                         "<gid>%d</gid>"
  287                                         "<timestamps>"
  288                                         "<access>%llu</access>"
  289                                         "<change>%llu</change>"
  290                                         "<modify>%llu</modify>"
  291                                         "</timestamps>",
  292                                         S->inf.fifo->mode & 07777,
  293                                         (int)S->inf.fifo->uid,
  294                                         (int)S->inf.fifo->gid,
  295                                         S->inf.fifo->timestamp.access,
  296                                         S->inf.fifo->timestamp.change,
  297                                         S->inf.fifo->timestamp.modify);
  298                                 break;
  299 
  300                         case Service_Filesystem:
  301                                 StringBuffer_append(B,
  302                                         "<fstype>%s</fstype>"
  303                                         "<fsflags>%s</fsflags>"
  304                                         "<mode>%o</mode>"
  305                                         "<uid>%d</uid>"
  306                                         "<gid>%d</gid>"
  307                                         "<block>"
  308                                         "<percent>%.1f</percent>"
  309                                         "<usage>%.1lf</usage>"
  310                                         "<total>%.1lf</total>"
  311                                         "</block>",
  312                                         S->inf.filesystem->object.type,
  313                                         S->inf.filesystem->flags,
  314                                         S->inf.filesystem->mode & 07777,
  315                                         (int)S->inf.filesystem->uid,
  316                                         (int)S->inf.filesystem->gid,
  317                                         S->inf.filesystem->space_percent,
  318                                         S->inf.filesystem->f_bsize > 0 ? (double)S->inf.filesystem->f_blocksused / 1048576. * (double)S->inf.filesystem->f_bsize : 0.,
  319                                         S->inf.filesystem->f_bsize > 0 ? (double)S->inf.filesystem->f_blocks / 1048576. * (double)S->inf.filesystem->f_bsize : 0.);
  320                                 if (S->inf.filesystem->f_files > 0) {
  321                                         StringBuffer_append(B,
  322                                                 "<inode>"
  323                                                 "<percent>%.1f</percent>"
  324                                                 "<usage>%lld</usage>"
  325                                                 "<total>%lld</total>"
  326                                                 "</inode>",
  327                                                 S->inf.filesystem->inode_percent,
  328                                                 S->inf.filesystem->f_filesused,
  329                                                 S->inf.filesystem->f_files);
  330                                 }
  331                                 _ioStatistics(B, "read", &(S->inf.filesystem->read));
  332                                 _ioStatistics(B, "write", &(S->inf.filesystem->write));
  333                                 bool hasReadTime = Statistics_initialized(&(S->inf.filesystem->time.read));
  334                                 bool hasWriteTime = Statistics_initialized(&(S->inf.filesystem->time.write));
  335                                 bool hasWaitTime = Statistics_initialized(&(S->inf.filesystem->time.wait));
  336                                 bool hasRunTime = Statistics_initialized(&(S->inf.filesystem->time.run));
  337                                 if (hasReadTime || hasWriteTime || hasWaitTime || hasRunTime) {
  338                                         StringBuffer_append(B, "<servicetime>");
  339                                         if (hasReadTime)
  340                                                 StringBuffer_append(B, "<read>%.3f</read>", Statistics_deltaNormalize(&(S->inf.filesystem->time.read)));
  341                                         if (hasWriteTime)
  342                                                 StringBuffer_append(B, "<write>%.3f</write>", Statistics_deltaNormalize(&(S->inf.filesystem->time.write)));
  343                                         if (hasWaitTime)
  344                                                 StringBuffer_append(B, "<wait>%.3f</wait>", Statistics_deltaNormalize(&(S->inf.filesystem->time.wait)));
  345                                         if (hasRunTime)
  346                                                 StringBuffer_append(B, "<run>%.3f</run>", Statistics_deltaNormalize(&(S->inf.filesystem->time.run)));
  347                                         StringBuffer_append(B, "</servicetime>");
  348                                 }
  349                                 break;
  350 
  351                         case Service_Net:
  352                                 StringBuffer_append(B,
  353                                         "<link>"
  354                                         "<state>%d</state>"
  355                                         "<speed>%lld</speed>"
  356                                         "<duplex>%d</duplex>"
  357                                         "<download>"
  358                                         "<packets>"
  359                                         "<now>%lld</now>"
  360                                         "<total>%lld</total>"
  361                                         "</packets>"
  362                                         "<bytes>"
  363                                         "<now>%lld</now>"
  364                                         "<total>%lld</total>"
  365                                         "</bytes>"
  366                                         "<errors>"
  367                                         "<now>%lld</now>"
  368                                         "<total>%lld</total>"
  369                                         "</errors>"
  370                                         "</download>"
  371                                         "<upload>"
  372                                         "<packets>"
  373                                         "<now>%lld</now>"
  374                                         "<total>%lld</total>"
  375                                         "</packets>"
  376                                         "<bytes>"
  377                                         "<now>%lld</now>"
  378                                         "<total>%lld</total>"
  379                                         "</bytes>"
  380                                         "<errors>"
  381                                         "<now>%lld</now>"
  382                                         "<total>%lld</total>"
  383                                         "</errors>"
  384                                         "</upload>"
  385                                         "</link>",
  386                                         Link_getState(S->inf.net->stats),
  387                                         Link_getSpeed(S->inf.net->stats),
  388                                         Link_getDuplex(S->inf.net->stats),
  389                                         Link_getPacketsInPerSecond(S->inf.net->stats),
  390                                         Link_getPacketsInTotal(S->inf.net->stats),
  391                                         Link_getBytesInPerSecond(S->inf.net->stats),
  392                                         Link_getBytesInTotal(S->inf.net->stats),
  393                                         Link_getErrorsInPerSecond(S->inf.net->stats),
  394                                         Link_getErrorsInTotal(S->inf.net->stats),
  395                                         Link_getPacketsOutPerSecond(S->inf.net->stats),
  396                                         Link_getPacketsOutTotal(S->inf.net->stats),
  397                                         Link_getBytesOutPerSecond(S->inf.net->stats),
  398                                         Link_getBytesOutTotal(S->inf.net->stats),
  399                                         Link_getErrorsOutPerSecond(S->inf.net->stats),
  400                                         Link_getErrorsOutTotal(S->inf.net->stats));
  401                                 break;
  402 
  403                         case Service_Process:
  404                                 StringBuffer_append(B,
  405                                         "<pid>%d</pid>"
  406                                         "<ppid>%d</ppid>"
  407                                         "<uid>%d</uid>"
  408                                         "<euid>%d</euid>"
  409                                         "<gid>%d</gid>"
  410                                         "<uptime>%lld</uptime>",
  411                                         S->inf.process->pid,
  412                                         S->inf.process->ppid,
  413                                         S->inf.process->uid,
  414                                         S->inf.process->euid,
  415                                         S->inf.process->gid,
  416                                         (long long)S->inf.process->uptime);
  417                                 if (Run.flags & Run_ProcessEngineEnabled) {
  418                                         StringBuffer_append(B,
  419                                                 "<threads>%d</threads>"
  420                                                 "<children>%d</children>"
  421                                                 "<memory>"
  422                                                 "<percent>%.1f</percent>"
  423                                                 "<percenttotal>%.1f</percenttotal>"
  424                                                 "<kilobyte>%llu</kilobyte>"
  425                                                 "<kilobytetotal>%llu</kilobytetotal>"
  426                                                 "</memory>"
  427                                                 "<cpu>"
  428                                                 "<percent>%.1f</percent>"
  429                                                 "<percenttotal>%.1f</percenttotal>"
  430                                                 "</cpu>"
  431                                                 "<filedescriptors>"
  432                                                 "<open>%lld</open>"
  433                                                 "<opentotal>%lld</opentotal>"
  434                                                 "<limit>"
  435                                                 "<soft>%lld</soft>"
  436                                                 "<hard>%lld</hard>"
  437                                                 "</limit>"
  438                                                 "</filedescriptors>",
  439                                                 S->inf.process->threads,
  440                                                 S->inf.process->children,
  441                                                 S->inf.process->mem_percent,
  442                                                 S->inf.process->total_mem_percent,
  443                                                 (unsigned long long)((double)S->inf.process->mem / 1024.),       // Send as kB for backward compatibility
  444                                                 (unsigned long long)((double)S->inf.process->total_mem / 1024.), // Send as kB for backward compatibility
  445                                                 S->inf.process->cpu_percent,
  446                                                 S->inf.process->total_cpu_percent,
  447                                                 S->inf.process->filedescriptors.open,
  448                                                 S->inf.process->filedescriptors.openTotal,
  449                                                 S->inf.process->filedescriptors.limit.soft,
  450                                                 S->inf.process->filedescriptors.limit.hard);
  451                                 }
  452                                 _ioStatistics(B, "read", &(S->inf.process->read));
  453                                 _ioStatistics(B, "write", &(S->inf.process->write));
  454                                 break;
  455 
  456                         default:
  457                                 break;
  458                 }
  459                 for (Icmp_T i = S->icmplist; i; i = i->next) {
  460                         StringBuffer_append(B,
  461                                             "<icmp>"
  462                                             "<type>%s</type>"
  463                                             "<responsetime>%.6f</responsetime>"
  464                                             "</icmp>",
  465                                             icmpnames[i->type],
  466                                             i->is_available == Connection_Ok ? i->responsetime.current / 1000. : -1.); // We send the response time in [s] for backward compatibility (with microseconds precision)
  467                 }
  468                 for (Port_T p = S->portlist; p; p = p->next) {
  469                         StringBuffer_append(B,
  470                                             "<port>"
  471                                             "<hostname>%s</hostname>"
  472                                             "<portnumber>%d</portnumber>"
  473                                             "<request><![CDATA[%s]]></request>"
  474                                             "<protocol>%s</protocol>"
  475                                             "<type>%s</type>"
  476                                             "<responsetime>%.6f</responsetime>",
  477                                             p->hostname ? p->hostname : "",
  478                                             p->target.net.port,
  479                                             Util_portRequestDescription(p),
  480                                             p->protocol->name ? p->protocol->name : "",
  481                                             Util_portTypeDescription(p),
  482                                             p->is_available == Connection_Ok ? p->responsetime.current / 1000. : -1.); // We send the response time in [s] for backward compatibility (with microseconds precision)
  483                         if (p->target.net.ssl.options.flags)
  484                                 StringBuffer_append(B,
  485                                             "<certificate>"
  486                                             "<valid>%d</valid>"
  487                                             "</certificate>",
  488                                             p->target.net.ssl.certificate.validDays);
  489                         StringBuffer_append(B,
  490                                             "</port>");
  491                 }
  492                 for (Port_T p = S->socketlist; p; p = p->next) {
  493                         StringBuffer_append(B,
  494                                             "<unix>"
  495                                             "<path>%s</path>"
  496                                             "<protocol>%s</protocol>"
  497                                             "<responsetime>%.6f</responsetime>"
  498                                             "</unix>",
  499                                             p->target.unix.pathname ? p->target.unix.pathname : "",
  500                                             p->protocol->name ? p->protocol->name : "",
  501                                             p->is_available == Connection_Ok ? p->responsetime.current / 1000. : -1.); // We send the response time in [s] for backward compatibility (with microseconds precision)
  502                 }
  503                 if (S->type == Service_System) {
  504                         StringBuffer_append(B,
  505                                             "<system>"
  506                                             "<load>"
  507                                             "<avg01>%.2f</avg01>"
  508                                             "<avg05>%.2f</avg05>"
  509                                             "<avg15>%.2f</avg15>"
  510                                             "</load>"
  511                                             "<cpu>",
  512                                             systeminfo.loadavg[0],
  513                                             systeminfo.loadavg[1],
  514                                             systeminfo.loadavg[2]);
  515                         if (systeminfo.statisticsAvailable & Statistics_CpuUser)
  516                                 StringBuffer_append(B, "<user>%.1f</user>", systeminfo.cpu.usage.user > 0. ? systeminfo.cpu.usage.user : 0.);
  517                         if (systeminfo.statisticsAvailable & Statistics_CpuSystem)
  518                                 StringBuffer_append(B, "<system>%.1f</system>", systeminfo.cpu.usage.system > 0. ? systeminfo.cpu.usage.system : 0.);
  519                         if (systeminfo.statisticsAvailable & Statistics_CpuNice)
  520                                 StringBuffer_append(B, "<nice>%.1f</nice>", systeminfo.cpu.usage.nice > 0. ? systeminfo.cpu.usage.nice : 0.);
  521                         if (systeminfo.statisticsAvailable & Statistics_CpuIOWait)
  522                                 StringBuffer_append(B, "<wait>%.1f</wait>", systeminfo.cpu.usage.iowait > 0. ? systeminfo.cpu.usage.iowait : 0.);
  523                         if (systeminfo.statisticsAvailable & Statistics_CpuHardIRQ)
  524                                 StringBuffer_append(B, "<hardirq>%.1f</hardirq>", systeminfo.cpu.usage.hardirq > 0. ? systeminfo.cpu.usage.hardirq : 0.);
  525                         if (systeminfo.statisticsAvailable & Statistics_CpuSoftIRQ)
  526                                 StringBuffer_append(B, "<softirq>%.1f</softirq>", systeminfo.cpu.usage.softirq > 0. ? systeminfo.cpu.usage.softirq : 0.);
  527                         if (systeminfo.statisticsAvailable & Statistics_CpuSteal)
  528                                 StringBuffer_append(B, "<steal>%.1f</steal>", systeminfo.cpu.usage.steal > 0. ? systeminfo.cpu.usage.steal : 0.);
  529                         if (systeminfo.statisticsAvailable & Statistics_CpuGuest)
  530                                 StringBuffer_append(B, "<guest>%.1f</guest>", systeminfo.cpu.usage.guest > 0. ? systeminfo.cpu.usage.guest : 0.);
  531                         if (systeminfo.statisticsAvailable & Statistics_CpuGuestNice)
  532                                 StringBuffer_append(B, "<guestnice>%.1f</guestnice>", systeminfo.cpu.usage.guest_nice > 0. ? systeminfo.cpu.usage.guest_nice : 0.);
  533                         StringBuffer_append(B,
  534                                             "</cpu>"
  535                                             "<memory>"
  536                                             "<percent>%.1f</percent>"
  537                                             "<kilobyte>%llu</kilobyte>"
  538                                             "</memory>"
  539                                             "<swap>"
  540                                             "<percent>%.1f</percent>"
  541                                             "<kilobyte>%llu</kilobyte>"
  542                                             "</swap>"
  543                                             "</system>",
  544                                             systeminfo.memory.usage.percent,
  545                                             (unsigned long long)((double)systeminfo.memory.usage.bytes / 1024.),               // Send as kB for backward compatibility
  546                                             systeminfo.swap.usage.percent,
  547                                             (unsigned long long)((double)systeminfo.swap.usage.bytes / 1024.));             // Send as kB for backward compatibility
  548                 }
  549                 if (S->type == Service_Program && S->program->started) {
  550                         StringBuffer_append(B,
  551                                             "<program>"
  552                                             "<started>%lld</started>"
  553                                             "<status>%d</status>"
  554                                             "<output><![CDATA[",
  555                                             (long long)S->program->started,
  556                                             S->program->exitStatus);
  557                         _escapeCDATA(B, StringBuffer_toString(S->program->lastOutput));
  558                         StringBuffer_append(B,
  559                                             "]]></output>"
  560                                             "</program>");
  561                 }
  562         }
  563         StringBuffer_append(B, "</service>");
  564 }
  565 
  566 
  567 /**
  568  * Prints a servicegroups into the given buffer.
  569  * @param SG ServiceGroup object
  570  * @param B StringBuffer object
  571  */
  572 static void status_servicegroup(ServiceGroup_T SG, StringBuffer_T B) {
  573         StringBuffer_append(B, "<servicegroup name=\"%s\">", SG->name);
  574         for (list_t m = SG->members->head; m; m = m->next) {
  575                 Service_T s = m->e;
  576                 StringBuffer_append(B, "<service>%s</service>", s->name);
  577         }
  578         StringBuffer_append(B, "</servicegroup>");
  579 }
  580 
  581 
  582 /**
  583  * Prints a event description into the given buffer.
  584  * @param E Event object
  585  * @param B StringBuffer object
  586  */
  587 static void status_event(Event_T E, StringBuffer_T B) {
  588         StringBuffer_append(B,
  589                             "<event>"
  590                             "<collected_sec>%lld</collected_sec>"
  591                             "<collected_usec>%ld</collected_usec>"
  592                             "<service>%s</service>"
  593                             "<type>%d</type>"
  594                             "<id>%ld</id>"
  595                             "<state>%d</state>"
  596                             "<action>%d</action>"
  597                             "<message><![CDATA[",
  598                             (long long)E->collected.tv_sec,
  599                             (long)E->collected.tv_usec,
  600                             E->id == Event_Instance ? "Monit" : E->source->name,
  601                             E->type,
  602                             E->id,
  603                             E->state,
  604                             Event_get_action(E));
  605         if (E->message)
  606                 _escapeCDATA(B, E->message);
  607         StringBuffer_append(B, "]]></message>");
  608         StringBuffer_append(B, "</event>");
  609 }
  610 
  611 
  612 /* ------------------------------------------------------------------ Public */
  613 
  614 
  615 /**
  616  * Get a XML formatted message for event notification or general status
  617  * of monitored services and resources.
  618  * @param E An event object or NULL for general status
  619  * @param V Format version
  620  * @param myip The client-side IP address
  621  */
  622 void status_xml(StringBuffer_T B, Event_T E, int V, const char *myip) {
  623         Service_T S;
  624         ServiceGroup_T SG;
  625 
  626         document_head(B, V, myip);
  627         if (V == 2)
  628                 StringBuffer_append(B, "<services>");
  629         for (S = servicelist_conf; S; S = S->next_conf)
  630                 status_service(S, B, V);
  631         if (V == 2) {
  632                 StringBuffer_append(B, "</services><servicegroups>");
  633                 for (SG = servicegrouplist; SG; SG = SG->next)
  634                         status_servicegroup(SG, B);
  635                 StringBuffer_append(B, "</servicegroups>");
  636         }
  637         if (E)
  638                 status_event(E, B);
  639         document_foot(B);
  640 }
  641