2
* Stonith module for WTI Remote Power Controllers (RPS-10M device)
4
* Original code from baytech.c by
5
* Copyright (c) 2000 Alan Robertson <alanr@unix.sh>
7
* Modifications for WTI RPS10
8
* Copyright (c) 2000 Computer Generation Incorporated
9
* Eric Z. Ayers <eric.ayers@compgen.com>
11
* Mangled by Zhaokai <zhaokai@cn.ibm.com>, IBM, 2005
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.
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.
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
29
#include <lha_internal.h>
31
#define DEVICE "WTI RPS10 Power Switch"
32
#include "stonith_plugin_common.h"
35
#define PIL_PLUGIN rps10
36
#define PIL_PLUGIN_S "rps10"
37
#define PIL_PLUGINLICENSE LICENSE_LGPL
38
#define PIL_PLUGINLICENSEURL URL_LGPL
39
#define ST_RPS10 "serial_to_targets"
41
#include <pils/plugin.h>
43
static StonithPlugin * rps10_new(const char *);
44
static void rps10_destroy(StonithPlugin *);
45
static int rps10_set_config(StonithPlugin *, StonithNVpair *);
46
static const char** rps10_get_confignames(StonithPlugin *);
47
static const char * rps10_getinfo(StonithPlugin * s, int InfoType);
48
static int rps10_status(StonithPlugin * );
49
static int rps10_reset_req(StonithPlugin * s, int request, const char * host);
50
static char ** rps10_hostlist(StonithPlugin *);
52
static struct stonith_ops rps10Ops ={
53
rps10_new, /* Create new STONITH object */
54
rps10_destroy, /* Destroy STONITH object */
55
rps10_getinfo, /* Return STONITH info string */
56
rps10_get_confignames, /* Return STONITH info string */
57
rps10_set_config, /* Get configuration from NVpairs */
58
rps10_status, /* Return STONITH device status */
59
rps10_reset_req, /* Request a reset */
60
rps10_hostlist, /* Return list of supported hosts */
63
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
64
static const PILPluginImports* PluginImports;
65
static PILPlugin* OurPlugin;
66
static PILInterface* OurInterface;
67
static StonithImports* OurImports;
68
static void* interfprivate;
70
#include "stonith_signal.h"
71
#define DOESNT_USE_STONITHKILLCOMM
72
#define DOESNT_USE_STONITHSCANLINE
73
#include "stonith_expect_helpers.h"
76
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
79
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
81
/* Force the compiler to do a little type checking */
82
(void)(PILPluginInitFun)PIL_PLUGIN_INIT;
84
PluginImports = imports;
87
/* Register ourself as a plugin */
88
imports->register_plugin(us, &OurPIExports);
90
/* Register our interface implementation */
91
return imports->register_interface(us, PIL_PLUGINTYPE_S
101
* This was written for a Western Telematic Inc. (WTI)
102
* Remote Power Switch - RPS-10M.
104
* It has a DB9 serial port, a Rotary Address Switch,
105
* and a pair of RJ-11 jacks for linking multiple switches
106
* together. The 'M' unit is a master unit which can control
107
* up to 9 additional slave units. (the master unit also has an
108
* A/C outlet, so you can control up to 10 devices)
110
* There are a set of dip switches. The default shipping configuration
111
* is with all dip switches down. I highly recommend that you flip
112
* switch #3 up, so that when the device is plugged in, the power
113
* to the unit comes on.
115
* The serial interface is fixed at 9600 BPS (well, you *CAN*
116
* select 2400 BPS with a dip switch, but why?) 8-N-1
118
* The ASCII command string is:
122
* ^B^X^X^B^X^X "fixed password" prefix (CTRL-B CTRL-X ... )
123
* ^M the carriage return character
125
* a = 0-9 Indicates the address of the module to receive the command
126
* a = * Sends the command to all modules
128
* c = 0 Switch the AC outlet OFF
133
* c = 1 Switch the AC outlet ON
138
* c = T Toggle AC OFF (delay) then back ON
144
* c = ? Read and display status of the selected module
146
* Plug 0 On # or Plug 0 Off
149
* e.g. ^B^X^X^B^X^X0T^M toggles the power on plug 0 OFF and then ON
153
* Computer Generation, Inc.
157
char outlet_id; /* value 0-9, '*' */
158
char * node; /* name of the node attached to this outlet */
161
struct pluginDevice {
163
const char * pluginid;
166
int fd; /* FD open to the serial port */
168
char * device; /* Serial device name to use to communicate
172
#define WTI_NUM_CONTROLLERS 10
174
controllers[WTI_NUM_CONTROLLERS];
175
/* one master switch can address 10 controllers */
177
/* Number of actually configured units */
182
/* This string is used to identify this type of object in the config file */
183
static const char * pluginid = "WTI_RPS10";
184
static const char * NOTwtiid = "OBJECT DESTROYED: (WTI RPS-10)";
186
#include "stonith_config_xml.h"
188
#define XML_RPS10_SHORTDESC \
189
XML_PARM_SHORTDESC_BEGIN("en") \
190
"Value in the format \"serial_device remotenode outlet [remotenode outlet]...\"" \
191
XML_PARM_SHORTDESC_END
193
#define XML_RPS10_LONGDESC \
194
XML_PARM_LONGDESC_BEGIN("en") \
195
"The RPS-10 STONITH device configuration information in the format \"serial_device remotenode outlet [remotenode outlet]...\"" \
196
XML_PARM_LONGDESC_END
198
#define XML_RPS10_PARM \
199
XML_PARAMETER_BEGIN(ST_RPS10, "string", "1") \
200
XML_RPS10_SHORTDESC \
204
static const char *rps10XML =
209
/* WTIpassword - The fixed string ^B^X^X^B^X^X */
210
static const char WTIpassword[7] = {2,24,24,2,24,24,0};
213
* Different expect strings that we get from the WTI_RPS10
214
* Remote Power Controllers...
217
static struct Etoken WTItokReady[] = { {"RPS-10 Ready", 0, 0}, {NULL,0,0}};
218
static struct Etoken WTItokComplete[] = { {"Complete", 0, 0} ,{NULL,0,0}};
219
static struct Etoken WTItokPlug[] = { {"Plug", 0, 0}, {NULL,0,0}};
220
static struct Etoken WTItokOutlet[] = { {"0", 0, 0},
232
static struct Etoken WTItokOff[] = { {"Off", 0, 0}, {NULL,0,0}};
235
* Tokens currently not used because they don't show up on all RPS10 units:
238
static struct Etoken WTItokOn[] = { {"On", 0, 0}, {NULL,0,0}};
240
/* Accept either a CR/NL or an NL/CR */
241
static struct Etoken WTItokCRNL[] = { {"\n\r",0,0},{"\r\n",0,0},{NULL,0,0}};
243
static int RPSConnect(struct pluginDevice * ctx);
244
static int RPSDisconnect(struct pluginDevice * ctx);
246
static int RPSReset(struct pluginDevice*, char unit_id, const char * rebootid);
247
#if defined(ST_POWERON)
248
static int RPSOn(struct pluginDevice*, char unit_id, const char * rebootid);
250
#if defined(ST_POWEROFF)
251
static int RPSOff(struct pluginDevice*, char unit_id, const char * rebootid);
253
static signed char RPSNametoOutlet ( struct pluginDevice * ctx, const char * host );
255
static int RPS_parse_config_info(struct pluginDevice* ctx, const char * info);
257
#define SENDCMD(outlet, cmd, timeout) { \
258
int ret_val = RPSSendCommand(ctx, outlet, cmd, timeout);\
259
if (ret_val != S_OK) { \
265
* RPSSendCommand - send a command to the specified outlet
268
RPSSendCommand (struct pluginDevice *ctx, char outlet, char command, int timeout)
270
char writebuf[10]; /* all commands are 9 chars long! */
271
int return_val; /* system call result */
272
fd_set rfds, wfds, xfds;
273
struct timeval tv; /* */
275
/* list of FDs for select() */
277
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
284
snprintf (writebuf, sizeof(writebuf), "%s%c%c\r",
285
WTIpassword, outlet, command);
288
LOG(PIL_DEBUG, "Sending %s\n", writebuf);
291
/* Make sure the serial port won't block on us. use select() */
292
FD_SET(ctx->fd, &wfds);
293
FD_SET(ctx->fd, &xfds);
298
return_val = select(ctx->fd+1, NULL, &wfds,&xfds, &tv);
299
if (return_val == 0) {
300
/* timeout waiting on serial port */
301
LOG(PIL_CRIT, "%s: Timeout writing to %s",
302
pluginid, ctx->device);
304
} else if ((return_val == -1) || FD_ISSET(ctx->fd, &xfds)) {
305
/* an error occured */
306
LOG(PIL_CRIT, "%s: Error before writing to %s: %s",
307
pluginid, ctx->device, strerror(errno));
311
/* send the command */
312
if (write(ctx->fd, writebuf, strlen(writebuf)) !=
313
(int)strlen(writebuf)) {
314
LOG(PIL_CRIT, "%s: Error writing to %s : %s",
315
pluginid, ctx->device, strerror(errno));
322
} /* end RPSSendCommand() */
325
* RPSReset - Reset (power-cycle) the given outlet id
328
RPSReset(struct pluginDevice* ctx, char unit_id, const char * rebootid)
332
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
336
LOG(PIL_CRIT, "%s: device %s is not open!", pluginid,
341
/* send the "toggle power" command */
342
SENDCMD(unit_id, 'T', 10);
344
/* Expect "Plug 0 Off" */
345
/* Note: If asked to control "*", the RPS10 will report all units it
346
* separately; however, we don't know how many, so we can only wait
347
* for the first unit to report something and then wait until the
349
EXPECT(ctx->fd, WTItokPlug, 5);
351
LOG(PIL_DEBUG, "Got Plug\n");
353
EXPECT(ctx->fd, WTItokOutlet, 2);
355
LOG(PIL_DEBUG, "Got Outlet #\n");
357
EXPECT(ctx->fd, WTItokOff, 2);
359
LOG(PIL_DEBUG, "Got Off\n");
361
EXPECT(ctx->fd, WTItokCRNL, 2);
362
LOG(PIL_INFO, "Host is being rebooted: %s", rebootid);
364
/* Expect "Complete" */
365
EXPECT(ctx->fd, WTItokComplete, 14);
367
LOG(PIL_DEBUG, "Got Complete\n");
369
EXPECT(ctx->fd, WTItokCRNL, 2);
371
LOG(PIL_DEBUG, "Got NL\n");
376
} /* end RPSReset() */
379
#if defined(ST_POWERON)
381
* RPSOn - Turn OFF the given outlet id
384
RPSOn(struct pluginDevice* ctx, char unit_id, const char * host)
387
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
391
LOG(PIL_CRIT, "%s: device %s is not open!", pluginid,
396
/* send the "On" command */
397
SENDCMD(unit_id, '1', 10);
399
/* Expect "Plug 0 On" */
400
EXPECT(ctx->fd, WTItokPlug, 5);
401
EXPECT(ctx->fd, WTItokOutlet, 2);
402
EXPECT(ctx->fd, WTItokOn, 2);
403
EXPECT(ctx->fd, WTItokCRNL, 2);
404
LOG(PIL_INFO, "Host is being turned on: %s", host);
406
/* Expect "Complete" */
407
EXPECT(ctx->fd, WTItokComplete, 5);
408
EXPECT(ctx->fd, WTItokCRNL, 2);
416
#if defined(ST_POWEROFF)
418
* RPSOff - Turn Off the given outlet id
421
RPSOff(struct pluginDevice* ctx, char unit_id, const char * host)
425
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
429
LOG(PIL_CRIT, "%s: device %s is not open!", pluginid,
434
/* send the "Off" command */
435
SENDCMD(unit_id, '0', 10);
437
/* Expect "Plug 0 Off" */
438
EXPECT(ctx->fd, WTItokPlug, 5);
439
EXPECT(ctx->fd, WTItokOutlet, 2);
440
EXPECT(ctx->fd, WTItokOff, 2);
441
EXPECT(ctx->fd, WTItokCRNL, 2);
442
LOG(PIL_INFO, "Host is being turned on: %s", host);
444
/* Expect "Complete" */
445
EXPECT(ctx->fd, WTItokComplete, 5);
446
EXPECT(ctx->fd, WTItokCRNL, 2);
455
* rps10_status - API entry point to probe the status of the stonith device
456
* (basically just "is it reachable and functional?", not the
457
* status of the individual outlets)
460
* S_OOPS - some error occured
461
* S_OK - if the stonith device is reachable and online.
464
rps10_status(StonithPlugin *s)
466
struct pluginDevice* ctx;
469
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
472
ERRIFNOTCONFIGED(s,S_OOPS);
474
ctx = (struct pluginDevice*) s;
475
if (RPSConnect(ctx) != S_OK) {
479
/* The "connect" really does enough work to see if the
480
controller is alive... It verifies that it is returning
484
return(RPSDisconnect(ctx));
488
* rps10_hostlist - API entry point to return the list of hosts
489
* for the devices on this WTI_RPS10 unit
491
* This type of device is configured from the config file,
492
* so we don't actually have to connect to figure this
493
* out, just peruse the 'ctx' structure.
496
* a malloced array, terminated with a NULL,
497
* of null-terminated malloc'ed strings.
500
rps10_hostlist(StonithPlugin *s)
502
char ** ret = NULL; /* list to return */
505
struct pluginDevice* ctx;
508
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
511
ERRIFNOTCONFIGED(s,NULL);
513
ctx = (struct pluginDevice*) s;
515
if (ctx->unit_count >= 1) {
516
ret = (char **)MALLOC((ctx->unit_count+1)*sizeof(char*));
518
LOG(PIL_CRIT, "out of memory");
521
ret[ctx->unit_count]=NULL; /* null terminate the array */
522
for (i=0; i < ctx->unit_count; i++) {
523
ret[i] = STRDUP(ctx->controllers[i].node);
524
if (ret[i] == NULL) {
528
FREE(ret); ret = NULL;
531
} /* end for each possible outlet */
532
} /* end if any outlets are configured */
534
} /* end si_hostlist() */
537
* Parse the given configuration information, and stash
540
* The format of <info> for this module is:
541
* <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ...
543
* e.g. A machine named 'nodea' can kill a machine named 'nodeb' through
544
* a device attached to serial port /dev/ttyS0.
545
* A machine named 'nodeb' can kill machines 'nodea' and 'nodec'
546
* through a device attached to serial port /dev/ttyS1 (outlets 0
547
* and 1 respectively)
549
* <assuming this is the heartbeat configuration syntax:>
551
* stonith nodea rps10 /dev/ttyS0 nodeb 0
552
* stonith nodeb rps10 /dev/ttyS0 nodea 0 nodec 1
554
* Another possible configuration is for 2 stonith devices
555
* accessible through 2 different serial ports on nodeb:
557
* stonith nodeb rps10 /dev/ttyS0 nodea 0
558
* stonith nodeb rps10 /dev/ttyS1 nodec 0
564
* Most of the large block of comments above is incorrect as far as this
565
* module is concerned. It is somewhat applicable to the heartbeat code,
566
* but not to this Stonith module.
568
* The format of parameter string for this module is:
569
* <serial device> <remotenode> <outlet> [<remotenode> <outlet>] ...
573
RPS_parse_config_info(struct pluginDevice* ctx, const char * info)
580
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
583
/* strtok() is nice to use to parse a string with
584
(other than it isn't threadsafe), but it is destructive, so
585
we're going to alloc our own private little copy for the
586
duration of this function.
591
LOG(PIL_CRIT, "out of memory");
595
/* Grab the serial device */
596
token = strtok (copy, " \t");
599
LOG(PIL_CRIT, "%s: Can't find serial device on config line '%s'",
604
ctx->device = STRDUP(token);
606
LOG(PIL_CRIT, "out of memory");
610
/* Loop through the rest of the command line which should consist of */
611
/* <nodename> <outlet> pairs */
612
while ((node = strtok (NULL, " \t"))
613
&& (outlet = strtok (NULL, " \t\n"))) {
616
/* validate the outlet token */
617
if ((sscanf (outlet, "%c", &outlet_id) != 1)
618
|| !( ((outlet_id >= '0') && (outlet_id <= '9'))
619
|| (outlet_id == '*') || (outlet_id == 'A') )
622
, "%s: the outlet_id %s must be between"
623
" 0 and 9 or '*' / 'A'",
628
if (outlet_id == 'A') {
629
/* Remap 'A' to '*'; in some configurations,
630
* a '*' can't be configured because it breaks
635
if (ctx->unit_count >= WTI_NUM_CONTROLLERS) {
637
"%s: Tried to configure too many controllers",
642
ctx->controllers[ctx->unit_count].node = STRDUP(node);
643
g_strdown(ctx->controllers[ctx->unit_count].node);
644
ctx->controllers[ctx->unit_count].outlet_id = outlet_id;
649
/* free our private copy of the string we've been destructively
650
* parsing with strtok()
653
return ((ctx->unit_count > 0) ? S_OK : S_BADCONFIG);
666
* dtrtoggle - toggle DTR on the serial port
668
* snarfed from minicom, sysdep1.c, a well known POSIX trick.
671
static void dtrtoggle(int fd) {
672
struct termios tty, old;
676
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
681
cfsetospeed(&tty, B0);
682
cfsetispeed(&tty, B0);
683
tcsetattr(fd, TCSANOW, &tty);
686
tcsetattr(fd, TCSANOW, &old);
690
LOG(PIL_DEBUG, "dtrtoggle Complete (%s)\n", pluginid);
697
* Connect to the given WTI_RPS10 device.
699
* DTR on the serial port is toggled
700
* ctx->fd now contains a valid file descriptor to the serial port
701
* ??? LOCK THE SERIAL PORT ???
706
* S_TIMEOUT if the device did not respond
710
RPSConnect(struct pluginDevice * ctx)
713
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
716
/* Open the serial port if it isn't already open */
720
if (OurImports->TtyLock(ctx->device) < 0) {
721
LOG(PIL_CRIT, "%s: TtyLock failed.", pluginid);
725
ctx->fd = open (ctx->device, O_RDWR);
727
LOG(PIL_CRIT, "%s: Can't open %s : %s",
728
pluginid, ctx->device, strerror(errno));
732
/* set the baudrate to 9600 8 - N - 1 */
733
memset (&tio, 0, sizeof(tio));
735
/* ??? ALAN - the -tradtitional flag on gcc causes the
736
CRTSCTS constant to generate a warning, and warnings
737
are treated as errors, so I can't set this flag! - EZA ???
739
Hmmm. now that I look at the documentation, RTS
740
is just wired high on this device! we don't need it.
742
/* tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD | CRTSCTS ;*/
743
tio.c_cflag = B9600 | CS8 | CLOCAL | CREAD ;
744
tio.c_lflag = ICANON;
746
if (tcsetattr (ctx->fd, TCSANOW, &tio) < 0) {
747
LOG(PIL_CRIT, "%s: Can't set attributes %s : %s",
748
pluginid, ctx->device, strerror(errno));
750
OurImports->TtyUnlock(ctx->device);
754
/* flush all data to and fro the serial port before we start */
755
if (tcflush (ctx->fd, TCIOFLUSH) < 0) {
756
LOG(PIL_CRIT, "%s: Can't flush %s : %s",
757
pluginid, ctx->device, strerror(errno));
759
OurImports->TtyUnlock(ctx->device);
766
/* Toggle DTR - this 'resets' the controller serial port interface
767
In minicom, try CTRL-A H to hangup and you can see this behavior.
771
/* Wait for the switch to respond with "RPS-10 Ready".
772
Emperically, this usually takes 5-10 seconds...
773
... If this fails, this may be a hint that you got
774
a broken serial cable, which doesn't connect hardware
778
LOG(PIL_DEBUG, "Waiting for READY\n");
780
EXPECT(ctx->fd, WTItokReady, 12);
782
LOG(PIL_DEBUG, "Got READY\n");
784
EXPECT(ctx->fd, WTItokCRNL, 2);
786
LOG(PIL_DEBUG, "Got NL\n");
793
RPSDisconnect(struct pluginDevice * ctx)
797
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
801
/* Flush the serial port, we don't care what happens to the
802
* characters and failing to do this can cause close to hang.
804
tcflush(ctx->fd, TCIOFLUSH);
806
if (ctx->device != NULL) {
807
OurImports->TtyUnlock(ctx->device);
816
* RPSNametoOutlet - Map a hostname to an outlet on this stonith device.
819
* 0-9, * on success ( the outlet id on the RPS10 )
820
* -1 on failure (host not found in the config file)
824
RPSNametoOutlet ( struct pluginDevice * ctx, const char * host )
829
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
832
/* scan the controllers[] array to see if this host is there */
833
for (i=0;i<ctx->unit_count;i++) {
834
/* return the outlet id */
835
if ( ctx->controllers[i].node
836
&& !strcasecmp(host, ctx->controllers[i].node)) {
842
if (i == ctx->unit_count) {
845
return ctx->controllers[i].outlet_id;
851
* rps10_reset - API call to Reset (reboot) the given host on
852
* this Stonith device. This involves toggling the power off
853
* and then on again, OR just calling the builtin reset command
854
* on the stonith device.
857
rps10_reset_req(StonithPlugin * s, int request, const char * host)
861
signed char outlet_id = -1;
862
struct pluginDevice* ctx;
865
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
868
ERRIFNOTCONFIGED(s,S_OOPS);
870
ctx = (struct pluginDevice*) s;
872
if ((rc = RPSConnect(ctx)) != S_OK) {
876
outlet_id = RPSNametoOutlet(ctx, host);
879
LOG(PIL_WARN, "%s: %s doesn't control host [%s]"
880
, pluginid, ctx->device, host );
887
#if defined(ST_POWERON)
889
rc = RPSOn(ctx, outlet_id, host);
892
#if defined(ST_POWEROFF)
894
rc = RPSOff(ctx, outlet_id, host);
897
case ST_GENERIC_RESET:
898
rc = RPSReset(ctx, outlet_id, host);
905
lorc = RPSDisconnect(ctx);
907
return(rc != S_OK ? rc : lorc);
911
* Parse the information in the given string,
912
* and stash it away...
915
rps10_set_config(StonithPlugin* s, StonithNVpair* list)
917
struct pluginDevice* ctx;
918
StonithNamesToGet namestocopy [] =
925
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
928
ERRIFWRONGDEV(s,S_OOPS);
930
if (s->isconfigured) {
931
/* The module is already configured. */
935
ctx = (struct pluginDevice*) s;
937
if((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK){
938
LOG(PIL_DEBUG , "get all calues failed");
942
rc = RPS_parse_config_info(ctx, namestocopy[0].s_value);
943
FREE(namestocopy[0].s_value);
948
* Return the Stonith plugin configuration parameter
952
rps10_get_confignames(StonithPlugin* p)
954
static const char * Rps10Params[] = {ST_RPS10 ,NULL };
957
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
964
* rps10_getinfo - API entry point to retrieve something from the handle
967
rps10_getinfo(StonithPlugin * s, int reqtype)
969
struct pluginDevice* ctx;
973
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
976
ERRIFWRONGDEV(s,NULL);
979
* We look in the ST_TEXTDOMAIN catalog for our messages
981
ctx = (struct pluginDevice *)s;
991
ret = "Western Telematic Inc. (WTI) "
992
"Remote Power Switch - RPS-10M.\n";
995
ret = "http://www.wti.com/";
997
case ST_CONF_XML: /* XML metadata */
1008
* rps10_destroy - API entry point to destroy a WTI_RPS10 Stonith object.
1011
rps10_destroy(StonithPlugin *s)
1013
struct pluginDevice* ctx;
1017
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
1020
VOIDERRIFWRONGDEV(s);
1022
ctx = (struct pluginDevice *)s;
1024
ctx->pluginid = NOTwtiid;
1026
/* close the fd if open and set ctx->fd to invalid */
1029
if (ctx->device != NULL) {
1033
if (ctx->unit_count > 0) {
1034
for (i = 0; i < ctx->unit_count; i++) {
1035
if (ctx->controllers[i].node != NULL) {
1036
FREE(ctx->controllers[i].node);
1037
ctx->controllers[i].node = NULL;
1045
* rps10_new - API entry point called to create a new WTI_RPS10 Stonith device
1048
static StonithPlugin *
1049
rps10_new(const char *subplugin)
1051
struct pluginDevice* ctx = ST_MALLOCT(struct pluginDevice);
1054
LOG(PIL_DEBUG, "%s:called.", __FUNCTION__);
1058
LOG(PIL_CRIT, "out of memory");
1061
memset(ctx, 0, sizeof(*ctx));
1062
ctx->pluginid = pluginid;
1064
ctx->unit_count = 0;
1066
ctx->idinfo = DEVICE;
1067
ctx->sp.s_ops = &rps10Ops;