Roger Price
2016-Jul-11 09:02 UTC
[Nut-upsdev] Proposal for technique to stop a timer at any moment
Here is patch 1 of 2. Roger diff -rup nut-2.7.4.orig/clients/upsmon.c nut-2.7.4.dev/clients/upsmon.c --- nut-2.7.4.orig/clients/upsmon.c 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/clients/upsmon.c 2016-07-01 09:46:21.567766415 +0200 @@ -525,6 +525,18 @@ static int get_var(utype_t *ups, const c numq = 2; } + /* Subcommands for polling SIGUSR1, SIGUSR2 RP */ + if (strcmp(var, "SIGUSR1") == 0) { + query[0] = "SIGUSR1"; + query[1] = ups->upsname; + numq = 2; + } + if (strcmp(var, "SIGUSR2") == 0) { + query[0] = "SIGUSR2"; + query[1] = ups->upsname; + numq = 2; + } + if (!strcmp(var, "status")) { query[0] = "VAR"; query[1] = ups->upsname; @@ -1518,7 +1530,25 @@ static void pollups(utype_t *ups) if (get_var(ups, "status", status, sizeof(status)) == 0) { clear_alarm(); parse_status(ups, status); - return; + /* All is well, continue to poll SIGUSR1 RP */ + set_alarm(); + if (get_var(ups, "SIGUSR1", status, sizeof(status)) == 0) { + clear_alarm(); + if ( ! (strcmp(status,"0") == 0)) { /* See K&R p.53 */ + /* We have a SIGUSR1 */ + do_notify(ups, NOTIFY_SIGUSR1); + } + /* All is well, continue to poll SIGUSR2 RP */ + set_alarm(); + if (get_var(ups, "SIGUSR2", status, sizeof(status)) == 0) { + clear_alarm(); + if ( ! (strcmp(status,"0") == 0)) { + /* We have a SIGUSR2 */ + do_notify(ups, NOTIFY_SIGUSR2); + } + } + return; + } } /* fallthrough: no communications */ diff -rup nut-2.7.4.orig/clients/upsmon.h nut-2.7.4.dev/clients/upsmon.h --- nut-2.7.4.orig/clients/upsmon.h 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/clients/upsmon.h 2016-06-20 11:24:20.494863128 +0200 @@ -68,13 +68,15 @@ typedef struct { #define NOTIFY_ONLINE 0 /* UPS went on-line */ #define NOTIFY_ONBATT 1 /* UPS went on battery */ #define NOTIFY_LOWBATT 2 /* UPS went to low battery */ -#define NOTIFY_FSD 3 /* Master upsmon set FSD flag */ +#define NOTIFY_FSD 3 /* Master upsmon set FSD flag */ #define NOTIFY_COMMOK 4 /* Communication established */ #define NOTIFY_COMMBAD 5 /* Communication lost */ #define NOTIFY_SHUTDOWN 6 /* System shutdown in progress */ #define NOTIFY_REPLBATT 7 /* UPS battery needs to be replaced */ #define NOTIFY_NOCOMM 8 /* UPS hasn't been contacted in awhile */ #define NOTIFY_NOPARENT 9 /* privileged parent process died */ +#define NOTIFY_SIGUSR1 10 /* Server received SIGUSR1 RP */ +#define NOTIFY_SIGUSR2 11 /* Server received SIGUSR2 RP */ /* notify flag values */ @@ -97,13 +99,15 @@ struct { { NOTIFY_ONLINE, "ONLINE", NULL, "UPS %s on line power", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_ONBATT, "ONBATT", NULL, "UPS %s on battery", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_LOWBATT, "LOWBATT", NULL, "UPS %s battery is low", NOTIFY_SYSLOG | NOTIFY_WALL }, - { NOTIFY_FSD, "FSD", NULL, "UPS %s: forced shutdown in progress", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_FSD, "FSD", NULL, "UPS %s: forced shutdown in progress", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_COMMOK, "COMMOK", NULL, "Communications with UPS %s established", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_COMMBAD, "COMMBAD", NULL, "Communications with UPS %s lost", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_SHUTDOWN, "SHUTDOWN", NULL, "Auto logout and shutdown proceeding", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_REPLBATT, "REPLBATT", NULL, "UPS %s battery needs to be replaced", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_NOCOMM, "NOCOMM", NULL, "UPS %s is unavailable", NOTIFY_SYSLOG | NOTIFY_WALL }, { NOTIFY_NOPARENT, "NOPARENT", NULL, "upsmon parent process died - shutdown impossible", NOTIFY_SYSLOG | NOTIFY_WALL }, + { NOTIFY_SIGUSR1, "SIGUSR1", NULL, "UPS % received SIGUSR1", NOTIFY_SYSLOG }, /* No default wall for SIGUSR1 RP */ + { NOTIFY_SIGUSR2, "SIGUSR2", NULL, "UPS % received SIGUSR2", NOTIFY_SYSLOG }, /* No default wall for SIGUSR2 RP */ { 0, NULL, NULL, NULL, 0 } }; diff -rup nut-2.7.4.orig/clients/upssched.c nut-2.7.4.dev/clients/upssched.c --- nut-2.7.4.orig/clients/upssched.c 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/clients/upssched.c 2016-06-30 16:56:32.911812443 +0200 @@ -686,6 +686,10 @@ static void sendcmd(const char *cmd, con if (!arg1) return; + if (verbose > 1) { /* Detailed trace of timer actions RP */ + upslogx(LOG_NOTICE, "%s: cmd=%s, arg1=%s, arg2=%s", __func__, cmd, arg1, arg2); + } + /* build the request */ snprintf(buf, sizeof(buf), "%s \"%s\"", cmd, pconf_encode(arg1, enc, sizeof(enc))); @@ -902,6 +906,8 @@ int main(int argc, char **argv) { const char *prog = xbasename(argv[0]); + /* Please keep this very useful trace of upssched activity. RP) + 0 = no trace, 1 = trace, 2 = detailed trace. */ verbose = 1; /* TODO: remove when done testing */ /* normally we don't have stderr, so get this going to syslog early */ diff -rup nut-2.7.4.orig/common/common.c nut-2.7.4.dev/common/common.c --- nut-2.7.4.orig/common/common.c 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/common/common.c 2016-07-01 09:51:14.779883781 +0200 @@ -407,10 +407,25 @@ void upslogx(int priority, const char *f void upsdebug_with_errno(int level, const char *fmt, ...) { va_list va; - - if (nut_debug_level < level) - return; + /* Sysadmin may use "echo n > /etc/ups/NUT_DEBUG_LEVEL" to set debug level n. RP */ + char fn[SMALLBUF]; + FILE *fp; + int ndl; /* 0 through 4 */ + + snprintf(fn, sizeof(fn), "%s/NUT_DEBUG_LEVEL", confpath()); /* E.g. /etc/ups/NUT_DEBUG_LEVEL RP */ + fp = fopen(fn, "r"); + if (!fp) { + ndl = 0; /* Ignore errors */ + } else { + if (fscanf(fp, "%d", &ndl) != 1) { + ndl = 0; /* Ignore errors */ + } + fclose(fp); + } + if (nut_debug_level < level && ndl < level) { + return; + } va_start(va, fmt); vupslog(LOG_DEBUG, fmt, va, 1); va_end(va); @@ -419,10 +434,25 @@ void upsdebug_with_errno(int level, cons void upsdebugx(int level, const char *fmt, ...) { va_list va; - - if (nut_debug_level < level) - return; + /* Sysadmin may use "echo n > /etc/ups/NUT_DEBUG_LEVEL" to set debug level n. RP */ + char fn[SMALLBUF]; + FILE *fp; + int ndl; /* 0 through 4 */ + + snprintf(fn, sizeof(fn), "%s/NUT_DEBUG_LEVEL", confpath()); /* E.g. /etc/ups/NUT_DEBUG_LEVEL RP */ + fp = fopen(fn, "r"); + if (!fp) { + ndl = 0; /* Ignore errors */ + } else { + if (fscanf(fp, "%d", &ndl) != 1) { + ndl = 0; /* Ignore errors */ + } + fclose(fp); + } + if (nut_debug_level < level && ndl < level) { + return; + } va_start(va, fmt); vupslog(LOG_DEBUG, fmt, va, 0); va_end(va); diff -rup nut-2.7.4.orig/server/netget.c nut-2.7.4.dev/server/netget.c --- nut-2.7.4.orig/server/netget.c 2016-03-08 13:01:11.000000000 +0100 +++ nut-2.7.4.dev/server/netget.c 2016-06-29 15:36:45.829340912 +0200 @@ -44,6 +44,51 @@ static void get_numlogins(nut_ctype_t *c sendback(client, "NUMLOGINS %s %d\n", upsname, ups->numlogins); } +/* The SIGUSR1 and SIGUSR2 signals to the UPS's are received and remembered + by the server on behalf of the UPS's. RP */ +static void get_sigusr1(nut_ctype_t *client, const char *upsname) +{ + upstype_t *ups; + + ups = get_ups_ptr(upsname); + + if (!ups) { + send_err(client, NUT_ERR_UNKNOWN_UPS); + return; + } + + if (!ups_available(ups, client)) + return; + + sendback(client, "SIGUSR1 %s %d\n", upsname, ups->sigusr1); + if (ups->sigusr1 > 0) { + --(ups->sigusr1); /* If still >0 further user signals await a GET */ + upsdebugx(1, "%s: UPS %s, sigusr1 down to %d", __func__, ups->name, ups->sigusr1); + } +} + +static void get_sigusr2(nut_ctype_t *client, const char *upsname) +{ + upstype_t *ups; + + ups = get_ups_ptr(upsname); + + if (!ups) { + send_err(client, NUT_ERR_UNKNOWN_UPS); + return; + } + + if (!ups_available(ups, client)) + return; + + sendback(client, "SIGUSR2 %s %d\n", upsname, ups->sigusr2); + + if (ups->sigusr2 > 0) { + --(ups->sigusr2); /* If still >0 further user signals await a GET */ + upsdebugx(1, "%s: UPS %s, sigusr2 down to %d", __func__, ups->name, ups->sigusr2); + } +} + static void get_upsdesc(nut_ctype_t *client, const char *upsname) { const upstype_t *ups; @@ -229,6 +274,18 @@ void net_get(nut_ctype_t *client, int nu return; } + /* GET SIGUSR1 UPS RP */ + if (!strcasecmp(arg[0], "SIGUSR1")) { + get_sigusr1(client, arg[1]); + return; + } + + /* GET SIGUSR2 UPS RP */ + if (!strcasecmp(arg[0], "SIGUSR2")) { + get_sigusr2(client, arg[1]); + return; + } + /* GET UPSDESC UPS */ if (!strcasecmp(arg[0], "UPSDESC")) { get_upsdesc(client, arg[1]); diff -rup nut-2.7.4.orig/server/upsd.c nut-2.7.4.dev/server/upsd.c --- nut-2.7.4.orig/server/upsd.c 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/server/upsd.c 2016-07-01 09:56:59.589903339 +0200 @@ -848,6 +848,32 @@ static void set_exit_flag(int sig) exit_flag = sig; } +static void sigusr1_handler(int sig) +{ + /* SIGUSR1 signals are passed on to every known UPS RP */ + upstype_t *u; + + for (u = firstups; u; u = u->next) { + if ( u->sigusr1 < MAX_SIGUSR1 ) { + (u->sigusr1)++; + upsdebugx(1, "%s: UPS %s, sigusr1 up to %d", __func__, u->name, u->sigusr1); + } + } +} + +static void sigusr2_handler(int sig) +{ + /* SIGUSR2 signals are passed on to every known UPS RP */ + upstype_t *u; + + for (u = firstups; u; u = u->next) { + if ( u->sigusr2 < MAX_SIGUSR2 ) { + (u->sigusr2)++; + upsdebugx(1, "%s: UPS %s, sigusr2 up to %d", __func__, u->name, u->sigusr2); + } + } +} + static void setup_signals(void) { struct sigaction sa; @@ -869,6 +895,12 @@ static void setup_signals(void) /* handle reloading */ sa.sa_handler = set_reload_flag; sigaction(SIGHUP, &sa, NULL); + + /* Handle user signals. RP */ + sa.sa_handler = sigusr1_handler; + sigaction(SIGUSR1, &sa, NULL); + sa.sa_handler = sigusr2_handler; + sigaction(SIGUSR2, &sa, NULL); } void check_perms(const char *fn) diff -rup nut-2.7.4.orig/server/upsd.h nut-2.7.4.dev/server/upsd.h --- nut-2.7.4.orig/server/upsd.h 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/server/upsd.h 2016-06-16 12:28:07.066830712 +0200 @@ -80,6 +80,11 @@ extern nut_ctype_t *firstclient; #define SIGCMD_STOP SIGTERM #define SIGCMD_RELOAD SIGHUP +/* How many user signals may be sent in a burst? RP */ + +#define MAX_SIGUSR1 1 /* Safe */ +#define MAX_SIGUSR2 8 /* Experimental */ + /* awkward way to make a string out of a numeric constant */ #define string_const_aux(x) #x diff -rup nut-2.7.4.orig/server/upstype.h nut-2.7.4.dev/server/upstype.h --- nut-2.7.4.orig/server/upstype.h 2015-12-29 13:08:34.000000000 +0100 +++ nut-2.7.4.dev/server/upstype.h 2016-06-23 16:35:18.940499226 +0200 @@ -46,6 +46,9 @@ typedef struct upstype_s { PCONF_CTX_t sock_ctx; struct st_tree_s *inforoot; struct cmdlist_s *cmdlist; + + int sigusr1; /* Each UPS receives the SIGUSR1 sent to server. RP */ + int sigusr2; /* Each UPS receives the SIGUSR2 sent to server. RP */ int numlogins; int fsd; /* forced shutdown in effect? */