~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): Reinhard Tartler
  • Date: 2005-07-20 19:48:50 UTC
  • mto: (16.1.1 squeeze)
  • mto: This revision was merged to the branch mainline in revision 4.
  • Revision ID: james.westby@ubuntu.com-20050720194850-oo61wjr33rrx2mre
Tags: upstream-2.0.2
ImportĀ upstreamĀ versionĀ 2.0.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
 
}