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

« back to all changes in this revision

Viewing changes to lib/plugins/stonith/rcd_serial.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 RCD_SERIAL Stonith device
3
 
 *
4
 
 * Original code from null.c by
5
 
 * Copyright (c) 2000 Alan Robertson <alanr@unix.sh>
6
 
 *
7
 
 * Copious borrowings from nw_rpc100s.c by
8
 
 * Copyright (c) 2000 Computer Generation Incorporated
9
 
 *          Eric Z. Ayers <eric.ayers@compgen.com>
10
 
 *
11
 
 *                and from apcsmart.c by
12
 
 * Copyright (c) 2000 Andreas Piesk <a.piesk@gmx.net>
13
 
 *
14
 
 * Modifications for RC Delayed Serial Ciruit by 
15
 
 * Copyright (c) 2002 John Sutton <john@scl.co.uk>
16
 
 *
17
 
 * Mangled by Zhaokai <zhaokai@cn.ibm.com>, IBM, 2005
18
 
 *
19
 
 * This library is free software; you can redistribute it and/or
20
 
 * modify it under the terms of the GNU Lesser General Public
21
 
 * License as published by the Free Software Foundation; either
22
 
 * version 2.1 of the License, or (at your option) any later version.
23
 
 * 
24
 
 * This library is distributed in the hope that it will be useful,
25
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27
 
 * Lesser General Public License for more details.
28
 
 * 
29
 
 * You should have received a copy of the GNU Lesser General Public
30
 
 * License along with this library; if not, write to the Free Software
31
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
32
 
 *
33
 
 */
34
 
 
35
 
#include <lha_internal.h>
36
 
 
37
 
#define DEVICE  "RC Delayed Serial"
38
 
#include "stonith_plugin_common.h"
39
 
#include "stonith_signal.h"
40
 
 
41
 
#define PIL_PLUGIN              rcd_serial
42
 
#define PIL_PLUGIN_S            "rcd_serial"
43
 
#define PIL_PLUGINLICENSE       LICENSE_LGPL
44
 
#define PIL_PLUGINLICENSEURL    URL_LGPL
45
 
 
46
 
#define ST_DTRRTS               "dtr|rts"
47
 
#define ST_MSDURATION           "msduration"
48
 
#define MAX_RCD_SERIALLINE      512
49
 
 
50
 
#include <pils/plugin.h>
51
 
#include <sys/ioctl.h>
52
 
#include <sys/time.h>
53
 
 
54
 
static StonithPlugin*   rcd_serial_new(const char *);
55
 
static void             rcd_serial_destroy(StonithPlugin *);
56
 
static int              rcd_serial_set_config(StonithPlugin *, StonithNVpair *);
57
 
static const char **    rcd_serial_get_confignames(StonithPlugin *);
58
 
static const char *     rcd_serial_getinfo(StonithPlugin * s, int InfoType);
59
 
static int              rcd_serial_status(StonithPlugin * );
60
 
static int              rcd_serial_reset_req(StonithPlugin * s, int request, const char * host);
61
 
static char **          rcd_serial_hostlist(StonithPlugin  *);
62
 
 
63
 
static struct stonith_ops rcd_serialOps ={
64
 
        rcd_serial_new,         /* Create new STONITH object            */
65
 
        rcd_serial_destroy,     /* Destroy STONITH object               */
66
 
        rcd_serial_getinfo,     /* Return STONITH info string           */
67
 
        rcd_serial_get_confignames,/* Return STONITH info string        */
68
 
        rcd_serial_set_config,  /* Get configuration from NVpairs       */
69
 
        rcd_serial_status,      /* Return STONITH device status         */
70
 
        rcd_serial_reset_req,   /* Request a reset                      */
71
 
        rcd_serial_hostlist,    /* Return list of supported hosts       */
72
 
};
73
 
 
74
 
PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
75
 
static const PILPluginImports*  PluginImports;
76
 
static PILPlugin*               OurPlugin;
77
 
static PILInterface*            OurInterface;
78
 
static StonithImports*          OurImports;
79
 
static void*                    interfprivate;
80
 
 
81
 
PIL_rc
82
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);
83
 
 
84
 
PIL_rc
85
 
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
86
 
{
87
 
        /* Force the compiler to do a little type checking */
88
 
        (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
89
 
 
90
 
        PluginImports = imports;
91
 
        OurPlugin = us;
92
 
 
93
 
        /* Register ourself as a plugin */
94
 
        imports->register_plugin(us, &OurPIExports);  
95
 
 
96
 
        /*  Register our interface implementation */
97
 
        return imports->register_interface(us, PIL_PLUGINTYPE_S
98
 
        ,       PIL_PLUGIN_S
99
 
        ,       &rcd_serialOps
100
 
        ,       NULL            /*close */
101
 
        ,       &OurInterface
102
 
        ,       (void*)&OurImports
103
 
        ,       &interfprivate); 
104
 
}
105
 
 
106
 
/* ------------------- RCD specific stuff -------------- */
107
 
 
108
 
/*
109
 
  A diagram of a circuit suitable for use with this plugin is in
110
 
  README.rcd_serial which should be somewhere in the distribution (if Alan
111
 
  includes it ;-) and/or at http://www.scl.co.uk/rcd_serial/ (if I remember
112
 
  to put it there ;-).
113
 
 
114
 
  Once you've got this built, you can test things using the stonith command
115
 
  as follows:
116
 
 
117
 
        stonith -L
118
 
                will show a list of plugin types, including rcd_serial
119
 
 
120
 
        stonith -t rcd_serial testhost
121
 
                will show required parameters
122
 
 
123
 
  In these 3 you can either pass the params after the -p option or you can
124
 
  put them in a config file and use -F configname instead of -p "param ...".
125
 
 
126
 
        stonith -t rcd_serial -p "testhost /dev/ttyS0 rts 1500" -S
127
 
                will show the status of the device
128
 
 
129
 
        stonith -t rcd_serial -p "testhost /dev/ttyS0 rts 1500" -l
130
 
                will list the single host testhost
131
 
 
132
 
        stonith -t rcd_serial -p "testhost /dev/ttyS0 rts 1500" testhost
133
 
                will reset testhost (provided testhost has its reset pins
134
 
                suitably wired to the RTS signal coming out of port /dev/ttyS0
135
 
                and that 1.5s is enough time to cause a reset ;-)
136
 
*/
137
 
 
138
 
/*
139
 
  Define RCD_NOPAUSE if you are using the serial port for some purpose
140
 
  _in_addition_ to using it as a stonith device.  For example, I use one
141
 
  of the input pins on the same serial port for monitoring the state of a
142
 
  power supply.  Periodically, a cron job has to open the port to read the
143
 
  state of this input and thus has to clear down the output pins DTR and RTS
144
 
  in order to avoid causing a spurious stonith reset.  Now, if it should
145
 
  happen that just at the same time as we are _really_ trying to do a stonith
146
 
  reset, this cron job starts up, then the stonith reset won't occur ;-(.
147
 
  To avoid this (albeit unlikely) outcome, you should #define RCD_NOPAUSE.
148
 
  The effect of this is that instead of setting the line high just once and
149
 
  then falling into a pause until an alarm goes off, rather, the program falls
150
 
  into a loop which is continuously setting the line high.  That costs us a bit
151
 
  of CPU as compared with sitting in a pause, but hey, how often is this code
152
 
  going to get exercised!  Never, we hope...
153
 
*/
154
 
#undef RCD_NOPAUSE
155
 
 
156
 
#ifdef RCD_NOPAUSE
157
 
static int RCD_alarmcaught;
158
 
#endif
159
 
 
160
 
/*
161
 
 * own prototypes
162
 
 */
163
 
 
164
 
static void RCD_alarm_handler(int sig);
165
 
static int RCD_open_serial_port(char *device);
166
 
static int RCD_close_serial_port(char *device, int fd);
167
 
 
168
 
static void
169
 
RCD_alarm_handler(int sig) {
170
 
#if !defined(HAVE_POSIX_SIGNALS)
171
 
        if (sig) {
172
 
                signal(sig, SIG_DFL);
173
 
        }else{
174
 
                signal(sig, RCD_alarm_handler);
175
 
        }
176
 
#else
177
 
        struct sigaction sa;
178
 
        sigset_t sigmask;
179
 
 
180
 
        /* Maybe a bit naughty but it works and it saves duplicating all */
181
 
        /* this setup code - if handler called with 0 for sig, we install */
182
 
        /* ourself as handler. */
183
 
        if (sig) { 
184
 
                 sa.sa_handler = (void (*)(int))SIG_DFL;
185
 
        }else{
186
 
                sa.sa_handler = RCD_alarm_handler;
187
 
        }
188
 
 
189
 
        sigemptyset(&sigmask);
190
 
        sa.sa_mask = sigmask;
191
 
        sa.sa_flags = 0;
192
 
        sigaction(SIGALRM, &sa, NULL);
193
 
#endif
194
 
 
195
 
#ifdef RCD_NOPAUSE
196
 
        RCD_alarmcaught = 1;
197
 
#endif
198
 
        return;
199
 
}
200
 
 
201
 
static int
202
 
RCD_open_serial_port(char *device) {
203
 
        int fd;
204
 
        int status;
205
 
        int bothbits;
206
 
 
207
 
        if (OurImports->TtyLock(device) < 0) {
208
 
                if (Debug) {
209
 
                        LOG(PIL_DEBUG, "%s: ttylock failed.", __FUNCTION__);
210
 
                }
211
 
                return -1;
212
 
        }
213
 
 
214
 
        bothbits = TIOCM_RTS | TIOCM_DTR;
215
 
 
216
 
        if ((fd = open(device, O_RDONLY | O_NDELAY)) != -1) {
217
 
                /*
218
 
                        Opening the device always sets DTR & CTS high.
219
 
                        Clear them down immediately.
220
 
                */
221
 
                status = ioctl(fd, TIOCMBIC, &bothbits);
222
 
                /* If there was an error clearing bits, set the fd to -1 
223
 
                 * ( indicates error ) */
224
 
                if (status != 0 ) { 
225
 
                        fd = -1;
226
 
                }
227
 
        }
228
 
 
229
 
        return fd;
230
 
}
231
 
 
232
 
static int
233
 
RCD_close_serial_port(char *device, int fd) {
234
 
        int rc = close(fd);
235
 
        if (device != NULL) {
236
 
                OurImports->TtyUnlock(device);
237
 
        }
238
 
        return rc;
239
 
}
240
 
 
241
 
/*
242
 
 *      RCD_Serial STONITH device.
243
 
 */
244
 
struct pluginDevice {
245
 
        StonithPlugin   sp;
246
 
        const char *    pluginid;
247
 
        const char *    idinfo;
248
 
        char **         hostlist;       /* name of single host we can reset */
249
 
        int             hostcount;      /* i.e. 1 after initialisation */
250
 
        char *          device;         /* serial device name */
251
 
        char *          signal;         /* either rts or dtr */
252
 
        long            msduration;     /* how long (ms) to assert the signal */
253
 
};
254
 
 
255
 
static const char * pluginid = "RCD_SerialDevice-Stonith";
256
 
static const char * NOTrcd_serialID = "RCD_Serial device has been destroyed";
257
 
 
258
 
#include "stonith_config_xml.h"
259
 
 
260
 
#define XML_DTRRTS_SHORTDESC \
261
 
        XML_PARM_SHORTDESC_BEGIN("en") \
262
 
        ST_DTRRTS \
263
 
        XML_PARM_SHORTDESC_END
264
 
 
265
 
#define XML_DTRRTS_LONGDESC \
266
 
        XML_PARM_LONGDESC_BEGIN("en") \
267
 
        "The hardware handshaking technique to use with " ST_TTYDEV "(\"dtr\" or \"rts\")" \
268
 
        XML_PARM_LONGDESC_END
269
 
 
270
 
#define XML_DTRRTS_PARM \
271
 
        XML_PARAMETER_BEGIN(ST_DTRRTS, "string", "1") \
272
 
          XML_DTRRTS_SHORTDESC \
273
 
          XML_DTRRTS_LONGDESC \
274
 
        XML_PARAMETER_END
275
 
 
276
 
#define XML_MSDURATION_SHORTDESC \
277
 
        XML_PARM_SHORTDESC_BEGIN("en") \
278
 
        ST_MSDURATION \
279
 
        XML_PARM_SHORTDESC_END
280
 
 
281
 
#define XML_MSDURATION_LONGDESC \
282
 
        XML_PARM_LONGDESC_BEGIN("en") \
283
 
        "The delay duration (in milliseconds) between the assertion of the control signal on " ST_TTYDEV " and the closing of the reset switch" \
284
 
        XML_PARM_LONGDESC_END
285
 
 
286
 
#define XML_MSDURATION_PARM \
287
 
        XML_PARAMETER_BEGIN(ST_MSDURATION, "string", "1") \
288
 
          XML_MSDURATION_SHORTDESC \
289
 
          XML_MSDURATION_LONGDESC \
290
 
        XML_PARAMETER_END
291
 
 
292
 
static const char *rcd_serialXML = 
293
 
  XML_PARAMETERS_BEGIN
294
 
    XML_HOSTLIST_PARM
295
 
    XML_TTYDEV_PARM
296
 
    XML_DTRRTS_PARM
297
 
    XML_MSDURATION_PARM
298
 
  XML_PARAMETERS_END;
299
 
 
300
 
static int
301
 
rcd_serial_status(StonithPlugin  *s)
302
 
{
303
 
        struct pluginDevice*    rcd;
304
 
        int fd;
305
 
        const char * err;
306
 
 
307
 
        ERRIFWRONGDEV(s,S_OOPS);
308
 
 
309
 
        rcd = (struct pluginDevice*) s;
310
 
 
311
 
        /*
312
 
        All we can do is make sure the serial device exists and
313
 
        can be opened and closed without error.
314
 
        */
315
 
 
316
 
        if ((fd = RCD_open_serial_port(rcd->device)) == -1) {
317
 
                err = strerror(errno);
318
 
                LOG(PIL_CRIT, "%s: open of %s failed - %s",
319
 
                        __FUNCTION__, rcd->device, err);
320
 
                return(S_OOPS);
321
 
        }
322
 
 
323
 
        if (RCD_close_serial_port(rcd->device, fd) != 0) {
324
 
                err = strerror(errno);
325
 
                LOG(PIL_CRIT, "%s: close of %s failed - %s",
326
 
                        __FUNCTION__, rcd->device, err);
327
 
                return(S_OOPS);
328
 
        }
329
 
 
330
 
        return S_OK;
331
 
}
332
 
 
333
 
 
334
 
/*
335
 
 *      Return the list of hosts configured for this RCD_SERIAL device
336
 
 */
337
 
static char **
338
 
rcd_serial_hostlist(StonithPlugin  *s)
339
 
{
340
 
        struct pluginDevice*    rcd;
341
 
 
342
 
        ERRIFWRONGDEV(s,NULL);
343
 
        rcd = (struct pluginDevice*) s;
344
 
        if (rcd->hostcount < 0) {
345
 
                LOG(PIL_CRIT
346
 
                ,       "unconfigured stonith object in RCD_SERIAL_list_hosts");
347
 
                return(NULL);
348
 
        }
349
 
 
350
 
        return OurImports->CopyHostList((const char **)rcd->hostlist);
351
 
}
352
 
 
353
 
/*
354
 
 *      At last, we really do it! I don't know what the request argument
355
 
 *      is so am just ignoring it...
356
 
 */
357
 
static int
358
 
rcd_serial_reset_req(StonithPlugin * s, int request, const char * host)
359
 
{
360
 
        struct pluginDevice*    rcd;
361
 
        int fd;
362
 
        int sigbit;
363
 
        struct itimerval timer;
364
 
        const char * err;
365
 
        
366
 
        ERRIFWRONGDEV(s,S_OOPS);
367
 
 
368
 
        rcd = (struct pluginDevice *) s;
369
 
 
370
 
        /* check that host matches */
371
 
        if (strcasecmp(host, rcd->hostlist[0])) {
372
 
                LOG(PIL_CRIT, "%s: host '%s' not in hostlist.",
373
 
                        __FUNCTION__, host);
374
 
                return(S_BADHOST);
375
 
        }
376
 
 
377
 
        /* Set the appropriate bit for the signal */
378
 
        sigbit = *(rcd->signal)=='r' ? TIOCM_RTS : TIOCM_DTR;
379
 
 
380
 
        /* Set up the timer */
381
 
        timer.it_interval.tv_sec  = 0;
382
 
        timer.it_interval.tv_usec = 0;
383
 
        timer.it_value.tv_sec  =  rcd->msduration / 1000;
384
 
        timer.it_value.tv_usec = (rcd->msduration % 1000) * 1000;
385
 
 
386
 
        /* Open the device */
387
 
        if ((fd = RCD_open_serial_port(rcd->device)) == -1) {
388
 
#ifdef HAVE_STRERROR
389
 
                err = strerror(errno);
390
 
#else
391
 
                err = sys_errlist[errno];
392
 
#endif
393
 
                LOG(PIL_CRIT, "%s: open of %s failed - %s",
394
 
                        __FUNCTION__, rcd->device, err);
395
 
                return(S_OOPS);
396
 
        }
397
 
 
398
 
        /* Start the timer */
399
 
        RCD_alarm_handler(0);
400
 
#ifdef RCD_NOPAUSE
401
 
        RCD_alarmcaught = 0;
402
 
#endif
403
 
        setitimer(ITIMER_REAL, &timer, 0);
404
 
 
405
 
        /* Set the line high */
406
 
        ioctl(fd, TIOCMBIS, &sigbit);
407
 
 
408
 
        /* Wait for the alarm signal */
409
 
#ifdef RCD_NOPAUSE
410
 
        while(!RCD_alarmcaught) ioctl(fd, TIOCMBIS, &sigbit);
411
 
#else
412
 
        pause();
413
 
#endif
414
 
 
415
 
        /* Clear the line low */
416
 
        ioctl(fd, TIOCMBIC, &sigbit);
417
 
 
418
 
        /* Close the port */
419
 
        if (RCD_close_serial_port(rcd->device, fd) != 0) {
420
 
                err = strerror(errno);
421
 
                LOG(PIL_CRIT, "%s: close of %s failed - %s",
422
 
                        __FUNCTION__, rcd->device, err);
423
 
                return(S_OOPS);
424
 
        }
425
 
 
426
 
        LOG(PIL_INFO,"Host rcd_serial-reset: %s", host);
427
 
        return S_OK;
428
 
}
429
 
 
430
 
/*
431
 
 *      Parse the information in the given string 
432
 
 *      and stash it away...
433
 
 */
434
 
static int
435
 
rcd_serial_set_config(StonithPlugin* s, StonithNVpair *list)
436
 
{
437
 
        struct pluginDevice*    rcd;
438
 
        StonithNamesToGet       namestocopy [] =
439
 
        {       {ST_HOSTLIST,   NULL}
440
 
        ,       {ST_TTYDEV,     NULL}
441
 
        ,       {ST_DTRRTS,     NULL}
442
 
        ,       {ST_MSDURATION, NULL}
443
 
        ,       {NULL,          NULL}
444
 
        };
445
 
        char *endptr;
446
 
        int rc = 0;
447
 
 
448
 
        LOG(PIL_DEBUG, "%s:called", __FUNCTION__);
449
 
        
450
 
        ERRIFWRONGDEV(s,S_OOPS);
451
 
        if (s->isconfigured) {
452
 
                return S_OOPS;
453
 
        }
454
 
 
455
 
        rcd = (struct pluginDevice*) s;
456
 
 
457
 
        if ((rc = OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
458
 
                return rc;
459
 
        }
460
 
 
461
 
        if ((rcd->hostlist = (char **)MALLOC(2*sizeof(char*))) == NULL) {
462
 
                LOG(PIL_CRIT, "%s: out of memory!", __FUNCTION__);
463
 
                FREE(namestocopy[0].s_value);
464
 
                FREE(namestocopy[1].s_value);
465
 
                FREE(namestocopy[2].s_value);
466
 
                FREE(namestocopy[3].s_value);
467
 
                return S_OOPS;
468
 
        }
469
 
        rcd->hostlist[0] = namestocopy[0].s_value;
470
 
        g_strdown(rcd->hostlist[0]);
471
 
        rcd->hostlist[1] = NULL;
472
 
        rcd->hostcount = 1;
473
 
        rcd->device = namestocopy[1].s_value;
474
 
        rcd->signal = namestocopy[2].s_value;
475
 
        if (strcmp(rcd->signal, "rts") && strcmp(rcd->signal, "dtr")) {
476
 
                LOG(PIL_CRIT, "%s: Invalid signal name '%s'",
477
 
                        pluginid, rcd->signal);
478
 
                FREE(namestocopy[3].s_value);
479
 
                return S_BADCONFIG;
480
 
        }
481
 
 
482
 
        errno = 0;
483
 
        rcd->msduration = strtol(namestocopy[3].s_value, &endptr, 0);
484
 
        if (((errno == ERANGE)
485
 
        &&   (rcd->msduration == LONG_MIN || rcd->msduration == LONG_MAX))
486
 
        || *endptr != 0 || rcd->msduration < 1) {
487
 
                LOG(PIL_CRIT, "%s: Invalid msduration '%s'",
488
 
                        pluginid, namestocopy[3].s_value);
489
 
                FREE(namestocopy[3].s_value);
490
 
                return S_BADCONFIG;
491
 
        }
492
 
        FREE(namestocopy[3].s_value);
493
 
        
494
 
        return S_OK;
495
 
}
496
 
 
497
 
/*
498
 
 * Return STONITH config vars
499
 
 */
500
 
static const char**
501
 
rcd_serial_get_confignames(StonithPlugin* p)
502
 
{
503
 
        static const char *     RcdParams[] = {ST_HOSTLIST, ST_TTYDEV
504
 
                                , ST_DTRRTS, ST_MSDURATION,  NULL };
505
 
        return RcdParams;
506
 
}
507
 
 
508
 
/*
509
 
 * Return STONITH info string
510
 
 */
511
 
static const char *
512
 
rcd_serial_getinfo(StonithPlugin * s, int reqtype)
513
 
{
514
 
        struct pluginDevice* rcd;
515
 
        const char * ret;
516
 
 
517
 
        ERRIFWRONGDEV(s,NULL);
518
 
        /*
519
 
         *      We look in the ST_TEXTDOMAIN catalog for our messages
520
 
         */
521
 
        rcd = (struct pluginDevice *)s;
522
 
 
523
 
        switch (reqtype) {
524
 
                case ST_DEVICEID:
525
 
                        ret = rcd->idinfo;
526
 
                        break;
527
 
                case ST_DEVICENAME:
528
 
                        ret = rcd->device;
529
 
                        break;
530
 
                case ST_DEVICEDESCR:
531
 
                        ret = "RC Delayed Serial STONITH Device\n"
532
 
                        "This device can be constructed cheaply from"
533
 
                        " readily available components,\n"
534
 
                        "with sufficient expertise and testing.\n"
535
 
                        "See README.rcd_serial for circuit diagram.\n";
536
 
                        break;
537
 
                case ST_DEVICEURL:
538
 
                        ret = "http://www.scl.co.uk/rcd_serial/";
539
 
                        break;
540
 
                case ST_CONF_XML:               /* XML metadata */
541
 
                        ret = rcd_serialXML;
542
 
                        break;
543
 
                default:
544
 
                        ret = NULL;
545
 
                        break;
546
 
        }
547
 
        return ret;
548
 
}
549
 
 
550
 
/*
551
 
 *      RCD_SERIAL Stonith destructor...
552
 
 */
553
 
static void
554
 
rcd_serial_destroy(StonithPlugin *s)
555
 
{
556
 
        struct pluginDevice* rcd;
557
 
 
558
 
        VOIDERRIFWRONGDEV(s);
559
 
 
560
 
        rcd = (struct pluginDevice *)s;
561
 
 
562
 
        rcd->pluginid = NOTrcd_serialID;
563
 
        if (rcd->hostlist) {
564
 
                stonith_free_hostlist(rcd->hostlist);
565
 
                rcd->hostlist = NULL;
566
 
        }
567
 
        rcd->hostcount = -1;
568
 
        if (rcd->device) {
569
 
                FREE(rcd->device);
570
 
        }
571
 
        if (rcd->signal) {
572
 
                FREE(rcd->signal);
573
 
        }
574
 
        FREE(rcd);
575
 
}
576
 
 
577
 
/*
578
 
 * Create a new RCD_Serial Stonith device.
579
 
 * Too bad this function can't be static. (Hmm, weird, it _is_ static?)
580
 
 */
581
 
static StonithPlugin *
582
 
rcd_serial_new(const char *subplugin)
583
 
{
584
 
        struct pluginDevice*    rcd = ST_MALLOCT(struct pluginDevice);
585
 
 
586
 
        if (rcd == NULL) {
587
 
                LOG(PIL_CRIT, "out of memory");
588
 
                return(NULL);
589
 
        }
590
 
        memset(rcd, 0, sizeof(*rcd));
591
 
 
592
 
        rcd->pluginid = pluginid;
593
 
        rcd->hostlist = NULL;
594
 
        rcd->hostcount = -1;
595
 
        rcd->device = NULL;
596
 
        rcd->signal = NULL;
597
 
        rcd->msduration = 0;
598
 
        rcd->idinfo = DEVICE;
599
 
        rcd->sp.s_ops = &rcd_serialOps;
600
 
 
601
 
        return &(rcd->sp);
602
 
}