~iheino+ub/+junk/nut-upsconf-docfix

« back to all changes in this revision

Viewing changes to clients/upsrw.c

  • Committer: Tuomas Heino
  • Author(s): Laurent Bigonville
  • Date: 2014-04-22 20:46:12 UTC
  • Revision ID: iheino+ub@cc.hut.fi-20140422204612-1x2gh3nkezfsdao4
Tags: upstream-2.7.2
ImportĀ upstreamĀ versionĀ 2.7.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* upsrw - simple client for read/write variable access (formerly upsct2)
 
2
 
 
3
   Copyright (C) 1999  Russell Kroll <rkroll@exploits.org>
 
4
 
 
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.
 
9
 
 
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.
 
14
 
 
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
 
18
*/
 
19
 
 
20
#include "common.h"
 
21
#include "nut_platform.h"
 
22
 
 
23
#include <pwd.h>
 
24
#include <netdb.h>
 
25
#include <netinet/in.h>
 
26
#include <sys/socket.h>
 
27
 
 
28
#include "upsclient.h"
 
29
 
 
30
static char             *upsname = NULL, *hostname = NULL;
 
31
static UPSCONN_t        *ups = NULL;
 
32
 
 
33
struct list_t {
 
34
        char    *name;
 
35
        struct  list_t  *next;
 
36
};
 
37
 
 
38
static void usage(const char *prog)
 
39
{
 
40
        printf("Network UPS Tools %s %s\n\n", prog, UPS_VERSION);
 
41
        printf("usage: %s [-h]\n", prog);
 
42
        printf("       %s [-s <variable>] [-u <username>] [-p <password>] <ups>\n\n", prog);
 
43
        printf("Demo program to set variables within UPS hardware.\n");
 
44
        printf("\n");
 
45
        printf("  -h            display this help text\n");
 
46
        printf("  -s <variable> specify variable to be changed\n");
 
47
        printf("                use -s VAR=VALUE to avoid prompting for value\n");
 
48
        printf("  -u <username> set username for command authentication\n");
 
49
        printf("  -p <password> set password for command authentication\n");
 
50
        printf("\n");
 
51
        printf("  <ups>         UPS identifier - <upsname>[@<hostname>[:<port>]]\n");
 
52
        printf("\n");
 
53
        printf("Call without -s to show all possible read/write variables.\n");
 
54
}
 
55
 
 
56
static void clean_exit(void)
 
57
{
 
58
        if (ups) {
 
59
                upscli_disconnect(ups);
 
60
        }
 
61
 
 
62
        free(upsname);
 
63
        free(hostname);
 
64
        free(ups);
 
65
}
 
66
 
 
67
static void do_set(const char *varname, const char *newval)
 
68
{
 
69
        char    buf[SMALLBUF], enc[SMALLBUF];
 
70
 
 
71
        snprintf(buf, sizeof(buf), "SET VAR %s %s \"%s\"\n", upsname, varname, pconf_encode(newval, enc, sizeof(enc)));
 
72
 
 
73
        if (upscli_sendline(ups, buf, strlen(buf)) < 0) {
 
74
                fatalx(EXIT_FAILURE, "Can't set variable: %s", upscli_strerror(ups));
 
75
        }
 
76
 
 
77
        if (upscli_readline(ups, buf, sizeof(buf)) < 0) {
 
78
                fatalx(EXIT_FAILURE, "Set variable failed: %s", upscli_strerror(ups));
 
79
        }
 
80
 
 
81
        /* FUTURE: status cookies will tie in here */
 
82
        if (strncmp(buf, "OK", 2) != 0) {
 
83
                fatalx(EXIT_FAILURE, "Unexpected response from upsd: %s", buf);
 
84
        }
 
85
 
 
86
        fprintf(stderr, "%s\n", buf);
 
87
}
 
88
 
 
89
static void do_setvar(const char *varname, char *uin, const char *pass)
 
90
{
 
91
        char    newval[SMALLBUF], temp[SMALLBUF], user[SMALLBUF], *ptr;
 
92
        struct passwd   *pw;
 
93
 
 
94
        if (uin) {
 
95
                snprintf(user, sizeof(user), "%s", uin);
 
96
        } else {
 
97
                memset(user, '\0', sizeof(user));
 
98
 
 
99
                pw = getpwuid(getuid());
 
100
 
 
101
                if (pw) {
 
102
                        printf("Username (%s): ", pw->pw_name);
 
103
                } else {
 
104
                        printf("Username: ");
 
105
                }
 
106
 
 
107
                if (fgets(user, sizeof(user), stdin) == NULL) {
 
108
                        upsdebug_with_errno(LOG_INFO, "%s", __func__);
 
109
                }
 
110
 
 
111
                /* deal with that pesky newline */
 
112
                if (strlen(user) > 1) {
 
113
                        user[strlen(user) - 1] = '\0';
 
114
                } else {
 
115
                        if (!pw) {
 
116
                                fatalx(EXIT_FAILURE, "No username available - even tried getpwuid");
 
117
                        }
 
118
 
 
119
                        snprintf(user, sizeof(user), "%s", pw->pw_name);
 
120
                }
 
121
        }
 
122
 
 
123
        /* leaks - use -p when running in valgrind */
 
124
        if (!pass) {
 
125
                pass = GETPASS("Password: " );
 
126
 
 
127
                if (!pass) {
 
128
                        fatal_with_errno(EXIT_FAILURE, "getpass failed");
 
129
                }
 
130
        }
 
131
 
 
132
        /* Check if varname is in VAR=VALUE form */
 
133
        if ((ptr = strchr(varname, '=')) != NULL) {
 
134
                *ptr++ = 0;
 
135
                snprintf(newval, sizeof(newval), "%s", ptr);
 
136
        } else {
 
137
                printf("Enter new value for %s: ", varname);
 
138
                fflush(stdout);
 
139
                if (fgets(newval, sizeof(newval), stdin) == NULL) {
 
140
                        upsdebug_with_errno(LOG_INFO, "%s", __func__);
 
141
                }
 
142
                newval[strlen(newval) - 1] = '\0';
 
143
        }
 
144
 
 
145
        snprintf(temp, sizeof(temp), "USERNAME %s\n", user);
 
146
 
 
147
        if (upscli_sendline(ups, temp, strlen(temp)) < 0) {
 
148
                fatalx(EXIT_FAILURE, "Can't set username: %s", upscli_strerror(ups));
 
149
        }
 
150
 
 
151
        if (upscli_readline(ups, temp, sizeof(temp)) < 0) {
 
152
 
 
153
                if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) {
 
154
                        fatalx(EXIT_FAILURE, "Set username failed due to an unknown command. You probably need to upgrade upsd.");
 
155
                }
 
156
 
 
157
                fatalx(EXIT_FAILURE, "Set username failed: %s", upscli_strerror(ups));
 
158
        }
 
159
 
 
160
        snprintf(temp, sizeof(temp), "PASSWORD %s\n", pass);
 
161
 
 
162
        if (upscli_sendline(ups, temp, strlen(temp)) < 0) {
 
163
                fatalx(EXIT_FAILURE, "Can't set password: %s", upscli_strerror(ups));
 
164
        }
 
165
 
 
166
        if (upscli_readline(ups, temp, sizeof(temp)) < 0) {
 
167
                fatalx(EXIT_FAILURE, "Set password failed: %s", upscli_strerror(ups));
 
168
        }
 
169
 
 
170
        /* no upsname means die */
 
171
        if (!upsname) {
 
172
                fatalx(EXIT_FAILURE, "Error: a UPS name must be specified (upsname[@hostname[:port]])");
 
173
        }
 
174
 
 
175
        /* old variable names are no longer supported */
 
176
        if (!strchr(varname, '.')) {
 
177
                fatalx(EXIT_FAILURE, "Error: old variable names are not supported");
 
178
        }
 
179
 
 
180
        do_set(varname, newval);
 
181
}
 
182
 
 
183
static const char *get_data(const char *type, const char *varname)
 
184
{
 
185
        int     ret;
 
186
        unsigned int    numq, numa;
 
187
        char    **answer;
 
188
        const char      *query[4];
 
189
 
 
190
        query[0] = type;
 
191
        query[1] = upsname;
 
192
        query[2] = varname;
 
193
 
 
194
        numq = 3;
 
195
 
 
196
        ret = upscli_get(ups, numq, query, &numa, &answer);
 
197
 
 
198
        if ((ret < 0) || (numa < numq)) {
 
199
                return NULL;
 
200
        }
 
201
 
 
202
        /* <type> <upsname> <varname> <desc> */
 
203
        return answer[3];
 
204
}
 
205
 
 
206
static void do_string(const char *varname, const int len)
 
207
{
 
208
        const char      *val;
 
209
 
 
210
        val = get_data("VAR", varname);
 
211
 
 
212
        if (!val) {
 
213
                fatalx(EXIT_FAILURE, "do_string: can't get current value of %s", varname);
 
214
        }
 
215
 
 
216
        printf("Type: STRING\n");
 
217
        printf("Maximum length: %d\n", len);
 
218
        printf("Value: %s\n", val);
 
219
}
 
220
 
 
221
static void do_enum(const char *varname)
 
222
{
 
223
        int     ret;
 
224
        unsigned int    numq, numa;
 
225
        char    **answer, buf[SMALLBUF];
 
226
        const char      *query[4], *val;
 
227
 
 
228
        /* get current value */
 
229
        val = get_data("VAR", varname);
 
230
 
 
231
        if (!val) {
 
232
                fatalx(EXIT_FAILURE, "do_enum: can't get current value of %s", varname);
 
233
        }
 
234
 
 
235
        snprintf(buf, sizeof(buf), "%s", val);
 
236
 
 
237
        query[0] = "ENUM";
 
238
        query[1] = upsname;
 
239
        query[2] = varname;
 
240
        numq = 3;
 
241
 
 
242
        ret = upscli_list_start(ups, numq, query);
 
243
 
 
244
        if (ret < 0) {
 
245
                fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
 
246
        }
 
247
 
 
248
        ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
249
 
 
250
        printf("Type: ENUM\n");
 
251
 
 
252
        while (ret == 1) {
 
253
 
 
254
                /* ENUM <upsname> <varname> <value> */
 
255
 
 
256
                if (numa < 4) {
 
257
                        fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 4)", numa);
 
258
                }
 
259
 
 
260
                printf("Option: \"%s\"", answer[3]);
 
261
 
 
262
                if (!strcmp(answer[3], buf)) {
 
263
                        printf(" SELECTED");
 
264
                }
 
265
 
 
266
                printf("\n");
 
267
 
 
268
                ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
269
        }
 
270
}
 
271
 
 
272
static void do_range(const char *varname)
 
273
{
 
274
        int     ret;
 
275
        unsigned int    numq, numa;
 
276
        char    **answer;
 
277
        const char      *query[4], *val;
 
278
        int ival, min, max;
 
279
 
 
280
        /* get current value */
 
281
        val = get_data("VAR", varname);
 
282
 
 
283
        if (!val) {
 
284
                fatalx(EXIT_FAILURE, "do_range: can't get current value of %s", varname);
 
285
        }
 
286
 
 
287
        ival = atoi(val);
 
288
 
 
289
        query[0] = "RANGE";
 
290
        query[1] = upsname;
 
291
        query[2] = varname;
 
292
        numq = 3;
 
293
 
 
294
        ret = upscli_list_start(ups, numq, query);
 
295
 
 
296
        if (ret < 0) {
 
297
                fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
 
298
        }
 
299
 
 
300
        ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
301
 
 
302
        printf("Type: RANGE\n");
 
303
 
 
304
        while (ret == 1) {
 
305
 
 
306
                /* RANGE <upsname> <varname> <min> <max> */
 
307
 
 
308
                if (numa < 5) {
 
309
                        fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 4)", numa);
 
310
                }
 
311
 
 
312
                min = atoi(answer[3]);
 
313
                max = atoi(answer[4]);
 
314
 
 
315
                printf("Option: \"%i-%i\"", min, max);
 
316
 
 
317
                if ((ival >= min) && (ival <= max)) {
 
318
                        printf(" SELECTED");
 
319
                }
 
320
 
 
321
                printf("\n");
 
322
 
 
323
                ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
324
        }
 
325
}
 
326
 
 
327
static void do_type(const char *varname)
 
328
{
 
329
        int     ret;
 
330
        unsigned int    i, numq, numa;
 
331
        char    **answer;
 
332
        const char      *query[4];
 
333
 
 
334
        query[0] = "TYPE";
 
335
        query[1] = upsname;
 
336
        query[2] = varname;
 
337
        numq = 3;
 
338
 
 
339
        ret = upscli_get(ups, numq, query, &numa, &answer);
 
340
 
 
341
        if ((ret < 0) || (numa < numq)) {
 
342
                printf("Unknown type\n");       
 
343
                return;
 
344
        }
 
345
 
 
346
        /* TYPE <upsname> <varname> <type>... */
 
347
        for (i = 3; i < numa; i++) {
 
348
 
 
349
                if (!strcasecmp(answer[i], "ENUM")) {
 
350
                        do_enum(varname);
 
351
                        return;
 
352
                }
 
353
 
 
354
                if (!strcasecmp(answer[i], "RANGE")) {
 
355
                        do_range(varname);
 
356
                        return;
 
357
                }
 
358
 
 
359
                if (!strncasecmp(answer[i], "STRING:", 7)) {
 
360
 
 
361
                        char    *len = answer[i] + 7;
 
362
                        int     length = strtol(len, NULL, 10);
 
363
 
 
364
                        do_string(varname, length);
 
365
                        return;
 
366
 
 
367
                }
 
368
 
 
369
                /* ignore this one */
 
370
                if (!strcasecmp(answer[i], "RW")) {
 
371
                        continue;
 
372
                }
 
373
 
 
374
                printf("Type: %s (unrecognized)\n", answer[i]);
 
375
        }
 
376
}
 
377
 
 
378
static void print_rw(const char *varname)
 
379
{
 
380
        const char      *tmp;
 
381
 
 
382
        printf("[%s]\n", varname);
 
383
 
 
384
        tmp = get_data("DESC", varname);
 
385
 
 
386
        if (tmp) {
 
387
                printf("%s\n", tmp);
 
388
        } else {
 
389
                printf("Description unavailable\n");
 
390
        }
 
391
 
 
392
        do_type(varname);
 
393
 
 
394
        printf("\n");
 
395
}
 
396
 
 
397
static void print_rwlist(void)
 
398
{
 
399
        int     ret;
 
400
        unsigned int    numq, numa;
 
401
        const char      *query[2];
 
402
        char    **answer;
 
403
        struct  list_t  *lhead, *llast, *ltmp, *lnext;
 
404
 
 
405
        /* the upsname is now required */
 
406
        if (!upsname) {
 
407
                fatalx(EXIT_FAILURE, "Error: a UPS name must be specified (upsname[@hostname[:port]])");
 
408
        }
 
409
 
 
410
        llast = lhead = NULL;
 
411
 
 
412
        query[0] = "RW";
 
413
        query[1] = upsname;
 
414
        numq = 2;
 
415
 
 
416
        ret = upscli_list_start(ups, numq, query);
 
417
 
 
418
        if (ret < 0) {
 
419
 
 
420
                /* old upsd --> fall back on old LISTRW technique */
 
421
                if (upscli_upserror(ups) == UPSCLI_ERR_UNKCOMMAND) {
 
422
                        fatalx(EXIT_FAILURE, "Error: upsd is too old to support this query");
 
423
                }
 
424
 
 
425
                fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
 
426
        }
 
427
 
 
428
        ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
429
 
 
430
        while (ret == 1) {
 
431
 
 
432
                /* RW <upsname> <varname> <value> */
 
433
                if (numa < 4) {
 
434
                        fatalx(EXIT_FAILURE, "Error: insufficient data (got %d args, need at least 4)", numa);
 
435
                }
 
436
 
 
437
                /* sock this entry away for later */
 
438
 
 
439
                ltmp = xmalloc(sizeof(struct list_t));
 
440
                ltmp->name = xstrdup(answer[2]);
 
441
                ltmp->next = NULL;
 
442
 
 
443
                if (llast) {
 
444
                        llast->next = ltmp;
 
445
                } else {
 
446
                        lhead = ltmp;
 
447
                }
 
448
 
 
449
                llast = ltmp;
 
450
 
 
451
                ret = upscli_list_next(ups, numq, query, &numa, &answer);
 
452
        }
 
453
 
 
454
        /* use the list to get descriptions and types */
 
455
 
 
456
        ltmp = lhead;
 
457
 
 
458
        while (ltmp) {
 
459
                lnext = ltmp->next;
 
460
 
 
461
                print_rw(ltmp->name);
 
462
 
 
463
                free(ltmp->name);
 
464
                free(ltmp);
 
465
                ltmp = lnext;
 
466
        }
 
467
}
 
468
 
 
469
int main(int argc, char **argv)
 
470
{
 
471
        int     i, port;
 
472
        const char      *prog = xbasename(argv[0]);
 
473
        char    *password = NULL, *username = NULL, *setvar = NULL;
 
474
 
 
475
        while ((i = getopt(argc, argv, "+hs:p:u:V")) != -1) {
 
476
                switch (i)
 
477
                {
 
478
                case 's':
 
479
                        setvar = optarg;
 
480
                        break;
 
481
                case 'p':
 
482
                        password = optarg;
 
483
                        break;
 
484
                case 'u':
 
485
                        username = optarg;
 
486
                        break;
 
487
                case 'V':
 
488
                        printf("Network UPS Tools %s %s\n", prog, UPS_VERSION);
 
489
                        exit(EXIT_SUCCESS);
 
490
                case 'h':
 
491
                default:
 
492
                        usage(prog);
 
493
                        exit(EXIT_SUCCESS);
 
494
                }
 
495
        }
 
496
 
 
497
        argc -= optind;
 
498
        argv += optind;
 
499
 
 
500
        if (argc < 1) {
 
501
                usage(prog);
 
502
                exit(EXIT_SUCCESS);
 
503
        }
 
504
 
 
505
        /* be a good little client that cleans up after itself */
 
506
        atexit(clean_exit);
 
507
 
 
508
        if (upscli_splitname(argv[0], &upsname, &hostname, &port) != 0) {
 
509
                fatalx(EXIT_FAILURE, "Error: invalid UPS definition.  Required format: upsname[@hostname[:port]]");
 
510
        }
 
511
 
 
512
        ups = xcalloc(1, sizeof(*ups));
 
513
 
 
514
        if (upscli_connect(ups, hostname, port, 0) < 0) {
 
515
                fatalx(EXIT_FAILURE, "Error: %s", upscli_strerror(ups));
 
516
        }
 
517
 
 
518
        if (setvar) {
 
519
                /* setting a variable */
 
520
                do_setvar(setvar, username, password);
 
521
        } else {
 
522
                /* if not, get the list of supported read/write variables */
 
523
                print_rwlist();
 
524
        }
 
525
 
 
526
        exit(EXIT_SUCCESS);
 
527
}
 
528
 
 
529
 
 
530
/* Formal do_upsconf_args implementation to satisfy linker on AIX */
 
531
#if (defined NUT_PLATFORM_AIX)
 
532
void do_upsconf_args(char *upsname, char *var, char *val) {
 
533
        fatalx(EXIT_FAILURE, "INTERNAL ERROR: formal do_upsconf_args called");
 
534
}
 
535
#endif  /* end of #if (defined NUT_PLATFORM_AIX) */