~ampelbein/ubuntu/oneiric/heartbeat/lp-770743

« back to all changes in this revision

Viewing changes to lib/plugins/stonith/apcmaster.c

  • Committer: Bazaar Package Importer
  • Author(s): Ante Karamatic
  • Date: 2010-02-17 21:59:18 UTC
  • mfrom: (1.1.11 upstream)
  • Revision ID: james.westby@ubuntu.com-20100217215918-06paxph5do4saw8v
Tags: 3.0.2-0ubuntu1
* New upstream release
* Drop hard dep on pacemaker for heartbet; moved to Recommends
* debian/heartbeat.install:
  - follow upstream changes
* debian/control:
  - added docbook-xsl and xsltproc to build depends

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
*
3
 
*  Copyright 2001 Mission Critical Linux, Inc.
4
 
*
5
 
*  All Rights Reserved.
6
 
*/
7
 
/*
8
 
 *      Stonith module for APC Master Switch (AP9211)
9
 
 *
10
 
 *  Copyright (c) 2001 Mission Critical Linux, Inc.
11
 
 *  author: mike ledoux <mwl@mclinux.com>
12
 
 *  author: Todd Wheeling <wheeling@mclinux.com>
13
 
 *  mangled by Sun Jiang Dong, <sunjd@cn.ibm.com>, IBM, 2005
14
 
 *
15
 
 *  Based strongly on original code from baytech.c by Alan Robertson.
16
 
 *
17
 
 * This library is free software; you can redistribute it and/or
18
 
 * modify it under the terms of the GNU Lesser General Public
19
 
 * License as published by the Free Software Foundation; either
20
 
 * version 2.1 of the License, or (at your option) any later version.
21
 
 * 
22
 
 * This library is distributed in the hope that it will be useful,
23
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
 
 * Lesser General Public License for more details.
26
 
 * 
27
 
 * You should have received a copy of the GNU Lesser General Public
28
 
 * License along with this library; if not, write to the Free Software
29
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
30
 
 *
31
 
 */
32
 
 
33
 
/*                          Observations/Notes
34
 
 * 
35
 
 * 1. The APC MasterSwitch, unlike the BayTech network power switch,
36
 
 *    accepts only one (telnet) connection/session at a time. When one
37
 
 *    session is active, any subsequent attempt to connect to the MasterSwitch 
38
 
 *    will result in a connection refused/closed failure. In a cluster 
39
 
 *    environment or other environment utilizing polling/monitoring of the 
40
 
 *    MasterSwitch (from multiple nodes), this can clearly cause problems. 
41
 
 *    Obviously the more nodes and the shorter the polling interval, the more 
42
 
 *    frequently such errors/collisions may occur.
43
 
 *
44
 
 * 2. We observed that on busy networks where there may be high occurances
45
 
 *    of broadcasts, the MasterSwitch became unresponsive.  In some 
46
 
 *    configurations this necessitated placing the power switch onto a 
47
 
 *    private subnet.
48
 
 */
49
 
 
50
 
#include <lha_internal.h>
51
 
 
52
 
#define DEVICE  "APC MasterSwitch"
53
 
 
54
 
#define DOESNT_USE_STONITHKILLCOMM      1
55
 
 
56
 
#include "stonith_plugin_common.h"
57
 
 
58
 
#define PIL_PLUGIN              apcmaster
59
 
#define PIL_PLUGIN_S            "apcmaster"
60
 
#define PIL_PLUGINLICENSE       LICENSE_LGPL
61
 
#define PIL_PLUGINLICENSEURL    URL_LGPL
62
 
#include <pils/plugin.h>
63
 
 
64
 
#include "stonith_signal.h"
65
 
 
66
 
static StonithPlugin *  apcmaster_new(const char *);
67
 
static void             apcmaster_destroy(StonithPlugin *);
68
 
static const char **    apcmaster_get_confignames(StonithPlugin *);
69
 
static int              apcmaster_set_config(StonithPlugin *, StonithNVpair *);
70
 
static const char *     apcmaster_getinfo(StonithPlugin * s, int InfoType);
71
 
static int              apcmaster_status(StonithPlugin * );
72
 
static int              apcmaster_reset_req(StonithPlugin * s, int request, const char * host);
73
 
static char **          apcmaster_hostlist(StonithPlugin  *);
74
 
 
75
 
static struct stonith_ops apcmasterOps ={
76
 
        apcmaster_new,          /* Create new STONITH object    */
77
 
        apcmaster_destroy,              /* Destroy STONITH object       */
78
 
        apcmaster_getinfo,              /* Return STONITH info string   */
79
 
        apcmaster_get_confignames,      /* Get configuration parameters */
80
 
        apcmaster_set_config,           /* Set configuration */
81
 
        apcmaster_status,               /* Return STONITH device status */
82
 
        apcmaster_reset_req,            /* Request a reset */
83
 
        apcmaster_hostlist,             /* Return list of supported hosts */
84
 
};
85
 
 
86
 
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
87
 
 
88
 
static const PILPluginImports*  PluginImports;
89
 
static PILPlugin*               OurPlugin;
90
 
static PILInterface*            OurInterface;
91
 
static StonithImports*          OurImports;
92
 
static void*                    interfprivate;
93
 
 
94
 
#include "stonith_expect_helpers.h"
95
 
 
96
 
PIL_rc
97
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
98
 
 
99
 
PIL_rc
100
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
101
 
{
102
 
        /* Force the compiler to do a little type checking */
103
 
        (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
104
 
 
105
 
        PluginImports = imports;
106
 
        OurPlugin = us;
107
 
 
108
 
        /* Register ourself as a plugin */
109
 
        imports->register_plugin(us, &OurPIExports);  
110
 
 
111
 
        /*  Register our interface implementation */
112
 
        return imports->register_interface(us, PIL_PLUGINTYPE_S
113
 
        ,       PIL_PLUGIN_S
114
 
        ,       &apcmasterOps
115
 
        ,       NULL            /*close */
116
 
        ,       &OurInterface
117
 
        ,       (void*)&OurImports
118
 
        ,       &interfprivate); 
119
 
}
120
 
 
121
 
/*
122
 
 *      I have an AP9211.  This code has been tested with this switch.
123
 
 */
124
 
 
125
 
struct pluginDevice {
126
 
        StonithPlugin   sp;
127
 
        const char *    pluginid;
128
 
        const char *    idinfo;
129
 
        pid_t           pid;
130
 
        int             rdfd;
131
 
        int             wrfd;
132
 
        char *          device;
133
 
        char *          user;
134
 
        char *          passwd;
135
 
};
136
 
 
137
 
static const char * pluginid = "APCMS-Stonith";
138
 
static const char * NOTpluginID = "APCMS device has been destroyed";
139
 
 
140
 
/*
141
 
 *      Different expect strings that we get from the APC MasterSwitch
142
 
 */
143
 
 
144
 
#define APCMSSTR        "American Power Conversion"
145
 
 
146
 
static struct Etoken EscapeChar[] =     { {"Escape character is '^]'.", 0, 0}
147
 
                                        ,       {NULL,0,0}};
148
 
static struct Etoken login[] =          { {"User Name :", 0, 0}, {NULL,0,0}};
149
 
static struct Etoken password[] =       { {"Password  :", 0, 0} ,{NULL,0,0}};
150
 
static struct Etoken Prompt[] = { {"> ", 0, 0} ,{NULL,0,0}};
151
 
static struct Etoken LoginOK[] =        { {APCMSSTR, 0, 0}
152
 
                    , {"User Name :", 1, 0} ,{NULL,0,0}};
153
 
static struct Etoken Separator[] =      { {"-----", 0, 0} ,{NULL,0,0}};
154
 
 
155
 
/* We may get a notice about rebooting, or a request for confirmation */
156
 
static struct Etoken Processing[] =     { {"Press <ENTER> to continue", 0, 0}
157
 
                                ,       {"Enter 'YES' to continue", 1, 0}
158
 
                                ,       {NULL,0,0}};
159
 
 
160
 
#include "stonith_config_xml.h"
161
 
 
162
 
static const char *apcmasterXML = 
163
 
  XML_PARAMETERS_BEGIN
164
 
    XML_IPADDR_PARM
165
 
    XML_LOGIN_PARM
166
 
    XML_PASSWD_PARM
167
 
  XML_PARAMETERS_END;
168
 
 
169
 
static int      MS_connect_device(struct pluginDevice * ms);
170
 
static int      MSLogin(struct pluginDevice * ms);
171
 
static int      MSRobustLogin(struct pluginDevice * ms);
172
 
static int      MSNametoOutlet(struct pluginDevice*, const char * name);
173
 
static int      MSReset(struct pluginDevice*, int outletNum, const char * host);
174
 
static int      MSLogout(struct pluginDevice * ms);
175
 
 
176
 
#if defined(ST_POWERON) && defined(ST_POWEROFF)
177
 
static int      apcmaster_onoff(struct pluginDevice*, int outletnum, const char * unitid
178
 
,               int request);
179
 
#endif
180
 
 
181
 
/* Login to the APC Master Switch */
182
 
 
183
 
static int
184
 
MSLogin(struct pluginDevice * ms)
185
 
{
186
 
        EXPECT(ms->rdfd, EscapeChar, 10);
187
 
 
188
 
        /* 
189
 
         * We should be looking at something like this:
190
 
         *      User Name :
191
 
         */
192
 
        EXPECT(ms->rdfd, login, 10);
193
 
        SEND(ms->wrfd, ms->user);       
194
 
        SEND(ms->wrfd, "\r");
195
 
 
196
 
        /* Expect "Password  :" */
197
 
        EXPECT(ms->rdfd, password, 10);
198
 
        SEND(ms->wrfd, ms->passwd);
199
 
        SEND(ms->wrfd, "\r");
200
 
 
201
 
        switch (StonithLookFor(ms->rdfd, LoginOK, 30)) {
202
 
 
203
 
                case 0: /* Good! */
204
 
                        LOG(PIL_INFO, "Successful login to %s.", ms->idinfo); 
205
 
                        break;
206
 
 
207
 
                case 1: /* Uh-oh - bad password */
208
 
                        LOG(PIL_CRIT, "Invalid password for %s.", ms->idinfo);
209
 
                        return(S_ACCESS);
210
 
 
211
 
                default:
212
 
                        return(errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS);
213
 
        } 
214
 
 
215
 
        return(S_OK);
216
 
}
217
 
 
218
 
/* Attempt to login up to 20 times... */
219
 
 
220
 
static int
221
 
MSRobustLogin(struct pluginDevice * ms)
222
 
{
223
 
        int rc = S_OOPS;
224
 
        int j = 0;
225
 
 
226
 
        for ( ; ; ) {
227
 
          if (MS_connect_device(ms) == S_OK) {  
228
 
                rc = MSLogin(ms);
229
 
                if( rc == S_OK ) {
230
 
                        break;
231
 
                }
232
 
          }
233
 
          if ((++j) == 20) {
234
 
                break;
235
 
          } else {
236
 
                sleep(1);
237
 
          }
238
 
        }
239
 
 
240
 
        return rc;
241
 
}
242
 
 
243
 
/* Log out of the APC Master Switch */
244
 
 
245
 
static 
246
 
int MSLogout(struct pluginDevice* ms)
247
 
{
248
 
        int     rc;
249
 
 
250
 
        /* Make sure we're in the right menu... */
251
 
        /*SEND(ms->wrfd, "\033\033\033\033\033\033\033"); */
252
 
        SEND(ms->wrfd, "\033");
253
 
        EXPECT(ms->rdfd, Prompt, 5);
254
 
        SEND(ms->wrfd, "\033");
255
 
        EXPECT(ms->rdfd, Prompt, 5);
256
 
        SEND(ms->wrfd, "\033");
257
 
        EXPECT(ms->rdfd, Prompt, 5);
258
 
        SEND(ms->wrfd, "\033");
259
 
        EXPECT(ms->rdfd, Prompt, 5);
260
 
        SEND(ms->wrfd, "\033");
261
 
        
262
 
        /* Expect "> " */
263
 
        rc = StonithLookFor(ms->rdfd, Prompt, 5);
264
 
 
265
 
        /* "4" is logout */
266
 
        SEND(ms->wrfd, "4\r");
267
 
 
268
 
        close(ms->wrfd);
269
 
        close(ms->rdfd);
270
 
        ms->wrfd = ms->rdfd = -1;
271
 
 
272
 
        return(rc >= 0 ? S_OK : (errno == ETIMEDOUT ? S_TIMEOUT : S_OOPS));
273
 
}
274
 
/* Reset (power-cycle) the given outlets */
275
 
static int
276
 
MSReset(struct pluginDevice* ms, int outletNum, const char *host)
277
 
{
278
 
        char            unum[32];
279
 
 
280
 
        /* Make sure we're in the top level menu */
281
 
        SEND(ms->wrfd, "\033");
282
 
        EXPECT(ms->rdfd, Prompt, 5);
283
 
        SEND(ms->wrfd, "\033");
284
 
        EXPECT(ms->rdfd, Prompt, 5);
285
 
        SEND(ms->wrfd, "\033");
286
 
        EXPECT(ms->rdfd, Prompt, 5);
287
 
        SEND(ms->wrfd, "\033");
288
 
        EXPECT(ms->rdfd, Prompt, 5);
289
 
        SEND(ms->wrfd, "\033");
290
 
        
291
 
        /* Expect ">" */
292
 
        EXPECT(ms->rdfd, Prompt, 5);
293
 
 
294
 
        /* Request menu 1 (Device Control) */
295
 
        SEND(ms->wrfd, "1\r");
296
 
 
297
 
        /* Select requested outlet */
298
 
        EXPECT(ms->rdfd, Prompt, 5);
299
 
        snprintf(unum, sizeof(unum), "%i\r", outletNum);
300
 
        SEND(ms->wrfd, unum);
301
 
 
302
 
        /* Select menu 1 (Control Outlet) */
303
 
        EXPECT(ms->rdfd, Prompt, 5);
304
 
        SEND(ms->wrfd, "1\r");
305
 
 
306
 
        /* Select menu 3 (Immediate Reboot) */
307
 
        EXPECT(ms->rdfd, Prompt, 5);
308
 
        SEND(ms->wrfd, "3\r");
309
 
 
310
 
        /* Expect "Press <ENTER> " or "Enter 'YES'" (if confirmation turned on) */
311
 
        retry:
312
 
        switch (StonithLookFor(ms->rdfd, Processing, 5)) {
313
 
                case 0: /* Got "Press <ENTER>" Do so */
314
 
                        SEND(ms->wrfd, "\r");
315
 
                        break;
316
 
 
317
 
                case 1: /* Got that annoying command confirmation :-( */
318
 
                        SEND(ms->wrfd, "YES\r");
319
 
                        goto retry;
320
 
 
321
 
                default: 
322
 
                        return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
323
 
        }
324
 
 
325
 
        
326
 
        LOG(PIL_INFO, "Host being rebooted: %s", host); 
327
 
 
328
 
        /* Expect ">" */
329
 
        if (StonithLookFor(ms->rdfd, Prompt, 10) < 0) {
330
 
                return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
331
 
        }
332
 
 
333
 
        /* All Right!  Power is back on.  Life is Good! */
334
 
 
335
 
        LOG(PIL_INFO, "Power restored to host: %s", host);
336
 
 
337
 
        /* Return to top level menu */
338
 
        SEND(ms->wrfd, "\033");
339
 
        EXPECT(ms->rdfd, Prompt, 5);
340
 
        SEND(ms->wrfd, "\033");
341
 
        EXPECT(ms->rdfd, Prompt, 5);
342
 
        SEND(ms->wrfd, "\033");
343
 
        EXPECT(ms->rdfd, Prompt, 5);
344
 
        SEND(ms->wrfd, "\033");
345
 
        EXPECT(ms->rdfd, Prompt, 5);
346
 
        SEND(ms->wrfd, "\033");
347
 
        EXPECT(ms->rdfd, Prompt, 5);
348
 
        SEND(ms->wrfd, "\033");
349
 
 
350
 
        return(S_OK);
351
 
}
352
 
 
353
 
#if defined(ST_POWERON) && defined(ST_POWEROFF)
354
 
static int
355
 
apcmaster_onoff(struct pluginDevice* ms, int outletNum, const char * unitid, int req)
356
 
{
357
 
        char            unum[32];
358
 
 
359
 
        const char *    onoff = (req == ST_POWERON ? "1\r" : "2\r");
360
 
        int     rc;
361
 
 
362
 
        if ((rc = MSRobustLogin(ms) != S_OK)) {
363
 
                LOG(PIL_CRIT, "Cannot log into %s.", ms->idinfo);
364
 
                return(rc);
365
 
        }
366
 
        
367
 
        /* Make sure we're in the top level menu */
368
 
        SEND(ms->wrfd, "\033");
369
 
        EXPECT(ms->rdfd, Prompt, 5);
370
 
        SEND(ms->wrfd, "\033");
371
 
        EXPECT(ms->rdfd, Prompt, 5);
372
 
        SEND(ms->wrfd, "\033");
373
 
        EXPECT(ms->rdfd, Prompt, 5);
374
 
        SEND(ms->wrfd, "\033");
375
 
        EXPECT(ms->rdfd, Prompt, 5);
376
 
        SEND(ms->wrfd, "\033");
377
 
 
378
 
        /* Expect ">" */
379
 
        EXPECT(ms->rdfd, Prompt, 5);
380
 
 
381
 
        /* Request menu 1 (Device Control) */
382
 
        SEND(ms->wrfd, "1\r");
383
 
 
384
 
        /* Select requested outlet */
385
 
        snprintf(unum, sizeof(unum), "%d\r", outletNum); 
386
 
        SEND(ms->wrfd, unum); 
387
 
 
388
 
        /* Select menu 1 (Control Outlet) */
389
 
        SEND(ms->wrfd, "1\r");
390
 
 
391
 
        /* Send ON/OFF command for given outlet */
392
 
        SEND(ms->wrfd, onoff);
393
 
 
394
 
        /* Expect "Press <ENTER> " or "Enter 'YES'" (if confirmation turned on) */
395
 
        retry:
396
 
        switch (StonithLookFor(ms->rdfd, Processing, 5)) {
397
 
                case 0: /* Got "Press <ENTER>" Do so */
398
 
                        SEND(ms->wrfd, "\r");
399
 
                        break;
400
 
 
401
 
                case 1: /* Got that annoying command confirmation :-( */
402
 
                        SEND(ms->wrfd, "YES\r");
403
 
                        goto retry;
404
 
 
405
 
                default: 
406
 
                        return(errno == ETIMEDOUT ? S_RESETFAIL : S_OOPS);
407
 
        }
408
 
        
409
 
        EXPECT(ms->rdfd, Prompt, 10);
410
 
 
411
 
        /* All Right!  Command done. Life is Good! */
412
 
        LOG(PIL_INFO, "Power to MS outlet(s) %d turned %s", outletNum, onoff);
413
 
        /* Pop back to main menu */
414
 
        SEND(ms->wrfd, "\033\033\033\033\033\033\033\r");
415
 
        return(S_OK);
416
 
}
417
 
#endif /* defined(ST_POWERON) && defined(ST_POWEROFF) */
418
 
 
419
 
/*
420
 
 *      Map the given host name into an (AC) Outlet number on the power strip
421
 
 */
422
 
 
423
 
static int
424
 
MSNametoOutlet(struct pluginDevice* ms, const char * name)
425
 
{
426
 
        char    NameMapping[128];
427
 
        int     sockno;
428
 
        char    sockname[32];
429
 
        int times = 0;
430
 
        int ret = -1;
431
 
 
432
 
        /* Verify that we're in the top-level menu */
433
 
        EXPECT(ms->rdfd, Prompt, 5);
434
 
        SEND(ms->wrfd, "\033");
435
 
        EXPECT(ms->rdfd, Prompt, 5);
436
 
        SEND(ms->wrfd, "\033"); 
437
 
        EXPECT(ms->rdfd, Prompt, 5);
438
 
        SEND(ms->wrfd, "\033");
439
 
        EXPECT(ms->rdfd, Prompt, 5);
440
 
        SEND(ms->wrfd, "\033");
441
 
 
442
 
        /* Expect ">" */
443
 
        EXPECT(ms->rdfd, Prompt, 5);
444
 
        
445
 
        /* Request menu 1 (Device Control) */
446
 
        SEND(ms->wrfd, "1\r");
447
 
 
448
 
        /* Expect: "-----" so we can skip over it... */
449
 
        EXPECT(ms->rdfd, Separator, 5);
450
 
        EXPECT(ms->rdfd, CRNL, 5);
451
 
        EXPECT(ms->rdfd, CRNL, 5);
452
 
 
453
 
        /* Looks Good!  Parse the status output */
454
 
 
455
 
        do {
456
 
                times++;
457
 
                NameMapping[0] = EOS;
458
 
                SNARF(ms->rdfd, NameMapping, 5);
459
 
                if (sscanf(NameMapping
460
 
                ,       "%d- %23c",&sockno, sockname) == 2) {
461
 
 
462
 
                        char *  last = sockname+23;
463
 
                        *last = EOS;
464
 
                        --last;
465
 
 
466
 
                        /* Strip off trailing blanks */
467
 
                        for(; last > sockname; --last) {
468
 
                                if (*last == ' ') {
469
 
                                        *last = EOS;
470
 
                                }else{
471
 
                                        break;
472
 
                                }
473
 
                        }
474
 
                        if (strcasecmp(name, sockname) == 0) {
475
 
                                ret = sockno;
476
 
                        }
477
 
                }
478
 
        } while (strlen(NameMapping) > 2 && times < 8);
479
 
 
480
 
        /* Pop back out to the top level menu */
481
 
        EXPECT(ms->rdfd, Prompt, 5);
482
 
        SEND(ms->wrfd, "\033");
483
 
        EXPECT(ms->rdfd, Prompt, 5);
484
 
        SEND(ms->wrfd, "\033"); 
485
 
        EXPECT(ms->rdfd, Prompt, 5);
486
 
        SEND(ms->wrfd, "\033");
487
 
        EXPECT(ms->rdfd, Prompt, 5);
488
 
        SEND(ms->wrfd, "\033");
489
 
        return(ret);
490
 
}
491
 
 
492
 
static int
493
 
apcmaster_status(StonithPlugin  *s)
494
 
{
495
 
        struct pluginDevice*    ms;
496
 
        int     rc;
497
 
 
498
 
        ERRIFNOTCONFIGED(s,S_OOPS);
499
 
 
500
 
        ms = (struct pluginDevice*) s;
501
 
 
502
 
        if ((rc = MSRobustLogin(ms) != S_OK)) {
503
 
                LOG(PIL_CRIT, "Cannot log into %s.", ms->idinfo);
504
 
                return(rc);
505
 
        }
506
 
 
507
 
        /* Expect ">" */
508
 
        SEND(ms->wrfd, "\033\r");
509
 
        EXPECT(ms->rdfd, Prompt, 5);
510
 
 
511
 
        return(MSLogout(ms));
512
 
}
513
 
 
514
 
/*
515
 
 *      Return the list of hosts (outlet names) for the devices on this MS unit
516
 
 */
517
 
 
518
 
static char **
519
 
apcmaster_hostlist(StonithPlugin  *s)
520
 
{
521
 
        char            NameMapping[128];
522
 
        char*           NameList[64];
523
 
        unsigned int    numnames = 0;
524
 
        char **         ret = NULL;
525
 
        struct pluginDevice*    ms;
526
 
        unsigned int    i;
527
 
 
528
 
        ERRIFNOTCONFIGED(s,NULL);
529
 
 
530
 
        ms = (struct pluginDevice*) s;
531
 
                
532
 
        if (MSRobustLogin(ms) != S_OK) {
533
 
                LOG(PIL_CRIT, "Cannot log into %s.", ms->idinfo);
534
 
                return(NULL);
535
 
        }
536
 
 
537
 
        /* Expect ">" */
538
 
        NULLEXPECT(ms->rdfd, Prompt, 10);
539
 
 
540
 
        /* Request menu 1 (Device Control) */
541
 
        SEND(ms->wrfd, "1\r");
542
 
 
543
 
        /* Expect: "-----" so we can skip over it... */
544
 
        NULLEXPECT(ms->rdfd, Separator, 5);
545
 
        NULLEXPECT(ms->rdfd, CRNL, 5);
546
 
        NULLEXPECT(ms->rdfd, CRNL, 5);
547
 
 
548
 
        /* Looks Good!  Parse the status output */
549
 
        do {
550
 
                int     sockno;
551
 
                char    sockname[64];
552
 
                NameMapping[0] = EOS;
553
 
                NULLSNARF(ms->rdfd, NameMapping, 5);
554
 
                if (sscanf(NameMapping
555
 
                ,       "%d- %23c",&sockno, sockname) == 2) {
556
 
 
557
 
                        char *  last = sockname+23;
558
 
                        char *  nm;
559
 
                        *last = EOS;
560
 
                        --last;
561
 
 
562
 
                        /* Strip off trailing blanks */
563
 
                        for(; last > sockname; --last) {
564
 
                                if (*last == ' ') {
565
 
                                        *last = EOS;
566
 
                                }else{
567
 
                                        break;
568
 
                                }
569
 
                        }
570
 
                        if (numnames >= DIMOF(NameList)-1) {
571
 
                                break;
572
 
                        }
573
 
                        if ((nm = (char*)STRDUP(sockname)) == NULL) {
574
 
                                goto out_of_memory;
575
 
                        }
576
 
                        g_strdown(nm);
577
 
                        NameList[numnames] = nm;
578
 
                        ++numnames;
579
 
                        NameList[numnames] = NULL;
580
 
                }
581
 
        } while (strlen(NameMapping) > 2);
582
 
 
583
 
        /* Pop back out to the top level menu */
584
 
        SEND(ms->wrfd, "\033");
585
 
        NULLEXPECT(ms->rdfd, Prompt, 10);
586
 
        SEND(ms->wrfd, "\033");
587
 
        NULLEXPECT(ms->rdfd, Prompt, 10);
588
 
        SEND(ms->wrfd, "\033");
589
 
        NULLEXPECT(ms->rdfd, Prompt, 10);
590
 
        SEND(ms->wrfd, "\033");
591
 
        NULLEXPECT(ms->rdfd, Prompt, 10);
592
 
      
593
 
 
594
 
        if (numnames >= 1) {
595
 
                ret = (char **)MALLOC((numnames+1)*sizeof(char*));
596
 
                if (ret == NULL) {
597
 
                        goto out_of_memory;
598
 
                }else{
599
 
                        memcpy(ret, NameList, (numnames+1)*sizeof(char*));
600
 
                }
601
 
        }
602
 
        (void)MSLogout(ms);
603
 
        return(ret);
604
 
 
605
 
out_of_memory:
606
 
        LOG(PIL_CRIT, "out of memory");
607
 
        for (i=0; i<numnames; i++) {
608
 
                FREE(NameList[i]);
609
 
        }
610
 
        return(NULL);
611
 
}
612
 
 
613
 
/*
614
 
 *      Connect to the given MS device.  We should add serial support here
615
 
 *      eventually...
616
 
 */
617
 
static int
618
 
MS_connect_device(struct pluginDevice * ms)
619
 
{
620
 
        int fd = OurImports->OpenStreamSocket(ms->device
621
 
        ,       TELNET_PORT, TELNET_SERVICE);
622
 
 
623
 
        if (fd < 0) {
624
 
                return(S_OOPS);
625
 
        }
626
 
        ms->rdfd = ms->wrfd = fd;
627
 
        return(S_OK);
628
 
}
629
 
 
630
 
/*
631
 
 *      Reset the given host on this StonithPlugin device.  
632
 
 */
633
 
static int
634
 
apcmaster_reset_req(StonithPlugin * s, int request, const char * host)
635
 
{
636
 
        int     rc = 0;
637
 
        int     lorc = 0;
638
 
        struct pluginDevice*    ms;
639
 
 
640
 
        ERRIFNOTCONFIGED(s,S_OOPS);
641
 
 
642
 
        ms = (struct pluginDevice*) s;
643
 
 
644
 
        if ((rc = MSRobustLogin(ms)) != S_OK) {
645
 
                LOG(PIL_CRIT, "Cannot log into %s.", ms->idinfo);
646
 
                return(rc);
647
 
        }else{
648
 
                int noutlet; 
649
 
                noutlet = MSNametoOutlet(ms, host);
650
 
                if (noutlet < 1) {
651
 
                        LOG(PIL_WARN, "%s doesn't control host [%s]"
652
 
                        ,       ms->device, host);
653
 
                        return(S_BADHOST);
654
 
                }
655
 
                switch(request) {
656
 
 
657
 
#if defined(ST_POWERON) && defined(ST_POWEROFF)
658
 
                case ST_POWERON:
659
 
                        rc = apcmaster_onoff(ms, noutlet, host, request);
660
 
                        break;
661
 
                case ST_POWEROFF:
662
 
                        rc = apcmaster_onoff(ms, noutlet, host, request);
663
 
                        break;
664
 
#endif
665
 
                case ST_GENERIC_RESET:
666
 
                        rc = MSReset(ms, noutlet, host);
667
 
                        break;
668
 
                default:
669
 
                        rc = S_INVAL;
670
 
                        break;
671
 
                }
672
 
        }
673
 
 
674
 
        lorc = MSLogout(ms);
675
 
        return(rc != S_OK ? rc : lorc);
676
 
}
677
 
 
678
 
/*
679
 
 *      Get the configuration parameters names
680
 
 */
681
 
static const char **
682
 
apcmaster_get_confignames(StonithPlugin * s)
683
 
{
684
 
        static const char * ret[] = {ST_IPADDR, ST_LOGIN, ST_PASSWD, NULL};
685
 
        return ret;
686
 
}
687
 
 
688
 
/*
689
 
 *      Set the configuration parameters
690
 
 */
691
 
static int
692
 
apcmaster_set_config(StonithPlugin * s, StonithNVpair * list)
693
 
{
694
 
        struct pluginDevice* sd = (struct pluginDevice *)s;
695
 
        int             rc;
696
 
        StonithNamesToGet       namestocopy [] =
697
 
        {       {ST_IPADDR,     NULL}
698
 
        ,       {ST_LOGIN,      NULL}
699
 
        ,       {ST_PASSWD,     NULL}
700
 
        ,       {NULL,          NULL}
701
 
        };
702
 
 
703
 
        ERRIFWRONGDEV(s, S_OOPS);
704
 
        if (sd->sp.isconfigured) {
705
 
                return S_OOPS;
706
 
        }
707
 
 
708
 
        if ((rc=OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
709
 
                return rc;
710
 
        }
711
 
        sd->device = namestocopy[0].s_value;
712
 
        sd->user = namestocopy[1].s_value;
713
 
        sd->passwd = namestocopy[2].s_value;
714
 
 
715
 
        return(S_OK);
716
 
}
717
 
 
718
 
static const char *
719
 
apcmaster_getinfo(StonithPlugin * s, int reqtype)
720
 
{
721
 
        struct pluginDevice* ms;
722
 
        const char *            ret;
723
 
 
724
 
        ERRIFWRONGDEV(s,NULL);
725
 
 
726
 
        /*
727
 
         *      We look in the ST_TEXTDOMAIN catalog for our messages
728
 
         */
729
 
        ms = (struct pluginDevice *)s;
730
 
 
731
 
        switch (reqtype) {
732
 
                case ST_DEVICEID:
733
 
                        ret = ms->idinfo;
734
 
                        break;
735
 
 
736
 
                case ST_DEVICENAME:             /* Which particular device? */
737
 
                        ret = ms->device;
738
 
                        break;
739
 
 
740
 
                case ST_DEVICEDESCR:
741
 
                        ret = "APC MasterSwitch (via telnet)\n"
742
 
                        "NOTE: The APC MasterSwitch accepts only one (telnet)\n"
743
 
                        "connection/session a time. When one session is active,\n"
744
 
                        "subsequent attempts to connect to the MasterSwitch"
745
 
                        " will fail.";
746
 
                        break;
747
 
 
748
 
                case ST_DEVICEURL:
749
 
                        ret = "http://www.apc.com/";
750
 
                        break;
751
 
 
752
 
                case ST_CONF_XML:               /* XML metadata */
753
 
                        ret = apcmasterXML;
754
 
                        break;
755
 
 
756
 
                default:
757
 
                        ret = NULL;
758
 
                        break;
759
 
        }
760
 
        return ret;
761
 
}
762
 
 
763
 
/*
764
 
 *      APC MasterSwitch StonithPlugin destructor...
765
 
 */
766
 
static void
767
 
apcmaster_destroy(StonithPlugin *s)
768
 
{
769
 
        struct pluginDevice* ms;
770
 
 
771
 
        VOIDERRIFWRONGDEV(s);
772
 
 
773
 
        ms = (struct pluginDevice *)s;
774
 
 
775
 
        ms->pluginid = NOTpluginID;
776
 
        if (ms->rdfd >= 0) {
777
 
                close(ms->rdfd);
778
 
                ms->rdfd = -1;
779
 
        }
780
 
        if (ms->wrfd >= 0) {
781
 
                close(ms->wrfd);
782
 
                ms->wrfd = -1;
783
 
        }
784
 
        if (ms->device != NULL) {
785
 
                FREE(ms->device);
786
 
                ms->device = NULL;
787
 
        }
788
 
        if (ms->user != NULL) {
789
 
                FREE(ms->user);
790
 
                ms->user = NULL;
791
 
        }
792
 
        if (ms->passwd != NULL) {
793
 
                FREE(ms->passwd);
794
 
                ms->passwd = NULL;
795
 
        }
796
 
        FREE(ms);
797
 
}
798
 
 
799
 
/* Create a new APC Master Switch StonithPlugin device. */
800
 
 
801
 
static StonithPlugin *
802
 
apcmaster_new(const char *subplugin)
803
 
{
804
 
        struct pluginDevice*    ms = ST_MALLOCT(struct pluginDevice);
805
 
 
806
 
        if (ms == NULL) {
807
 
                LOG(PIL_CRIT, "out of memory");
808
 
                return(NULL);
809
 
        }
810
 
        memset(ms, 0, sizeof(*ms));
811
 
        ms->pluginid = pluginid;
812
 
        ms->pid = -1;
813
 
        ms->rdfd = -1;
814
 
        ms->wrfd = -1;
815
 
        ms->user = NULL;
816
 
        ms->device = NULL;
817
 
        ms->passwd = NULL;
818
 
        ms->idinfo = DEVICE;
819
 
        ms->sp.s_ops = &apcmasterOps;
820
 
 
821
 
        return(&(ms->sp));
822
 
}