diff options
Diffstat (limited to '')
-rw-r--r-- | heartbeat/IPv6addr.c | 899 |
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; +} |