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

« back to all changes in this revision

Viewing changes to lib/plugins/stonith/nw_rpc100s.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
 
 *      Stonith module for Night/Ware RPC100S 
3
 
 *
4
 
 *      Original code from baytech.c by
5
 
 *      Copyright (c) 2000 Alan Robertson <alanr@unix.sh>
6
 
 *
7
 
 *      Modifications for NW RPC100S
8
 
 *      Copyright (c) 2000 Computer Generation Incorporated
9
 
 *               Eric Z. Ayers <eric.ayers@compgen.com>
10
 
 *
11
 
 *      Mangled by Zhaokai <zhaokai@cn.ibm.com>, IBM, 2005
12
 
 *
13
 
 * This library is free software; you can redistribute it and/or
14
 
 * modify it under the terms of the GNU Lesser General Public
15
 
 * License as published by the Free Software Foundation; either
16
 
 * version 2.1 of the License, or (at your option) any later version.
17
 
 * 
18
 
 * This library is distributed in the hope that it will be useful,
19
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21
 
 * Lesser General Public License for more details.
22
 
 * 
23
 
 * You should have received a copy of the GNU Lesser General Public
24
 
 * License along with this library; if not, write to the Free Software
25
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
 
 *
27
 
 */
28
 
 
29
 
#include <lha_internal.h>
30
 
#define DEVICE  "NW RPC100S Power Switch"
31
 
#include "stonith_plugin_common.h"
32
 
 
33
 
#define PIL_PLUGIN              nw_rpc100s
34
 
#define PIL_PLUGIN_S            "nw_rpc100s"
35
 
#define PIL_PLUGINLICENSE       LICENSE_LGPL
36
 
#define PIL_PLUGINLICENSEURL    URL_LGPL
37
 
#define MAX_CFGLINE             256
38
 
#include <pils/plugin.h>
39
 
 
40
 
static StonithPlugin *  nw_rpc100s_new(const char *);
41
 
static void             nw_rpc100s_destroy(StonithPlugin *);
42
 
static int              nw_rpc100s_set_config(StonithPlugin *, StonithNVpair *);
43
 
static const char**     nw_rpc100s_get_confignames(StonithPlugin *);
44
 
static const char *     nw_rpc100s_getinfo(StonithPlugin * s, int InfoType);
45
 
static int              nw_rpc100s_status(StonithPlugin * );
46
 
static int              nw_rpc100s_reset_req(StonithPlugin * s, int request, const char * host);
47
 
static char **          nw_rpc100s_hostlist(StonithPlugin  *);
48
 
 
49
 
static struct stonith_ops nw_rpc100sOps ={
50
 
        nw_rpc100s_new,         /* Create new STONITH object            */
51
 
        nw_rpc100s_destroy,     /* Destroy STONITH object               */
52
 
        nw_rpc100s_getinfo,     /* Return STONITH info string           */
53
 
        nw_rpc100s_get_confignames,/* Return STONITH info string        */
54
 
        nw_rpc100s_set_config,  /* Get configuration from NVpairs       */
55
 
        nw_rpc100s_status,      /* Return STONITH device status         */
56
 
        nw_rpc100s_reset_req,   /* Request a reset                      */
57
 
        nw_rpc100s_hostlist,    /* Return list of supported hosts       */
58
 
};
59
 
 
60
 
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
61
 
static const PILPluginImports*  PluginImports;
62
 
static PILPlugin*               OurPlugin;
63
 
static PILInterface*            OurInterface;
64
 
static StonithImports*          OurImports;
65
 
static void*                    interfprivate;
66
 
 
67
 
#include "stonith_signal.h"
68
 
 
69
 
#define DOESNT_USE_STONITHKILLCOMM
70
 
#define DOESNT_USE_STONITHSCANLINE
71
 
#include "stonith_expect_helpers.h"
72
 
 
73
 
PIL_rc
74
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
75
 
 
76
 
PIL_rc
77
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
78
 
{
79
 
        /* Force the compiler to do a little type checking */
80
 
        (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
81
 
 
82
 
        PluginImports = imports;
83
 
        OurPlugin = us;
84
 
 
85
 
        /* Register ourself as a plugin */
86
 
        imports->register_plugin(us, &OurPIExports);  
87
 
 
88
 
        /*  Register our interface implementation */
89
 
        return imports->register_interface(us, PIL_PLUGINTYPE_S
90
 
        ,       PIL_PLUGIN_S
91
 
        ,       &nw_rpc100sOps
92
 
        ,       NULL            /*close */
93
 
        ,       &OurInterface
94
 
        ,       (void*)&OurImports
95
 
        ,       &interfprivate); 
96
 
}
97
 
 
98
 
/*
99
 
   The Nightware RPS-100S is manufactured by:
100
 
   
101
 
      Micro Energetics Corp
102
 
      +1 703 250-3000
103
 
      http://www.nightware.com/
104
 
 
105
 
   Thank you to David Hicks of Micro Energetics Corp. for providing
106
 
   a demo unit to write this software.
107
 
      
108
 
   This switch has a very simple protocol, 
109
 
   You issue a command and it  gives a response.
110
 
   Sample commands are conveniently documented on a sticker on the
111
 
      bottom of the device.
112
 
      
113
 
   The switch accepts a single command of the form
114
 
 
115
 
   //0,yyy,zzz[/m][/h]<CR>
116
 
   
117
 
     Where yyy is the wait time before activiting the relay.
118
 
           zzz is the relay time.
119
 
 
120
 
     The default is that the relay is in a default state of ON, which
121
 
     means that  usually yyy is the number of seconds to wait
122
 
     before shutting off the power  and zzz is the number of seconds the
123
 
     power remains off.  There is a dip switch to change the default
124
 
     state to 'OFF'.  Don't set this switch. It will screw up this code. 
125
 
 
126
 
     An asterisk can be used for zzz to specify an infinite switch time.
127
 
     The /m /and /h command options will convert the specified wait and
128
 
     switch times to either minutewes or hours. 
129
 
   
130
 
   A response is either
131
 
    <cr><lf>OK<cr><lf>
132
 
       or
133
 
    <cr><lf>Invalid Entry<cr><lf>
134
 
 
135
 
 
136
 
   As far as THIS software is concerned, we have to implement 4 commands:
137
 
 
138
 
   status     -->    //0,0,BOGUS; # Not a real command, this is just a
139
 
                                  #   probe to see if switch is alive
140
 
   open(on)   -->    //0,0,0;     # turn power to default state (on)
141
 
   close(off) -->    //0,0,*;     # leave power off indefinitely
142
 
   reboot     -->    //0,0,10;    # immediately turn power off for 10 seconds.
143
 
 
144
 
   and expect the response 'OK' to confirm that the unit is operational.
145
 
*/
146
 
 
147
 
 
148
 
 
149
 
struct pluginDevice {
150
 
        StonithPlugin   sp;
151
 
        const char *    pluginid;
152
 
        const char *    idinfo;
153
 
 
154
 
        int     fd;      /* FD open to the serial port */
155
 
 
156
 
        char *  device;  /* Serial device name to use to communicate 
157
 
                            to this RPS10
158
 
                         */
159
 
 
160
 
        char *  node;    /* Name of the node that this is controlling */
161
 
 
162
 
};
163
 
 
164
 
/* This string is used to identify this type of object in the config file */
165
 
static const char * pluginid = "NW_RPC100S";
166
 
static const char * NOTrpcid = "NW RPC100S device has been destroyed";
167
 
 
168
 
#include "stonith_config_xml.h"
169
 
 
170
 
static const char *nw_rpc100sXML = 
171
 
  XML_PARAMETERS_BEGIN
172
 
    XML_TTYDEV_PARM
173
 
    XML_HOSTLIST_PARM
174
 
  XML_PARAMETERS_END;
175
 
 
176
 
/*
177
 
 *      Different expect strings that we get from the NW_RPC100S
178
 
 *      Remote Power Controllers...
179
 
 */
180
 
 
181
 
static struct Etoken NWtokOK[] =        { {"OK", 0, 0}, {NULL,0,0}};
182
 
static struct Etoken NWtokInvalidEntry[] = { {"Invalid Entry", 0, 0}, {NULL,0,0}};
183
 
/* Accept either a CR/NL or an NL/CR */
184
 
static struct Etoken NWtokCRNL[] =      { {"\n\r",0,0},{"\r\n",0,0},{NULL,0,0}};
185
 
 
186
 
static int      RPCConnect(struct pluginDevice * ctx);
187
 
static int      RPCDisconnect(struct pluginDevice * ctx);
188
 
 
189
 
static int      RPCReset(struct pluginDevice*, int unitnum, const char * rebootid);
190
 
#if defined(ST_POWERON) 
191
 
static int      RPCOn(struct pluginDevice*, int unitnum, const char * rebootid);
192
 
#endif
193
 
#if defined(ST_POWEROFF) 
194
 
static int      RPCOff(struct pluginDevice*, int unitnum, const char * rebootid);
195
 
#endif
196
 
static int      RPCNametoOutlet ( struct pluginDevice * ctx, const char * host );
197
 
 
198
 
/*static int RPC_parse_config_info(struct pluginDevice* ctx, const char * info);*/
199
 
 
200
 
 
201
 
#define        SENDCMD(cmd, timeout)              {                     \
202
 
                int return_val = RPCSendCommand(ctx, cmd, timeout);     \
203
 
                if (return_val != S_OK) {                               \
204
 
                        return return_val;                              \
205
 
                }                                                       \
206
 
        }
207
 
 
208
 
/*
209
 
 * RPCSendCommand - send a command to the specified outlet
210
 
 */
211
 
static int
212
 
RPCSendCommand (struct pluginDevice *ctx, const char *command, int timeout)
213
 
{
214
 
        char            writebuf[64]; /* All commands are short.
215
 
                                         They should be WAY LESS
216
 
                                         than 64 chars long!
217
 
                                      */
218
 
        int             return_val;  /* system call result */
219
 
        fd_set          rfds, wfds, xfds;
220
 
                                     /*  list of FDs for select() */
221
 
        struct timeval  tv;          /*  */
222
 
 
223
 
        FD_ZERO(&rfds);
224
 
        FD_ZERO(&wfds);
225
 
        FD_ZERO(&xfds);
226
 
 
227
 
        snprintf (writebuf, sizeof(writebuf), "%s\r", command);
228
 
 
229
 
        if (Debug) {
230
 
                LOG(PIL_DEBUG, "Sending %s", writebuf);
231
 
        }
232
 
 
233
 
        /* Make sure the serial port won't block on us. use select()  */
234
 
        FD_SET(ctx->fd, &wfds);
235
 
        FD_SET(ctx->fd, &xfds);
236
 
        
237
 
        tv.tv_sec = timeout;
238
 
        tv.tv_usec = 0;
239
 
        
240
 
        return_val = select(ctx->fd+1, NULL, &wfds,&xfds, &tv);
241
 
        if (return_val == 0) {
242
 
                /* timeout waiting on serial port */
243
 
                LOG(PIL_CRIT, "%s: Timeout writing to %s"
244
 
                ,       pluginid, ctx->device);
245
 
                return S_TIMEOUT;
246
 
        } else if ((return_val == -1) || FD_ISSET(ctx->fd, &xfds)) {
247
 
                /* an error occured */
248
 
                LOG(PIL_CRIT, "%s: Error before writing to %s: %s"
249
 
                ,       pluginid, ctx->device, strerror(errno));                
250
 
                return S_OOPS;
251
 
        }
252
 
 
253
 
        /* send the command */
254
 
        if (write(ctx->fd, writebuf, strlen(writebuf)) != 
255
 
                        (int)strlen(writebuf)) {
256
 
                LOG(PIL_CRIT, "%s: Error writing to  %s : %s"
257
 
                ,       pluginid, ctx->device, strerror(errno));
258
 
                return S_OOPS;
259
 
        }
260
 
 
261
 
        /* suceeded! */
262
 
        return S_OK;
263
 
 
264
 
}  /* end RPCSendCommand() */
265
 
 
266
 
/* 
267
 
 * RPCReset - Reset (power-cycle) the given outlet number
268
 
 *
269
 
 * This device can only control one power outlet - unitnum is ignored.
270
 
 *
271
 
 */
272
 
static int
273
 
RPCReset(struct pluginDevice* ctx, int unitnum, const char * rebootid)
274
 
{
275
 
 
276
 
        if (Debug) {
277
 
                LOG(PIL_DEBUG, "Calling RPCReset (%s)", pluginid);
278
 
        }
279
 
        
280
 
        if (ctx->fd < 0) {
281
 
                LOG(PIL_CRIT, "%s: device %s is not open!", pluginid
282
 
                ,       ctx->device);
283
 
                return S_OOPS;
284
 
        }
285
 
 
286
 
        /* send the "toggle power" command */
287
 
        SENDCMD("//0,0,10;\r\n", 12);
288
 
 
289
 
        /* Expect "OK" */
290
 
        EXPECT(ctx->fd, NWtokOK, 5);
291
 
        if (Debug) {
292
 
                LOG(PIL_DEBUG, "Got OK");
293
 
        }
294
 
        EXPECT(ctx->fd, NWtokCRNL, 2);
295
 
        if (Debug) {
296
 
                LOG(PIL_DEBUG, "Got NL");
297
 
        }
298
 
        
299
 
        return(S_OK);
300
 
 
301
 
} /* end RPCReset() */
302
 
 
303
 
 
304
 
#if defined(ST_POWERON) 
305
 
/* 
306
 
 * RPCOn - Turn OFF the given outlet number 
307
 
 */
308
 
static int
309
 
RPCOn(struct pluginDevice* ctx, int unitnum, const char * host)
310
 
{
311
 
 
312
 
        if (ctx->fd < 0) {
313
 
                LOG(PIL_CRIT, "%s: device %s is not open!", pluginid
314
 
                ,       ctx->device);
315
 
                return S_OOPS;
316
 
        }
317
 
 
318
 
        /* send the "On" command */
319
 
        SENDCMD("//0,0,0;\r\n", 10);
320
 
 
321
 
        /* Expect "OK" */
322
 
        EXPECT(ctx->fd, NWtokOK, 5);
323
 
        EXPECT(ctx->fd, NWtokCRNL, 2);
324
 
 
325
 
        return(S_OK);
326
 
 
327
 
} /* end RPCOn() */
328
 
#endif
329
 
 
330
 
 
331
 
#if defined(ST_POWEROFF) 
332
 
/* 
333
 
 * RPCOff - Turn Off the given outlet number 
334
 
 */
335
 
static int
336
 
RPCOff(struct pluginDevice* ctx, int unitnum, const char * host)
337
 
{
338
 
 
339
 
        if (ctx->fd < 0) {
340
 
                LOG(PIL_CRIT, "%s: device %s is not open!", pluginid
341
 
                ,       ctx->device);
342
 
                return S_OOPS;
343
 
        }
344
 
 
345
 
        /* send the "Off" command */
346
 
        SENDCMD("//0,0,*;\r\n", 10);
347
 
 
348
 
        /* Expect "OK" */
349
 
        EXPECT(ctx->fd, NWtokOK, 5);
350
 
        EXPECT(ctx->fd, NWtokCRNL, 2);
351
 
 
352
 
        return(S_OK);
353
 
 
354
 
} /* end RPCOff() */
355
 
#endif
356
 
 
357
 
 
358
 
/*
359
 
 * nw_rpc100s_status - API entry point to probe the status of the stonith device 
360
 
 *           (basically just "is it reachable and functional?", not the
361
 
 *            status of the individual outlets)
362
 
 * 
363
 
 * Returns:
364
 
 *    S_OOPS - some error occured
365
 
 *    S_OK   - if the stonith device is reachable and online.
366
 
 */
367
 
static int
368
 
nw_rpc100s_status(StonithPlugin  *s)
369
 
{
370
 
        struct pluginDevice*    ctx;
371
 
        
372
 
        if (Debug) {
373
 
                LOG(PIL_DEBUG, "Calling nw_rpc100s_status (%s)", pluginid);
374
 
        }
375
 
        
376
 
        ERRIFNOTCONFIGED(s,S_OOPS);
377
 
 
378
 
        ctx = (struct pluginDevice*) s;
379
 
        if (RPCConnect(ctx) != S_OK) {
380
 
                return(S_OOPS);
381
 
        }
382
 
 
383
 
        /* The "connect" really does enough work to see if the 
384
 
           controller is alive...  It verifies that it is returning 
385
 
           RPS-10 Ready 
386
 
        */
387
 
 
388
 
        return(RPCDisconnect(ctx));
389
 
}
390
 
 
391
 
/*
392
 
 * nw_rpc100s_hostlist - API entry point to return the list of hosts 
393
 
 *                 for the devices on this NW_RPC100S unit
394
 
 * 
395
 
 *               This type of device is configured from the config file,
396
 
 *                 so we don't actually have to connect to figure this
397
 
 *                 out, just peruse the 'ctx' structure.
398
 
 * Returns:
399
 
 *     NULL on error
400
 
 *     a malloced array, terminated with a NULL,
401
 
 *         of null-terminated malloc'ed strings.
402
 
 */
403
 
static char **
404
 
nw_rpc100s_hostlist(StonithPlugin  *s)
405
 
{
406
 
        char **         ret = NULL;     /* list to return */
407
 
        struct pluginDevice*    ctx;
408
 
 
409
 
        if (Debug) {
410
 
                LOG(PIL_DEBUG, "Calling nw_rpc100s_hostlist (%s)", pluginid);
411
 
        }
412
 
        
413
 
        ERRIFNOTCONFIGED(s,NULL);
414
 
 
415
 
        ctx = (struct pluginDevice*) s;
416
 
 
417
 
        ret = OurImports->StringToHostList(ctx->node);
418
 
        if (ret == NULL) {
419
 
                LOG(PIL_CRIT, "%s: out of memory", __FUNCTION__);
420
 
        } else {
421
 
                g_strdown(ret[0]);
422
 
        }
423
 
 
424
 
        return(ret);
425
 
} /* end si_hostlist() */
426
 
 
427
 
/*
428
 
 *      Parse the given configuration information, and stash it away...
429
 
 *
430
 
 *      <info> contains the parameters specific to this type of object
431
 
 *
432
 
 *         The format of <parameters> for this module is:
433
 
 *            <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ...
434
 
 *
435
 
 *      e.g. A machine named 'nodea' can kill a machine named 'nodeb' through
436
 
 *           a device attached to serial port /dev/ttyS0.
437
 
 *           A machine named 'nodeb' can kill machines 'nodea' and 'nodec'
438
 
 *           through a device attached to serial port /dev/ttyS1 (outlets 0 
439
 
 *             and 1 respectively)
440
 
 *
441
 
 *      stonith nodea NW_RPC100S /dev/ttyS0 nodeb 0 
442
 
 *      stonith nodeb NW_RPC100S /dev/ttyS0 nodea 0 nodec 1
443
 
 *
444
 
 *      Another possible configuration is for 2 stonith devices accessible
445
 
 *         through 2 different serial ports on nodeb:
446
 
 *
447
 
 *      stonith nodeb NW_RPC100S /dev/ttyS0 nodea 0 
448
 
 *      stonith nodeb NW_RPC100S /dev/ttyS1 nodec 0
449
 
 */
450
 
 
451
 
/*static int
452
 
RPC_parse_config_info(struct pluginDevice* ctx, const char * info)
453
 
{
454
 
}*/
455
 
 
456
 
 
457
 
/*
458
 
 * RPCConnect -
459
 
 *
460
 
 * Connect to the given NW_RPC100S device.  
461
 
 * Side Effects
462
 
 *    ctx->fd now contains a valid file descriptor to the serial port
463
 
 *    ??? LOCK THE SERIAL PORT ???
464
 
 *  
465
 
 * Returns 
466
 
 *    S_OK on success
467
 
 *    S_OOPS on error
468
 
 *    S_TIMEOUT if the device did not respond
469
 
 *
470
 
 */
471
 
static int
472
 
RPCConnect(struct pluginDevice * ctx)
473
 
{
474
 
          
475
 
        /* Open the serial port if it isn't already open */
476
 
        if (ctx->fd < 0) {
477
 
                struct termios tio;
478
 
 
479
 
                if (OurImports->TtyLock(ctx->device) < 0) {
480
 
                        LOG(PIL_CRIT, "%s: TtyLock failed.", pluginid);
481
 
                        return S_OOPS;
482
 
                }
483
 
 
484
 
                ctx->fd = open (ctx->device, O_RDWR);
485
 
                if (ctx->fd <0) {
486
 
                        LOG(PIL_CRIT, "%s: Can't open %s : %s"
487
 
                        ,       pluginid, ctx->device, strerror(errno));
488
 
                        return S_OOPS;
489
 
                }
490
 
 
491
 
                /* set the baudrate to 9600 8 - N - 1 */
492
 
                memset (&tio, 0, sizeof(tio));
493
 
 
494
 
                /* ??? ALAN - the -tradtitional flag on gcc causes the 
495
 
                   CRTSCTS constant to generate a warning, and warnings 
496
 
                   are treated as errors, so I can't set this flag! - EZA ???
497
 
                   
498
 
                   Hmmm. now that I look at the documentation, RTS
499
 
                   is just wired high on this device! we don't need it.
500
 
                */
501
 
                /* tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CRTSCTS ;*/
502
 
                tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD ;
503
 
                tio.c_lflag = ICANON;
504
 
 
505
 
                if (tcsetattr (ctx->fd, TCSANOW, &tio) < 0) {
506
 
                        LOG(PIL_CRIT, "%s: Can't set attributes %s : %s"
507
 
                        ,       pluginid, ctx->device, strerror(errno));
508
 
                        close (ctx->fd);
509
 
                        OurImports->TtyUnlock(ctx->device);
510
 
                        ctx->fd=-1;
511
 
                        return S_OOPS;
512
 
                }
513
 
                /* flush all data to and fro the serial port before we start */
514
 
                if (tcflush (ctx->fd, TCIOFLUSH) < 0) {
515
 
                        LOG(PIL_CRIT, "%s: Can't flush %s : %s"
516
 
                        ,       pluginid, ctx->device, strerror(errno));
517
 
                        close (ctx->fd);
518
 
                        OurImports->TtyUnlock(ctx->device);
519
 
                        ctx->fd=-1;
520
 
                        return S_OOPS;          
521
 
                }
522
 
                
523
 
        }
524
 
 
525
 
 
526
 
        /* Send a BOGUS string */
527
 
        SENDCMD("//0,0,BOGUS;\r\n", 10);
528
 
        
529
 
        /* Should reply with "Invalid Command" */
530
 
        if (Debug) {
531
 
                LOG(PIL_DEBUG, "Waiting for \"Invalid Entry\"");
532
 
        }
533
 
        EXPECT(ctx->fd, NWtokInvalidEntry, 12);
534
 
        if (Debug) {
535
 
                LOG(PIL_DEBUG, "Got Invalid Entry");
536
 
        }
537
 
        EXPECT(ctx->fd, NWtokCRNL, 2);
538
 
        if (Debug) {
539
 
                LOG(PIL_DEBUG, "Got NL");
540
 
        }
541
 
           
542
 
  return(S_OK);
543
 
}
544
 
 
545
 
static int
546
 
RPCDisconnect(struct pluginDevice * ctx)
547
 
{
548
 
 
549
 
  if (ctx->fd >= 0) {
550
 
    /* Flush the serial port, we don't care what happens to the characters
551
 
       and failing to do this can cause close to hang.
552
 
    */
553
 
    tcflush(ctx->fd, TCIOFLUSH);
554
 
    close (ctx->fd);
555
 
    if (ctx->device != NULL) {
556
 
      OurImports->TtyUnlock(ctx->device);
557
 
    }
558
 
  }
559
 
  ctx->fd = -1;
560
 
 
561
 
  return S_OK;
562
 
563
 
 
564
 
/*
565
 
 * RPCNametoOutlet - Map a hostname to an outlet number on this stonith device.
566
 
 *
567
 
 * Returns:
568
 
 *     0 on success ( the outlet number on the RPS10 - there is only one )
569
 
 *     -1 on failure (host not found in the config file)
570
 
 * 
571
 
 */
572
 
static int
573
 
RPCNametoOutlet ( struct pluginDevice * ctx, const char * host )
574
 
{
575
 
        int rc = -1;
576
 
        
577
 
        if (!strcasecmp(ctx->node, host)) {
578
 
                rc = 0;
579
 
        }
580
 
 
581
 
        return rc;
582
 
}
583
 
 
584
 
 
585
 
/*
586
 
 *      nw_rpc100s_reset - API call to Reset (reboot) the given host on 
587
 
 *          this Stonith device.  This involves toggling the power off 
588
 
 *          and then on again, OR just calling the builtin reset command
589
 
 *          on the stonith device.
590
 
 */
591
 
static int
592
 
nw_rpc100s_reset_req(StonithPlugin * s, int request, const char * host)
593
 
{
594
 
        int     rc = S_OK;
595
 
        int     lorc = S_OK;
596
 
        int outletnum = -1;
597
 
        struct pluginDevice*    ctx;
598
 
        
599
 
        if (Debug) {
600
 
                LOG(PIL_DEBUG, "Calling nw_rpc100s_reset (%s)", pluginid);
601
 
        }
602
 
        
603
 
        ERRIFNOTCONFIGED(s,S_OOPS);
604
 
 
605
 
        ctx = (struct pluginDevice*) s;
606
 
 
607
 
        if ((rc = RPCConnect(ctx)) != S_OK) {
608
 
                return(rc);
609
 
        }
610
 
 
611
 
        outletnum = RPCNametoOutlet(ctx, host);
612
 
        LOG(PIL_DEBUG, "zk:outletname=%d", outletnum);
613
 
 
614
 
        if (outletnum < 0) {
615
 
                LOG(PIL_WARN, "%s doesn't control host [%s]"
616
 
                ,       ctx->device, host);
617
 
                RPCDisconnect(ctx);
618
 
                return(S_BADHOST);
619
 
        }
620
 
 
621
 
        switch(request) {
622
 
 
623
 
#if defined(ST_POWERON) 
624
 
                case ST_POWERON:
625
 
                        rc = RPCOn(ctx, outletnum, host);
626
 
                        break;
627
 
#endif
628
 
#if defined(ST_POWEROFF)
629
 
                case ST_POWEROFF:
630
 
                        rc = RPCOff(ctx, outletnum, host);
631
 
                        break;
632
 
#endif
633
 
        case ST_GENERIC_RESET:
634
 
                rc = RPCReset(ctx, outletnum, host);
635
 
                break;
636
 
        default:
637
 
                rc = S_INVAL;
638
 
                break;
639
 
        }
640
 
 
641
 
        lorc = RPCDisconnect(ctx);
642
 
 
643
 
        return(rc != S_OK ? rc : lorc);
644
 
}
645
 
 
646
 
/*
647
 
 *      Parse the information in the given string 
648
 
 *      and stash it away...
649
 
 */
650
 
static int
651
 
nw_rpc100s_set_config(StonithPlugin* s, StonithNVpair *list)
652
 
{
653
 
        struct pluginDevice*    ctx;
654
 
        StonithNamesToGet       namestocopy [] =
655
 
        {       {ST_TTYDEV,     NULL}
656
 
        ,       {ST_HOSTLIST,   NULL}
657
 
        ,       {NULL,          NULL}
658
 
        };
659
 
        int rc;
660
 
 
661
 
 
662
 
        ERRIFWRONGDEV(s,S_OOPS);
663
 
        if (s->isconfigured) {
664
 
                return S_OOPS;
665
 
        }
666
 
 
667
 
        ctx = (struct pluginDevice*) s;
668
 
        
669
 
        if ((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
670
 
                return rc;
671
 
        }
672
 
        ctx->device = namestocopy[0].s_value;
673
 
        ctx->node = namestocopy[1].s_value;
674
 
 
675
 
        return S_OK;
676
 
}
677
 
 
678
 
/*
679
 
 * Return STONITH config vars
680
 
 */
681
 
static const char **
682
 
nw_rpc100s_get_confignames(StonithPlugin* p)
683
 
{
684
 
        static const char *     RpcParams[] = {ST_TTYDEV , ST_HOSTLIST, NULL };
685
 
        return RpcParams;
686
 
}
687
 
 
688
 
 
689
 
 
690
 
/*
691
 
 * nw_rpc100s_getinfo - API entry point to retrieve something from the handle
692
 
 */
693
 
static const char *
694
 
nw_rpc100s_getinfo(StonithPlugin * s, int reqtype)
695
 
{
696
 
        struct pluginDevice* ctx;
697
 
        const char *            ret;
698
 
 
699
 
        ERRIFWRONGDEV(s,NULL);
700
 
 
701
 
        /*
702
 
         *      We look in the ST_TEXTDOMAIN catalog for our messages
703
 
         */
704
 
        ctx = (struct pluginDevice *)s;
705
 
 
706
 
        switch (reqtype) {
707
 
                case ST_DEVICEID:
708
 
                        ret = ctx->idinfo;
709
 
                        break;
710
 
                case ST_DEVICENAME:
711
 
                        ret = ctx->device;
712
 
                        break;
713
 
                case ST_DEVICEDESCR:
714
 
                        ret = "Micro Energetics Night/Ware RPC100S";
715
 
                        break;
716
 
                case ST_DEVICEURL:
717
 
                        ret = "http://www.microenergeticscorp.com/";
718
 
                        break;
719
 
                case ST_CONF_XML:               /* XML metadata */
720
 
                        ret = nw_rpc100sXML;
721
 
                        break;
722
 
                default:
723
 
                        ret = NULL;
724
 
                        break;
725
 
        }
726
 
        return ret;
727
 
}
728
 
 
729
 
/*
730
 
 * nw_rpc100s_destroy - API entry point to destroy a NW_RPC100S Stonith object.
731
 
 */
732
 
static void
733
 
nw_rpc100s_destroy(StonithPlugin *s)
734
 
{
735
 
        struct pluginDevice* ctx;
736
 
 
737
 
        VOIDERRIFWRONGDEV(s);
738
 
 
739
 
        ctx = (struct pluginDevice *)s;
740
 
 
741
 
        ctx->pluginid = NOTrpcid;
742
 
 
743
 
        /*  close the fd if open and set ctx->fd to invalid */
744
 
        RPCDisconnect(ctx);
745
 
        
746
 
        if (ctx->device != NULL) {
747
 
                FREE(ctx->device);
748
 
                ctx->device = NULL;
749
 
        }
750
 
        if (ctx->node != NULL) {
751
 
                FREE(ctx->node);
752
 
                ctx->node = NULL;
753
 
        }
754
 
        FREE(ctx);
755
 
}
756
 
 
757
 
/* 
758
 
 * nw_rpc100s_new - API entry point called to create a new NW_RPC100S Stonith
759
 
 * device object. 
760
 
 */
761
 
static StonithPlugin *
762
 
nw_rpc100s_new(const char *subplugin)
763
 
{
764
 
        struct pluginDevice*    ctx = ST_MALLOCT(struct pluginDevice);
765
 
 
766
 
        if (ctx == NULL) {
767
 
                LOG(PIL_CRIT, "out of memory");
768
 
                return(NULL);
769
 
        }
770
 
        memset(ctx, 0, sizeof(*ctx));
771
 
        ctx->pluginid = pluginid;
772
 
        ctx->fd = -1;
773
 
        ctx->device = NULL;
774
 
        ctx->node = NULL;
775
 
        ctx->idinfo = DEVICE;
776
 
        ctx->sp.s_ops = &nw_rpc100sOps;
777
 
 
778
 
        return &(ctx->sp);
779
 
}