/* * apcreports.c * * Event logging functions. */ /* * Copyright (C) 2000-2004 Kern Sibbald * Copyright (C) 1996-1999 Andre M. Hedrick * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General * Public License as published by the Free Software Foundation. * * 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, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ #include "apc.h" static char largebuf[4096]; static int stat_recs; static int logstats = 0; static time_t last_time_status; static time_t last_time_logging; static FILE *statusfile = NULL; /* initial value set to NULL for terminate */ void clear_files(void) { if (statusfile != NULL) { fflush(statusfile); fclose(statusfile); statusfile = NULL; } } static void log_status_open(UPSINFO *ups) { largebuf[0] = 0; stat_recs = 0; rewind(statusfile); logstats = ups->logstats; } #define STAT_REV 1 static int log_status_close(UPSINFO *ups, int fd) { int i; char buf[MAXSTRING]; char *sptr, *eptr; i = strlen(largebuf); if (i > (int)sizeof(largebuf) - 1) { log_event(ups, LOG_ERR, _("Status buffer overflow %d bytes\n"), i - sizeof(largebuf)); return -1; } asnprintf(buf, sizeof(buf), "APC : %03d,%03d,%04d\n", STAT_REV, stat_recs, i); fputs(buf, statusfile); fputs(largebuf, statusfile); fflush(statusfile); /* * Write out the status log to syslog() one record at a * time. */ if (logstats) { buf[strlen(buf) - 1] = 0; log_event(ups, LOG_NOTICE, buf); sptr = eptr = largebuf; for (; i > 0; i--) { if (*eptr == '\n') { *eptr++ = 0; log_event(ups, LOG_NOTICE, sptr); sptr = eptr; } else { eptr++; } } } return 0; } /* * Log one line of the status file; * also send it to system log */ static void log_status_write(UPSINFO *ups, const char *fmt, ...) { va_list ap; char buf[MAXSTRING]; va_start(ap, fmt); avsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap); strncat(largebuf, buf, sizeof(largebuf)); largebuf[sizeof(largebuf) - 1] = 0; stat_recs++; } /* * Log current UPS data * * Format of output for SmartUPS * vmin, vmax, vout, vbat, freq, load%,temp,amb-temp,humid, vline * 223.6,230.1,227.5,27.74,50.00,020.8,034.6,,,229.8 * * currently ambient temp and humidity are not included */ static void log_data(UPSINFO *ups) { const char *ptr; char msg[MAXSTRING]; static int toggle = 0; if (ups->datatime == 0) return; switch (ups->mode.type) { case BK: case SHAREBASIC: if (!ups->is_onbatt()) { if (!ups->is_replacebatt()) { ptr = "OK"; } else { ptr = "REPLACE"; } log_event(ups, LOG_INFO, "LINEFAIL:OK BATTSTAT:%s", ptr); } else { if (!ups->is_battlow()) ptr = "RUNNING"; else ptr = "FAILING"; log_event(ups, LOG_INFO, "LINEFAIL:DOWN BATTSTAT:%s", ptr); } break; case BKPRO: case VS: if (!ups->is_onbatt()) { if (ups->is_boost()) ptr = "LOW"; else if (ups->is_trim()) ptr = "HIGH"; else ptr = "OK"; log_event(ups, LOG_INFO, "LINEFAIL:OK BATTSTAT:OK MAINS:%s", ptr); } else { if (!ups->is_battlow()) ptr = "RUNNING"; else ptr = "FAILING"; log_event(ups, LOG_INFO, "LINEFAIL:DOWN BATTSTAT:%s", ptr); } switch (ups->lastxfer) { case XFER_NONE: ptr = "POWER UP"; break; case XFER_SELFTEST: ptr = "SELF TEST"; break; case XFER_UNDERVOLT: ptr = "LINE VOLTAGE DECREASE"; break; case XFER_OVERVOLT: ptr = "LINE VOLTAGE INCREASE"; break; case XFER_NOTCHSPIKE: ptr = "POWER FAILURE"; break; case XFER_RIPPLE: ptr = "R-EVENT"; break; default: asnprintf(msg, sizeof(msg), "UNKNOWN EVENT"); ptr = msg; break; } log_event(ups, LOG_INFO, "LASTEVENT: %s", ptr); break; case NBKPRO: case SMART: case SHARESMART: case MATRIX: case USB_UPS: case TEST_UPS: case DUMB_UPS: case NETWORK_UPS: case SNMP_UPS: case APCSMART_UPS: toggle = !toggle; /* flip bit */ log_event(ups, LOG_INFO, "%05.1f,%05.1f,%05.1f,%05.2f,%05.2f,%04.1f,%04.1f,%05.1f,%05.1f,%05.1f,%05.1f,%d", ups->LineMin, ups->LineMax, ups->OutputVoltage, ups->BattVoltage, ups->LineFreq, ups->UPSLoad, ups->UPSTemp, ups->ambtemp, ups->humidity, ups->LineVoltage, ups->BattChg, toggle); break; default: break; } return; } void do_reports(UPSINFO *ups) { static int first_time = TRUE; time_t now = time(NULL); if (first_time) { first_time = FALSE; /* Set up logging and status timers. */ last_time_logging = 0; last_time_status = 0; if (ups->stattime != 0) { if ((statusfile = fopen(ups->statfile, "w")) == NULL) { log_event(ups, LOG_ERR, "Cannot open STATUS file %s: %s\n", ups->statfile, strerror(errno)); } } else { unlink(ups->statfile); } } /* Check if it is time to log DATA record */ if ((ups->datatime > 0) && (now - last_time_logging) >= ups->datatime) { last_time_logging = now; log_data(ups); } /* Check if it is time to write STATUS file */ if ((statusfile != NULL) && (now - last_time_status) >= ups->stattime) { last_time_status = now; output_status(ups, 0, log_status_open, log_status_write, log_status_close); } /* Trim the EVENTS file */ trim_eventfile(ups); }