/** * Validate timestamps of a service s */ static void check_timestamp(Service_T s) { Timestamp_T t; time_t now; ASSERT(s && s->timestamplist); if ((int)time(&now) == -1) { Event_post(s, Event_Data, STATE_FAILED, s->action_DATA, "can't obtain actual system time"); return; } else Event_post(s, Event_Data, STATE_SUCCEEDED, s->action_DATA, "actual system time obtained"); for (t = s->timestamplist; t; t = t->next) { if (t->test_changes) { /* if we are testing for changes only, the value is variable */ if (t->timestamp != s->inf->timestamp) { /* reset expected value for next cycle */ t->timestamp = s->inf->timestamp; Event_post(s, Event_Timestamp, STATE_CHANGED, t->action, "timestamp was changed for %s", s->path); } else { DEBUG("'%s' timestamp was not changed for %s\n", s->name, s->path); Event_post(s, Event_Timestamp, STATE_CHANGEDNOT, t->action, "timestamp was not changed for %s", s->path); } break; } else { /* we are testing constant value for failed or succeeded state */ if (Util_evalQExpression(t->operator, (int)(now - s->inf->timestamp), t->time)) Event_post(s, Event_Timestamp, STATE_FAILED, t->action, "timestamp test failed for %s", s->path); else { DEBUG("'%s' timestamp test succeeded for %s\n", s->name, s->path); Event_post(s, Event_Timestamp, STATE_SUCCEEDED, t->action, "timestamp succeeded"); } } } }
/** * Check that the server returns a valid HTTP response as well as checksum * or content regex if required * @param s A socket * @return TRUE if the response is valid otherwise FALSE */ static int check_request(Socket_T socket, Port_T P) { int status, content_length = -1; char buf[LINE_SIZE]; if (! socket_readln(socket, buf, LINE_SIZE)) { socket_setError(socket, "HTTP: Error receiving data -- %s", STRERROR); return FALSE; } Str_chomp(buf); if (! sscanf(buf, "%*s %d", &status)) { socket_setError(socket, "HTTP error: Cannot parse HTTP status in response: %s", buf); return FALSE; } if (! Util_evalQExpression(P->operator, status, P->status)) { socket_setError(socket, "HTTP error: Server returned status %d", status); return FALSE; } /* Get Content-Length header value */ while (socket_readln(socket, buf, LINE_SIZE)) { if ((buf[0] == '\r' && buf[1] == '\n') || (buf[0] == '\n')) break; Str_chomp(buf); if (Str_startsWith(buf, "Content-Length")) { if (! sscanf(buf, "%*s%*[: ]%d", &content_length)) { socket_setError(socket, "HTTP error: Parsing Content-Length response header '%s'", buf); return FALSE; } if (content_length < 0) { socket_setError(socket, "HTTP error: Illegal Content-Length response header '%s'", buf); return FALSE; } } } if (P->url_request && P->url_request->regex && ! do_regex(socket, content_length, P->url_request)) return FALSE; if (P->request_checksum) return check_request_checksum(socket, content_length, P->request_checksum, P->request_hashtype); return TRUE; }
/** * Test size */ static void check_size(Service_T s) { Size_T sl; ASSERT(s && s->sizelist); for (sl = s->sizelist; sl; sl = sl->next) { /* if we are testing for changes only, the value is variable */ if (sl->test_changes) { if (!sl->test_changes_ok) { /* the size was not initialized during monit start, so set the size now * and allow further size change testing */ sl->test_changes_ok = TRUE; sl->size = s->inf->priv.file.st_size; } else { if (sl->size != s->inf->priv.file.st_size) { Event_post(s, Event_Size, STATE_CHANGED, sl->action, "size was changed for %s", s->path); /* reset expected value for next cycle */ sl->size = s->inf->priv.file.st_size; } else { DEBUG("'%s' size has not changed [current size=%llu B]\n", s->name, s->inf->priv.file.st_size); Event_post(s, Event_Size, STATE_CHANGEDNOT, sl->action, "size was not changed", s->path); } } break; } /* we are testing constant value for failed or succeeded state */ if (Util_evalQExpression(sl->operator, s->inf->priv.file.st_size, sl->size)) Event_post(s, Event_Size, STATE_FAILED, sl->action, "size test failed for %s -- current size is %llu B", s->path, s->inf->priv.file.st_size); else { DEBUG("'%s' file size check succeeded [current size=%llu B]\n", s->name, s->inf->priv.file.st_size); Event_post(s, Event_Size, STATE_SUCCEEDED, sl->action, "size succeeded"); } } }
/** * Extract the Scoreboard line from the mod_status response. * Count the active apache child processes, and those which are * in other states. If each percentage exceeds the corresponding * limit, then return FALSE. * @param s A socket * @param limit The maximum percentage of logging processes * @return TRUE if logging is OK otherwise FALSE */ static int check_apache_stat(Socket_T socket) { int scored = 0; int errors = 0; char line[READ_SIZE]; char search_string[READ_SIZE + 1]; int loglimit= 0; int closelimit= 0; int dnslimit= 0; int keepalivelimit= 0; int replylimit= 0; int requestlimit= 0; int startlimit= 0; int waitlimit= 0; int gracefullimit= 0; int cleanuplimit= 0; int no_logging = 0; int no_close = 0; int no_dns = 0; int no_keepalive = 0; int no_reply = 0; int no_request = 0; int no_start = 0; int no_wait = 0; int no_graceful = 0; int no_cleanup = 0; int active_servers = 0; char *p; Port_T myPort= (Port_T)socket_get_Port(socket); ASSERT(myPort); loglimit= myPort->ApacheStatus.loglimit; closelimit= myPort->ApacheStatus.closelimit; dnslimit= myPort->ApacheStatus.dnslimit; keepalivelimit= myPort->ApacheStatus.keepalivelimit; replylimit= myPort->ApacheStatus.replylimit; requestlimit= myPort->ApacheStatus.requestlimit; startlimit= myPort->ApacheStatus.startlimit; waitlimit= myPort->ApacheStatus.waitlimit; gracefullimit= myPort->ApacheStatus.gracefullimit; cleanuplimit= myPort->ApacheStatus.cleanuplimit; while(NULL != socket_readln(socket, line, READ_SIZE)) { if(Str_startsWith(line, "Scoreboard")) { if(1 != sscanf(line, "%*s%*[: ]%1024s", search_string)) { Str_chomp(line); socket_setError(socket, "APACHE-STATUS error: parsing Apache status response '%s'\n", line); return FALSE; } else { scored = 1; } } } DEBUG("Scoreboard: %s\n", search_string); /* Check that some scoreboard line was found, if not return an error */ if(!scored){ socket_setError(socket, "APACHE-STATUS error: no scoreboard line returned by Apache\n"); return FALSE; } /* Total each of the status messages in the scoreboard */ for(p = search_string ; *p ; p++){ active_servers++; switch(*p){ case 'S': no_start++; break; case 'R': no_request++; break; case 'W': no_reply++; break; case 'K': no_keepalive++; break; case 'D': no_dns++; break; case 'C': no_close++; break; case 'L': no_logging++; break; case 'G': no_graceful++; break; case 'I': no_cleanup++; break; case '_': no_wait++; break; case '.': active_servers--; break; } } if(active_servers <= 0){ socket_setError(socket, "APACHE-STATUS warning: No idle server or threads found\n"); /* This is not really an error, only a very bussy server */ return TRUE; } /* * Conditions are only tested if the limit parameter is greater than zero. */ if(loglimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.loglimitOP, (100 * no_logging / active_servers), loglimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are logging\n", loglimit); errors++; } } if(startlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.startlimitOP, (100 * no_start / active_servers), startlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are starting\n", startlimit); errors++; } } if(requestlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.requestlimitOP, (100 * no_request / active_servers), requestlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are reading requests\n", requestlimit); errors++; } } if(replylimit > 0 ){ if(Util_evalQExpression(myPort->ApacheStatus.replylimitOP, (100 * no_reply / active_servers), replylimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are sending a reply\n", replylimit); errors++; } } if(keepalivelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.keepalivelimitOP, (100 * no_keepalive / active_servers), keepalivelimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are in keepalive\n", keepalivelimit); errors++; } } if(dnslimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.dnslimitOP, (100 * no_dns / active_servers), dnslimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are waiting for DNS\n", dnslimit); errors++; } } if(closelimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.closelimitOP, (100 * no_close / active_servers), closelimit)){ socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are closing connections\n", closelimit); errors++; } } if(gracefullimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.gracefullimitOP, (100 * no_graceful / active_servers), gracefullimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are finishing gracefully\n", gracefullimit); errors++; } } if(cleanuplimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.cleanuplimitOP, (100 * no_cleanup / active_servers), cleanuplimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are in idle cleanup\n", cleanuplimit); errors++; } } if(waitlimit > 0){ if(Util_evalQExpression(myPort->ApacheStatus.waitlimitOP, (100 * no_wait / active_servers), waitlimit)) { socket_setError(socket, "APACHE-STATUS error:" " %i percent of Apache processes are waiting for a connection\n", waitlimit); errors++; } } return (errors==0); }
static int parse_scoreboard(Socket_T socket, char *scoreboard) { int logging = 0, close = 0, dns = 0, keepalive = 0, reply = 0, request = 0, start = 0, wait = 0, graceful = 0, cleanup = 0, open = 0; for (char *state = scoreboard; *state; state++) { switch (*state) { case 'S': start++; break; case 'R': request++; break; case 'W': reply++; break; case 'K': keepalive++; break; case 'D': dns++; break; case 'C': close++; break; case 'L': logging++; break; case 'G': graceful++; break; case 'I': cleanup++; break; case '_': wait++; break; case '.': open++; break; } } int total = logging + close + dns + keepalive + reply + request + start + wait + graceful + cleanup + open; if (! total) return TRUE; // Idle server int errors = 0; Port_T p = socket_get_Port(socket); ASSERT(p); //FIXME: socket_setError overrides previous => either stop on first error, or append errors and set error at the end (convert error buffer to stringbuffer?) if (p->ApacheStatus.loglimit > 0 && Util_evalQExpression(p->ApacheStatus.loglimitOP, (100 * logging / total), p->ApacheStatus.loglimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are logging", 100 * logging / total); errors++; } if (p->ApacheStatus.startlimit > 0 && Util_evalQExpression(p->ApacheStatus.startlimitOP, (100 * start / total), p->ApacheStatus.startlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are starting", 100 * start / total); errors++; } if (p->ApacheStatus.requestlimit > 0 && Util_evalQExpression(p->ApacheStatus.requestlimitOP, (100 * request / total), p->ApacheStatus.requestlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are reading requests", 100 * request / total); errors++; } if (p->ApacheStatus.replylimit > 0 && Util_evalQExpression(p->ApacheStatus.replylimitOP, (100 * reply / total), p->ApacheStatus.replylimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are sending a reply", 100 * reply / total); errors++; } if (p->ApacheStatus.keepalivelimit > 0 && Util_evalQExpression(p->ApacheStatus.keepalivelimitOP, (100 * keepalive / total), p->ApacheStatus.keepalivelimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are in keepalive", 100 * keepalive / total); errors++; } if (p->ApacheStatus.dnslimit > 0 && Util_evalQExpression(p->ApacheStatus.dnslimitOP, (100 * dns / total), p->ApacheStatus.dnslimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are waiting for DNS", 100 * dns / total); errors++; } if (p->ApacheStatus.closelimit > 0 && Util_evalQExpression(p->ApacheStatus.closelimitOP, (100 * close / total), p->ApacheStatus.closelimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are closing connections", 100 * close / total); errors++; } if (p->ApacheStatus.gracefullimit > 0 && Util_evalQExpression(p->ApacheStatus.gracefullimitOP, (100 * graceful / total), p->ApacheStatus.gracefullimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are finishing gracefully", 100 * graceful / total); errors++; } if (p->ApacheStatus.cleanuplimit > 0 && Util_evalQExpression(p->ApacheStatus.cleanuplimitOP, (100 * cleanup / total), p->ApacheStatus.cleanuplimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are in idle cleanup", 100 * cleanup / total); errors++; } if (p->ApacheStatus.waitlimit > 0 && Util_evalQExpression(p->ApacheStatus.waitlimitOP, (100 * wait / total), p->ApacheStatus.waitlimit)) { socket_setError(socket, "APACHE-STATUS: error -- %d percent of processes are waiting for a connection", 100 * wait / total); errors++; } return (errors == 0); }
/** * Check process resources */ static void check_process_resources(Service_T s, Resource_T r) { int okay = TRUE; char report[STRLEN]={0}; ASSERT(s && r); switch(r->resource_id) { case RESOURCE_ID_CPU_PERCENT: if (s->monitor == MONITOR_INIT || s->inf->priv.process.cpu_percent < 0) { DEBUG("'%s' cpu usage check skipped (initializing)\n", s->name); } else if (Util_evalQExpression(r->operator, s->inf->priv.process.cpu_percent, r->limit)) { snprintf(report, STRLEN, "cpu usage of %.1f%% matches resource limit [cpu usage%s%.1f%%]", s->inf->priv.process.cpu_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' cpu usage check succeeded [current cpu usage=%.1f%%]", s->name, s->inf->priv.process.cpu_percent/10.0); break; case RESOURCE_ID_TOTAL_CPU_PERCENT: if (s->monitor == MONITOR_INIT || s->inf->priv.process.total_cpu_percent < 0) { DEBUG("'%s' total cpu usage check skipped (initializing)\n", s->name); } else if (Util_evalQExpression(r->operator, s->inf->priv.process.total_cpu_percent, r->limit)) { snprintf(report, STRLEN, "total cpu usage of %.1f%% matches resource limit [cpu usage%s%.1f%%]", s->inf->priv.process.total_cpu_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' total cpu usage check succeeded [current cpu usage=%.1f%%]", s->name, s->inf->priv.process.total_cpu_percent/10.0); break; case RESOURCE_ID_CPUUSER: if (s->monitor == MONITOR_INIT || systeminfo.total_cpu_user_percent < 0) { DEBUG("'%s' cpu user usage check skipped (initializing)\n", s->name); } else if (Util_evalQExpression(r->operator, systeminfo.total_cpu_user_percent, r->limit)) { snprintf(report, STRLEN, "cpu user usage of %.1f%% matches resource limit [cpu user usage%s%.1f%%]", systeminfo.total_cpu_user_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' cpu user usage check succeeded [current cpu user usage=%.1f%%]", s->name, systeminfo.total_cpu_user_percent/10.0); break; case RESOURCE_ID_CPUSYSTEM: if (s->monitor == MONITOR_INIT || systeminfo.total_cpu_syst_percent < 0) { DEBUG("'%s' cpu system usage check skipped (initializing)\n", s->name); } else if (Util_evalQExpression(r->operator, systeminfo.total_cpu_syst_percent, r->limit)) { snprintf(report, STRLEN, "cpu system usage of %.1f%% matches resource limit [cpu system usage%s%.1f%%]", systeminfo.total_cpu_syst_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' cpu system usage check succeeded [current cpu system usage=%.1f%%]", s->name, systeminfo.total_cpu_syst_percent/10.0); break; case RESOURCE_ID_CPUWAIT: if (s->monitor == MONITOR_INIT || systeminfo.total_cpu_wait_percent < 0) { DEBUG("'%s' cpu wait usage check skipped (initializing)\n", s->name); } else if (Util_evalQExpression(r->operator, systeminfo.total_cpu_wait_percent, r->limit)) { snprintf(report, STRLEN, "cpu wait usage of %.1f%% matches resource limit [cpu wait usage%s%.1f%%]", systeminfo.total_cpu_wait_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' cpu wait usage check succeeded [current cpu wait usage=%.1f%%]", s->name, systeminfo.total_cpu_wait_percent/10.0); break; case RESOURCE_ID_MEM_PERCENT: if (s->type == TYPE_SYSTEM) { if (Util_evalQExpression(r->operator, systeminfo.total_mem_percent, r->limit)) { snprintf(report, STRLEN, "mem usage of %.1f%% matches resource limit [mem usage%s%.1f%%]", systeminfo.total_mem_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' mem usage check succeeded [current mem usage=%.1f%%]", s->name, systeminfo.total_mem_percent/10.0); } else { if (Util_evalQExpression(r->operator, s->inf->priv.process.mem_percent, r->limit)) { snprintf(report, STRLEN, "mem usage of %.1f%% matches resource limit [mem usage%s%.1f%%]", s->inf->priv.process.mem_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' mem usage check succeeded [current mem usage=%.1f%%]", s->name, s->inf->priv.process.mem_percent/10.0); } break; case RESOURCE_ID_MEM_KBYTE: if (s->type == TYPE_SYSTEM) { if (Util_evalQExpression(r->operator, systeminfo.total_mem_kbyte, r->limit)) { snprintf(report, STRLEN, "mem amount of %ldkB matches resource limit [mem amount%s%ldkB]", systeminfo.total_mem_kbyte, operatorshortnames[r->operator], r->limit); okay = FALSE; } else snprintf(report, STRLEN, "'%s' mem amount check succeeded [current mem amount=%ldkB]", s->name, systeminfo.total_mem_kbyte); } else { if (Util_evalQExpression(r->operator, s->inf->priv.process.mem_kbyte, r->limit)) { snprintf(report, STRLEN, "mem amount of %ldkB matches resource limit [mem amount%s%ldkB]", s->inf->priv.process.mem_kbyte, operatorshortnames[r->operator], r->limit); okay = FALSE; } else snprintf(report, STRLEN, "'%s' mem amount check succeeded [current mem amount=%ldkB]", s->name, s->inf->priv.process.mem_kbyte); } break; case RESOURCE_ID_SWAP_PERCENT: if (s->type == TYPE_SYSTEM) { if (Util_evalQExpression(r->operator, systeminfo.total_swap_percent, r->limit)) { snprintf(report, STRLEN, "swap usage of %.1f%% matches resource limit [swap usage%s%.1f%%]", systeminfo.total_swap_percent/10.0, operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' swap usage check succeeded [current swap usage=%.1f%%]", s->name, systeminfo.total_swap_percent/10.0); } break; case RESOURCE_ID_SWAP_KBYTE: if (s->type == TYPE_SYSTEM) { if (Util_evalQExpression(r->operator, systeminfo.total_swap_kbyte, r->limit)) { snprintf(report, STRLEN, "swap amount of %ldkB matches resource limit [swap amount%s%ldkB]", systeminfo.total_swap_kbyte, operatorshortnames[r->operator], r->limit); okay = FALSE; } else snprintf(report, STRLEN, "'%s' swap amount check succeeded [current swap amount=%ldkB]", s->name, systeminfo.total_swap_kbyte); } break; case RESOURCE_ID_LOAD1: if (Util_evalQExpression(r->operator, (int)(systeminfo.loadavg[0]*10.0), r->limit)) { snprintf(report, STRLEN, "loadavg(1min) of %.1f matches resource limit [loadavg(1min)%s%.1f]", systeminfo.loadavg[0], operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' loadavg(1min) check succeeded [current loadavg(1min)=%.1f]", s->name, systeminfo.loadavg[0]); break; case RESOURCE_ID_LOAD5: if (Util_evalQExpression(r->operator, (int)(systeminfo.loadavg[1]*10.0), r->limit)) { snprintf(report, STRLEN, "loadavg(5min) of %.1f matches resource limit [loadavg(5min)%s%.1f]", systeminfo.loadavg[1], operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' loadavg(5min) check succeeded [current loadavg(5min)=%.1f]", s->name, systeminfo.loadavg[1]); break; case RESOURCE_ID_LOAD15: if (Util_evalQExpression(r->operator, (int)(systeminfo.loadavg[2]*10.0), r->limit)) { snprintf(report, STRLEN, "loadavg(15min) of %.1f matches resource limit [loadavg(15min)%s%.1f]", systeminfo.loadavg[2], operatorshortnames[r->operator], r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' loadavg(15min) check succeeded [current loadavg(15min)=%.1f]", s->name, systeminfo.loadavg[2]); break; case RESOURCE_ID_CHILDREN: if (Util_evalQExpression(r->operator, s->inf->priv.process.children, r->limit)) { snprintf(report, STRLEN, "children of %i matches resource limit [children%s%ld]", s->inf->priv.process.children, operatorshortnames[r->operator], r->limit); okay = FALSE; } else snprintf(report, STRLEN, "'%s' children check succeeded [current children=%i]", s->name, s->inf->priv.process.children); break; case RESOURCE_ID_TOTAL_MEM_KBYTE: if (Util_evalQExpression(r->operator, s->inf->priv.process.total_mem_kbyte, r->limit)) { snprintf(report, STRLEN, "total mem amount of %ldkB matches resource limit [total mem amount%s%ldkB]", s->inf->priv.process.total_mem_kbyte, operatorshortnames[r->operator], r->limit); okay = FALSE; } else snprintf(report, STRLEN, "'%s' total mem amount check succeeded [current total mem amount=%ldkB]", s->name, s->inf->priv.process.total_mem_kbyte); break; case RESOURCE_ID_TOTAL_MEM_PERCENT: if (Util_evalQExpression(r->operator, s->inf->priv.process.total_mem_percent, r->limit)) { snprintf(report, STRLEN, "total mem amount of %.1f%% matches resource limit [total mem amount%s%.1f%%]", (float)s->inf->priv.process.total_mem_percent/10.0, operatorshortnames[r->operator], (float)r->limit/10.0); okay = FALSE; } else snprintf(report, STRLEN, "'%s' total mem amount check succeeded [current total mem amount=%.1f%%]", s->name, s->inf->priv.process.total_mem_percent/10.0); break; default: LogError("'%s' error -- unknown resource ID: [%d]\n", s->name, r->resource_id); return; } if (! okay) Event_post(s, Event_Resource, STATE_FAILED, r->action, "%s", report); else { Event_post(s, Event_Resource, STATE_SUCCEEDED, r->action, "%s", report); if (*report) DEBUG("%s\n", report); } }