2 * clumanager 1.2.x STONITH and/or linux-cluster fence and/or GFS fence
3 * module for Intel/Bull/Dell Tiger4 machines via IPMI over lan.
4 * (Probably works with anything ipmitool can control, though.)
6 * Note: REQUIRES ipmitool to operate. On certain machines, the hardware
7 * manufacturer provides this tool for you. Otherwise, check:
9 * http://ipmitool.sourceforge.net
11 * Copyright 2005 Red Hat, Inc.
12 * author: Lon Hohberger <lhh at redhat.com>
14 * This library is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU Lesser General Public
16 * License as published by the Free Software Foundation; either
17 * version 2.1 of the License, or (at your option) any later version.
19 * This library is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 * Lesser General Public License for more details.
24 * You should have received a copy of the GNU Lesser General Public
25 * License along with this library; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
42 #define log(lvl, fmt, args...) \
44 syslog(lvl, fmt, ##args); \
45 fprintf(stderr, "%s: " fmt, #lvl, ##args); \
48 /* fenced doesn't use the remote calls */
52 #define ST_GENERIC_RESET 3
54 #define log(lvl, fmt, args...) fprintf(stderr, fmt, ##args)
58 #include <copyright.cf>
60 #define REDHAT_COPYRIGHT "Copyright (C) 2005 Red Hat, Inc.\n"
61 #define FENCE_RELEASE_NAME "TEST ONLY; Not for distribution\n"
68 #define IPMIID 0x6301fee
69 #define NOTIPMI 0x00010010
72 const char *i_ipmitool
;
85 Supported installation paths
87 const char *ipmitool_paths
[] = {
88 "/usr/local/bull/NSMasterHW/bin/ipmitool",
93 "/usr/local/bin/ipmitool",
94 "/usr/local/sbin/ipmitool",
99 static struct Etoken power_on_complete
[] = {
100 {"Password:", EPERM
, 0},
101 {"Unable to establish LAN", EAGAIN
, 0}, /* Retry */
102 {"IPMI mutex", EFAULT
, 0}, /* Death */
107 static struct Etoken power_off_complete
[] = {
108 {"Password:", EPERM
, 0},
109 {"Unable to establish LAN", EAGAIN
, 0}, /* Retry */
110 {"IPMI mutex", EFAULT
, 0}, /* Death */
116 #define STATE_OFF 4096
117 #define STATE_ON 8192
118 static struct Etoken power_status
[] = {
119 {"Password:", EPERM
, 0},
120 {"Unable to establish LAN", EAGAIN
, 0}, /* Retry */
121 {"IPMI mutex", EFAULT
, 0}, /* Death */
122 {"Chassis Power is off", STATE_OFF
, 0},
123 {"Chassis Power is on", STATE_ON
, 0},
138 for (x
= 0; ipmitool_paths
[x
]; x
++) {
139 p
= (char *)ipmitool_paths
[x
];
140 if (stat(p
, &sb
) != 0)
143 if (!S_ISREG(sb
.st_mode
))
147 if ((sb
.st_mode
& S_IXUSR
) == 0)
150 return (const char *)p
;
158 build_cmd(char *command
, size_t cmdlen
, struct ipmi
*ipmi
, int op
)
164 snprintf(cmd
, sizeof(cmd
), "%s -I lan -H %s", ipmi
->i_ipmitool
,
168 snprintf(arg
, sizeof(arg
), " -U %s", ipmi
->i_user
);
169 strncat(cmd
, arg
, sizeof(cmd
) - strlen(arg
));
172 if (ipmi
->i_password
) {
173 snprintf(arg
, sizeof(arg
), " -P %s", ipmi
->i_password
);
174 strncat(cmd
, arg
, sizeof(cmd
) - strlen(arg
));
179 snprintf(arg
, sizeof(arg
),
180 "%s chassis power on", cmd
);
183 snprintf(arg
, sizeof(arg
),
184 "%s chassis power off", cmd
);
187 snprintf(arg
, sizeof(arg
),
188 "%s chassis power status", cmd
);
192 strncpy(command
, arg
, cmdlen
);
198 ipmi_spawn(struct ipmi
*ipmi
, const char *cmd
)
205 if (ipmi
->i_pid
!= -1) {
210 if ((ipmi
->i_pid
= StartProcess(cmd
, &ipmi
->i_rdfd
,
212 EXP_STDERR
|EXP_NOCTTY
)) >= 0)
219 ipmi_reap(struct ipmi
*ipmi
)
221 if (ipmi
->i_pid
>= 0) {
222 kill(ipmi
->i_pid
, 9);
223 waitpid(ipmi
->i_pid
, NULL
, 0);
226 if (ipmi
->i_rdfd
>= 0) {
230 if (ipmi
->i_wrfd
>= 0) {
239 ipmi_expect(struct ipmi
*ipmi
, struct Etoken
*toklist
, int timeout
)
243 ret
= ExpectToken(ipmi
->i_rdfd
, toklist
, timeout
, NULL
, 0);
252 ipmi_op(struct ipmi
*ipmi
, int op
, struct Etoken
*toklist
)
258 build_cmd(cmd
, sizeof(cmd
), ipmi
, op
);
260 if (ipmi_spawn(ipmi
, cmd
) != 0)
262 ret
= ipmi_expect(ipmi
, toklist
, 120);
265 while ((ret
== EAGAIN
|| ret
== ETIMEDOUT
) && retries
> 0) {
269 if (ipmi_spawn(ipmi
, cmd
) != 0)
271 ret
= ipmi_expect(ipmi
, toklist
, 120);
280 log(LOG_CRIT
, "ipmilan: ipmitool failed to create "
281 "mutex; unable to complete operation\n");
286 /*!!! Still couldn't get through?! */
288 "ipmilan: Failed to connect after 30 seconds\n");
296 ipmi_off(struct ipmi
*ipmi
)
298 int ret
, retries
= 5;
300 ret
= ipmi_op(ipmi
, ST_STATUS
, power_status
);
310 ret
= ipmi_op(ipmi
, ST_POWEROFF
, power_off_complete
);
317 ret
= ipmi_op(ipmi
, ST_STATUS
, power_status
);
331 log(LOG_WARNING
, "ipmilan: Power still on\n");
338 ipmi_on(struct ipmi
*ipmi
)
340 int ret
, retries
= 5;
342 ret
= ipmi_op(ipmi
, ST_STATUS
, power_status
);
352 ret
= ipmi_op(ipmi
, ST_POWERON
, power_on_complete
);
359 ret
= ipmi_op(ipmi
, ST_STATUS
, power_status
);
373 log(LOG_WARNING
, "ipmilan: Power still off\n");
380 Squash all our private data
383 ipmi_destroy(struct ipmi
*i
)
404 Multipurpose initializer. Used to either create a new, blank ipmi,
405 or update an existing one, or both.
408 ipmi_init(struct ipmi
*i
, char *host
, char *user
, char *password
)
412 if (!i
|| !i
->i_ipmitool
)
418 log(LOG_WARNING
, "ipmilan: ipmitool not found!\n");
423 i
= malloc (sizeof(*i
));
427 if (host
&& strlen(host
)) {
428 i
->i_host
= strdup(host
);
436 if (password
&& strlen(password
)) {
437 i
->i_password
= strdup(password
);
438 if (!i
->i_password
) {
444 i
->i_password
= NULL
;
446 if (user
&& strlen(user
)) {
447 i
->i_user
= strdup(user
);
471 #define ISIPMI(s) (s && s->pinfo && ((struct ipmi *)s->pinfo)->i_id == IPMIID)
474 st_getinfo(Stonith
* __attribute__ ((unused
)) s
, int __attribute__((unused
))i
)
476 return "Not really useful info";
480 st_destroy(Stonith
*s
)
485 log(LOG_ERR
, "st_destroy(IPMI): Invalid Argument");
489 i
= (struct ipmi
*)s
->pinfo
;
499 i
= malloc(sizeof(*i
));
501 log(LOG_ERR
, "st_new(IPMI) %s", strerror(errno
));
505 memset((void *)i
, 0, sizeof(*i
));
506 ipmi_init(i
, NULL
, NULL
, NULL
);
512 st_status(Stonith
*s
)
519 ret
= ipmi_op((struct ipmi
*)s
->pinfo
, ST_STATUS
, power_status
);
520 if (ret
== STATE_ON
|| ret
== STATE_OFF
)
523 /* Permission denied? */
532 st_reset(Stonith
*s
, int req
, char * port
)
538 ret
= ipmi_on((struct ipmi
*)s
->pinfo
);
541 ret
= ipmi_off((struct ipmi
*)s
->pinfo
);
543 case ST_GENERIC_RESET
:
544 /* Could use chassis power cycle, but this works too*/
545 ret
= ipmi_off((struct ipmi
*)s
->pinfo
);
547 ipmi_on((struct ipmi
*)s
->pinfo
);
558 log(LOG_CRIT
, "ipmilan: unable to complete request\n");
565 log(LOG_ERR
, "Power to host %s still ON\n", port
);
568 log(LOG_WARNING
, "Power to host %s still OFF\n", port
);
577 Complicated parser. Has to deal with whitespace as well as the
578 possibility of having 1, 2, or 3 arguments.
581 _ipmilan_setconfinfo(Stonith
*s
, const char *info
)
583 char info_priv
[1024];
584 char *host
= info_priv
;
593 i
= (struct ipmi
*)s
->pinfo
;
595 snprintf(info_priv
, sizeof(info_priv
), "%s", info
);
596 len
= strcspn(host
, "\n\r\t ");
597 if (len
>= strlen(host
))
606 /* No separator or end of string reached */
609 len
= strcspn(user
, "\n\r\t ");
610 if (len
>= strlen(user
))
619 /* We don't need a username for this one */
620 if (!passwd
|| !*passwd
) {
625 len
= strcspn(passwd
, "\n\r\t ");
631 if (!*user
|| !strcmp(user
, "(null)"))
634 i
= ipmi_init(i
, host
, user
, passwd
);
644 st_setconfinfo(Stonith
*s
, const char *info
)
646 /* XXX dlmap collisions? */
647 return _ipmilan_setconfinfo(s
, info
);
651 /* -- Ripped from old STONITH drivers.
652 * Parse the information in the given configuration file,
653 * and stash it away...
656 st_setconffile(Stonith
* s
, const char * configname
)
664 if ((cfgfile
= fopen(configname
, "r")) == NULL
) {
665 printf("Can't open %s\n", configname
);
666 log(LOG_ERR
, "Cannot open %s", configname
);
669 while (fgets(sid
, sizeof(sid
), cfgfile
) != NULL
){
670 if (*sid
== '#' || *sid
== '\n' || *sid
== EOS
) {
674 return _ipmilan_setconfinfo(s
, sid
);
682 /* Fence module instead of STONITH module */
684 Remove leading and trailing whitespace from a line of text.
687 cleanup(char *line
, size_t linelen
)
692 /* Remove leading whitespace. */
694 for (x
= 0; x
<= linelen
; x
++) {
707 /* Move the remainder down by as many whitespace chars as we
710 memmove(p
, &line
[x
], linelen
-x
);
712 /* Remove trailing whitespace. */
713 for (x
=0; x
<= linelen
; x
++) {
731 Parse args from stdin. Dev + devlen + op + oplen must be valid.
734 get_options_stdin(char *ip
, size_t iplen
,
735 char *passwd
, size_t pwlen
,
736 char *user
, size_t userlen
,
737 char *op
, size_t oplen
,
746 while (fgets(in
, sizeof(in
), stdin
)) {
752 if (cleanup(in
, sizeof(in
)) == -1)
756 if ((val
= strchr(in
, '='))) {
761 if (!strcasecmp(name
, "agent")) {
762 /* Used by fenced? */
763 } else if (!strcasecmp(name
, "verbose")) {
765 } else if (!strcasecmp(name
, "ipaddr")) {
766 /* IP address to use. E.g. 10.1.1.2 */
768 strncpy(ip
, val
, iplen
);
772 } else if (!strcasecmp(name
, "passwd")) {
775 strncpy(passwd
, val
, pwlen
);
779 } else if (!strcasecmp(name
, "user")) {
782 strncpy(user
, val
, userlen
);
786 } else if (!strcasecmp(name
, "option") ||
787 !strcasecmp(name
, "operation") ||
788 !strcasecmp(name
, "action")) {
790 strncpy(op
, val
, oplen
);
795 "parse error: illegal name on line %d\n",
806 Print a message to stderr and call exit(1).
811 fprintf(stderr
, "failed: %s\n", msg
);
816 usage_exit(char *pname
)
818 printf("usage: %s <options>\n", pname
);
819 printf(" -i <ipaddr> IPMI Lan IP to talk to\n");
820 printf(" -p <password> Password (if required) to control power on\n"
822 printf(" -l <login> Username/Login (if required) to control power\n"
823 " on IPMI device\n");
824 printf(" -o <op> Operation to perform.\n");
825 printf(" Valid operations: on, off, reboot\n");
826 printf(" -V Print version and exit\n");
827 printf(" -v Verbose mode\n\n");
828 printf("If no options are specified, the following options will be read\n");
829 printf("from standard input (one per line):\n\n");
830 printf(" ipaddr=<#> Same as -i\n");
831 printf(" passwd=<pass> Same as -p\n");
832 printf(" login=<login> Same as -u\n");
833 printf(" option=<op> Same as -o\n");
834 printf(" operation=<op> Same as -o\n");
835 printf(" action=<op> Same as -o\n");
836 printf(" verbose Same as -v\n\n");
842 main(int argc
, char **argv
)
851 char *pname
= basename(argv
[0]);
854 memset(ip
, 0, sizeof(ip
));
855 memset(passwd
, 0, sizeof(passwd
));
856 memset(user
, 0, sizeof(user
));
860 Parse command line options if any were specified
862 while ((opt
= getopt(argc
, argv
, "i:l:p:o:vV?hH")) != EOF
) {
866 strncpy(ip
, optarg
, sizeof(ip
));
870 strncpy(user
, optarg
, sizeof(user
));
874 strncpy(passwd
, optarg
, sizeof(passwd
));
878 strncpy(op
, optarg
, sizeof(op
));
884 printf("%s %s (built %s %s)\n", pname
,
896 No command line args? Get stuff from stdin
898 if (get_options_stdin(ip
, sizeof(ip
),
900 passwd
, sizeof(passwd
),
901 op
, sizeof(op
), &verbose
) != 0)
906 Validate the operating parameters
909 fail_exit("no IP address specified");
911 if (strcasecmp(op
, "off") && strcasecmp(op
, "on") &&
912 strcasecmp(op
, "reboot")) {
913 fail_exit("operation must be 'on', 'off', or 'reboot'");
916 /* Ok, set up the IPMI struct */
917 i
= ipmi_init(NULL
, ip
, user
, passwd
);
919 fail_exit("Failed to initialize\n");
922 Perform the requested operation
924 if (!strcasecmp(op
, "reboot")) {
925 printf("Rebooting machine @ IPMI:%s...", ip
);
932 } else if (!strcasecmp(op
, "on")) {
933 printf("Powering on machine @ IPMI:%s...", ip
);
937 } else if (!strcasecmp(op
, "off")) {
938 printf("Powering off machine @ IPMI:%s...", ip
);