1
/* upscmd - simple "client" to test instant commands via upsd
3
Copyright (C) 2000 Russell Kroll <rkroll@exploits.org>
5
This program is free software; you can redistribute it and/or modify
6
it under the terms of the GNU General Public License as published by
7
the Free Software Foundation; either version 2 of the License, or
8
(at your option) any later version.
10
This program is distributed in the hope that it will be useful,
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
GNU General Public License for more details.
15
You should have received a copy of the GNU General Public License
16
along with this program; if not, write to the Free Software
17
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "nut_platform.h"
25
#include <sys/types.h>
26
#include <netinet/in.h>
27
#include <sys/socket.h>
29
#include "upsclient.h"
31
static char *upsname = NULL, *hostname = NULL;
32
static UPSCONN_t *ups = NULL;
39
static void usage(const char *prog)
41
printf("Network UPS Tools upscmd %s\n\n", UPS_VERSION);
42
printf("usage: %s [-h]\n", prog);
43
printf(" %s [-l <ups>]\n", prog);
44
printf(" %s [-u <username>] [-p <password>] <ups> <command> [<value>]\n\n", prog);
45
printf("Administration program to initiate instant commands on UPS hardware.\n");
47
printf(" -h display this help text\n");
48
printf(" -l <ups> show available commands on UPS <ups>\n");
49
printf(" -u <username> set username for command authentication\n");
50
printf(" -p <password> set password for command authentication\n");
52
printf(" <ups> UPS identifier - <upsname>[@<hostname>[:<port>]]\n");
53
printf(" <command> Valid instant command - test.panel.start, etc.\n");
54
printf(" [<value>] Additional data for command - number of seconds, etc.\n");
57
static void print_cmd(char *cmdname)
60
unsigned int numq, numa;
69
ret = upscli_get(ups, numq, query, &numa, &answer);
71
if ((ret < 0) || (numa < numq)) {
72
printf("%s\n", cmdname);
76
/* CMDDESC <upsname> <cmdname> <desc> */
77
printf("%s - %s\n", cmdname, answer[3]);
80
static void listcmds(void)
83
unsigned int numq, numa;
86
struct list_t *lhead = NULL, *llast = NULL, *ltmp, *lnext;
92
ret = upscli_list_start(ups, numq, query);
96
/* old upsd = no way to continue */
97
if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) {
98
fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query");
101
fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
104
while (upscli_list_next(ups, numq, query, &numa, &answer) == 1) {
106
/* CMD <upsname> <cmdname> */
108
fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 3)", numa);
111
/* we must first read the entire list of commands,
112
before we can start reading the descriptions */
114
ltmp = xcalloc(1, sizeof(*ltmp));
115
ltmp->name = xstrdup(answer[2]);
126
/* walk the list and try to get descriptions, freeing as we go */
127
printf("Instant commands supported on UPS [%s]:\n\n", upsname);
129
for (ltmp = lhead; ltmp; ltmp = lnext) {
132
print_cmd(ltmp->name);
139
static void do_cmd(char **argv, const int argc)
144
snprintf(buf, sizeof(buf), "INSTCMD %s %s %s\n", upsname, argv[0], argv[1]);
146
snprintf(buf, sizeof(buf), "INSTCMD %s %s\n", upsname, argv[0]);
149
if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
150
fatalx(EXIT_FAILURE, "Can't send instant command: %s", upscli_strerror(ups));
153
if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
154
fatalx(EXIT_FAILURE, "Instant command failed: %s", upscli_strerror(ups));
157
/* FUTURE: status cookies will tie in here */
158
if (strncmp(buf, "OK", 2) != 0) {
159
fatalx(EXIT_FAILURE, "Unexpected response from upsd: %s", buf);
162
fprintf(stderr, "%s\n", buf);
165
static void clean_exit(void)
168
upscli_disconnect(ups);
176
int main(int argc, char **argv)
179
int have_un = 0, have_pw = 0, cmdlist = 0;
180
char buf[SMALLBUF], username[SMALLBUF], password[SMALLBUF];
181
const char *prog = xbasename(argv[0]);
183
while ((i = getopt(argc, argv, "+lhu:p:V")) != -1) {
192
snprintf(username, sizeof(username), "%s", optarg);
197
snprintf(password, sizeof(password), "%s", optarg);
202
fatalx(EXIT_SUCCESS, "Network UPS Tools upscmd %s", UPS_VERSION);
219
/* be a good little client that cleans up after itself */
222
if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) {
223
fatalx(EXIT_FAILURE, "Error: invalid UPS definition. Required format: upsname[@hostname[:port]]");
226
ups = xcalloc(1, sizeof(*ups));
228
if (upscli_connect(ups, hostname, port, 0) < 0) {
229
fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
242
/* also fallback for old command names */
243
if (!strchr(argv[1], '.')) {
244
fatalx(EXIT_FAILURE, "Error: old command names are not supported");
250
memset(username, '\0', sizeof(username));
251
pw = getpwuid(getuid());
254
printf("Username (%s): ", pw->pw_name);
256
printf("Username: ");
259
if (!fgets(username, sizeof(username), stdin)) {
260
fatalx(EXIT_FAILURE, "Error reading from stdin!");
263
/* deal with that pesky newline */
264
if (strlen(username) > 1) {
265
username[strlen(username) - 1] = '\0';
268
fatalx(EXIT_FAILURE, "No username available - even tried getpwuid");
271
snprintf(username, sizeof(username), "%s", pw->pw_name);
275
/* getpass leaks slightly - use -p when testing in valgrind */
277
/* using getpass or getpass_r might not be a
278
good idea here (marked obsolete in POSIX) */
279
char *pwtmp = GETPASS("Password: ");
282
fatalx(EXIT_FAILURE, "getpass failed: %s", strerror(errno));
285
snprintf(password, sizeof(password), "%s", pwtmp);
288
snprintf(buf, sizeof(buf), "USERNAME %s\n", username);
290
if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
291
fatalx(EXIT_FAILURE, "Can't set username: %s", upscli_strerror(ups));
294
ret = upscli_readline(ups, buf, sizeof(buf));
297
if (upscli_upserror(ups) != UPSCLI_ERR_UNKCOMMAND) {
298
fatalx(EXIT_FAILURE, "Set username failed: %s", upscli_strerror(ups));
302
"Set username failed due to an unknown command.\n"
303
"You probably need to upgrade upsd.");
306
snprintf(buf, sizeof(buf), "PASSWORD %s\n", password);
308
if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
309
fatalx(EXIT_FAILURE, "Can't set password: %s", upscli_strerror(ups));
312
if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
313
fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups));
316
do_cmd(&argv[1], argc - 1);
322
/* Formal do_upsconf_args implementation to satisfy linker on AIX */
323
#if (defined NUT_PLATFORM_AIX)
324
void do_upsconf_args(char *upsname, char *var, char *val) {
325
fatalx(EXIT_FAILURE, "INTERNAL ERROR: formal do_upsconf_args called");
327
#endif /* end of #if (defined NUT_PLATFORM_AIX) */