*/
- if (!strcmp(ctx.arglist[0], "MONITOR"))
+ if (handle_MONITOR && !strcmp(ctx.arglist[0], "MONITOR"))
add_ups(ctx.arglist[1], ctx.arglist[2]);
}
pconf_finish(&ctx);
- if (!ulhead) {
+ if (!ulhead && handle_MONITOR) {
/* Don't print HTML here if we are in JSON mode.
* The JSON function will handle the error.
*/
@@ -1326,7 +1503,7 @@ static void display_single(void)
if (treemode)
display_tree(1);
else
- display_template("upsstats-single.html");
+ display_template(template_single, 1);
upscli_disconnect(&ups);
upsdebug_call_finished0();
@@ -1368,7 +1545,7 @@ static void display_json(void)
add_ups(monhost, monhostdesc);
currups = ulhead;
} else {
- load_hosts_conf(); /* This populates ulhead */
+ load_hosts_conf(1); /* This populates ulhead */
currups = ulhead;
}
@@ -1489,14 +1666,14 @@ int main(int argc, char **argv)
int i;
#ifdef WIN32
- /* Required ritual before calling any socket functions */
- static WSADATA WSAdata;
- static int WSA_Started = 0;
- if (!WSA_Started) {
- WSAStartup(2, &WSAdata);
- atexit((void(*)(void))WSACleanup);
- WSA_Started = 1;
- }
+ /* Required ritual before calling any socket functions */
+ static WSADATA WSAdata;
+ static int WSA_Started = 0;
+ if (!WSA_Started) {
+ WSAStartup(2, &WSAdata);
+ atexit((void(*)(void))WSACleanup);
+ WSA_Started = 1;
+ }
/* Avoid binary output conversions, e.g.
* mangling what looks like CRLF on WIN32 */
@@ -1516,6 +1693,28 @@ int main(int argc, char **argv)
nut_debug_level = i;
}
+
+#ifdef NUT_CGI_DEBUG_UPSSTATS
+# if (NUT_CGI_DEBUG_UPSSTATS - 0 < 1)
+# undef NUT_CGI_DEBUG_UPSSTATS
+# define NUT_CGI_DEBUG_UPSSTATS 6
+# endif
+ /* Un-comment via make flags when developer-troubleshooting: */
+ nut_debug_level = NUT_CGI_DEBUG_UPSSTATS;
+#endif
+
+ if (nut_debug_level > 0) {
+ cgilogbit_set();
+ printf("Content-type: text/html\n");
+ printf("Pragma: no-cache\n");
+ printf("\n");
+ printf("NUT CGI Debugging enabled, level: %d
\n\n", nut_debug_level);
+ }
+
+ /* Built-in defaults */
+ template_single = xstrdup("upsstats-single.html");
+ template_list = xstrdup("upsstats.html");
+
extractcgiargs();
upscli_init_default_connect_timeout(NULL, NULL, UPSCLI_DEFAULT_CONNECT_TIMEOUT);
@@ -1541,6 +1740,8 @@ int main(int argc, char **argv)
}
free(upsname);
free(hostname);
+ free(template_single);
+ free(template_list);
exit(EXIT_SUCCESS);
}
@@ -1551,14 +1752,18 @@ int main(int argc, char **argv)
printf("Pragma: no-cache\n");
printf("\n");
- /* if a host is specified, use upsstats-single.html instead */
+ /* if a host is specified, use upsstats-single.html instead
+ * of listing whatever we know about with upsstats.html */
+ add_allowed_template_single("upsstats-single.html");
+ add_allowed_template_list("upsstats.html");
if (monhost) {
+ load_hosts_conf(0);
display_single();
} else {
/* default: multimon replacement mode */
- load_hosts_conf();
+ load_hosts_conf(1);
currups = ulhead;
- display_template("upsstats.html");
+ display_template(template_list, 2);
}
/* Clean up memory */
@@ -1573,6 +1778,25 @@ int main(int argc, char **argv)
free(ulhead);
ulhead = currups;
}
+ free(template_single);
+ free(template_list);
+
+ /* Free storage of allowed template names (reusing same kind of structure as UPSes) */
+ while (allowed_template_single_lhead) {
+ currups = (ulist_t *)allowed_template_single_lhead->next;
+ free(allowed_template_single_lhead->sys);
+ free(allowed_template_single_lhead->desc);
+ free(allowed_template_single_lhead);
+ allowed_template_single_lhead = currups;
+ }
+
+ while (allowed_template_list_lhead) {
+ currups = (ulist_t *)allowed_template_list_lhead->next;
+ free(allowed_template_list_lhead->sys);
+ free(allowed_template_list_lhead->desc);
+ free(allowed_template_list_lhead);
+ allowed_template_list_lhead = currups;
+ }
return 0;
}
diff --git a/common/common.c b/common/common.c
index 50803b25f4..832871ae77 100644
--- a/common/common.c
+++ b/common/common.c
@@ -588,6 +588,16 @@ int syslog_is_disabled(void)
return value;
}
+/* enable writing upslog_with_errno() and upslogx() type messages to
+ * the stdout instead of stderr, and end them with HTML
tag,
+ * to help troubleshoot NUT CGI programs specifically */
+void cgilogbit_set(void)
+{
+ xbit_set(&upslog_flags, UPSLOG_STDOUT);
+ xbit_set(&upslog_flags, UPSLOG_CGI_BR);
+ xbit_clear(&upslog_flags, UPSLOG_STDERR);
+}
+
/* enable writing upslog_with_errno() and upslogx() type messages to
the syslog */
void syslogbit_set(void)
@@ -3927,7 +3937,7 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror)
upslog_start = now;
}
- if (xbit_test(upslog_flags, UPSLOG_STDERR)) {
+ if (xbit_test(upslog_flags, UPSLOG_STDERR) || xbit_test(upslog_flags, UPSLOG_STDOUT)) {
if (nut_debug_level > 0) {
struct timeval now;
@@ -3940,15 +3950,42 @@ static void vupslog(int priority, const char *fmt, va_list va, int use_strerror)
/* Print all in one shot, to better avoid
* mixed lines in parallel threads */
- fprintf(stderr, "%4.0f.%06ld\t%s\n",
- difftime(now.tv_sec, upslog_start.tv_sec),
- (long)(now.tv_usec - upslog_start.tv_usec),
- buf);
+ if (xbit_test(upslog_flags, UPSLOG_STDERR)) {
+#ifdef WIN32
+ fflush(stderr);
+#endif /* WIN32 */
+ fprintf(stderr, "%s%4.0f.%06ld\t%s%s\n",
+ xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "" : "",
+ difftime(now.tv_sec, upslog_start.tv_sec),
+ (long)(now.tv_usec - upslog_start.tv_usec),
+ buf,
+ xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : ""
+ );
+ }
+
+ if (xbit_test(upslog_flags, UPSLOG_STDOUT)) {
+#ifdef WIN32
+ fflush(stdout);
+#endif /* WIN32 */
+ fprintf(stdout, "%s%4.0f.%06ld\t%s%s\n",
+ xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "" : "",
+ difftime(now.tv_sec, upslog_start.tv_sec),
+ (long)(now.tv_usec - upslog_start.tv_usec),
+ buf,
+ xbit_test(upslog_flags, UPSLOG_CGI_BR) ? "
" : ""
+ );
+ }
} else {
- fprintf(stderr, "%s\n", buf);
+ if (xbit_test(upslog_flags, UPSLOG_STDERR))
+ fprintf(stderr, "%s\n", buf);
+ if (xbit_test(upslog_flags, UPSLOG_STDOUT))
+ fprintf(stdout, "%s\n", buf);
}
#ifdef WIN32
- fflush(stderr);
+ if (xbit_test(upslog_flags, UPSLOG_STDERR))
+ fflush(stderr);
+ if (xbit_test(upslog_flags, UPSLOG_STDOUT))
+ fflush(stdout);
#endif /* WIN32 */
}
if (xbit_test(upslog_flags, UPSLOG_SYSLOG))
diff --git a/conf/hosts.conf.sample b/conf/hosts.conf.sample
index 37e561e78b..ef9fb8b525 100644
--- a/conf/hosts.conf.sample
+++ b/conf/hosts.conf.sample
@@ -9,8 +9,21 @@
# -----------------------------------------------------------------------
#
# upsstats will use the list of MONITOR entries when displaying the
-# default template (upsstats.html). The "FOREACHUPS" directive in the
-# template will use this file to find systems running upsd.
+# list template (default upsstats.html). The "FOREACHUPS" directive
+# in the template will use this file to find systems running upsd.
+#
+# upsstats allows to use custom HTML template files for some of its
+# outputs (JSON and "treemode" mark-ups are currently hard-coded in
+# the binary), which you can specify in the query string part of the
+# URI (in your `index.html` and/or added cells of `header.html`) as e.g.
+# .../cgi-bin/upsstats.cgi?template_single=upsstats-custom-single.html&template_list=upsstats-custom-list.html
+# Specific file names must be permitted below with `CUSTOM_TEMPLATE_LIST`
+# or `CUSTOM_TEMPLATE_SINGLE` directive, as applicable; they must contain
+# the `.htm` substring, and be located directly in the NUT configuration
+# directory (same as default templates). If custom templates are used
+# in the original request URI, they will be automatically suffixed to
+# generated links (primarily HOSTLINK, but also just in case added to
+# TREELINK and TREELINK_JSON).
#
# upsstats and upsimage also use this file to determine if a host may be
# monitored. This keeps evil people from using your system to annoy
@@ -30,3 +43,19 @@
# MONITOR myups@localhost "Local UPS"
# MONITOR su2200@10.64.1.1 "Finance department"
# MONITOR matrix@shs-server.example.edu "Sierra High School data room #1"
+
+# -----------------------------------------------------------------------
+#
+# Allowed custom template file (adapted copy of upsstats.html) for listing
+# your devices, which must be located in the same configuration directory
+# and contain `.htm` in the file name.
+#
+# CUSTOM_TEMPLATE_LIST
+
+# -----------------------------------------------------------------------
+#
+# Allowed custom template file (adapted copy of upsstats-single.html) for
+# listing details about a single device, which must be located in the same
+# configuration directory and contain `.htm` in the file name.
+#
+# CUSTOM_TEMPLATE_SINGLE
diff --git a/docs/man/hosts.conf.txt b/docs/man/hosts.conf.txt
index 940329b871..9f57e657d4 100644
--- a/docs/man/hosts.conf.txt
+++ b/docs/man/hosts.conf.txt
@@ -40,6 +40,26 @@ The description must be one element, so if it has spaces, then it must
be wrapped with quotes as shown above. The default hostname is
"localhost".
+*CUSTOM_TEMPLATE_LIST* 'filename'::
+*CUSTOM_TEMPLATE_SINGLE* 'filename'::
+
+linkman:upsstats[8] allows to use custom HTML template files for some of
+its outputs (JSON and "treemode" mark-ups are currently hard-coded in
+the binary), which you can specify in the query string part of the
+URI (in your `index.html` and/or added cells of `header.html`) as e.g.
+------
+.../cgi-bin/upsstats.cgi?template_single=custom-s.htm&template_list=custom-l.htm
+------
++
+Specific file names for a specific role must be permitted with these
+directives (can be repeated). File names must contain the `.htm` sub-string
+and must be located directly in the NUT configuration directory (same as
+default templates). If custom templates are used in the original request
+URI, they will be automatically suffixed to generated links (primarily
+`HOSTLINK`, but also just in case added to `TREELINK` and `TREELINK_JSON`,
+see linkman:upsstats.html[5] for more details).
+
+
SEE ALSO
--------
diff --git a/docs/man/upsstats.cgi.txt b/docs/man/upsstats.cgi.txt
index b83fca8c13..b30a37a03e 100644
--- a/docs/man/upsstats.cgi.txt
+++ b/docs/man/upsstats.cgi.txt
@@ -48,9 +48,24 @@ The web page that is displayed is actually a template containing
commands to `upsstats` which are replaced by status information.
The default file used for the overview of devices is `upsstats.html`.
+An alternate template may be provided by `&template_list=...` CGI
+query option; relevant file must be allowed via `CUSTOM_TEMPLATE_LIST`
+option in linkman:hosts.conf[5].
When monitoring a single UPS, the file displayed is
`upsstats-single.html`.
+An alternate template may be provided by `&template_single=...` CGI
+query option; relevant file must be allowed via `CUSTOM_TEMPLATE_SINGLE`
+option in linkman:hosts.conf[5].
+
+Alternate templates must be structured similarly to default ones,
+located in the same directory, and contain `.htm` in the file name.
+You can specify in the query string part of the URI (for example,
+in your local `index.html` and/or added cells of `header.html`) as e.g.
+
+------
+.../cgi-bin/upsstats.cgi?template_single=custom-s.html&template_list=custom-l.html
+------
The format of these files, including the possible commands, is
documented in linkman:upsstats.html[5].
@@ -83,7 +98,7 @@ parameter is also provided:
In both modes, each UPS object includes:
* *host*: The UPS identifier (e.g., "myups@localhost")
-* *desc*: The host description from ``hosts.conf``
+* *desc*: The host description from `hosts.conf`
* *status_raw*: The raw status string (e.g., "OL")
* *status_parsed*: An array of human-readable status strings
(e.g., ["Online"])
diff --git a/include/common.h b/include/common.h
index 39987916ca..85bb4e8291 100644
--- a/include/common.h
+++ b/include/common.h
@@ -446,6 +446,11 @@ int sendsignalfnaliases(const char *pidfn, const char * sig, const char **progna
* caller should strdup() a copy to retain beyond the lifetime of "file" */
const char *xbasename(const char *file);
+/* enable writing upslog_with_errno() and upslogx() type messages to
+ * the stdout instead of stderr, and end them with HTML
tag,
+ * to help troubleshoot NUT CGI programs specifically */
+void cgilogbit_set(void);
+
/* enable writing upslog_with_errno() and upslogx() type messages to
the syslog */
void syslogbit_set(void);
@@ -755,6 +760,12 @@ extern int optind;
#define UPSLOG_STDERR_ON_FATAL 0x0004
#define UPSLOG_SYSLOG_ON_FATAL 0x0008
+/* Special cases, primarily for NUT CGI programs to dump logs
+ * in a way better usable when troubleshooting with a browser:
+ */
+#define UPSLOG_STDOUT 0x0010
+#define UPSLOG_CGI_BR 0x0020
+
#ifndef HAVE_SETEUID
# define seteuid(x) setresuid(-1,x,-1) /* Works for HP-UX 10.20 */
# define setegid(x) setresgid(-1,x,-1) /* Works for HP-UX 10.20 */