~ubuntu-branches/ubuntu/saucy/nut/saucy

« back to all changes in this revision

Viewing changes to drivers/powernet.c

  • Committer: Bazaar Package Importer
  • Author(s): Arnaud Quette
  • Date: 2004-05-28 13:10:01 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20040528131001-yj2m9qcez4ya2w14
Tags: upstream-1.4.2
ImportĀ upstreamĀ versionĀ 1.4.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * vim: ts=4 sw=4
 
3
 */
 
4
 
 
5
/*
 
6
 * powernet.c -- SNMP interface driver for APC SNMP devices.
 
7
 * Tested on AP9606 APC Web/SNMP managenent card.
 
8
 * Dmitry Frolov <frolov@riss-telecom.ru>
 
9
 *
 
10
 * Based on NUT snmp-ups driver:
 
11
 * Copyright (C) 2002 Arnaud Quette <arnaud.quette@free.fr>
 
12
 * some parts are Copyright (C) :
 
13
 *               Russell Kroll <rkroll@exploits.org>
 
14
 *               Hans Ekkehard Plesser <hans.plesser@itf.nlh.no>
 
15
 *
 
16
 * References: PowerNet MIB v 3.3.0
 
17
 * You can get it from http://apcc.com/tools/download/
 
18
 */
 
19
 
 
20
/*
 
21
 * Suggested entry in the makefile:
 
22
 *
 
23
 * COMMON_LIBDEP=       main.o upscommon.o ../common/upsconf.o ../common/parseconf.o
 
24
 * COMMON_INCDEP=       ../include/shared.h ../include/shared-tables.h
 
25
 *
 
26
 * powernet: powernet.o $(COMMON_LIBDEP) $(LIBDEP)
 
27
 *              $(CC) $(CFLAGS) -o $@ $@.o $(COMMON_LIBDEP) $(LIBOBJ) \
 
28
 *                      -lsnmp -lcrypto
 
29
 *
 
30
 * powernet.o: powernet.c powernet.h $(COMMON_INCDEP)
 
31
 *              $(CC) $(CFLAGS) -c powernet.c
 
32
 */
 
33
 
 
34
/*
 
35
 *                     GNU GENERAL PUBLIC LICENSE
 
36
 *                        Version 2, June 1991
 
37
 *
 
38
 *  Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 
39
 *            59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
40
 *
 
41
 *  Everyone is permitted to copy and distribute verbatim copies
 
42
 *  of this license document, but changing it is not allowed.
 
43
 *
 
44
 *  This program is free software; you can redistribute it and/or modify
 
45
 *  it under the terms of the GNU General Public License as published by
 
46
 *  the Free Software Foundation; either version 2 of the License, or
 
47
 *  (at your option) any later version.
 
48
 *
 
49
 *  This program is distributed in the hope that it will be useful,
 
50
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
51
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
52
 *  GNU General Public License for more details.
 
53
 *
 
54
 *  You should have received a copy of the GNU General Public License
 
55
 *  along with this program; if not, write to the Free Software
 
56
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
57
 *
 
58
 */
 
59
 
 
60
/* UCD SNMP includes and global data */
 
61
#include <arpa/inet.h> /* for ucd-snmp include bug */
 
62
#include <ucd-snmp/ucd-snmp-config.h>
 
63
#include <ucd-snmp/ucd-snmp-includes.h>
 
64
#include <ucd-snmp/system.h>
 
65
 
 
66
/* NUT includes and global data */
 
67
#include "main.h"
 
68
#include "powernet.h"
 
69
 
 
70
unsigned long g_ups_status[PN_STATUS_NUM_ELEM];
 
71
struct snmp_session g_snmp_sess, *g_snmp_sess_p = NULL;
 
72
 
 
73
extern char *upsname;
 
74
 
 
75
/* -----------------------------------------------------------
 
76
 * SNMP functions.
 
77
 * ----------------------------------------------------------- */
 
78
 
 
79
void pn_snmp_init(const char *type, const char *hostname, const char *community)
 
80
{
 
81
        /* Initialize the SNMP library */
 
82
        init_snmp(type);
 
83
 
 
84
        /* Initialize session */
 
85
        snmp_sess_init(&g_snmp_sess);
 
86
 
 
87
        g_snmp_sess.peername = (char *)hostname;
 
88
        g_snmp_sess.community = (char *)community;
 
89
        g_snmp_sess.community_len = strlen(community);
 
90
        g_snmp_sess.version = SNMP_VERSION_1;
 
91
 
 
92
        /* Open the session */
 
93
        SOCK_STARTUP;
 
94
        g_snmp_sess_p = snmp_open(&g_snmp_sess);        /* establish the session */
 
95
        if (g_snmp_sess_p == NULL) {
 
96
                pn_snmp_perror(&g_snmp_sess, 0, NULL, "pn_snmp_init: snmp_open");
 
97
                exit(1);
 
98
        }
 
99
}
 
100
 
 
101
void pn_snmp_cleanup(void)
 
102
{
 
103
        /* close snmp session. */
 
104
        if (g_snmp_sess_p) {
 
105
                snmp_close(g_snmp_sess_p);
 
106
                g_snmp_sess_p = NULL;
 
107
        }
 
108
        SOCK_CLEANUP;
 
109
}
 
110
 
 
111
struct snmp_pdu *pn_snmp_get(const char *OID)
 
112
{
 
113
        int status;
 
114
        struct snmp_pdu *pdu, *response = NULL;
 
115
        oid name[MAX_OID_LEN];
 
116
        size_t name_len = MAX_OID_LEN;
 
117
 
 
118
        /* create and send request. */
 
119
 
 
120
        if (!read_objid(OID, name, &name_len)) {
 
121
                upslogx(LOG_ERR, "[%s] pn_snmp_get: %s: %s",
 
122
                        upsname, OID, snmp_api_errstring(snmp_errno));
 
123
                return NULL;
 
124
        }
 
125
 
 
126
        pdu = snmp_pdu_create(SNMP_MSG_GET);
 
127
        if (pdu == NULL)
 
128
                fatalx("Not enough memory");
 
129
        snmp_add_null_var(pdu, name, name_len);
 
130
 
 
131
        status = snmp_synch_response(g_snmp_sess_p, pdu,
 
132
                &response);
 
133
 
 
134
        if (!((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR)))
 
135
        {
 
136
                pn_snmp_perror(g_snmp_sess_p, status, response, "pn_snmp_get: %s", OID);
 
137
                snmp_free_pdu(response);
 
138
                response = NULL;
 
139
        }
 
140
 
 
141
        return response;
 
142
}
 
143
 
 
144
bool pn_snmp_get_str(const char *OID, char *buf, size_t buf_len)
 
145
{
 
146
        size_t len = 0;
 
147
        struct snmp_pdu *pdu;
 
148
 
 
149
        /* zero out buffer. */
 
150
        memset(buf, 0, buf_len);
 
151
 
 
152
        pdu = pn_snmp_get(OID);
 
153
        if (pdu == NULL)
 
154
                return FALSE;
 
155
 
 
156
        switch (pdu->variables->type) {
 
157
        case ASN_OCTET_STR:
 
158
        case ASN_OPAQUE:
 
159
                len = pdu->variables->val_len > buf_len - 1 ?
 
160
                        buf_len - 1 : pdu->variables->val_len;
 
161
                memcpy(buf, pdu->variables->val.string, len);
 
162
                buf[len] = '\0';
 
163
                break;
 
164
        case ASN_INTEGER:
 
165
        case ASN_GAUGE:
 
166
                len = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer);
 
167
                break;
 
168
        case ASN_TIMETICKS:
 
169
                /* convert timeticks to seconds */
 
170
                len = snprintf(buf, buf_len, "%ld", *pdu->variables->val.integer / 100);
 
171
                break;
 
172
        default:
 
173
                upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x recieved from %s",
 
174
                        upsname, pdu->variables->type, OID);
 
175
                return FALSE;
 
176
                break;
 
177
        }
 
178
 
 
179
        snmp_free_pdu(pdu);
 
180
 
 
181
        return TRUE;
 
182
}
 
183
 
 
184
bool pn_snmp_get_int(const char *OID, long *pval)
 
185
{
 
186
        struct snmp_pdu *pdu;
 
187
        long value;
 
188
        char *buf;
 
189
 
 
190
        pdu = pn_snmp_get(OID);
 
191
        if (pdu == NULL)
 
192
                return FALSE;
 
193
 
 
194
        switch (pdu->variables->type) {
 
195
        case ASN_OCTET_STR:
 
196
        case ASN_OPAQUE:
 
197
                buf = xmalloc(pdu->variables->val_len + 1);
 
198
                memcpy(buf, pdu->variables->val.string, pdu->variables->val_len);
 
199
                buf[pdu->variables->val_len] = '\0';
 
200
                value = strtol(buf, NULL, 0);
 
201
                free(buf);
 
202
                break;
 
203
        case ASN_INTEGER:
 
204
        case ASN_GAUGE:
 
205
                value = *pdu->variables->val.integer;
 
206
                break;
 
207
        case ASN_TIMETICKS:
 
208
                /* convert timeticks to seconds */
 
209
                value = *pdu->variables->val.integer / 100;
 
210
                break;
 
211
        default:
 
212
                upslogx(LOG_ERR, "[%s] unhandled ASN 0x%x recieved from %s",
 
213
                        upsname, pdu->variables->type, OID);
 
214
                return FALSE;
 
215
                break;
 
216
        }
 
217
 
 
218
        snmp_free_pdu(pdu);
 
219
 
 
220
        if (pval != NULL)
 
221
                *pval = value;
 
222
 
 
223
        return TRUE;
 
224
}
 
225
 
 
226
bool pn_snmp_set(const char *OID, char type, const char *value)
 
227
{
 
228
        int status;
 
229
        bool ret = FALSE;
 
230
        struct snmp_pdu *pdu, *response = NULL;
 
231
        oid name[MAX_OID_LEN];
 
232
        size_t name_len = MAX_OID_LEN;
 
233
 
 
234
        if (!read_objid(OID, name, &name_len)) {
 
235
                upslogx(LOG_ERR, "[%s] pn_snmp_set: %s: %s",
 
236
                        upsname, OID, snmp_api_errstring(snmp_errno));
 
237
                return FALSE;
 
238
        }
 
239
 
 
240
        pdu = snmp_pdu_create(SNMP_MSG_SET);
 
241
        if (pdu == NULL)
 
242
                fatalx("Not enough memory");
 
243
 
 
244
        if (snmp_add_var(pdu, name, name_len, type, value)) {
 
245
                upslogx(LOG_ERR, "[%s] pn_snmp_set: %s: %s",
 
246
                        upsname, OID, snmp_api_errstring(snmp_errno));
 
247
                return FALSE;
 
248
        }
 
249
 
 
250
        status = snmp_synch_response(g_snmp_sess_p, pdu, &response);
 
251
 
 
252
        if ((status == STAT_SUCCESS) && (response->errstat == SNMP_ERR_NOERROR))
 
253
                ret = TRUE;
 
254
        else
 
255
                pn_snmp_perror(g_snmp_sess_p, status, response,
 
256
                        "pn_snmp_set: can't set %s", OID);
 
257
 
 
258
        snmp_free_pdu(response);
 
259
 
 
260
        return ret;
 
261
}
 
262
 
 
263
bool pn_snmp_set_str(const char *OID, const char *value)
 
264
{
 
265
        return pn_snmp_set(OID, 's', value);
 
266
}
 
267
 
 
268
bool pn_snmp_set_int(const char *OID, long value)
 
269
{
 
270
        bool ret;
 
271
        char *buf = xmalloc(PN_BUFSIZE);
 
272
 
 
273
        snprintf(buf, PN_BUFSIZE, "%ld", value);
 
274
        ret = pn_snmp_set(OID, 'i', buf);
 
275
        free(buf);
 
276
        return ret;
 
277
}
 
278
 
 
279
bool pn_snmp_set_time(const char *OID, long value)
 
280
{
 
281
        bool ret;
 
282
        char *buf = xmalloc(PN_BUFSIZE);
 
283
 
 
284
        snprintf(buf, PN_BUFSIZE, "%ld", value * 100);
 
285
        ret = pn_snmp_set(OID, 't', buf);
 
286
        free(buf);
 
287
        return ret;
 
288
}
 
289
 
 
290
/* log descriptive SNMP error message. */
 
291
void pn_snmp_perror(struct snmp_session *sess, int status,
 
292
        struct snmp_pdu *response, const char *fmt, ...)
 
293
{
 
294
        va_list va;
 
295
        int cliberr, snmperr;
 
296
        char *snmperrstr;
 
297
        char *buf;
 
298
 
 
299
        buf = xmalloc(PN_LARGEBUF);
 
300
 
 
301
        va_start(va, fmt);
 
302
        vsnprintf(buf, PN_LARGEBUF, fmt, va);
 
303
        va_end(va);
 
304
 
 
305
        if (response == NULL) {
 
306
                snmp_error(sess, &cliberr, &snmperr, &snmperrstr);
 
307
                upslogx(LOG_ERR, "[%s] %s: %s",
 
308
                        upsname, buf, snmperrstr);
 
309
                free(snmperrstr);
 
310
        } else if (status == STAT_SUCCESS) {
 
311
                if (response->errstat != SNMP_ERR_NOERROR)
 
312
                        upslogx(LOG_ERR, "[%s] %s: Error in packet: %s",
 
313
                                upsname, buf, snmp_errstring(response->errstat));
 
314
        } else if (status == STAT_TIMEOUT) {
 
315
                upslogx(LOG_ERR, "[%s] %s: Timeout: no response from %s",
 
316
                        upsname, sess->peername);
 
317
        } else {
 
318
                snmp_sess_error(sess, &cliberr, &snmperr, &snmperrstr);
 
319
                upslogx(LOG_ERR, "[%s] %s: %s",
 
320
                        upsname, buf, snmperrstr);
 
321
                free(snmperrstr);
 
322
        }
 
323
 
 
324
        free(buf);
 
325
}
 
326
 
 
327
/* -----------------------------------------------------------
 
328
 * utility functions.
 
329
 * ----------------------------------------------------------- */
 
330
 
 
331
/* called on startup. */
 
332
void pn_startup(void)
 
333
{
 
334
        pn_snmp_init(progname, device_path,
 
335
                (testvar(PN_VAR_COMMUNITY) ? getval(PN_VAR_COMMUNITY) : "public"));
 
336
}
 
337
 
 
338
/* clean up before exit. */
 
339
void pn_cleanup(void)
 
340
{
 
341
        pn_snmp_cleanup();
 
342
}
 
343
 
 
344
/* add instant commands into info database. */
 
345
void pn_init_instcmds(void)
 
346
{
 
347
        pn_info_t *pn_info_p;
 
348
 
 
349
        for (pn_info_p = &pn_info[0]; pn_info_p->info_type; pn_info_p++)
 
350
                if (pn_info_p->info_type & PN_CMD_MASK)
 
351
                        addinfo(INFO_INSTCMD, "", 0, pn_info_p->info_type);
 
352
}
 
353
 
 
354
/* install pointers to functions for msg handlers called from msgparse */
 
355
void pn_setuphandlers(void)
 
356
{
 
357
        upsh.instcmd = pn_ups_instcmd;
 
358
        upsh.setvar = pn_ups_set;
 
359
}
 
360
 
 
361
/* universal function to add or update info element. */
 
362
void pn_setinfo(int type, const char *value, int flags, int auxdata)
 
363
{
 
364
        if (type == INFO_INSTCMD)
 
365
                return;
 
366
        if (getdata(type))
 
367
                setinfo(type, "%s", value);
 
368
        else
 
369
                addinfo(type, value, flags, auxdata);
 
370
}
 
371
 
 
372
void pn_status_init(void)
 
373
{
 
374
        memset(g_ups_status, 0, sizeof(g_ups_status));
 
375
}
 
376
 
 
377
void pn_status_set(pn_info_t *pn_info_p, long value)
 
378
{
 
379
        g_ups_status[PN_STATUS_INDEX(pn_info_p->flags)] = value;
 
380
}
 
381
 
 
382
void pn_status_commit(void)
 
383
{
 
384
        char buf[PN_INFOSIZE];
 
385
        pn_info_t *pn_info_p;
 
386
 
 
387
        switch (g_ups_status[PN_STATUS_INDEX(PN_STATUS_PWR)]) {
 
388
        case PWR_OTHER:                 /*  INFO_STATUS/? */
 
389
        case PWR_REBOOTING:
 
390
        case PWR_SOFT_BYPASS:
 
391
        case PWR_HARD_BYPASS:
 
392
        case PWR_FAIL_BYPASS:
 
393
                break;
 
394
        case PWR_NONE:                  /* none -> INFO_STATUS/OFF */
 
395
        case PWR_SLEEPING:
 
396
        case PWR_SLEEPING2:
 
397
                snprintf(buf, sizeof(buf), "OFF");
 
398
                break;
 
399
        case PWR_NORMAL:                /* normal -> INFO_STATUS/OL */
 
400
                snprintf(buf, sizeof(buf), "OL");
 
401
                break;
 
402
        case PWR_BATTERY:               /* battery -> INFO_STATUS/OB */
 
403
                snprintf(buf, sizeof(buf), "OB");
 
404
                break;
 
405
        case PWR_BOOSTER:               /* booster -> INFO_STATUS/BOOST */
 
406
                snprintf(buf, sizeof(buf), "BOOST");
 
407
                break;
 
408
        case PWR_REDUCER:               /* reducer -> INFO_STATUS/TRIM */
 
409
                snprintf(buf, sizeof(buf), "TRIM");
 
410
                break;
 
411
        }
 
412
 
 
413
        switch (g_ups_status[PN_STATUS_INDEX(PN_STATUS_BATT)]) {
 
414
        case BATT_UNKNOWN:              /* unknown -> INFO_STATUS/? */
 
415
        case BATT_NORMAL:               /* batteryNormal -> INFO_STATUS/? */
 
416
                break;
 
417
        case BATT_LOW:                  /* batteryLow -> INFO_STATUS/LB */
 
418
                snprintfcat(buf, sizeof(buf),
 
419
                        (strlen(buf) == 0 ? "%s" : " %s"), "LB");
 
420
                break;
 
421
        }
 
422
 
 
423
        switch (g_ups_status[PN_STATUS_INDEX(PN_STATUS_CAL)]) {
 
424
        case CAL_INPROGRESS:
 
425
                snprintfcat(buf, sizeof(buf),
 
426
                        (strlen(buf) == 0 ? "%s" : " %s"), "CAL");
 
427
                break;
 
428
        }
 
429
 
 
430
        switch (g_ups_status[PN_STATUS_INDEX(PN_STATUS_RB)]) {
 
431
        case RB_NEED:
 
432
                snprintfcat(buf, sizeof(buf),
 
433
                        (strlen(buf) == 0 ? "%s" : " %s"), "RB");
 
434
                break;
 
435
        }
 
436
 
 
437
        pn_info_p = pn_find_info(INFO_STATUS);
 
438
 
 
439
        pn_setinfo(pn_info_p->info_type, buf, pn_info_p->info_flags,
 
440
                pn_info_p->info_len);
 
441
}
 
442
 
 
443
/* find info element definition in my info array. */
 
444
pn_info_t *pn_find_info(int type)
 
445
{
 
446
        pn_info_t *pn_info_p;
 
447
 
 
448
        for (pn_info_p = &pn_info[0]; pn_info_p->info_type; pn_info_p++)
 
449
                if (pn_info_p->info_type == type)
 
450
                        return pn_info_p;
 
451
        fatalx("pn_find_info: unknown info type: 0x%x", type);
 
452
        return NULL;
 
453
}
 
454
 
 
455
/* find description of INFO_ element. */
 
456
struct netvars_t *pn_find_netvar(int type)
 
457
{
 
458
        struct netvars_t *netvar;
 
459
 
 
460
        for (netvar = &netvars[0]; netvar->name; netvar++) {
 
461
                if (netvar->type == type)
 
462
                        return netvar;
 
463
        }
 
464
        fatalx("pn_find_netvar: unknown netvar type: 0x%x", type);
 
465
        return NULL;
 
466
}
 
467
 
 
468
/* find description of CMD_ element. */
 
469
struct instcmds_t *pn_find_instcmd(int cmd)
 
470
{
 
471
        struct instcmds_t *instcmd;
 
472
 
 
473
        for (instcmd = &instcmds[0]; instcmd->name; instcmd++) {
 
474
                if (instcmd->cmd == cmd)
 
475
                        return instcmd;
 
476
        }
 
477
        fatalx("pn_find_instcmd: unknown instcmd: 0x%x", cmd);
 
478
        return NULL;
 
479
}
 
480
 
 
481
/* -----------------------------------------------------------
 
482
 * some logic here.
 
483
 * ----------------------------------------------------------- */
 
484
 
 
485
/* walk ups variables and set elements of the info array. */
 
486
void pn_ups_walk(int mode)
 
487
{
 
488
        static unsigned long iterations = 0;
 
489
 
 
490
        pn_info_t *pn_info_p;
 
491
        bool status;
 
492
        struct netvars_t *netvar;
 
493
        
 
494
        pn_status_init();
 
495
 
 
496
        for (pn_info_p = &pn_info[0]; pn_info_p->info_type; pn_info_p++) {
 
497
 
 
498
                /* skip instcmd. */
 
499
                if (pn_info_p->info_type & PN_CMD_MASK)
 
500
                        continue;
 
501
 
 
502
                /* skip elements we shouldn't show. */
 
503
                if (!(pn_info_p->flags & PN_FLAG_OK))
 
504
                        continue;
 
505
 
 
506
                /* skip static elements in update mode. */
 
507
                if (mode == PN_WALKMODE_UPDATE && 
 
508
                                pn_info_p->flags & PN_FLAG_STATIC)
 
509
                        continue;
 
510
 
 
511
                /* set default value if we cannot fetch it */
 
512
                /* and set static flag on this element. */
 
513
                if (pn_info_p->flags & PN_FLAG_ABSENT) {
 
514
                        if (mode == PN_WALKMODE_INIT) {
 
515
                                if (pn_info_p->dfl) {
 
516
                                        /* Set default value if we cannot fetch it from ups. */
 
517
                                        pn_setinfo(pn_info_p->info_type, pn_info_p->dfl,
 
518
                                                pn_info_p->info_flags, pn_info_p->info_len);
 
519
                                }
 
520
                                pn_info_p->flags |= PN_FLAG_STATIC;
 
521
                        }
 
522
                        continue;
 
523
                }
 
524
 
 
525
                /* check stale elements only on each PN_STALE_RETRY iteration. */
 
526
                if ((pn_info_p->flags & PN_FLAG_STALE) &&
 
527
                                (iterations % PN_STALE_RETRY) != 0)
 
528
                        continue;
 
529
 
 
530
                /* ok, update this element. */
 
531
 
 
532
                status = pn_ups_get(pn_info_p);
 
533
 
 
534
                /* set stale flag if data is stale, clear if not. */
 
535
                if (status == TRUE) {
 
536
                        if (pn_info_p->flags & PN_FLAG_STALE) {
 
537
                                netvar = pn_find_netvar(pn_info_p->info_type);
 
538
                                upslogx(LOG_INFO, "[%s] pn_ups_walk: data resumed for %s",
 
539
                                        upsname, netvar->name);
 
540
                        }
 
541
                        pn_info_p->flags &= ~PN_FLAG_STALE;
 
542
                } else {
 
543
                        if (!(pn_info_p->flags & PN_FLAG_STALE)) {
 
544
                                netvar = pn_find_netvar(pn_info_p->info_type);
 
545
                                upslogx(LOG_INFO, "[%s] pn_ups_walk: data stale for %s",
 
546
                                        upsname, netvar->name);
 
547
                        }
 
548
                        pn_info_p->flags |= PN_FLAG_STALE;
 
549
                }
 
550
 
 
551
        }       /* for (pn_info_p... */
 
552
 
 
553
        pn_status_commit();
 
554
 
 
555
        iterations++;
 
556
}
 
557
 
 
558
bool pn_ups_get(pn_info_t *pn_info_p)
 
559
{
 
560
        static char buf[PN_INFOSIZE];
 
561
        bool status;
 
562
        long value;
 
563
 
 
564
        switch (pn_info_p->info_type) {
 
565
 
 
566
        case INFO_STATUS:
 
567
                status = pn_snmp_get_int(pn_info_p->OID, &value);
 
568
                if (status == TRUE)
 
569
                        pn_status_set(pn_info_p, value);
 
570
 
 
571
                break;
 
572
 
 
573
        case INFO_SLFTSTRES:
 
574
                status = pn_snmp_get_int(pn_info_p->OID, &value);
 
575
                if (status == TRUE) {
 
576
                        static char *slftstres[] = 
 
577
                                { "OK", "FAILED", "TEST INVALID", "INPROGRESS" };
 
578
 
 
579
                        if (value >= 1 && value <= 4)
 
580
                                pn_setinfo(pn_info_p->info_type, slftstres[value - 1],
 
581
                                        pn_info_p->info_flags, pn_info_p->info_len);
 
582
                }
 
583
                break;
 
584
 
 
585
        case INFO_RUNTIME:
 
586
                status = pn_snmp_get_int(pn_info_p->OID, &value);
 
587
                if (status == TRUE) {
 
588
                        /* convert seconds to minutes. */
 
589
                        snprintf(buf, sizeof(buf), "%ld", value / 60);
 
590
                        pn_setinfo(pn_info_p->info_type, buf,
 
591
                                pn_info_p->info_flags, pn_info_p->info_len);
 
592
                }
 
593
                break;
 
594
 
 
595
        case INFO_LINESENS:
 
596
                status = pn_snmp_get_int(pn_info_p->OID, &value);
 
597
                if (status == TRUE) {
 
598
                        if (value >= 1 && value <= 4) {
 
599
                                static char *linesens[] = { "A", "L", "M", "H" };
 
600
                                pn_setinfo(pn_info_p->info_type, linesens[value - 1],
 
601
                                        pn_info_p->info_flags, pn_info_p->info_len);
 
602
                        }
 
603
                }
 
604
                break;
 
605
 
 
606
        default:
 
607
                /* get snmp OID value. */
 
608
                status = pn_snmp_get_str(pn_info_p->OID,
 
609
                        buf, sizeof(buf));
 
610
 
 
611
                if (status == TRUE) {
 
612
                        pn_setinfo(pn_info_p->info_type, buf,
 
613
                                pn_info_p->info_flags, pn_info_p->info_len);
 
614
                }
 
615
                break;
 
616
        }       /* switch (pn_info_p->info_type) */
 
617
 
 
618
        return status;
 
619
}
 
620
 
 
621
/* set r/w INFO_ element to a value. */
 
622
void pn_ups_set(int type, int data_len, char *data)
 
623
{
 
624
        pn_info_t *pn_info_p;
 
625
        bool ret;
 
626
        struct netvars_t *netvar;
 
627
 
 
628
        pn_info_p = pn_find_info(type);
 
629
        netvar = pn_find_netvar(type);
 
630
 
 
631
        upslogx(LOG_INFO, "[%s] setting variable %s to %s",
 
632
                upsname, netvar->name, data);
 
633
 
 
634
        if (pn_info_p == NULL || pn_info_p->info_type == 0 ||
 
635
                !(pn_info_p->flags & PN_FLAG_OK))
 
636
        {
 
637
                upslogx(LOG_ERR, "[%s] pn_ups_set: info element unavailable %s",
 
638
                        upsname, netvar->name);
 
639
                return;
 
640
        }
 
641
 
 
642
        if (! (pn_info_p->info_flags & FLAG_RW) || pn_info_p->OID == NULL) {
 
643
                upslogx(LOG_ERR, "[%s] pn_ups_set: not writable %s",
 
644
                        upsname, netvar->name);
 
645
                return;
 
646
        }
 
647
 
 
648
        /* set value. */
 
649
 
 
650
        if (PN_TYPE(pn_info_p) == PN_TYPE_STRING) {
 
651
                ret = pn_snmp_set_str(pn_info_p->OID, data);
 
652
        } else if (PN_TYPE(pn_info_p) == PN_TYPE_TIME) {
 
653
                ret = pn_snmp_set_time(pn_info_p->OID, strtol(data, NULL, 0));
 
654
        } else {
 
655
                switch (pn_info_p->info_type) {
 
656
                case INFO_LINESENS: /* convert letter to int */
 
657
                        {
 
658
                                int i;
 
659
                                static char *linesens[] = { "A", "L", "M", "H" };
 
660
 
 
661
                                ret = FALSE;
 
662
                                for (i = 1; i <= 4; i++) {
 
663
                                        if (!strcasecmp(linesens[i - 1],data)) {
 
664
                                                ret = pn_snmp_set_int(pn_info_p->OID, i);
 
665
                                                break;
 
666
                                        }
 
667
                                }
 
668
                        }
 
669
                        break;
 
670
                default:
 
671
                        ret = pn_snmp_set_int(pn_info_p->OID, strtol(data, NULL, 0));
 
672
                }
 
673
        }
 
674
 
 
675
        if (ret == FALSE)
 
676
                upslogx(LOG_ERR, "[%s] pn_ups_set: cannot set value %s for %s",
 
677
                        upsname, data, pn_info_p->OID);
 
678
 
 
679
        /* update info array. */
 
680
        pn_setinfo(type, data, pn_info_p->info_flags, pn_info_p->info_len);
 
681
}
 
682
 
 
683
/* process instant command and take action. */
 
684
void pn_ups_instcmd(int auxcmd, int data_len, char *data)
 
685
{
 
686
        pn_info_t *pn_info_p;
 
687
        int status;
 
688
        struct instcmds_t *instcmd;
 
689
 
 
690
        pn_info_p = pn_find_info(auxcmd);
 
691
        instcmd = pn_find_instcmd(auxcmd);
 
692
 
 
693
        upslogx(LOG_INFO, "[%s] sending instant command %s",
 
694
                upsname, instcmd->name);
 
695
 
 
696
        if (pn_info_p->info_type == 0 || !(pn_info_p->flags & PN_FLAG_OK) ||
 
697
                pn_info_p->OID == NULL)
 
698
        {
 
699
                upslogx(LOG_ERR, "[%s] pn_ups_instcmd: %s unavailable",
 
700
                        upsname, instcmd->name);
 
701
                return;
 
702
        }
 
703
 
 
704
        /* set value. */
 
705
 
 
706
        if (pn_info_p->info_flags & FLAG_STRING) {
 
707
                status = pn_snmp_set_str(pn_info_p->OID, pn_info_p->dfl);
 
708
        } else {
 
709
                status = pn_snmp_set_int(pn_info_p->OID, pn_info_p->info_len);
 
710
        }
 
711
 
 
712
        if (status == FALSE)
 
713
                upslogx(LOG_ERR, "[%s] pn_ups_instcmd: cannot set value for %s",
 
714
                        upsname, instcmd->name);
 
715
}
 
716
 
 
717
/* do the shutdown immediately. */
 
718
void pn_shutdown_ups(void)
 
719
{
 
720
        int sdtype = 0;
 
721
        long pwr_status;
 
722
 
 
723
        if (pn_snmp_get_int(OID_POWER_STATUS, &pwr_status) == FALSE)
 
724
                fatalx("cannot determine UPS status");
 
725
 
 
726
        if (testvar(PN_VAR_SDTYPE))
 
727
                sdtype = atoi(getval(PN_VAR_SDTYPE));
 
728
 
 
729
        /* logic from newapc.c */
 
730
        switch (sdtype) {
 
731
        case 3:         /* shutdown with grace period */
 
732
                pn_ups_instcmd(CMD_SHUTDOWN, 0, 0);
 
733
                break;
 
734
        case 2:         /* instant shutdown */
 
735
                pn_ups_instcmd(CMD_OFF, 0, 0);
 
736
                break;
 
737
        case 1:
 
738
                /* Send a combined set of shutdown commands which can work better */
 
739
                /* if the UPS gets power during shutdown process */
 
740
                /* Specifically it sends both the soft shutdown 'S' */
 
741
                /* and the powerdown after grace period - '@000' commands */
 
742
                upslogx(LOG_INFO, "[%s] UPS - sending shutdown/powerdown",
 
743
                        upsname);
 
744
                if (pwr_status == PWR_BATTERY)
 
745
                        pn_ups_instcmd(CMD_SOFTDOWN, 0, 0);
 
746
                pn_ups_instcmd(CMD_SDRET, 0, 0);
 
747
                break;
 
748
        default:
 
749
                /* if on battery... */
 
750
                if (pwr_status == PWR_BATTERY) {
 
751
                        upslogx(LOG_INFO,
 
752
                                "[%s] UPS is on battery, sending shutdown command...",
 
753
                                upsname);
 
754
                        pn_ups_instcmd(CMD_SOFTDOWN, 0, 0);
 
755
                } else {
 
756
                        upslogx(LOG_INFO,
 
757
                                "[%s] UPS is online, sending shutdown+return command...",
 
758
                                upsname);
 
759
                        pn_ups_instcmd(CMD_SDRET, 0, 0);
 
760
                }
 
761
                break;
 
762
        }
 
763
}
 
764
 
 
765
/* ---------------------------------------------
 
766
 * driver functions implementations
 
767
 * --------------------------------------------- */
 
768
 
 
769
void upsdrv_initinfo(void)
 
770
{
 
771
        /* add instant commands to the info database. */
 
772
        pn_init_instcmds();
 
773
 
 
774
        /* set habdlers for instcmds and set commands. */
 
775
        pn_setuphandlers();
 
776
 
 
777
        /* initialize all INFO_ fields */
 
778
        pn_ups_walk(PN_WALKMODE_INIT);
 
779
}
 
780
 
 
781
void upsdrv_updateinfo(void)
 
782
{
 
783
        /* update all dynamic info fields */
 
784
        pn_ups_walk(PN_WALKMODE_UPDATE);
 
785
}
 
786
 
 
787
/* do the shutdown immediately and cleanup for exit. */
 
788
/* upsdrv_initups already called, but upsdrv_initinfo isn't. */
 
789
void upsdrv_shutdown(void)
 
790
{
 
791
        pn_shutdown_ups();
 
792
        pn_cleanup();
 
793
}
 
794
 
 
795
void upsdrv_help(void)
 
796
{
 
797
        printf("\nShutdown types:\n");
 
798
        printf("  0: soft shutdown or powerdown, depending on battery status\n");
 
799
        printf("  1: soft shutdown followed by powerdown\n");
 
800
        printf("  2: instant power off\n");
 
801
        printf("  3: power off with grace period\n");
 
802
        printf("Modes 0-1 will make the UPS come back when power returns\n");
 
803
        printf("Modes 2-3 will make the UPS stay turned off when power returns\n");
 
804
}
 
805
 
 
806
/* list flags and values that you want to receive via -x */
 
807
void upsdrv_makevartable(void)
 
808
{
 
809
        addvar(VAR_VALUE, PN_VAR_SDTYPE,
 
810
                "Specify shutdown type (1-3, default 0)");
 
811
        addvar(VAR_VALUE, PN_VAR_COMMUNITY,
 
812
                "Set SNMP community name (default=public)");
 
813
}
 
814
 
 
815
void upsdrv_banner(void)
 
816
{
 
817
        upslogx(1,"Network UPS Tools %s APC Powernet SNMP driver %s",
 
818
                UPS_VERSION, PN_UPSDRV_VERSION);
 
819
}
 
820
 
 
821
void upsdrv_initups(void)
 
822
{
 
823
        pn_info_t *pn_info_p;
 
824
        char model[PN_INFOSIZE];
 
825
        bool status;
 
826
 
 
827
        /* init SNMP library, etc... */
 
828
        pn_startup();
 
829
 
 
830
        /* get value of UPS model OID */
 
831
        pn_info_p = pn_find_info(INFO_MODEL);
 
832
        status = pn_snmp_get_str(pn_info_p->OID, model, sizeof(model));
 
833
        if (status == TRUE)
 
834
                upslogx(0, "detected %s on host %s", model, device_path);
 
835
        else
 
836
                fatalx("Powernet MIB %s wasn't found on %s",
 
837
                        OID_POWERNET_MIB, g_snmp_sess.peername);   
 
838
}
 
839
 
 
840
void upsdrv_cleanup(void)
 
841
{
 
842
}