[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