/*************************************************************************** * Copyright (C) 05/2009 by Olaf Rempel * * razzor@kopf-tisch.de * * * * 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; version 2 of the License * * * * 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 #include #include #include #include "configfile.h" #include "event.h" #include "logging.h" #include "unixsocket.h" #include "usvdevice.h" #define DEFAULT_SOCKET "alix-usvd.sock" #define SENDMAIL "/usr/sbin/sendmail -t" enum { STATE_IDLE = 0x01, STATE_TEST = 0x02, STATE_CHARGE = 0x04, STATE_DISCHARGE = 0x08, STATE_POWEROFF = 0x10, }; static struct event_fd *listen_event; static struct event_timeout *timeout_event; static const char *mail_from; static const char *mail_to; static char * state2str(int state) { switch (state) { case STATE_IDLE: return "IDLE"; case STATE_TEST: return "TEST"; case STATE_CHARGE: return "CHARGE"; case STATE_DISCHARGE: return "DISCHARGE"; case STATE_POWEROFF: return "POWEROFF"; default: return "UNKNOWN"; } } static int str2state(char *buf) { int state = -1; if (strncasecmp(buf, "IDLE", 4) == 0) state = STATE_IDLE; else if (strncasecmp(buf, "TEST", 4) == 0) state = STATE_TEST; else if (strncasecmp(buf, "CHARGE", 6) == 0) state = STATE_CHARGE; else if (strncasecmp(buf, "DISCHARGE", 9) == 0) state = STATE_DISCHARGE; else if (strncasecmp(buf, "POWEROFF", 8) == 0) state = STATE_POWEROFF; return state; } static int usvstate_update(int state, struct usvdev_status *status) { static int old_state; if (status != NULL) state = status->state; if (state == old_state) return state; log_print(LOG_INFO, "usv state changed: %s => %s", state2str(old_state), state2str(state)); if (mail_to != NULL) { FILE *mail = popen(SENDMAIL, "w"); if (mail != NULL) { fprintf(mail, "From: %s\n", mail_from); fprintf(mail, "To: %s\n", mail_to); fprintf(mail, "Subject: alix-usvd state change: %s => %s\n\n", state2str(old_state), state2str(state)); if (status != NULL) { fprintf(mail, "Current USV status:\n"); fprintf(mail, "Ibat: %1.3lf mA\nUbat: %2.3lf V\nUin : %2.3lf V\n\n", status->ibat / 1000.0, status->ubat / 1000.0, status->uin / 1000.0); } fprintf(mail, "Faithfully yours, etc.\n"); fclose(mail); } } old_state = state; return state; } static int unix_read_cb(int fd, void *privdata) { char buf[64]; int len = read(fd, buf, sizeof(buf)); if (len < 0) return -1; int new_state = str2state(buf); if (new_state != -1) { usvdev_setstate(new_state); new_state = usvstate_update(new_state, NULL); int len = snprintf(buf, sizeof(buf), "%s", state2str(new_state)); write(fd, buf, len); } else if (strncasecmp(buf, "status", 6) == 0) { struct usvdev_status status; if (usvdev_getstatus(&status) == 0) usvstate_update(-1, &status); int len = snprintf(buf, sizeof(buf), "%s:%d:%d:%d", state2str(status.state), (short)status.ibat, status.ubat, status.uin); write(fd, buf, len); } close(fd); return -1; } static int status_interval(void *privdata) { struct usvdev_status status; if (usvdev_getstatus(&status) < 0) return 0; usvstate_update(-1, &status); return 0; } static int unix_accept_cb(int fd, void *privdata) { int con = accept(fd, NULL, NULL); if (con < 0) { log_print(LOG_ERROR, "unix_accept_cb: accept()"); return 0; } event_add_readfd(NULL, con, unix_read_cb, NULL); return 0; } int usvstate_init(void) { const char *socket_path = config_get_string("global", "socket", DEFAULT_SOCKET); int sockfd = unix_listen(socket_path); if (sockfd < 0) return -1; listen_event = event_add_readfd(NULL, sockfd, unix_accept_cb, NULL); if (listen_event == NULL) { close(sockfd); return -1; } int interval = config_get_int("global", "check-interval", 60); struct timeval tv = { .tv_sec = interval, .tv_usec = 0 }; timeout_event = event_add_timeout(&tv, status_interval, NULL); mail_from = config_get_string("alerts", "mail-from", NULL); mail_to = config_get_string("alerts", "mail-to", NULL); usvstate_update(-1, NULL); return 0; } int usvstate_close(void) { event_remove_timeout(timeout_event); event_remove_fd(listen_event); close(event_get_fd(listen_event)); return 0; }