summaryrefslogtreecommitdiffstats
path: root/heartbeat/IPv6addr.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--heartbeat/IPv6addr.c899
1 files changed, 899 insertions, 0 deletions
diff --git a/heartbeat/IPv6addr.c b/heartbeat/IPv6addr.c
new file mode 100644
index 0000000..2e9e126
--- /dev/null
+++ b/heartbeat/IPv6addr.c
@@ -0,0 +1,899 @@
+
+/*
+ * This program manages IPv6 address with OCF Resource Agent standard.
+ *
+ * Author: Huang Zhen <zhenh@cn.ibm.com>
+ * Copyright (c) 2004 International Business Machines
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * It can add an IPv6 address, or remove one.
+ *
+ * Usage: IPv6addr {start|stop|status|monitor|meta-data}
+ *
+ * The "start" arg adds an IPv6 address.
+ * The "stop" arg removes one.
+ * The "status" arg shows whether the IPv6 address exists
+ * The "monitor" arg shows whether the IPv6 address can be pinged (ICMPv6 ECHO)
+ * The "meta_data" arg shows the meta data(XML)
+ */
+
+/*
+ * ipv6-address:
+ *
+ * currently the following forms are legal:
+ * address
+ * address/prefix
+ *
+ * E.g.
+ * 3ffe:ffff:0:f101::3
+ * 3ffe:ffff:0:f101::3/64
+ *
+ * It should be passed by environment variant:
+ * OCF_RESKEY_ipv6addr=3ffe:ffff:0:f101::3
+ * OCF_RESKEY_cidr_netmask=64
+ * OCF_RESKEY_nic=eth0
+ *
+ */
+
+/*
+ * start:
+ * 1.IPv6addr will choice a proper interface for the new address.
+ * 2.Then assign the new address to the interface.
+ * 3.Wait until the new address is available (reply ICMPv6 ECHO packet)
+ * 4.Send out the unsolicited advertisements.
+ *
+ * return 0(OCF_SUCCESS) for success
+ * return 1(OCF_ERR_GENERIC) for failure
+ * return 2(OCF_ERR_ARGS) for invalid or excess argument(s)
+ *
+ *
+ * stop:
+ * remove the address from the inferface.
+ *
+ * return 0(OCF_SUCCESS) for success
+ * return 1(OCF_ERR_GENERIC) for failure
+ * return 2(OCF_ERR_ARGS) for invalid or excess argument(s)
+ *
+ * status:
+ * return the status of the address. only check whether it exists.
+ *
+ * return 0(OCF_SUCCESS) for existing
+ * return 1(OCF_NOT_RUNNING) for not existing
+ * return 2(OCF_ERR_ARGS) for invalid or excess argument(s)
+ *
+ *
+ * monitor:
+ * ping the address by ICMPv6 ECHO request.
+ *
+ * return 0(OCF_SUCCESS) for response correctly.
+ * return 1(OCF_NOT_RUNNING) for no response.
+ * return 2(OCF_ERR_ARGS) for invalid or excess argument(s)
+ */
+
+#include <config.h>
+#include <IPv6addr.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/icmp6.h>
+#include <arpa/inet.h> /* for inet_pton */
+#include <net/if.h> /* for if_nametoindex */
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <syslog.h>
+#include <signal.h>
+#include <errno.h>
+#include <poll.h>
+#include <clplumbing/cl_log.h>
+
+
+#define PIDFILE_BASE HA_RSCTMPDIR "/IPv6addr-"
+
+/*
+0 No error, action succeeded completely
+1 generic or unspecified error (current practice)
+ The "monitor" operation shall return this for a crashed, hung or
+ otherwise non-functional resource.
+2 invalid or excess argument(s)
+ Likely error code for validate-all, if the instance parameters
+ do not validate. Any other action is free to also return this
+ exit status code for this case.
+3 unimplemented feature (for example, "reload")
+4 user had insufficient privilege
+5 program is not installed
+6 program is not configured
+7 program is not running
+8 resource is running in "master" mode and fully operational
+9 resource is in "master" mode but in a failed state
+*/
+#define OCF_SUCCESS 0
+#define OCF_ERR_GENERIC 1
+#define OCF_ERR_ARGS 2
+#define OCF_ERR_UNIMPLEMENTED 3
+#define OCF_ERR_PERM 4
+#define OCF_ERR_INSTALLED 5
+#define OCF_ERR_CONFIGURED 6
+#define OCF_NOT_RUNNING 7
+
+const char* APP_NAME = "IPv6addr";
+
+const char* START_CMD = "start";
+const char* STOP_CMD = "stop";
+const char* STATUS_CMD = "status";
+const char* MONITOR_CMD = "monitor";
+const char* ADVT_CMD = "advt";
+const char* RECOVER_CMD = "recover";
+const char* RELOAD_CMD = "reload";
+const char* META_DATA_CMD = "meta-data";
+const char* VALIDATE_CMD = "validate-all";
+
+const int QUERY_COUNT = 5;
+
+struct in6_ifreq {
+ struct in6_addr ifr6_addr;
+ uint32_t ifr6_prefixlen;
+ unsigned int ifr6_ifindex;
+};
+
+static int start_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int stop_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int status_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int monitor_addr6(struct in6_addr* addr6, int prefix_len);
+static int advt_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname);
+static int meta_data_addr6(void);
+
+
+static void usage(const char* self);
+int write_pid_file(const char *pid_file);
+int create_pid_directory(const char *pid_file);
+static void byebye(int nsig);
+
+static char* scan_if(struct in6_addr* addr_target, int* plen_target,
+ int use_mask, char* prov_ifname);
+static char* find_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname);
+static char* get_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname);
+static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
+static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name);
+int is_addr6_available(struct in6_addr* addr6);
+
+int
+main(int argc, char* argv[])
+{
+ char pid_file[256];
+ char* ipv6addr;
+ char* cidr_netmask;
+ int ret;
+ char* cp;
+ char* prov_ifname = NULL;
+ int prefix_len = -1;
+ struct in6_addr addr6;
+ struct sigaction act;
+
+ /* Check the count of parameters first */
+ if (argc < 2) {
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+
+ /* set termination signal */
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_flags &= ~SA_RESTART; /* redundant - to stress syscalls should fail */
+ act.sa_handler = byebye;
+ if ((sigemptyset(&act.sa_mask) < 0) || (sigaction(SIGTERM, &act, NULL) < 0)) {
+ cl_log(LOG_ERR, "Could not set handler for signal: %s", strerror(errno));
+ return OCF_ERR_GENERIC;
+ }
+
+ /* open system log */
+ cl_log_set_entity(APP_NAME);
+ cl_log_set_facility(LOG_DAEMON);
+
+ /* the meta-data dont need any parameter */
+ if (0 == strncmp(META_DATA_CMD, argv[1], strlen(META_DATA_CMD))) {
+ ret = meta_data_addr6();
+ return OCF_SUCCESS;
+ }
+
+ /* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */
+ ipv6addr = getenv("OCF_RESKEY_ipv6addr");
+
+ if (ipv6addr == NULL) {
+ cl_log(LOG_ERR, "Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage.");
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+
+ /* legacy option */
+ if ((cp = strchr(ipv6addr, '/'))) {
+ prefix_len = atol(cp + 1);
+ if ((prefix_len < 0) || (prefix_len > 128)) {
+ cl_log(LOG_ERR, "Invalid prefix_len [%s], should be an integer in [0, 128]", cp+1);
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+ *cp=0;
+ }
+
+ /* get provided netmask (optional) */
+ cidr_netmask = getenv("OCF_RESKEY_cidr_netmask");
+
+ if (cidr_netmask != NULL) {
+ if ((atol(cidr_netmask) < 0) || (atol(cidr_netmask) > 128)) {
+ cl_log(LOG_ERR, "Invalid prefix_len [%s], "
+ "should be an integer in [0, 128]", cidr_netmask);
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+ if (prefix_len != -1 && prefix_len != atol(cidr_netmask)) {
+ cl_log(LOG_DEBUG, "prefix_len(%d) is overwritted by cidr_netmask(%s)",
+ prefix_len, cidr_netmask);
+ }
+ prefix_len = atol(cidr_netmask);
+
+ } else if (prefix_len == -1) {
+ prefix_len = 0;
+ }
+
+ /* get provided interface name (optional) */
+ prov_ifname = getenv("OCF_RESKEY_nic");
+
+ if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) {
+ cl_log(LOG_ERR, "Invalid IPv6 address [%s]", ipv6addr);
+ usage(argv[0]);
+ return OCF_ERR_ARGS;
+ }
+
+ /* Check whether this system supports IPv6 */
+ if (access(IF_INET6, R_OK)) {
+ cl_log(LOG_ERR, "No support for INET6 on this system.");
+ return OCF_ERR_GENERIC;
+ }
+
+ /* create the pid file so we can make sure that only one IPv6addr
+ * for this address is running
+ */
+ if (snprintf(pid_file, sizeof(pid_file), "%s%s", PIDFILE_BASE, ipv6addr)
+ >= (int)sizeof(pid_file)) {
+ cl_log(LOG_ERR, "Pid file truncated");
+ return OCF_ERR_GENERIC;
+ }
+
+ if (write_pid_file(pid_file) < 0) {
+ return OCF_ERR_GENERIC;
+ }
+
+
+ /* switch the command */
+ if (0 == strncmp(START_CMD,argv[1], strlen(START_CMD))) {
+ ret = start_addr6(&addr6, prefix_len, prov_ifname);
+ }else if (0 == strncmp(STOP_CMD,argv[1], strlen(STOP_CMD))) {
+ ret = stop_addr6(&addr6, prefix_len, prov_ifname);
+ }else if (0 == strncmp(STATUS_CMD,argv[1], strlen(STATUS_CMD))) {
+ ret = status_addr6(&addr6, prefix_len, prov_ifname);
+ }else if (0 ==strncmp(MONITOR_CMD,argv[1], strlen(MONITOR_CMD))) {
+ ret = monitor_addr6(&addr6, prefix_len);
+ }else if (0 ==strncmp(RELOAD_CMD,argv[1], strlen(RELOAD_CMD))) {
+ ret = OCF_ERR_UNIMPLEMENTED;
+ }else if (0 ==strncmp(RECOVER_CMD,argv[1], strlen(RECOVER_CMD))) {
+ ret = OCF_ERR_UNIMPLEMENTED;
+ }else if (0 ==strncmp(VALIDATE_CMD,argv[1], strlen(VALIDATE_CMD))) {
+ /* ipv6addr has been validated by inet_pton, hence a valid IPv6 address */
+ ret = OCF_SUCCESS;
+ }else if (0 ==strncmp(ADVT_CMD,argv[1], strlen(MONITOR_CMD))) {
+ ret = advt_addr6(&addr6, prefix_len, prov_ifname);
+ }else{
+ usage(argv[0]);
+ ret = OCF_ERR_ARGS;
+ }
+
+ /* release the pid file */
+ unlink(pid_file);
+
+ return ret;
+}
+int
+start_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
+{
+ int i;
+ char* if_name;
+ if(OCF_SUCCESS == status_addr6(addr6,prefix_len,prov_ifname)) {
+ return OCF_SUCCESS;
+ }
+
+ /* we need to find a proper device to assign the address */
+ if_name = find_if(addr6, &prefix_len, prov_ifname);
+ if (NULL == if_name) {
+ cl_log(LOG_ERR, "no valid mechanisms");
+ return OCF_ERR_GENERIC;
+ }
+
+ /* Assign the address */
+ if (0 != assign_addr6(addr6, prefix_len, if_name)) {
+ cl_log(LOG_ERR, "failed to assign the address to %s", if_name);
+ return OCF_ERR_GENERIC;
+ }
+
+ /* Check whether the address available */
+ for (i = 0; i < QUERY_COUNT; i++) {
+ if (0 == is_addr6_available(addr6)) {
+ break;
+ }
+ sleep(1);
+ }
+ if (i == QUERY_COUNT) {
+ cl_log(LOG_ERR, "failed to ping the address");
+ return OCF_ERR_GENERIC;
+ }
+
+ /* Send unsolicited advertisement packet to neighbor */
+ for (i = 0; i < UA_REPEAT_COUNT; i++) {
+ send_ua(addr6, if_name);
+ sleep(1);
+ }
+ return OCF_SUCCESS;
+}
+
+int
+advt_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
+{
+ /* First, we need to find a proper device to assign the address */
+ char* if_name = get_if(addr6, &prefix_len, prov_ifname);
+ int i;
+ if (NULL == if_name) {
+ cl_log(LOG_ERR, "no valid mechanisms");
+ return OCF_ERR_GENERIC;
+ }
+ /* Send unsolicited advertisement packet to neighbor */
+ for (i = 0; i < UA_REPEAT_COUNT; i++) {
+ send_ua(addr6, if_name);
+ sleep(1);
+ }
+ return OCF_SUCCESS;
+}
+
+int
+stop_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
+{
+ char* if_name;
+ if(OCF_NOT_RUNNING == status_addr6(addr6,prefix_len,prov_ifname)) {
+ return OCF_SUCCESS;
+ }
+
+ if_name = get_if(addr6, &prefix_len, prov_ifname);
+
+ if (NULL == if_name) {
+ cl_log(LOG_ERR, "no valid mechanisms.");
+ /* I think this should be a success exit according to LSB. */
+ return OCF_ERR_GENERIC;
+ }
+
+ /* Unassign the address */
+ if (0 != unassign_addr6(addr6, prefix_len, if_name)) {
+ cl_log(LOG_ERR, "failed to assign the address to %s", if_name);
+ return OCF_ERR_GENERIC;
+ }
+
+ return OCF_SUCCESS;
+}
+
+int
+status_addr6(struct in6_addr* addr6, int prefix_len, char* prov_ifname)
+{
+ char* if_name = get_if(addr6, &prefix_len, prov_ifname);
+ if (NULL == if_name) {
+ return OCF_NOT_RUNNING;
+ }
+ return OCF_SUCCESS;
+}
+
+int
+monitor_addr6(struct in6_addr* addr6, int prefix_len)
+{
+ if(0 == is_addr6_available(addr6)) {
+ return OCF_SUCCESS;
+ }
+ return OCF_NOT_RUNNING;
+}
+
+/* find the network interface associated with an address */
+char*
+scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask, char* prov_ifname)
+{
+ FILE *f;
+ static char devname[21]="";
+ struct in6_addr addr;
+ struct in6_addr mask;
+ unsigned int plen, scope, dad_status, if_idx;
+ unsigned int addr6p[4];
+
+ /* open /proc/net/if_inet6 file */
+ if ((f = fopen(IF_INET6, "r")) == NULL) {
+ return NULL;
+ }
+
+ /* Loop for each entry */
+ while (1) {
+ int i;
+ int n;
+ int s;
+ gboolean same = TRUE;
+
+ i = fscanf(f, "%08x%08x%08x%08x %x %02x %02x %02x %20s\n",
+ &addr6p[0], &addr6p[1], &addr6p[2], &addr6p[3],
+ &if_idx, &plen, &scope, &dad_status, devname);
+ if (i == EOF) {
+ break;
+ }
+ else if (i != 9) {
+ cl_log(LOG_INFO, "Error parsing %s, "
+ "perhaps the format has changed\n", IF_INET6);
+ break;
+ }
+
+ /* Consider link-local addresses (scope == 0x20) only when
+ * the inerface name is provided, and global addresses
+ * (scope == 0). Skip everything else.
+ */
+ if (scope != 0) {
+ if (scope != 0x20 || prov_ifname == 0
+ || *prov_ifname == 0)
+ continue;
+ }
+
+ /* If specified prefix, only same prefix entry
+ * would be considered.
+ */
+ if (*plen_target!=0 && plen != *plen_target) {
+ continue;
+ }
+
+ /* If interface name provided, only same devname entry
+ * would be considered
+ */
+ if (prov_ifname!=0 && *prov_ifname!=0)
+ {
+ if (strcmp(devname, prov_ifname))
+ continue;
+ }
+
+ for (i = 0; i< 4; i++) {
+ addr.s6_addr32[i] = htonl(addr6p[i]);
+ }
+
+ /* Make the mask based on prefix length */
+ memset(mask.s6_addr, 0xff, 16);
+ if (use_mask && plen < 128) {
+ n = plen / 32;
+ memset(mask.s6_addr32 + n + 1, 0, (3 - n) * 4);
+ s = 32 - plen % 32;
+ if (s == 32)
+ mask.s6_addr32[n] = 0x0;
+ else
+ mask.s6_addr32[n] = 0xffffffff << s;
+ mask.s6_addr32[n] = htonl(mask.s6_addr32[n]);
+ }
+
+ /* compare addr and addr_target */
+ same = TRUE;
+ for (i = 0; i < 4; i++) {
+ if ((addr.s6_addr32[i]&mask.s6_addr32[i]) !=
+ (addr_target->s6_addr32[i]&mask.s6_addr32[i])) {
+ same = FALSE;
+ break;
+ }
+ }
+
+ /* We found it! */
+ if (same) {
+ fclose(f);
+ *plen_target = plen;
+ return devname;
+ }
+ }
+ fclose(f);
+ return NULL;
+}
+/* find a proper network interface to assign the address */
+char*
+find_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname)
+{
+ char *best_ifname = scan_if(addr_target, plen_target, 1, prov_ifname);
+
+ /* use the provided ifname and prefix if the address did not match */
+ if (best_ifname == NULL &&
+ prov_ifname != 0 && *prov_ifname != 0 && *plen_target != 0) {
+ cl_log(LOG_INFO, "Could not find a proper interface by the ipv6addr. Using the specified nic:'%s' and cidr_netmask:'%d'", prov_ifname, *plen_target);
+ return prov_ifname;
+ }
+ return best_ifname;
+}
+/* get the device name and the plen_target of a special address */
+char*
+get_if(struct in6_addr* addr_target, int* plen_target, char* prov_ifname)
+{
+ return scan_if(addr_target, plen_target, 0, prov_ifname);
+}
+int
+assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name)
+{
+ struct in6_ifreq ifr6;
+
+ /* Get socket first */
+ int fd;
+ struct ifreq ifr;
+
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return 1;
+ }
+
+ /* Query the index of the if */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
+ return -1;
+ }
+
+ /* Assign the address to the if */
+ ifr6.ifr6_addr = *addr6;
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefix_len;
+ if (ioctl(fd, SIOCSIFADDR, &ifr6) < 0) {
+ return -1;
+ }
+ close (fd);
+ return 0;
+}
+int
+unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name)
+{
+ int fd;
+ struct ifreq ifr;
+ struct in6_ifreq ifr6;
+
+ /* Get socket first */
+ fd = socket(AF_INET6, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ return 1;
+ }
+
+ /* Query the index of the if */
+ strcpy(ifr.ifr_name, if_name);
+ if (ioctl(fd, SIOGIFINDEX, &ifr) < 0) {
+ return -1;
+ }
+
+ /* Unassign the address to the if */
+ ifr6.ifr6_addr = *addr6;
+ ifr6.ifr6_ifindex = ifr.ifr_ifindex;
+ ifr6.ifr6_prefixlen = prefix_len;
+ if (ioctl(fd, SIOCDIFADDR, &ifr6) < 0) {
+ return -1;
+ }
+
+ close (fd);
+ return 0;
+}
+
+#define MINPACKSIZE 64
+int
+is_addr6_available(struct in6_addr* addr6)
+{
+ struct sockaddr_in6 addr;
+ struct icmp6_hdr icmph;
+ u_char outpack[MINPACKSIZE];
+ int icmp_sock;
+ int ret;
+ struct iovec iov;
+ u_char packet[MINPACKSIZE];
+ struct msghdr msg;
+ int i;
+ struct pollfd pfd;
+
+ if ((icmp_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) {
+ return -1;
+ }
+
+ memset(&icmph, 0, sizeof(icmph));
+ icmph.icmp6_type = ICMP6_ECHO_REQUEST;
+ icmph.icmp6_code = 0;
+ icmph.icmp6_cksum = 0;
+ icmph.icmp6_seq = htons(0);
+ icmph.icmp6_id = 0;
+
+ memset(&outpack, 0, sizeof(outpack));
+ memcpy(&outpack, &icmph, sizeof(icmph));
+
+ memset(&addr, 0, sizeof(struct sockaddr_in6));
+ addr.sin6_family = AF_INET6;
+ addr.sin6_port = htons(IPPROTO_ICMPV6);
+ memcpy(&addr.sin6_addr,addr6,sizeof(struct in6_addr));
+
+ /* Only the first 8 bytes of outpack are meaningful... */
+ ret = sendto(icmp_sock, (char *)outpack, sizeof(outpack), 0,
+ (struct sockaddr *) &addr,
+ sizeof(struct sockaddr_in6));
+ if (0 >= ret) {
+ return -1;
+ }
+
+ iov.iov_base = (char *)packet;
+ iov.iov_len = sizeof(packet);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+
+ for (i = 0; i < 3; i++) {
+ pfd.fd = icmp_sock;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ ret = poll(&pfd, 1, 10);
+
+ if (ret < 1)
+ continue;
+
+ ret = recvmsg(icmp_sock, &msg, MSG_DONTWAIT);
+ if (ret > 0)
+ return 0;
+ if (ret == 0)
+ break;
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR)
+ break;
+ }
+
+ return -1;
+}
+
+static void usage(const char* self)
+{
+ printf("usage: %s {start|stop|status|monitor|validate-all|meta-data}\n",self);
+ return;
+}
+
+/* Following code is copied from send_arp.c, linux-HA project. */
+void
+byebye(int nsig)
+{
+ (void)nsig;
+ /* Avoid an "error exit" log message if we're killed */
+ exit(0);
+}
+
+int
+create_pid_directory(const char *pid_file)
+{
+ int status;
+ int return_status = -1;
+ struct stat stat_buf;
+ char* dir;
+
+ dir = strdup(pid_file);
+ if (!dir) {
+ cl_log(LOG_INFO, "Memory allocation failure: %s",
+ strerror(errno));
+ return -1;
+ }
+
+ dirname(dir);
+
+ status = stat(dir, &stat_buf);
+
+ if (status < 0 && errno != ENOENT && errno != ENOTDIR) {
+ cl_log(LOG_INFO, "Could not stat pid-file directory "
+ "[%s]: %s", dir, strerror(errno));
+ goto err;
+ }
+
+ if (!status) {
+ if (S_ISDIR(stat_buf.st_mode)) {
+ goto out;
+ }
+ cl_log(LOG_INFO, "Pid-File directory exists but is "
+ "not a directory [%s]", dir);
+ goto err;
+ }
+
+ if (mkdir(dir, S_IRUSR|S_IWUSR|S_IXUSR | S_IRGRP|S_IXGRP) < 0) {
+ cl_log(LOG_INFO, "Could not create pid-file directory "
+ "[%s]: %s", dir, strerror(errno));
+ goto err;
+ }
+
+out:
+ return_status = 0;
+err:
+ free(dir);
+ return return_status;
+}
+
+int
+write_pid_file(const char *pid_file)
+{
+
+ int pidfilefd;
+ char pidbuf[11];
+ unsigned long pid;
+ ssize_t bytes;
+
+ if (*pid_file != '/') {
+ cl_log(LOG_INFO, "Invalid pid-file name, must begin with a "
+ "'/' [%s]\n", pid_file);
+ return -1;
+ }
+
+ if (create_pid_directory(pid_file) < 0) {
+ return -1;
+ }
+
+ while (1) {
+ pidfilefd = open(pid_file, O_CREAT|O_EXCL|O_RDWR,
+ S_IRUSR|S_IWUSR);
+ if (pidfilefd < 0) {
+ if (errno != EEXIST) { /* Old PID file */
+ cl_log(LOG_INFO, "Could not open pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+ }
+ else {
+ break;
+ }
+
+ pidfilefd = open(pid_file, O_RDONLY, S_IRUSR|S_IWUSR);
+ if (pidfilefd < 0) {
+ cl_log(LOG_INFO, "Could not open pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+
+ while (1) {
+ bytes = read(pidfilefd, pidbuf, sizeof(pidbuf)-1);
+ if (bytes < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ cl_log(LOG_INFO, "Could not read pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+ pidbuf[bytes] = '\0';
+ break;
+ }
+
+ if(unlink(pid_file) < 0) {
+ cl_log(LOG_INFO, "Could not delete pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+
+ if (!bytes) {
+ cl_log(LOG_INFO, "Invalid pid in pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+
+ close(pidfilefd);
+
+ pid = strtoul(pidbuf, NULL, 10);
+ if (pid == ULONG_MAX && errno == ERANGE) {
+ cl_log(LOG_INFO, "Invalid pid in pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+
+ if (kill(pid, SIGKILL) < 0 && errno != ESRCH) {
+ cl_log(LOG_INFO, "Error killing old process [%lu] "
+ "from pid-file [%s]: %s", pid,
+ pid_file, strerror(errno));
+ return -1;
+ }
+
+ cl_log(LOG_INFO, "Killed old send_ua process [%lu]", pid);
+ }
+
+ if (snprintf(pidbuf, sizeof(pidbuf), "%u"
+ , getpid()) >= (int)sizeof(pidbuf)) {
+ cl_log(LOG_INFO, "Pid too long for buffer [%u]", getpid());
+ return -1;
+ }
+
+ while (1) {
+ bytes = write(pidfilefd, pidbuf, strlen(pidbuf));
+ if (bytes != strlen(pidbuf)) {
+ if (bytes < 0 && errno == EINTR) {
+ continue;
+ }
+ cl_log(LOG_INFO, "Could not write pid-file "
+ "[%s]: %s", pid_file,
+ strerror(errno));
+ return -1;
+ }
+ break;
+ }
+
+ close(pidfilefd);
+
+ return 0;
+}
+static int
+meta_data_addr6(void)
+{
+ const char* meta_data=
+ "<?xml version=\"1.0\"?>\n"
+ "<!DOCTYPE resource-agent SYSTEM \"ra-api-1.dtd\">\n"
+ "<resource-agent name=\"IPv6addr\" version=\"1.0\">\n"
+ " <version>1.0</version>\n"
+ " <longdesc lang=\"en\">\n"
+ " This script manages IPv6 alias IPv6 addresses,It can add an IP6\n"
+ " alias, or remove one.\n"
+ " </longdesc>\n"
+ " <shortdesc lang=\"en\">Manages IPv6 aliases</shortdesc>\n"
+ " <parameters>\n"
+ " <parameter name=\"ipv6addr\" unique=\"0\" required=\"1\">\n"
+ " <longdesc lang=\"en\">\n"
+ " The IPv6 address this RA will manage \n"
+ " </longdesc>\n"
+ " <shortdesc lang=\"en\">IPv6 address</shortdesc>\n"
+ " <content type=\"string\" default=\"\" />\n"
+ " </parameter>\n"
+ " <parameter name=\"cidr_netmask\" unique=\"0\">\n"
+ " <longdesc lang=\"en\">\n"
+ " The netmask for the interface in CIDR format. (ie, 24).\n"
+ " The value of this parameter overwrites the value of _prefix_\n"
+ " of ipv6addr parameter.\n"
+ " </longdesc>\n"
+ " <shortdesc lang=\"en\">Netmask</shortdesc>\n"
+ " <content type=\"string\" default=\"\" />\n"
+ " </parameter>\n"
+ " <parameter name=\"nic\" unique=\"0\">\n"
+ " <longdesc lang=\"en\">\n"
+ " The base network interface on which the IPv6 address will\n"
+ " be brought online.\n"
+ " </longdesc>\n"
+ " <shortdesc lang=\"en\">Network interface</shortdesc>\n"
+ " <content type=\"string\" default=\"\" />\n"
+ " </parameter>\n"
+ " </parameters>\n"
+ " <actions>\n"
+ " <action name=\"start\" timeout=\"15s\" />\n"
+ " <action name=\"stop\" timeout=\"15s\" />\n"
+ " <action name=\"status\" timeout=\"15s\" interval=\"15s\" />\n"
+ " <action name=\"monitor\" timeout=\"15s\" interval=\"15s\" />\n"
+ " <action name=\"validate-all\" timeout=\"5s\" />\n"
+ " <action name=\"meta-data\" timeout=\"5s\" />\n"
+ " </actions>\n"
+ "</resource-agent>\n";
+ printf("%s\n",meta_data);
+ return OCF_SUCCESS;
+}