[Nut-upsdev] Proposal for technique to stop a timer at any moment
Roger Price
roger at rogerprice.org
Mon Jul 11 09:02:39 UTC 2016
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? */
More information about the Nut-upsdev
mailing list