1
/* upsfetch - library for UPS communications from client programs
3
Copyright (C) 1999 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
22
#include <netinet/in.h>
23
#include <sys/socket.h>
27
int upserror, syserrno;
29
const char *upsstrerror (int errnum)
31
static char buf[SMALLBUF];
37
return "Unknown error";
40
return "Variable not supported by UPS";
43
return "No such host";
45
case UPSF_SENDFAILURE:
46
snprintf (buf, sizeof(buf), "Send failure: %s",
49
case UPSF_RECVFAILURE:
50
snprintf (buf, sizeof(buf), "Receive failure: %s",
53
case UPSF_SOCKFAILURE:
54
snprintf (buf, sizeof(buf), "Socket failure: %s",
57
case UPSF_BINDFAILURE:
58
snprintf (buf, sizeof(buf), "bind failure: %s",
61
case UPSF_RECVTIMEOUT:
62
return "Receive timeout";
65
return "Data source is stale";
68
return "Unknown ups name";
70
case UPSF_ACCESSDENIED:
71
return "Access denied";
73
case UPSF_CONNFAILURE:
74
snprintf (buf, sizeof(buf), "Connection failure: %s",
78
snprintf (buf, sizeof(buf), "Read error: %s",
82
snprintf (buf, sizeof(buf), "Write error: %s",
86
return "Invalid password";
89
return "Password incorrect";
92
return "Received wrong variable";
95
return "Unknown level";
98
return "Unknown command";
103
case UPSF_VARUNKNOWN:
104
return "Variable not recognized by server";
107
snprintf(buf, sizeof(buf), "Unknown error 0x%04x", errnum);
114
/* common error condition handler */
115
int errcheck (const char *buf)
117
if (!strncmp(buf, "ERR", 3)) {
118
upserror = UPSF_UNKNOWN; /* default error */
120
if (!strncmp(buf, "ERR ACCESS-DENIED", 17))
121
upserror = UPSF_ACCESSDENIED;
123
if (!strncmp(buf, "ERR UNKNOWN-UPS", 15))
124
upserror = UPSF_UNKNOWNUPS;
126
if (!strncmp(buf, "ERR INVALID-PASSWORD", 20))
127
upserror = UPSF_INVALIDPW;
129
if (!strncmp(buf, "ERR PASSWORD-INCORRECT", 22))
130
upserror = UPSF_INVALIDPW;
132
if (!strncmp(buf, "ERR UNKNOWN-COMMAND", 19))
133
upserror = UPSF_UNKNOWNCMD;
135
if (!strncmp(buf, "ERR DATA-STALE", 14))
136
upserror = UPSF_DATASTALE;
138
if (!strncmp(buf, "ERR VAR-NOT-SUPPORTED", 21))
139
upserror = UPSF_VARNOTSUPP;
141
if (!strncmp(buf, "ERR VAR-UNKNOWN", 15))
142
upserror = UPSF_VARUNKNOWN;
144
if (!strncmp(buf, "ERR CMD-NOT-SUPPORTED", 21))
145
upserror = UPSF_CMDNOTSUPP;
150
/* legacy failure msg - deprecated */
151
if (!strncmp(buf, "Unknown command", 15)) {
152
upserror = UPSF_UNKNOWNCMD;
159
/* send <req> to <host> and put the answer in <buf> */
161
int fetch (const char *hostin, const char *req, char *buf, int buflen)
163
int res, port = PORT, fd, fromlen, err;
164
struct sockaddr_in xmit, dest, from;
165
struct hostent *serv;
166
char sbuf[LARGEBUF], host[LARGEBUF], *cpos;
170
upserror = UPSF_UNKNOWN;
172
snprintf (host, sizeof(host), "%s", hostin);
173
cpos = strstr (host, ":");
180
if ((serv = gethostbyname(host)) == (struct hostent *) NULL) {
181
upserror = UPSF_NOSUCHHOST;
185
fd = socket (AF_INET, SOCK_DGRAM, 0);
187
upserror = UPSF_SOCKFAILURE;
192
memset (&xmit, '\0', sizeof(xmit));
193
xmit.sin_family = AF_INET;
195
res = bind (fd, (struct sockaddr *) &xmit, sizeof(xmit));
197
upserror = UPSF_BINDFAILURE;
203
memset (&dest, '\0', sizeof(dest));
204
memcpy (&dest.sin_addr, serv->h_addr, serv->h_length);
205
dest.sin_family = AF_INET;
206
dest.sin_port = htons(port);
208
snprintf (sbuf, sizeof(sbuf), "%s", req);
209
res = sendto (fd, sbuf, strlen(sbuf), 0,
210
(struct sockaddr *) &dest, sizeof(dest));
214
upserror = UPSF_SENDFAILURE;
216
return (-1); /* failure */
221
tv.tv_sec = 2; /* 2.0 seconds allowed for reply */
224
res = select (fd + 1, &rfd, NULL, NULL, &tv);
227
memset (buf, '\0', buflen);
228
fromlen = sizeof(from);
229
res = recvfrom (fd, buf, buflen, 0, (struct sockaddr *) &from,
234
upserror = UPSF_RECVTIMEOUT;
236
return (-1); /* failure */
241
upserror = UPSF_RECVFAILURE;
243
return (-1); /* failure */
248
if ((err = errcheck(buf)) != 0)
252
return 1; /* success */
255
/* warn about old upsd quirks, but still handle them for now */
256
static void warn_oldupsd(char *tag)
258
fprintf(stderr, "upsfetch: old upsd detected (ANS %s)\n", tag);
261
int getupsvar(const char *hostin, const char *varname, char *buf, int buflen)
263
char cmd[SMALLBUF], tmp[LARGEBUF], *ptr, *host, *upsname, hosttmp[LARGEBUF],
267
/* host = ups-1@localhost */
269
snprintf(hosttmp, sizeof(hosttmp), "%s", hostin);
270
ptr = strstr(hosttmp, "@");
276
snprintf(cmd, sizeof(cmd), "REQ %s@%s", varname, upsname);
281
snprintf(cmd, sizeof(cmd), "REQ %s", varname);
284
ret = fetch(host, cmd, tmp, sizeof(tmp));
289
tmp[strlen(tmp) - 1] = 0;
291
/* ANS <varname> <answer> */
293
/* check variable name for sanity */
294
snprintf(vartmp, sizeof(vartmp), "%s", &tmp[4]);
295
vartmp [strlen(varname)] = 0;
297
if (strcasecmp(vartmp, varname) != 0) {
298
upserror = UPSF_WRONGVAR;
299
return -1; /* failure */
302
if (upsname == NULL) /* skip "ANS <varname> " */
303
ptr = tmp + strlen(varname) + 5;
304
else /* skip "ANS <varname>@<upsname> " */
305
ptr = tmp + strlen(varname) + 5 + strlen(upsname) + 1;
307
/* --- legacy stuff for older upsd versions --- */
309
/* old upsd versions returned some errors as ANS <var> <error> */
311
if (!strcmp(ptr, "DATA-STALE")) {
312
warn_oldupsd("DATA-STALE");
313
upserror = UPSF_DATASTALE;
314
return -1; /* failure */
317
if (!strcmp(ptr, "NOT-SUPPORTED")) {
318
warn_oldupsd("NOT-SUPPORTED");
319
upserror = UPSF_VARNOTSUPP;
320
return -1; /* failure */
323
if (!strcmp(ptr, "UNKNOWN")) {
324
warn_oldupsd("UNKNOWN");
325
upserror = UPSF_VARUNKNOWN;
326
return -1; /* failure */
329
if (!strcmp(ptr, "UNKNOWN-UPS")) {
330
warn_oldupsd("UNKNOWN-UPS");
331
upserror = UPSF_UNKNOWNUPS;
332
return -1; /* failure */
335
memset(buf, '\0', buflen);
336
strlcpy(buf, ptr, buflen);
341
int getupsvarlist (const char *hostin, char *buf, int buflen)
343
char tmp[LARGEBUF], *ptr, *upsname, *host, cmd[128], hosttmp[LARGEBUF];
346
/* host = ups-1@localhost */
348
snprintf (hosttmp, sizeof(hosttmp), "%s", hostin);
349
ptr = strstr (hosttmp, "@");
355
snprintf (cmd, sizeof(cmd), "LISTVARS %s", upsname);
360
snprintf (cmd, sizeof(cmd), "LISTVARS");
363
ret = fetch (host, cmd, tmp, sizeof(tmp));
369
tmp[strlen(tmp) - 1] = 0;
372
ptr = tmp + 5; /* skip "VARS " */
374
ptr = tmp + 5 + strlen(upsname) + 2; /* skip "VARS <name> " */
376
memset (buf, '\0', buflen);
377
strlcpy (buf, ptr, buflen);
382
int upsconnect (const char *hostin)
384
struct sockaddr_in local, server;
385
struct hostent *serv;
389
host = xstrdup (hostin);
390
cpos = strstr (host, ":");
396
if ((serv = gethostbyname(host)) == (struct hostent *) NULL) {
397
upserror = UPSF_NOSUCHHOST;
401
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
402
upserror = UPSF_SOCKFAILURE;
407
memset (&local, '\0', sizeof(struct sockaddr_in));
408
local.sin_family = AF_INET;
409
local.sin_port = htons (INADDR_ANY);
411
memset (&server, '\0', sizeof(struct sockaddr_in));
412
server.sin_family = AF_INET;
414
server.sin_port = htons (port);
415
memcpy (&server.sin_addr, serv->h_addr, serv->h_length);
417
if (bind (fd, (struct sockaddr *) &local, sizeof(struct sockaddr_in)) == -1) {
418
upserror = UPSF_BINDFAILURE;
424
if (connect (fd, (struct sockaddr *) &server, sizeof(struct sockaddr_in)) == -1) {
425
upserror = UPSF_CONNFAILURE;
434
void closeupsfd (int fd)
440
/* read from <fd> until a LF */
441
int ups_readline (int fd, char *tmp, int buflen)
447
ret = read (fd, &ch, 1);
450
upserror = UPSF_READERROR;
455
if ((ch == 10) || (tmpptr >= buflen))
465
int getupsvarlistfd (int fd, const char *upsname, char *buf, int buflen)
467
char tmp[LARGEBUF], *ptr, cmd[128];
471
snprintf (cmd, sizeof(cmd), "LISTVARS\n");
473
snprintf (cmd, sizeof(cmd), "LISTVARS %s\n", upsname);
475
ret = write (fd, cmd, strlen(cmd));
478
upserror = UPSF_WRITEERROR;
483
memset (tmp, '\0', sizeof(tmp));
485
if ((err = ups_readline (fd, tmp, buflen)) != 0)
488
if ((err = errcheck (tmp)) != 0)
493
ptr = tmp + 5; /* skip "VARS " */
495
ptr = tmp + 5 + strlen(upsname) + 2; /* skip "VARS <name> " */
497
memset (buf, '\0', buflen);
498
strlcpy (buf, ptr, buflen);
503
int getupsvarfd (int fd, const char *upsname, const char *varname, char *buf, int buflen)
505
char cmd[SMALLBUF], tmp[LARGEBUF], *ptr;
509
snprintf (cmd, sizeof(cmd), "REQ %s\n", varname);
511
snprintf (cmd, sizeof(cmd), "REQ %s@%s\n", varname, upsname);
513
ret = write (fd, cmd, strlen(cmd));
516
upserror = UPSF_WRITEERROR;
521
memset (tmp, '\0', sizeof(tmp));
523
if ((err = ups_readline (fd, tmp, buflen)) != 0)
526
if ((err = errcheck (tmp)) != 0)
529
/* ANS <varname> <answer> */
531
if (upsname == NULL) /* skip "ANS <varname> " */
532
ptr = tmp + strlen(varname) + 5;
533
else /* skip "ANS <varname>@<upsname> " */
534
ptr = tmp + strlen(varname) + 5 + strlen(upsname) + 1;
536
/* --- legacy stuff for older upsd versions --- */
538
/* old upsd versions returned some errors as ANS <var> <error> */
540
if (!strcmp(ptr, "DATA-STALE")) {
541
warn_oldupsd("DATA-STALE");
542
upserror = UPSF_DATASTALE;
543
return -1; /* failure */
546
if (!strcmp(ptr, "NOT-SUPPORTED")) {
547
warn_oldupsd("NOT-SUPPORTED");
548
fprintf(stderr, "upsfetch: old upsd detected! (ANS NOT-SUPPORTED)\n");
549
upserror = UPSF_VARNOTSUPP;
550
return -1; /* failure */
553
if (!strcmp(ptr, "UNKNOWN-UPS")) {
554
warn_oldupsd("UNKNOWN-UPS");
555
upserror = UPSF_UNKNOWNUPS;
556
return (-1); /* failure */
559
memset(buf, '\0', buflen);
560
strlcpy(buf, ptr, buflen);
565
/* send a raw buffer to upsd with basic error checking */
566
int upssendraw(int fd, const char *cmd)
570
upserror = UPSF_UNKNOWN;
572
ret = write(fd, cmd, strlen(cmd));
575
upserror = UPSF_WRITEERROR;
581
return 1; /* success */
584
/* read a response from upsd with basic error checking */
585
int upsreadraw(int fd, char *buf, int buflen)
590
memset(tmp, '\0', sizeof(tmp));
592
if ((err = ups_readline(fd, tmp, sizeof(tmp))) != 0)
595
if ((err = errcheck(tmp)) != 0)
598
strlcpy(buf, tmp, buflen);
601
return 1; /* success */