2009-05-03 16:16:56 +02:00
|
|
|
/***************************************************************************
|
|
|
|
* 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 <stdio.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
|
|
|
#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)
|
|
|
|
{
|
2009-06-01 13:51:12 +02:00
|
|
|
static int old_state;
|
2009-05-03 16:16:56 +02:00
|
|
|
|
2009-06-01 13:51:12 +02:00
|
|
|
if (status != NULL)
|
|
|
|
state = status->state;
|
2009-05-03 16:16:56 +02:00
|
|
|
|
|
|
|
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");
|
2009-06-01 13:51:12 +02:00
|
|
|
if (mail != NULL) {
|
2009-05-03 16:16:56 +02:00
|
|
|
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));
|
|
|
|
|
2009-06-01 13:51:12 +02:00
|
|
|
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);
|
|
|
|
}
|
2009-05-03 16:16:56 +02:00
|
|
|
|
|
|
|
fprintf(mail, "Faithfully yours, etc.\n");
|
|
|
|
fclose(mail);
|
|
|
|
}
|
|
|
|
}
|
2009-06-01 13:51:12 +02:00
|
|
|
|
|
|
|
old_state = state;
|
2009-05-03 16:16:56 +02:00
|
|
|
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),
|
2009-06-01 13:51:12 +02:00
|
|
|
(short)status.ibat, status.ubat, status.uin);
|
2009-05-03 16:16:56 +02:00
|
|
|
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;
|
|
|
|
}
|