Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
72241ad
INSTCMD and SET VAR status tracking implementation
aquette Feb 1, 2019
b7c0a9a
Missing Revision history
aquette Feb 1, 2019
97c51c9
Fix nut-names.txt modification that should not be here
aquette Feb 1, 2019
bf46107
Augeas support: add CMDSETSTATUSDELAY for upsd.conf
aquette Feb 1, 2019
a348995
INSTCMD and SET VAR status tracking completion
aquette Feb 4, 2019
2a171dd
INSTCMD and SET VAR status tracking completion
aquette Feb 4, 2019
f802054
upscmd/upsrw: delay retries for status tracking
aquette Feb 4, 2019
0f3a01b
Remove comment
aquette Feb 4, 2019
f67ab8d
Complete comment
aquette Feb 4, 2019
3104343
UUID v4 implementation
aquette Feb 4, 2019
f3ac852
status_info should be static
aquette Feb 6, 2019
fe6c478
No need for else, since fatalx is called before
aquette Feb 6, 2019
d30e0cb
Suppress \n from debug output
aquette Feb 6, 2019
6cdbe93
Group sanity checks
aquette Feb 6, 2019
823e968
Get rid of dynamic memory allocation
aquette Feb 6, 2019
4d36b83
Improve and enforce the use of UUID4_LEN
aquette Feb 6, 2019
aef9ea7
Comment on the size of dest for nut_uuid_v4()
aquette Feb 6, 2019
25eca74
Move structures and defines to more appropriate places
aquette Feb 6, 2019
2e9c27c
Add functions with timeout
aquette Feb 6, 2019
f91255d
upscmd/upsrw: add a timeout option
aquette Feb 6, 2019
1473496
Basic homebrew UUID v4 implementation
aquette Feb 6, 2019
f91c893
Prefer to use static buffer for UUID
aquette Feb 6, 2019
b7d278d
log actual result of instcmd / setvar
aquette Feb 6, 2019
9989123
Fix tracking ID reporting due to static memory changes
aquette Feb 7, 2019
7fda5a7
upsclient: use unsigned int for timeouts
zykh Feb 9, 2019
deb2279
upscmd/upsrw: use unsigned int for timeout + our str_to_uint() for it
zykh Feb 9, 2019
f688d2c
upscmd/upsrw: don't sleep after receiving a non-PENDING CMDSET_STATUS
zykh Feb 9, 2019
5da7391
net-protocol: clarify the format of GET CMDSET_STATUS + <status_id>
zykh Feb 9, 2019
8d5a035
sock-protocol: align case and markup of command parameters
zykh Feb 10, 2019
87f59e7
dstate: fix handling of INSTCMD's optional parameters
zykh Feb 10, 2019
a619455
common: document the recently added things
zykh Feb 10, 2019
69b66e6
upsd: in INSTCMD/SET handlers, also accept NULL for status_id
zykh Feb 10, 2019
57de34f
upsd: drop unnecessary/unused global
zykh Feb 10, 2019
e14c739
upsd: move sanity checks of cmdset_status_get() after declaration of …
zykh Feb 10, 2019
5a5c8c8
upsd: refine the tracking API
zykh Feb 10, 2019
7c7bc13
net-protocol: also return TRACKING between OK and <id>, for INSTCMD/S…
zykh Feb 10, 2019
0fdc984
dstate: *really* fix handling of INSTCMD's optional parameters
zykh Feb 11, 2019
496d2c6
Move from CMDSET_STATUS / STATUS_ID to TRACKING
zykh Feb 10, 2019
de0deb3
common: massage default timeouts
zykh Feb 11, 2019
787d584
upsd: ignore case of UUID4 in tracking API
zykh Feb 11, 2019
a31e5e4
libupsclient: generate manpages for upscli_{read,send}line_timeout()
zykh Feb 11, 2019
663dd9f
libupsclient: bump version as per recent changes
zykh Feb 11, 2019
c0c478b
upscmd/upsrw: warn that also the drivers need to support TRACKING, fo…
zykh Feb 13, 2019
3948f09
Merge branch 'master' into cmdset_status
jimklimov Feb 23, 2019
155e795
Fix typo and spelling
aquette Feb 26, 2019
9a40084
Add check around atoi() conversion
aquette Feb 26, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clients/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ endif
# object .so names would differ)

# libupsclient version information
libupsclient_la_LDFLAGS = -version-info 4:0:0
libupsclient_la_LDFLAGS = -version-info 5:0:0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self (and others): this impacts library filename and packaging/dependencies.


# libnutclient version information
libnutclient_la_SOURCES = nutclient.h nutclient.cpp
Expand Down
30 changes: 20 additions & 10 deletions clients/upsclient.c
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ static HOST_CERT_t* upscli_find_host_cert(const char* hostname)
return NULL;
}

int upscli_cleanup()
int upscli_cleanup(void)
{
#ifdef WITH_OPENSSL
if (ssl_ctx) {
Expand Down Expand Up @@ -567,7 +567,7 @@ static int upscli_select_read(const int fd, void *buf, const size_t buflen, cons
}

/* internal: abstract the SSL calls for the other functions */
static int net_read(UPSCONN_t *ups, char *buf, size_t buflen)
static int net_read(UPSCONN_t *ups, char *buf, size_t buflen, unsigned int timeout)
{
int ret = -1;

Expand All @@ -587,7 +587,7 @@ static int net_read(UPSCONN_t *ups, char *buf, size_t buflen)
}
#endif

ret = upscli_select_read(ups->fd, buf, buflen, 5, 0);
ret = upscli_select_read(ups->fd, buf, buflen, timeout, 0);

/* error reading data, server disconnected? */
if (ret < 0) {
Expand Down Expand Up @@ -628,7 +628,7 @@ static int upscli_select_write(const int fd, const void *buf, const size_t bufle
}

/* internal: abstract the SSL calls for the other functions */
static int net_write(UPSCONN_t *ups, const char *buf, size_t buflen)
static int net_write(UPSCONN_t *ups, const char *buf, size_t buflen, unsigned int timeout)
{
int ret = -1;

Expand All @@ -648,7 +648,7 @@ static int net_write(UPSCONN_t *ups, const char *buf, size_t buflen)
}
#endif

ret = upscli_select_write(ups->fd, buf, buflen, 0, 0);
ret = upscli_select_write(ups->fd, buf, buflen, timeout, 0);

/* error writing data, server disconnected? */
if (ret < 0) {
Expand Down Expand Up @@ -1326,7 +1326,7 @@ int upscli_list_next(UPSCONN_t *ups, unsigned int numq, const char **query,
return 1;
}

int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen)
int upscli_sendline_timeout(UPSCONN_t *ups, const char *buf, size_t buflen, unsigned int timeout)
{
int ret;

Expand All @@ -1349,7 +1349,7 @@ int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen)
return -1;
}

ret = net_write(ups, buf, buflen);
ret = net_write(ups, buf, buflen, timeout);

if (ret < 1) {
upscli_disconnect(ups);
Expand All @@ -1359,7 +1359,12 @@ int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen)
return 0;
}

int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen)
int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen)
{
return upscli_sendline_timeout(ups, buf, buflen, 0);
}

int upscli_readline_timeout(UPSCONN_t *ups, char *buf, size_t buflen, unsigned int timeout)
{
int ret;
size_t recv;
Expand Down Expand Up @@ -1387,7 +1392,7 @@ int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen)

if (ups->readidx == ups->readlen) {

ret = net_read(ups, ups->readbuf, sizeof(ups->readbuf));
ret = net_read(ups, ups->readbuf, sizeof(ups->readbuf), timeout);

if (ret < 1) {
upscli_disconnect(ups);
Expand All @@ -1409,6 +1414,11 @@ int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen)
return 0;
}

int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen)
{
return upscli_readline_timeout(ups, buf, buflen, DEFAULT_NETWORK_TIMEOUT);
}

/* split upsname[@hostname[:port]] into separate components */
int upscli_splitname(const char *buf, char **upsname, char **hostname, int *port)
{
Expand Down Expand Up @@ -1518,7 +1528,7 @@ int upscli_disconnect(UPSCONN_t *ups)
return 0;
}

net_write(ups, "LOGOUT\n", 7);
net_write(ups, "LOGOUT\n", 7, 0);

#ifdef WITH_OPENSSL
if (ups->ssl) {
Expand Down
4 changes: 3 additions & 1 deletion clients/upsclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ typedef struct {
const char *upscli_strerror(UPSCONN_t *ups);

int upscli_init(int certverify, const char *certpath, const char *certname, const char *certpasswd);
int upscli_cleanup();
int upscli_cleanup(void);

int upscli_tryconnect(UPSCONN_t *ups, const char *host, int port, int flags, struct timeval *tv);
int upscli_connect(UPSCONN_t *ups, const char *host, int port, int flags);
Expand All @@ -86,8 +86,10 @@ int upscli_list_start(UPSCONN_t *ups, unsigned int numq, const char **query);
int upscli_list_next(UPSCONN_t *ups, unsigned int numq, const char **query,
unsigned int *numa, char ***answer);

int upscli_sendline_timeout(UPSCONN_t *ups, const char *buf, size_t buflen, unsigned int timeout);
int upscli_sendline(UPSCONN_t *ups, const char *buf, size_t buflen);

int upscli_readline_timeout(UPSCONN_t *ups, char *buf, size_t buflen, unsigned int timeout);
int upscli_readline(UPSCONN_t *ups, char *buf, size_t buflen);

int upscli_splitname(const char *buf, char **upsname, char **hostname,
Expand Down
86 changes: 81 additions & 5 deletions clients/upscmd.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
/* upscmd - simple "client" to test instant commands via upsd

Copyright (C) 2000 Russell Kroll <[email protected]>
Copyright (C)
2000 Russell Kroll <[email protected]>
2019 EATON (author: Arnaud Quette <[email protected]>)

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
Expand Down Expand Up @@ -28,8 +30,10 @@

#include "upsclient.h"

static char *upsname = NULL, *hostname = NULL;
static char *upsname = NULL, *hostname = NULL;
static UPSCONN_t *ups = NULL;
static int tracking_enabled = 0;
static unsigned int timeout = DEFAULT_TRACKING_TIMEOUT;

struct list_t {
char *name;
Expand All @@ -41,13 +45,16 @@ static void usage(const char *prog)
printf("Network UPS Tools upscmd %s\n\n", UPS_VERSION);
printf("usage: %s [-h]\n", prog);
printf(" %s [-l <ups>]\n", prog);
printf(" %s [-u <username>] [-p <password>] <ups> <command> [<value>]\n\n", prog);
printf(" %s [-u <username>] [-p <password>] [-w] [-t <timeout>] <ups> <command> [<value>]\n\n", prog);
printf("Administration program to initiate instant commands on UPS hardware.\n");
printf("\n");
printf(" -h display this help text\n");
printf(" -l <ups> show available commands on UPS <ups>\n");
printf(" -u <username> set username for command authentication\n");
printf(" -p <password> set password for command authentication\n");
printf(" -w wait for the completion of command by the driver\n");
printf(" and return its actual result from the device\n");
printf(" -t <timeout> set a timeout when using -w (in seconds, default: %u)\n", DEFAULT_TRACKING_TIMEOUT);
printf("\n");
printf(" <ups> UPS identifier - <upsname>[@<hostname>[:<port>]]\n");
printf(" <command> Valid instant command - test.panel.start, etc.\n");
Expand Down Expand Up @@ -138,7 +145,10 @@ static void listcmds(void)

static void do_cmd(char **argv, const int argc)
{
int cmd_complete = 0;
char buf[SMALLBUF];
char tracking_id[UUID4_LEN];
time_t start, now;

if (argc > 1) {
snprintf(buf, sizeof(buf), "INSTCMD %s %s %s\n", upsname, argv[0], argv[1]);
Expand All @@ -154,11 +164,49 @@ static void do_cmd(char **argv, const int argc)
fatalx(EXIT_FAILURE, "Instant command failed: %s", upscli_strerror(ups));
}

/* FUTURE: status cookies will tie in here */
/* verify answer */
if (strncmp(buf, "OK", 2) != 0) {
fatalx(EXIT_FAILURE, "Unexpected response from upsd: %s", buf);
}

/* check for status tracking id */
if (
!tracking_enabled ||
/* sanity check on the size: "OK TRACKING " + UUID4_LEN */
strlen(buf) != (UUID4_LEN - 1 + strlen("OK TRACKING "))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From my reading of standards and docs in UUID-related codebases, at least two correct spellings of an UUID value are possible: the hexadecimal string broken by dashes in correct positions, or just the all-hex string (shorter).

Our updated header defines UUID4_LEN as "(Minimum) Size that a string must have to hold a UUID4", catering for the dashed spelling.

What if the user passes a valid non-dashed version (so strlen(buf) would be shorter than expected here)?
Should we convert one to another (if all hexes and length==X, then add dashes)?

At the very least, I think we should avoid surprises by documenting that the current code requires the particular spelling of UUID string.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure it's worth: the intent is not to have real UUID v4, but more something (a key) unique enough to avoid collisions. Whatever the user passes has to be valid, and was supposed to have been provided before. If he passes random string, or non dashed ID or whatever, this will be truncated and discarded.

) {
/* reply as usual */
fprintf(stderr, "%s\n", buf);
return;
}

snprintf(tracking_id, sizeof(tracking_id), "%s", buf + strlen("OK TRACKING "));
time(&start);

/* send status tracking request, looping if status is PENDING */
while (!cmd_complete) {

/* check for timeout */
time(&now);
if (difftime(now, start) >= timeout)
fatalx(EXIT_FAILURE, "Can't receive status tracking information: timeout");

snprintf(buf, sizeof(buf), "GET TRACKING %s\n", tracking_id);

if (upscli_sendline(ups, buf, strlen(buf)) < 0)
fatalx(EXIT_FAILURE, "Can't send status tracking request: %s", upscli_strerror(ups));

/* and get status tracking reply */
if (upscli_readline_timeout(ups, buf, sizeof(buf), timeout) < 0)
fatalx(EXIT_FAILURE, "Can't receive status tracking information: %s", upscli_strerror(ups));

if (strncmp(buf, "PENDING", 7))
cmd_complete = 1;
else
/* wait a second before retrying */
sleep(1);
}

fprintf(stderr, "%s\n", buf);
}

Expand All @@ -180,7 +228,7 @@ int main(int argc, char **argv)
char buf[SMALLBUF], username[SMALLBUF], password[SMALLBUF];
const char *prog = xbasename(argv[0]);

while ((i = getopt(argc, argv, "+lhu:p:V")) != -1) {
while ((i = getopt(argc, argv, "+lhu:p:t:wV")) != -1) {

switch (i)
{
Expand All @@ -198,6 +246,15 @@ int main(int argc, char **argv)
have_pw = 1;
break;

case 't':
if (!str_to_uint(optarg, &timeout, 10))
fatal_with_errno(EXIT_FAILURE, "Could not convert the provided value for timeout ('-t' option) to unsigned int");
break;

case 'w':
tracking_enabled = 1;
break;

case 'V':
fatalx(EXIT_SUCCESS, "Network UPS Tools upscmd %s", UPS_VERSION);

Expand Down Expand Up @@ -313,6 +370,25 @@ int main(int argc, char **argv)
fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups));
}

/* enable status tracking ID */
if (tracking_enabled) {

snprintf(buf, sizeof(buf), "SET TRACKING ON\n");

if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
fatalx(EXIT_FAILURE, "Can't enable command status tracking: %s", upscli_strerror(ups));
}

if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
fatalx(EXIT_FAILURE, "Enabling command status tracking failed: %s", upscli_strerror(ups));
}

/* Verify the result */
if (strncmp(buf, "OK", 2) != 0) {
fatalx(EXIT_FAILURE, "Enabling command status tracking failed. upsd answered: %s", buf);
}
}

do_cmd(&argv[1], argc - 1);

exit(EXIT_SUCCESS);
Expand Down
Loading