/* upssched.c - upsmon's scheduling helper for offset timers Copyright (C) 2000 Russell Kroll 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; either version 2 of the License, or (at your option) any later version. 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 */ /* design notes for the curious: * * 1. we get called with a upsname and notifytype from upsmon * 2. the config file is searched for an AT condition that matches * 3. the conditions on any matching lines are parsed * * starting a timer: the timer is added to the daemon's timer queue * cancelling a timer: the timer is removed from that queue * execute a command: the command is passed straight to the cmdscript * * if the daemon is not already running and is required (to start a timer) * it will be started automatically * * when the time arrives, the command associated with a timer will be * executed by the daemon (via the cmdscript) * * timers can be cancelled at any time before they trigger * * the daemon will shut down automatically when no more timers are active * */ #include "common.h" #include #include #include #include #include #include "upssched.h" #include "timehead.h" typedef struct { char *name; time_t etime; void *next; } ttype_t; ttype_t *thead = NULL; static struct conn_t *connhead = NULL; char *cmdscript = NULL, *pipefn = NULL, *lockfn = NULL; int verbose = 0; /* use for debugging */ /* ups name and notify type (string) as received from upsmon */ const char *upsname, *notify_type; #define PARENT_STARTED -2 #define PARENT_UNNECESSARY -3 #define MAX_TRIES 30 #define EMPTY_WAIT 15 /* min passes with no timers to exit */ #define US_LISTEN_BACKLOG 16 #define US_SOCK_BUF_LEN 256 #define US_MAX_READ 128 /* --- server functions --- */ static void exec_cmd(const char *cmd) { int err; char buf[LARGEBUF]; snprintf(buf, sizeof(buf), "%s %s", cmdscript, cmd); err = system(buf); if (WIFEXITED(err)) { if (WEXITSTATUS(err)) { upslogx(LOG_INFO, "exec_cmd(%s) returned %d", buf, WEXITSTATUS(err)); } } else { if (WIFSIGNALED(err)) { upslogx(LOG_WARNING, "exec_cmd(%s) terminated with signal %d", buf, WTERMSIG(err)); } else { upslogx(LOG_ERR, "Execute command failure: %s", buf); } } return; } static void removetimer(ttype_t *tfind) { ttype_t *tmp, *last; last = NULL; tmp = thead; while (tmp) { if (tmp == tfind) { /* found it */ if (last == NULL) /* deleting first */ thead = tmp->next; else last->next = tmp->next; free(tmp->name); free(tmp); return; } last = tmp; tmp = tmp->next; } /* this one should never happen */ upslogx(LOG_ERR, "removetimer: failed to locate target at %p", (void *)tfind); } static void checktimers(void) { ttype_t *tmp, *tmpnext; time_t now; static int emptyctr = 0; /* if the queue is empty we might be ready to exit */ if (!thead) { emptyctr++; /* wait a little while in case someone wants us again */ if (emptyctr < EMPTY_WAIT) return; if (verbose) upslogx(LOG_INFO, "Timer queue empty, exiting"); #ifdef UPSSCHED_RACE_TEST upslogx(LOG_INFO, "triggering race: sleeping 15 sec before exit"); sleep(15); #endif unlink(pipefn); exit(EXIT_SUCCESS); } emptyctr = 0; /* flip through LL, look for activity */ tmp = thead; time(&now); while (tmp) { tmpnext = tmp->next; if (now >= tmp->etime) { if (verbose) upslogx(LOG_INFO, "Event: %s ", tmp->name); exec_cmd(tmp->name); /* delete from queue */ removetimer(tmp); } tmp = tmpnext; } } static void start_timer(const char *name, const char *ofsstr) { time_t now; int ofs; ttype_t *tmp, *last; /* get the time */ time(&now); /* add an event for +