mirror of
https://github.com/samba-team/samba.git
synced 2025-03-22 02:50:28 +03:00
Merge commit 'origin/master'
(This used to be ctdb commit cb00f86752d276ef0ac4dad97f7b380439603286)
This commit is contained in:
commit
b5254bf4ef
@ -35,7 +35,8 @@ CFLAGS=-g -I$(srcdir)/include -Iinclude -Ilib -Ilib/util -I$(srcdir) \
|
||||
LIB_FLAGS=@LDFLAGS@ -Llib @LIBS@ $(POPT_LIBS) @INFINIBAND_LIBS@ @CTDB_PCAP_LDFLAGS@
|
||||
|
||||
UTIL_OBJ = lib/util/idtree.o lib/util/db_wrap.o lib/util/strlist.o lib/util/util.o \
|
||||
lib/util/util_time.o lib/util/util_file.o
|
||||
lib/util/util_time.o lib/util/util_file.o lib/util/fault.o lib/util/substitute.o \
|
||||
lib/util/signal.o
|
||||
|
||||
CTDB_COMMON_OBJ = common/ctdb_io.o common/ctdb_util.o \
|
||||
common/ctdb_ltdb.o common/ctdb_message.o common/cmdline.o \
|
||||
@ -210,6 +211,7 @@ install: all
|
||||
${INSTALLCMD} -m 644 include/ctdb_private.h $(DESTDIR)$(includedir) # for samba3
|
||||
${INSTALLCMD} -m 644 config/functions $(DESTDIR)$(etcdir)/ctdb
|
||||
${INSTALLCMD} -m 755 config/statd-callout $(DESTDIR)$(etcdir)/ctdb
|
||||
${INSTALLCMD} -m 755 config/interface_modify.sh $(DESTDIR)$(etcdir)/ctdb
|
||||
${INSTALLCMD} -m 644 config/events.d/README $(DESTDIR)$(docdir)/ctdb/README.eventscripts
|
||||
${INSTALLCMD} -m 644 doc/recovery-process.txt $(DESTDIR)$(docdir)/ctdb/recovery-process.txt
|
||||
${INSTALLCMD} -m 755 config/events.d/00.ctdb $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
@ -217,6 +219,7 @@ install: all
|
||||
${INSTALLCMD} -m 755 config/events.d/10.interface $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 755 config/events.d/11.natgw $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 755 config/events.d/11.routing $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 755 config/events.d/13.per_ip_routing $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 644 config/events.d/20.multipathd $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 644 config/events.d/31.clamd $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
${INSTALLCMD} -m 755 config/events.d/40.vsftpd $(DESTDIR)$(etcdir)/ctdb/events.d
|
||||
|
@ -2318,16 +2318,18 @@ int ctdb_ctrl_list_tunables(struct ctdb_context *ctdb,
|
||||
}
|
||||
|
||||
|
||||
int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips)
|
||||
int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32_t flags,
|
||||
struct ctdb_all_public_ips **ips)
|
||||
{
|
||||
int ret;
|
||||
TDB_DATA outdata;
|
||||
int32_t res;
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_PUBLIC_IPS, 0, tdb_null,
|
||||
CTDB_CONTROL_GET_PUBLIC_IPS, flags, tdb_null,
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret == 0 && res == -1) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control to get public ips failed, falling back to ipv4-only version\n"));
|
||||
@ -2344,6 +2346,16 @@ int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct ctdb_all_public_ips **ips)
|
||||
{
|
||||
return ctdb_ctrl_get_public_ips_flags(ctdb, timeout,
|
||||
destnode, mem_ctx,
|
||||
0, ips);
|
||||
}
|
||||
|
||||
int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips)
|
||||
@ -2377,6 +2389,162 @@ int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const ctdb_sock_addr *addr,
|
||||
struct ctdb_control_public_ip_info **_info)
|
||||
{
|
||||
int ret;
|
||||
TDB_DATA indata;
|
||||
TDB_DATA outdata;
|
||||
int32_t res;
|
||||
struct ctdb_control_public_ip_info *info;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
|
||||
indata.dptr = discard_const_p(uint8_t, addr);
|
||||
indata.dsize = sizeof(*addr);
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_PUBLIC_IP_INFO, 0, indata,
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
|
||||
"failed ret:%d res:%d\n",
|
||||
ret, res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = offsetof(struct ctdb_control_public_ip_info, ifaces);
|
||||
if (len > outdata.dsize) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
|
||||
"returned invalid data with size %u > %u\n",
|
||||
(unsigned int)outdata.dsize,
|
||||
(unsigned int)len));
|
||||
dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
info = (struct ctdb_control_public_ip_info *)outdata.dptr;
|
||||
len += info->num*sizeof(struct ctdb_control_iface_info);
|
||||
|
||||
if (len > outdata.dsize) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
|
||||
"returned invalid data with size %u > %u\n",
|
||||
(unsigned int)outdata.dsize,
|
||||
(unsigned int)len));
|
||||
dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure we null terminate the returned strings */
|
||||
for (i=0; i < info->num; i++) {
|
||||
info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
|
||||
}
|
||||
|
||||
*_info = (struct ctdb_control_public_ip_info *)talloc_memdup(mem_ctx,
|
||||
outdata.dptr,
|
||||
outdata.dsize);
|
||||
talloc_free(outdata.dptr);
|
||||
if (*_info == NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get public ip info "
|
||||
"talloc_memdup size %u failed\n",
|
||||
(unsigned int)outdata.dsize));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct ctdb_control_get_ifaces **_ifaces)
|
||||
{
|
||||
int ret;
|
||||
TDB_DATA outdata;
|
||||
int32_t res;
|
||||
struct ctdb_control_get_ifaces *ifaces;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_GET_IFACES, 0, tdb_null,
|
||||
mem_ctx, &outdata, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
|
||||
"failed ret:%d res:%d\n",
|
||||
ret, res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
len = offsetof(struct ctdb_control_get_ifaces, ifaces);
|
||||
if (len > outdata.dsize) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
|
||||
"returned invalid data with size %u > %u\n",
|
||||
(unsigned int)outdata.dsize,
|
||||
(unsigned int)len));
|
||||
dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ifaces = (struct ctdb_control_get_ifaces *)outdata.dptr;
|
||||
len += ifaces->num*sizeof(struct ctdb_control_iface_info);
|
||||
|
||||
if (len > outdata.dsize) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
|
||||
"returned invalid data with size %u > %u\n",
|
||||
(unsigned int)outdata.dsize,
|
||||
(unsigned int)len));
|
||||
dump_data(DEBUG_DEBUG, outdata.dptr, outdata.dsize);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure we null terminate the returned strings */
|
||||
for (i=0; i < ifaces->num; i++) {
|
||||
ifaces->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
|
||||
}
|
||||
|
||||
*_ifaces = (struct ctdb_control_get_ifaces *)talloc_memdup(mem_ctx,
|
||||
outdata.dptr,
|
||||
outdata.dsize);
|
||||
talloc_free(outdata.dptr);
|
||||
if (*_ifaces == NULL) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for get ifaces "
|
||||
"talloc_memdup size %u failed\n",
|
||||
(unsigned int)outdata.dsize));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const struct ctdb_control_iface_info *info)
|
||||
{
|
||||
int ret;
|
||||
TDB_DATA indata;
|
||||
int32_t res;
|
||||
|
||||
indata.dptr = discard_const_p(uint8_t, info);
|
||||
indata.dsize = sizeof(*info);
|
||||
|
||||
ret = ctdb_control(ctdb, destnode, 0,
|
||||
CTDB_CONTROL_SET_IFACE_LINK_STATE, 0, indata,
|
||||
mem_ctx, NULL, &res, &timeout, NULL);
|
||||
if (ret != 0 || res != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " ctdb_control for set iface link "
|
||||
"failed ret:%d res:%d\n",
|
||||
ret, res));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
set/clear the permanent disabled bit on a remote node
|
||||
*/
|
||||
|
@ -367,7 +367,7 @@ bool parse_ipv4(const char *s, unsigned port, struct sockaddr_in *sin)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_ipv6(const char *s, const char *iface, unsigned port, ctdb_sock_addr *saddr)
|
||||
static bool parse_ipv6(const char *s, const char *ifaces, unsigned port, ctdb_sock_addr *saddr)
|
||||
{
|
||||
saddr->ip6.sin6_family = AF_INET6;
|
||||
saddr->ip6.sin6_port = htons(port);
|
||||
@ -379,8 +379,14 @@ static bool parse_ipv6(const char *s, const char *iface, unsigned port, ctdb_soc
|
||||
return false;
|
||||
}
|
||||
|
||||
if (iface && IN6_IS_ADDR_LINKLOCAL(&saddr->ip6.sin6_addr)) {
|
||||
saddr->ip6.sin6_scope_id = if_nametoindex(iface);
|
||||
if (ifaces && IN6_IS_ADDR_LINKLOCAL(&saddr->ip6.sin6_addr)) {
|
||||
if (strchr(ifaces, ',')) {
|
||||
DEBUG(DEBUG_ERR, (__location__ " Link local address %s "
|
||||
"is specified for multiple ifaces %s\n",
|
||||
s, ifaces));
|
||||
return false;
|
||||
}
|
||||
saddr->ip6.sin6_scope_id = if_nametoindex(ifaces);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -430,7 +436,7 @@ bool parse_ip_port(const char *addr, ctdb_sock_addr *saddr)
|
||||
/*
|
||||
parse an ip
|
||||
*/
|
||||
bool parse_ip(const char *addr, const char *iface, unsigned port, ctdb_sock_addr *saddr)
|
||||
bool parse_ip(const char *addr, const char *ifaces, unsigned port, ctdb_sock_addr *saddr)
|
||||
{
|
||||
char *p;
|
||||
bool ret;
|
||||
@ -440,7 +446,7 @@ bool parse_ip(const char *addr, const char *iface, unsigned port, ctdb_sock_addr
|
||||
if (p == NULL) {
|
||||
ret = parse_ipv4(addr, port, &saddr->ip);
|
||||
} else {
|
||||
ret = parse_ipv6(addr, iface, port, saddr);
|
||||
ret = parse_ipv6(addr, ifaces, port, saddr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@ -449,7 +455,7 @@ bool parse_ip(const char *addr, const char *iface, unsigned port, ctdb_sock_addr
|
||||
/*
|
||||
parse a ip/mask pair
|
||||
*/
|
||||
bool parse_ip_mask(const char *str, const char *iface, ctdb_sock_addr *addr, unsigned *mask)
|
||||
bool parse_ip_mask(const char *str, const char *ifaces, ctdb_sock_addr *addr, unsigned *mask)
|
||||
{
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(NULL);
|
||||
char *s, *p;
|
||||
@ -482,7 +488,7 @@ bool parse_ip_mask(const char *str, const char *iface, ctdb_sock_addr *addr, uns
|
||||
|
||||
|
||||
/* now is this a ipv4 or ipv6 address ?*/
|
||||
ret = parse_ip(s, iface, 0, addr);
|
||||
ret = parse_ip(s, ifaces, 0, addr);
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
@ -653,6 +659,7 @@ void ctdb_lockdown_memory(struct ctdb_context *ctdb)
|
||||
}
|
||||
|
||||
const char *ctdb_eventscript_call_names[] = {
|
||||
"init",
|
||||
"startup",
|
||||
"startrecovery",
|
||||
"recovered",
|
||||
@ -662,5 +669,6 @@ const char *ctdb_eventscript_call_names[] = {
|
||||
"monitor",
|
||||
"status",
|
||||
"shutdown",
|
||||
"reload"
|
||||
"reload",
|
||||
"updateip"
|
||||
};
|
||||
|
@ -179,6 +179,65 @@ CTDB_RECOVERY_LOCK="/some/place/on/shared/storage"
|
||||
# CTDB_NATGW_PRIVATE_NETWORK=10.1.1.0/24
|
||||
# CTDB_NATGW_NODES=/etc/ctdb/natgw_nodes
|
||||
|
||||
|
||||
# PER_IP_ROUTING configuration
|
||||
#
|
||||
# Some setups have multiple network interfaces connected to the
|
||||
# same network. By default all traffic for a network is routed
|
||||
# through only one interface, while the others are idle.
|
||||
#
|
||||
# On Linux it possible to use policy based routing to spread the load
|
||||
# across all interfaces. The is implemented by using a separate
|
||||
# routing table per public ip address.
|
||||
#
|
||||
# The configuration file configured by CTDB_PER_IP_ROUTING_CONF
|
||||
# contains the list of additional routes. The routes are bound to the
|
||||
# interface that is holding the public ip address.
|
||||
#
|
||||
# The format of the config file looks like this:
|
||||
# <public_ip_address> <network> [<gateway>]
|
||||
# and it's possible to have multiple routes per public ip address.
|
||||
#
|
||||
# If the special value "__auto_link_local__" is used, the config
|
||||
# file autogenerated. Each public ip address gets a special route
|
||||
# for its own subnet bound to it's current interface.
|
||||
# E.g. 10.1.2.3/24 will result in a config file line
|
||||
# 10.1.2.3 10.1.2.0/24
|
||||
#
|
||||
# The CTDB_PER_IP_ROUTING_RULE_PREF option needs to be configured.
|
||||
# The value will be passed as "pref" argument of "ip rule".
|
||||
# The value should be between 1 and 32765. So that the rule
|
||||
# comes after the rule for "local" routing table and before
|
||||
# the rule for the "main" routing table. This way the specific
|
||||
# routing table just overloads the "main" routing table,
|
||||
# this is useful because with the "__auto_link_local__" setup
|
||||
# the default route still comes from the "main" routing table.
|
||||
#
|
||||
# The routing table ids are automaticly allocated. On
|
||||
# Linux the routing table ids must be in the range of 0 to 255.
|
||||
# But some are reserved values, see /etc/iproute2/rt_tables.
|
||||
# You need to configure a range (CTDB_PER_IP_ROUTING_TABLE_ID_LOW
|
||||
# and CTDB_PER_IP_ROUTING_TABLE_ID_HIGH) from which the table ids can be taken.
|
||||
#
|
||||
# The default value for CTDB_PER_IP_ROUTING_CONF is "",
|
||||
# which means the feature is disabled by default.
|
||||
#
|
||||
# CTDB_PER_IP_ROUTING_CONF="/etc/ctdb/per_ip_routing.conf"
|
||||
# CTDB_PER_IP_ROUTING_CONF="__auto_link_local__"
|
||||
# CTDB_PER_IP_ROUTING_TABLE_ID_LOW=10
|
||||
# CTDB_PER_IP_ROUTING_TABLE_ID_HIGH=250
|
||||
# CTDB_PER_IP_ROUTING_RULE_PREF=10000
|
||||
|
||||
# Make offline interfaces not a reason for being UNHEALTHY.
|
||||
# The CTDB_PARTIALLY_ONLINE_INTERFACES option changes
|
||||
# the behavior of the 10.interface monitor event.
|
||||
# In some setups it's desired that interfaces without
|
||||
# an active link don't change the node to unhealthy.
|
||||
# ctdbd is just informed about the interface status
|
||||
# and "ctdb status" dislays the node as "PARTIALLYONLINE".
|
||||
#
|
||||
# CTDB_PARTIALLY_ONLINE_INTERFACES="yes"
|
||||
|
||||
# where to log messages
|
||||
# the default is /var/log/log.ctdb
|
||||
# CTDB_LOGFILE=/var/log/log.ctdb
|
||||
|
@ -13,7 +13,7 @@
|
||||
loadconfig
|
||||
|
||||
case "$1" in
|
||||
startup)
|
||||
init)
|
||||
# make sure we have a blank state directory for the scripts to work with
|
||||
/bin/rm -rf $CTDB_BASE/state
|
||||
/bin/mkdir -p $CTDB_BASE/state
|
||||
|
@ -5,7 +5,7 @@
|
||||
loadconfig
|
||||
|
||||
case "$1" in
|
||||
startup)
|
||||
init)
|
||||
ctdb_counter_init
|
||||
;;
|
||||
|
||||
|
@ -17,10 +17,114 @@ loadconfig
|
||||
exit 0
|
||||
}
|
||||
|
||||
monitor_interfaces()
|
||||
{
|
||||
local INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
|
||||
sed -e "s/^[^\t ]*[\t ]*//" -e "s/,/ /g" -e "s/[\t ]*$//"`
|
||||
|
||||
[ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
|
||||
[ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"
|
||||
|
||||
local IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`
|
||||
|
||||
local I
|
||||
local IFACE
|
||||
|
||||
for I in $IFACES; do
|
||||
IFACE=`echo -n "$I" | cut -d ':' -f2`
|
||||
INTERFACES="$IFACE $INTERFACES"
|
||||
done
|
||||
|
||||
INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
|
||||
|
||||
local fail=0
|
||||
local force_fail=0
|
||||
local ok=0
|
||||
for IFACE in $INTERFACES ; do
|
||||
|
||||
local OLDLINK=`echo -n "$IFACES" | grep "^:$IFACE:" | cut -d ':' -f3 | xargs`
|
||||
test -z "$OLDLINK" && {
|
||||
force_fail=1
|
||||
}
|
||||
|
||||
# These interfaces are sometimes bond devices
|
||||
# When we use VLANs for bond interfaces, there will only
|
||||
# be an entry in /proc for the underlying real interface
|
||||
local REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
|
||||
[ -f /proc/net/bonding/$REALIFACE ] && {
|
||||
grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
|
||||
echo "ERROR: No active slaves for bond device $REALIFACE"
|
||||
fail=1
|
||||
test -n "$OLDLINK" && {
|
||||
ctdb setifacelink $IFACE down
|
||||
}
|
||||
continue;
|
||||
}
|
||||
grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
|
||||
echo "ERROR: public network interface $REALIFACE is down"
|
||||
fail=1
|
||||
test -n "$OLDLINK" && {
|
||||
ctdb setifacelink $IFACE down
|
||||
}
|
||||
continue;
|
||||
}
|
||||
test -n "$OLDLINK" && {
|
||||
ok=1 # we only set ok for interfaces known to ctdbd
|
||||
ctdb setifacelink $IFACE up
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case $IFACE in
|
||||
ib*)
|
||||
# we dont know how to test ib links
|
||||
;;
|
||||
*)
|
||||
[ -z "$IFACE" ] || {
|
||||
ethtool $IFACE | grep -q 'Link detected: yes' || {
|
||||
# On some systems, this is not successful when a
|
||||
# cable is plugged but the interface has not been
|
||||
# brought up previously. Bring the interface up and
|
||||
# try again...
|
||||
/sbin/ip link set $IFACE up
|
||||
ethtool $IFACE | grep -q 'Link detected: yes' || {
|
||||
echo "ERROR: No link on the public network interface $IFACE"
|
||||
fail=1
|
||||
test -n "$OLDLINK" && {
|
||||
ctdb setifacelink $IFACE down
|
||||
}
|
||||
continue
|
||||
}
|
||||
}
|
||||
test -n "$OLDLINK" && {
|
||||
ok=1 # we only set ok for interfaces known to ctdbd
|
||||
ctdb setifacelink $IFACE up
|
||||
}
|
||||
}
|
||||
;;
|
||||
esac
|
||||
|
||||
done
|
||||
|
||||
test x"$fail" = x"0" && {
|
||||
return 0;
|
||||
}
|
||||
|
||||
test x"$force_fail" != x"0" && {
|
||||
return 1;
|
||||
}
|
||||
|
||||
test x"$ok" = x"1" && {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
#############################
|
||||
# called when ctdbd starts up
|
||||
startup)
|
||||
init)
|
||||
# make sure that we only respond to ARP messages from the NIC where
|
||||
# a particular ip address is associated.
|
||||
[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
|
||||
@ -37,6 +141,14 @@ case "$1" in
|
||||
done
|
||||
;;
|
||||
|
||||
#############################
|
||||
# called after ctdbd has done its initial recovery
|
||||
# and we start the services to become healthy
|
||||
startup)
|
||||
monitor_interfaces
|
||||
|
||||
;;
|
||||
|
||||
|
||||
################################################
|
||||
# called when ctdbd wants to claim an IP address
|
||||
@ -49,14 +161,10 @@ case "$1" in
|
||||
ip=$3
|
||||
maskbits=$4
|
||||
|
||||
# we make sure the interface is up first
|
||||
/sbin/ip link set $iface up || {
|
||||
echo "Failed to bringup interface $iface"
|
||||
exit 1
|
||||
}
|
||||
/sbin/ip addr add $ip/$maskbits brd + dev $iface || {
|
||||
echo "Failed to add $ip/$maskbits on dev $iface"
|
||||
add_ip_to_iface $iface $ip $maskbits || {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# cope with the script being killed while we have the interface blocked
|
||||
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
|
||||
|
||||
@ -93,34 +201,74 @@ case "$1" in
|
||||
iptables -I INPUT -i $iface -d $ip -j DROP
|
||||
kill_tcp_connections $ip
|
||||
|
||||
# the ip tool will delete all secondary IPs if this is the primary. To work around
|
||||
# this _very_ annoying behaviour we have to keep a record of the secondaries and re-add
|
||||
# them afterwards. yuck
|
||||
secondaries=""
|
||||
if /sbin/ip addr list dev $iface primary | grep -q "inet $ip/$maskbits " ; then
|
||||
secondaries=`/sbin/ip addr list dev $iface secondary | grep " inet " | awk '{print $2}'`
|
||||
fi
|
||||
/sbin/ip addr del $ip/$maskbits dev $iface || failed=1
|
||||
[ -z "$secondaries" ] || {
|
||||
for i in $secondaries; do
|
||||
if /sbin/ip addr list dev $iface | grep -q "inet $i" ; then
|
||||
echo "kept secondary $i on dev $iface"
|
||||
else
|
||||
echo "re-adding secondary address $i to dev $iface"
|
||||
/sbin/ip addr add $i dev $iface || failed=1
|
||||
fi
|
||||
done
|
||||
delete_ip_from_iface $iface $ip $maskbits || {
|
||||
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
|
||||
exit 1;
|
||||
}
|
||||
|
||||
iptables -D INPUT -i $iface -d $ip -j DROP 2> /dev/null
|
||||
[ $failed = 0 ] || {
|
||||
echo "Failed to del $ip on dev $iface"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
;;
|
||||
|
||||
##################################################
|
||||
# called when ctdbd wants to update an IP address
|
||||
updateip)
|
||||
if [ $# != 5 ]; then
|
||||
echo "must supply old interface, new interface, IP and maskbits"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# moving an IP is a bit more complex than it seems.
|
||||
# First we drop all traffic on the old interface.
|
||||
# Then we try to add the ip to the new interface and before
|
||||
# we finally remove it from the old interface.
|
||||
#
|
||||
# 1) firewall this IP, so no new external packets arrive for it
|
||||
# 2) add the IP to the new interface
|
||||
# 3) remove the IP from the old interface
|
||||
# 4) remove the firewall rule
|
||||
# 5) use ctdb gratiousarp to propagate the new mac address
|
||||
# 6) use netstat -tn to find existing connections, and tickle them
|
||||
oiface=$2
|
||||
niface=$3
|
||||
ip=$4
|
||||
maskbits=$5
|
||||
|
||||
failed=0
|
||||
# we do an extra delete to cope with the script being killed
|
||||
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
|
||||
iptables -I INPUT -i $oiface -d $ip -j DROP
|
||||
|
||||
# we make sure the interface is up first
|
||||
add_ip_to_iface $niface $ip $maskbits || {
|
||||
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
|
||||
exit 1;
|
||||
}
|
||||
|
||||
delete_ip_from_iface $oiface $ip $maskbits || {
|
||||
delete_ip_from_iface $niface $ip $maskbits
|
||||
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# cope with the script being killed while we have the interface blocked
|
||||
iptables -D INPUT -i $oiface -d $ip -j DROP 2> /dev/null
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
|
||||
# propagate the new mac address
|
||||
ctdb gratiousarp $ip $niface
|
||||
|
||||
# tickle all existing connections, so that dropped packets
|
||||
# are retransmited and the tcp streams work
|
||||
|
||||
tickle_tcp_connections $ip
|
||||
|
||||
;;
|
||||
|
||||
|
||||
###########################################
|
||||
# called when ctdbd has finished a recovery
|
||||
@ -133,52 +281,21 @@ case "$1" in
|
||||
;;
|
||||
|
||||
monitor)
|
||||
INTERFACES=`cat $CTDB_PUBLIC_ADDRESSES |
|
||||
sed -e "s/^[^\t ]*[\t ]*//" -e "s/[\t ]*$//"`
|
||||
monitor_interfaces
|
||||
ret=$?
|
||||
|
||||
[ "$CTDB_PUBLIC_INTERFACE" ] && INTERFACES="$CTDB_PUBLIC_INTERFACE $INTERFACES"
|
||||
[ "$CTDB_NATGW_PUBLIC_IFACE" ] && INTERFACES="$CTDB_NATGW_PUBLIC_IFACE $INTERFACES"
|
||||
|
||||
INTERFACES=`for IFACE in $INTERFACES ; do echo $IFACE ; done | sort | uniq`
|
||||
|
||||
for IFACE in $INTERFACES ; do
|
||||
# These interfaces are sometimes bond devices
|
||||
# When we use VLANs for bond interfaces, there will only
|
||||
# be an entry in /proc for the underlying real interface
|
||||
REALIFACE=`echo $IFACE |sed -e 's/\..*$//'`
|
||||
[ -f /proc/net/bonding/$REALIFACE ] && {
|
||||
grep -q 'Currently Active Slave: None' /proc/net/bonding/$REALIFACE && {
|
||||
echo "ERROR: No active slaves for bond device $REALIFACE"
|
||||
exit 1
|
||||
test x"$ret" = x"2" && {
|
||||
test x"$CTDB_PARTIALLY_ONLINE_INTERFACES" != x"yes" && {
|
||||
exit 1;
|
||||
}
|
||||
grep -q '^MII Status: up' /proc/net/bonding/$REALIFACE || {
|
||||
echo "ERROR: public network interface $REALIFACE is down"
|
||||
exit 1
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
# as long as we have one interface available don't become
|
||||
# unhealthy
|
||||
ret=0
|
||||
}
|
||||
|
||||
case $IFACE in
|
||||
ib*)
|
||||
# we dont know how to test ib links
|
||||
;;
|
||||
*)
|
||||
[ -z "$IFACE" ] || {
|
||||
/usr/sbin/ethtool $IFACE | grep -q 'Link detected: yes' || {
|
||||
# On some systems, this is not successful when a
|
||||
# cable is plugged but the interface has not been
|
||||
# brought up previously. Bring the interface up and
|
||||
# try again...
|
||||
/sbin/ip link set $IFACE up
|
||||
/usr/sbin/ethtool $IFACE | grep -q 'Link detected: yes' || {
|
||||
echo "ERROR: No link on the public network interface $IFACE"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
}
|
||||
;;
|
||||
esac
|
||||
done
|
||||
test x"$ret" != x"0" && {
|
||||
exit 1;
|
||||
}
|
||||
;;
|
||||
*)
|
||||
ctdb_standard_event_handler "$@"
|
||||
|
444
ctdb/config/events.d/13.per_ip_routing
Executable file
444
ctdb/config/events.d/13.per_ip_routing
Executable file
@ -0,0 +1,444 @@
|
||||
#!/bin/sh
|
||||
|
||||
. $CTDB_BASE/functions
|
||||
loadconfig
|
||||
|
||||
[ -z "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
CTDB_PER_IP_ROUTING_STATE="$CTDB_BASE/state/per_ip_routing"
|
||||
}
|
||||
|
||||
AUTO_LINK_LOCAL="no"
|
||||
|
||||
case "$CTDB_PER_IP_ROUTING_CONF" in
|
||||
__auto_link_local__)
|
||||
AUTO_LINK_LOCAL="yes"
|
||||
CTDB_PER_IP_ROUTING_CONF="$CTDB_PER_IP_ROUTING_STATE/auto_link_local.conf"
|
||||
;;
|
||||
*)
|
||||
[ -z "$CTDB_PER_IP_ROUTING_CONF" ] && {
|
||||
#echo "No config file found. Nothing to do for 13.per_ip_routing"
|
||||
exit 0;
|
||||
}
|
||||
;;
|
||||
esac
|
||||
|
||||
_low=$CTDB_PER_IP_ROUTING_TABLE_ID_LOW
|
||||
_high=$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH
|
||||
|
||||
test -z "$_low" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW not configured";
|
||||
exit 1;
|
||||
}
|
||||
test -z "$_high" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_HIGH not configured";
|
||||
exit 1;
|
||||
}
|
||||
test "$_low" -ge "$_high" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_TABLE_ID_LOW[$_low] needs to be below CTDB_PER_IP_ROUTING_TABLE_ID_HIGH[$_high]";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
test -z "$CTDB_PER_IP_ROUTING_RULE_PREF" && {
|
||||
echo "$0: CTDB_PER_IP_ROUTING_RULE_PREF not configured";
|
||||
exit 1;
|
||||
}
|
||||
|
||||
locknesting=0
|
||||
lock_root="$CTDB_PER_IP_ROUTING_STATE"
|
||||
host=`hostname`
|
||||
|
||||
lock_debug()
|
||||
{
|
||||
echo -n ""
|
||||
}
|
||||
|
||||
############################
|
||||
# grab a lock file. Not atomic, but close :)
|
||||
# tries to cope with NFS
|
||||
lock_file() {
|
||||
if [ -z "$lock_root" ]; then
|
||||
lock_root=`pwd`;
|
||||
fi
|
||||
lckf="$lock_root/$1"
|
||||
machine=`cat "$lckf" 2> /dev/null | cut -d: -f1`
|
||||
pid=`cat "$lckf" 2> /dev/null | cut -d: -f2`
|
||||
|
||||
if [ "$pid" = "$$" ]; then
|
||||
locknesting=`expr $locknesting + 1`
|
||||
lock_debug "lock nesting now $locknesting"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if test -f "$lckf"; then
|
||||
test $machine = $host || {
|
||||
lock_debug "lock file $lckf is valid for other machine $machine"
|
||||
stat -c%y "$lckf"
|
||||
return 1
|
||||
}
|
||||
kill -0 $pid && {
|
||||
lock_debug "lock file $lckf is valid for process $pid"
|
||||
stat -c%y "$lckf"
|
||||
return 1
|
||||
}
|
||||
lock_debug "stale lock file $lckf for $machine:$pid"
|
||||
cat "$lckf"
|
||||
/bin/rm -f "$lckf"
|
||||
fi
|
||||
echo "$host:$$" > "$lckf"
|
||||
return 0
|
||||
}
|
||||
|
||||
############################
|
||||
# unlock a lock file
|
||||
unlock_file() {
|
||||
if [ -z "$lock_root" ]; then
|
||||
lock_root=`pwd`;
|
||||
fi
|
||||
if [ "$locknesting" != "0" ]; then
|
||||
locknesting=`expr $locknesting - 1`
|
||||
lock_debug "lock nesting now $locknesting"
|
||||
else
|
||||
lckf="$lock_root/$1"
|
||||
/bin/rm -f "$lckf"
|
||||
fi
|
||||
}
|
||||
|
||||
generate_table_id () {
|
||||
local _ip=$1
|
||||
local _ipsdir="$CTDB_PER_IP_ROUTING_STATE/ips"
|
||||
local _ipdir="$_ipsdir/$_ip"
|
||||
|
||||
mkdir -p $_ipdir
|
||||
|
||||
#echo "generate_table_id $_ip"
|
||||
|
||||
local _id=`cat $_ipdir/table_id 2>/dev/null| xargs`
|
||||
test -n "$_id" && {
|
||||
#echo "IP: $_ip => OLD TABLE: $_id"
|
||||
table_id=$_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
local _low="$CTDB_PER_IP_ROUTING_TABLE_ID_LOW"
|
||||
local _high="$CTDB_PER_IP_ROUTING_TABLE_ID_HIGH"
|
||||
|
||||
local _newid=""
|
||||
for _id in `seq $_low $_high | xargs`; do
|
||||
local _table_lck="table_id_$_id.lock"
|
||||
lock_file $_table_lck 2>/dev/null || {
|
||||
continue;
|
||||
}
|
||||
local _taken=`grep "^$_id$" $_ipsdir/*/table_id 2>/dev/null| wc -l | xargs`
|
||||
test x"$_taken" != x"0" && {
|
||||
unlock_file $_table_lck
|
||||
#echo "tableid: $_id taken"
|
||||
continue
|
||||
}
|
||||
_newid=$_id;
|
||||
echo "$_newid" > $_ipdir/table_id
|
||||
unlock_file $_table_lck
|
||||
break;
|
||||
done
|
||||
|
||||
test -z "$_newid" && {
|
||||
echo "generate_table_id: out of table ids: $_low - $_high"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
#echo "IP: $_ip => NEW TABLE: $_newid"
|
||||
table_id=$_newid
|
||||
return 0;
|
||||
}
|
||||
|
||||
run_release_script_once()
|
||||
{
|
||||
local _script=$1
|
||||
|
||||
#echo "run_release_script_once[$_script]"
|
||||
|
||||
test -x "$_script" && {
|
||||
#echo "run it: start"
|
||||
$_script || {
|
||||
echo "release_script: $_script - failed $?"
|
||||
return $?;
|
||||
}
|
||||
#echo "run it: end"
|
||||
}
|
||||
|
||||
echo -e "#!/bin/sh\n#\n" > $_script
|
||||
chmod +x $_script
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
generate_auto_link_local()
|
||||
{
|
||||
local _ip=$1
|
||||
local _maskbits=$2
|
||||
|
||||
#echo "generate_auto_link_local $_ip $_maskbits"
|
||||
|
||||
local _netip=`ipv4_host_addr_to_net_addr $_ip $_maskbits`
|
||||
|
||||
local _line="$_ip $_netip/$_maskbits"
|
||||
|
||||
local _config=`cat $CTDB_PER_IP_ROUTING_CONF 2>/dev/null`
|
||||
|
||||
local _exact=`echo -n "$_config" | grep "^$line$" | wc -l | xargs`
|
||||
|
||||
test x"$_exact" = x"1" && {
|
||||
return 0;
|
||||
}
|
||||
|
||||
local _tmp="$CTDB_PER_IP_ROUTING_CONF.$$.tmp"
|
||||
echo -n "$_config" | grep -v "^$_ip " > $_tmp
|
||||
echo "$_line" >> $_tmp
|
||||
|
||||
mv $_tmp $CTDB_PER_IP_ROUTING_CONF
|
||||
}
|
||||
|
||||
generate_per_ip_routing()
|
||||
{
|
||||
local _ip=$1
|
||||
local _maskbits=$2
|
||||
local _iface=$3
|
||||
local _readonly=$4
|
||||
local _ipdir="$CTDB_PER_IP_ROUTING_STATE/ips/$_ip"
|
||||
|
||||
table_id=""
|
||||
release_script="$_ipdir/release_script.sh"
|
||||
|
||||
test x"$_readonly" = x"yes" && {
|
||||
test -d $_ipdir || {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
mkdir -p $_ipdir || {
|
||||
echo "mkdir -p $_ipdir failed"
|
||||
return 1;
|
||||
}
|
||||
echo "$_ip" > $_ipdir/ip
|
||||
|
||||
generate_table_id $_ip
|
||||
|
||||
test x"$AUTO_LINK_LOCAL" = x"yes" && {
|
||||
generate_auto_link_local $_ip $_maskbits
|
||||
}
|
||||
|
||||
release_script="$_ipdir/release_script.sh"
|
||||
run_release_script_once $release_script
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
#############################
|
||||
# called when ctdbd starts up
|
||||
startup)
|
||||
# cleanup old rules
|
||||
pref=$CTDB_PER_IP_ROUTING_RULE_PREF
|
||||
rules=`ip rule show | grep "^$pref:" | sed -e 's/.*from \([^ ][^ ]*\) lookup \([^ ][^ ]*\)/\2;\1/' | xargs`
|
||||
for r in $rules; do
|
||||
table_id=`echo -n "$r" | cut -d ';' -f1`
|
||||
ip=`echo -n "$r" | cut -d ';' -f2-`
|
||||
|
||||
echo "Removing ip rule for public address $ip for routing table $table_id"
|
||||
cmd="ip rule del from $ip table $table_id pref $pref"
|
||||
#echo $cmd
|
||||
eval $cmd
|
||||
cmd="ip route flush table $table_id"
|
||||
#echo $cmd
|
||||
eval $cmd 2>/dev/null
|
||||
done
|
||||
|
||||
# make sure that we only respond to ARP messages from the NIC where
|
||||
# a particular ip address is associated.
|
||||
[ -f /proc/sys/net/ipv4/conf/all/arp_filter ] && {
|
||||
echo 1 > /proc/sys/net/ipv4/conf/all/arp_filter
|
||||
}
|
||||
|
||||
mkdir -p $CTDB_PER_IP_ROUTING_STATE
|
||||
|
||||
;;
|
||||
|
||||
shutdown)
|
||||
|
||||
for s in $CTDB_PER_IP_ROUTING_STATE/ips/*/release_script.sh; do
|
||||
run_release_script_once "$s"
|
||||
done
|
||||
rm -rf $CTDB_PER_IP_ROUTING_STATE
|
||||
|
||||
;;
|
||||
|
||||
################################################
|
||||
# called when ctdbd wants to claim an IP address
|
||||
takeip)
|
||||
if [ $# != 4 ]; then
|
||||
echo "must supply interface, IP and maskbits"
|
||||
exit 1
|
||||
fi
|
||||
iface=$2
|
||||
ip=$3
|
||||
maskbits=$4
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $iface "no" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface no - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
config=`cat $CTDB_PER_IP_ROUTING_CONF`
|
||||
lines=`echo -n "$config" | grep -n "^$ip " | cut -d ':' -f1 | xargs`
|
||||
|
||||
pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
|
||||
|
||||
test -n "$lines" && {
|
||||
echo "ip rule del from $ip pref $pref table $table_id" >> $release_script
|
||||
echo "ip route flush table $table_id 2>/dev/null" >> $release_script
|
||||
|
||||
ip rule del from $ip pref $pref 2>/dev/null
|
||||
ip rule add from $ip pref $pref table $table_id
|
||||
ip route flush table $table_id 2>/dev/null
|
||||
}
|
||||
for l in $lines; do
|
||||
line=`echo -n "$config" | head -n $l | tail -n 1`
|
||||
dest=`echo -n "$line" | cut -d ' ' -f 2`
|
||||
gw=`echo -n "$line" | cut -d ' ' -f 3`
|
||||
|
||||
via=""
|
||||
test -n "$gw" && {
|
||||
via="via $gw"
|
||||
}
|
||||
|
||||
ip route add $dest $via dev $iface table $table_id
|
||||
done
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
ctdb gratiousarp $ip $iface
|
||||
|
||||
;;
|
||||
|
||||
################################################
|
||||
# called when ctdbd wants to claim an IP address
|
||||
updateip)
|
||||
if [ $# != 5 ]; then
|
||||
echo "must supply old interface, new interface, IP and maskbits"
|
||||
exit 1
|
||||
fi
|
||||
oiface=$2
|
||||
niface=$3
|
||||
ip=$4
|
||||
maskbits=$5
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $niface "no" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $niface no - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
config=`cat $CTDB_PER_IP_ROUTING_CONF`
|
||||
lines=`echo -n "$config" | grep -n "^$ip " | cut -d ':' -f1 | xargs`
|
||||
|
||||
pref="$CTDB_PER_IP_ROUTING_RULE_PREF"
|
||||
|
||||
test -n "$lines" && {
|
||||
echo "ip rule del from $ip pref $pref table $table_id" >> $release_script
|
||||
echo "ip route flush table $table_id 2>/dev/null" >> $release_script
|
||||
|
||||
ip rule del from $ip pref $pref 2>/dev/null
|
||||
ip rule add from $ip pref $pref table $table_id
|
||||
ip route flush table $table_id 2>/dev/null
|
||||
}
|
||||
for l in $lines; do
|
||||
line=`echo -n "$config" | head -n $l | tail -n 1`
|
||||
dest=`echo -n "$line" | cut -d ' ' -f 2`
|
||||
gw=`echo -n "$line" | cut -d ' ' -f 3`
|
||||
|
||||
via=""
|
||||
test -n "$gw" && {
|
||||
via="via $gw"
|
||||
}
|
||||
|
||||
ip route add $dest $via dev $niface table $table_id
|
||||
done
|
||||
|
||||
# flush our route cache
|
||||
echo 1 > /proc/sys/net/ipv4/route/flush
|
||||
|
||||
ctdb gratiousarp $ip $niface
|
||||
tickle_tcp_connections $ip
|
||||
|
||||
;;
|
||||
|
||||
##################################################
|
||||
# called when ctdbd wants to release an IP address
|
||||
releaseip)
|
||||
if [ $# != 4 ]; then
|
||||
echo "must supply interface, IP and maskbits"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
iface=$2
|
||||
ip=$3
|
||||
maskbits=$4
|
||||
|
||||
ipv4_is_valid_addr $ip || {
|
||||
echo "$0: $1 not an ipv4 address skipping IP:$ip"
|
||||
exit 0;
|
||||
}
|
||||
|
||||
[ ! -d "$CTDB_PER_IP_ROUTING_STATE" ] && {
|
||||
echo "$0: $1 No state directory found, waiting for startup."
|
||||
exit 0;
|
||||
}
|
||||
|
||||
generate_per_ip_routing $ip $maskbits $iface "yes" || {
|
||||
echo "$0: $1: generate_per_ip_routing $ip $maskbits $iface yes - failed"
|
||||
exit 1;
|
||||
}
|
||||
|
||||
run_release_script_once "$release_script"
|
||||
|
||||
;;
|
||||
|
||||
|
||||
###########################################
|
||||
# called when ctdbd has finished a recovery
|
||||
recovered)
|
||||
;;
|
||||
|
||||
####################################
|
||||
# called when ctdbd is shutting down
|
||||
shutdown)
|
||||
;;
|
||||
|
||||
monitor)
|
||||
;;
|
||||
*)
|
||||
ctdb_standard_event_handler "$@"
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
@ -22,11 +22,20 @@ All of the events except the 'shutdown' and 'startrecovery' events will be
|
||||
called with the ctdb daemon in NORMAL mode (ie. not in recovery)
|
||||
|
||||
The events currently implemented are
|
||||
startup
|
||||
init
|
||||
This event does not take any additional arguments.
|
||||
This event is only invoked once, when ctdb is starting up.
|
||||
This event is used to wait for the service to start and all
|
||||
resources for the service becoming available.
|
||||
This event is used to do some cleanup work from earlier runs
|
||||
and prepare the basic setup.
|
||||
|
||||
Example: 00.ctdb cleans up $CTDB_BASE/state
|
||||
|
||||
startup
|
||||
This event does not take any additional arguments.
|
||||
This event is only invoked once, when ctdb has finished
|
||||
the initial recoveries. This event is used to wait for
|
||||
the service to start and all resources for the service
|
||||
becoming available.
|
||||
|
||||
This is used to prevent ctdb from starting up and advertize its
|
||||
services until all dependent services have become available.
|
||||
@ -105,6 +114,14 @@ releaseip
|
||||
|
||||
Example: 60.nfs
|
||||
|
||||
updateip
|
||||
This event is triggered everytime the node moves a public ip
|
||||
address between interfaces
|
||||
This event takes four additional arguments :
|
||||
'old-interface' 'new-interface' 'ipaddress' and 'netmask'
|
||||
|
||||
Example: 10.interface
|
||||
|
||||
startrecovery
|
||||
This event is triggered everytime we start a recovery process
|
||||
or before we start changing ip address allocations.
|
||||
|
@ -307,6 +307,36 @@ kill_tcp_connections_local_only() {
|
||||
echo "killed $_killcount TCP connections to released IP $_IP"
|
||||
}
|
||||
|
||||
##################################################################
|
||||
# tickle any TCP connections with the given IP
|
||||
##################################################################
|
||||
tickle_tcp_connections() {
|
||||
_IP="$1"
|
||||
_failed=0
|
||||
|
||||
_killcount=0
|
||||
connfile="$CTDB_BASE/state/connections.$_IP"
|
||||
netstat -tn |egrep "^tcp.*[[:space:]]+$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' > $connfile
|
||||
netstat -tn |egrep "^tcp.*[[:space:]]+::ffff:$_IP:.*ESTABLISHED" | awk '{print $4" "$5}' >> $connfile
|
||||
|
||||
while read dest src; do
|
||||
srcip=`echo $src | sed -e "s/:[^:]*$//"`
|
||||
srcport=`echo $src | sed -e "s/^.*://"`
|
||||
destip=`echo $dest | sed -e "s/:[^:]*$//"`
|
||||
destport=`echo $dest | sed -e "s/^.*://"`
|
||||
echo "Tickle TCP connection $srcip:$srcport $destip:$destport"
|
||||
ctdb tickle $srcip:$srcport $destip:$destport >/dev/null 2>&1 || _failed=1
|
||||
echo "Tickle TCP connection $destip:$destport $srcip:$srcport"
|
||||
ctdb tickle $destip:$destport $srcip:$srcport >/dev/null 2>&1 || _failed=1
|
||||
done < $connfile
|
||||
/bin/rm -f $connfile
|
||||
|
||||
[ $_failed = 0 ] || {
|
||||
echo "Failed to send tickle control"
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
########################################################
|
||||
# start/stop the nfs service on different platforms
|
||||
########################################################
|
||||
@ -391,9 +421,7 @@ startstop_nfslock() {
|
||||
esac
|
||||
}
|
||||
|
||||
########################################################
|
||||
# remove an ip address from an interface
|
||||
########################################################
|
||||
# better use delete_ip_from_iface() together with add_ip_to_iface
|
||||
remove_ip() {
|
||||
# the ip tool will delete all secondary IPs if this is the primary.
|
||||
# To work around this _very_ annoying behaviour we have to keep a
|
||||
@ -415,6 +443,36 @@ remove_ip() {
|
||||
}
|
||||
}
|
||||
|
||||
add_ip_to_iface()
|
||||
{
|
||||
local _iface=$1
|
||||
local _ip=$2
|
||||
local _maskbits=$3
|
||||
local _lockfile="$CTDB_BASE/state/interface_modify.$_iface.flock"
|
||||
|
||||
test -f $_lockfile || {
|
||||
touch $_lockfile
|
||||
}
|
||||
|
||||
flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh add "$_iface" "$_ip" "$_maskbits"
|
||||
return $?
|
||||
}
|
||||
|
||||
delete_ip_from_iface()
|
||||
{
|
||||
local _iface=$1
|
||||
local _ip=$2
|
||||
local _maskbits=$3
|
||||
local _lockfile="$CTDB_BASE/state/interface_modify.$_iface.flock"
|
||||
|
||||
test -f $_lockfile || {
|
||||
touch $_lockfile
|
||||
}
|
||||
|
||||
flock --timeout 30 $_lockfile $CTDB_BASE/interface_modify.sh delete "$_iface" "$_ip" "$_maskbits"
|
||||
return $?
|
||||
}
|
||||
|
||||
########################################################
|
||||
# some simple logic for counting events - per eventscript
|
||||
# usage: ctdb_counter_init
|
||||
@ -600,6 +658,70 @@ ctdb_standard_event_handler ()
|
||||
esac
|
||||
}
|
||||
|
||||
ipv4_host_addr_to_net_addr()
|
||||
{
|
||||
local HOST=$1
|
||||
local MASKBITS=$2
|
||||
|
||||
local HOST0=$(echo $HOST | awk -F . '{print $4}')
|
||||
local HOST1=$(echo $HOST | awk -F . '{print $3}')
|
||||
local HOST2=$(echo $HOST | awk -F . '{print $2}')
|
||||
local HOST3=$(echo $HOST | awk -F . '{print $1}')
|
||||
|
||||
local HOST_NUM=$(( $HOST0 + $HOST1 * 256 + $HOST2 * (256 ** 2) + $HOST3 * (256 ** 3) ))
|
||||
|
||||
local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
|
||||
|
||||
local NET_NUM=$(( $HOST_NUM & $MASK_NUM))
|
||||
|
||||
local NET0=$(( $NET_NUM & 255 ))
|
||||
local NET1=$(( ($NET_NUM & (255 * 256)) / 256 ))
|
||||
local NET2=$(( ($NET_NUM & (255 * 256**2)) / 256**2 ))
|
||||
local NET3=$(( ($NET_NUM & (255 * 256**3)) / 256**3 ))
|
||||
|
||||
echo "$NET3.$NET2.$NET1.$NET0"
|
||||
}
|
||||
|
||||
ipv4_maskbits_to_net_mask()
|
||||
{
|
||||
local MASKBITS=$1
|
||||
|
||||
local MASK_NUM=$(( ( (2**32 - 1) * (2**(32 - $MASKBITS)) ) & (2**32 - 1) ))
|
||||
|
||||
local MASK0=$(( $MASK_NUM & 255 ))
|
||||
local MASK1=$(( ($MASK_NUM & (255 * 256)) / 256 ))
|
||||
local MASK2=$(( ($MASK_NUM & (255 * 256**2)) / 256**2 ))
|
||||
local MASK3=$(( ($MASK_NUM & (255 * 256**3)) / 256**3 ))
|
||||
|
||||
echo "$MASK3.$MASK2.$MASK1.$MASK0"
|
||||
}
|
||||
|
||||
ipv4_is_valid_addr()
|
||||
{
|
||||
local ADDR=$1
|
||||
local fail=0
|
||||
|
||||
local N=`echo $ADDR | sed -e 's/[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*//'`
|
||||
test -n "$N" && fail=1
|
||||
|
||||
local ADDR0=$(echo $ADDR | awk -F . '{print $4}')
|
||||
local ADDR1=$(echo $ADDR | awk -F . '{print $3}')
|
||||
local ADDR2=$(echo $ADDR | awk -F . '{print $2}')
|
||||
local ADDR3=$(echo $ADDR | awk -F . '{print $1}')
|
||||
|
||||
test "$ADDR0" -gt 255 && fail=1
|
||||
test "$ADDR1" -gt 255 && fail=1
|
||||
test "$ADDR2" -gt 255 && fail=1
|
||||
test "$ADDR3" -gt 255 && fail=1
|
||||
|
||||
test x"$fail" != x"0" && {
|
||||
#echo "IPv4: '$ADDR' is not a valid address"
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
########################################################
|
||||
# load a site local config file
|
||||
########################################################
|
||||
|
87
ctdb/config/gdb_backtrace
Executable file
87
ctdb/config/gdb_backtrace
Executable file
@ -0,0 +1,87 @@
|
||||
#!/bin/sh
|
||||
|
||||
BASENAME=`basename $0`
|
||||
|
||||
if [ -n "$VALGRIND" -o -n "$SMBD_VALGRIND" ]; then
|
||||
echo "${BASENAME}: Not running debugger under valgrind"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# we want everything on stderr, so the program is not disturbed
|
||||
exec 1>&2
|
||||
|
||||
BASENAME=`basename $0`
|
||||
UNAME=`uname`
|
||||
|
||||
PID=$1
|
||||
BINARY=$2
|
||||
|
||||
test x"${PID}" = x"" && {
|
||||
echo "Usage: ${BASENAME} <pid> [<binary>]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
DB_LIST="gdb"
|
||||
case "${UNAME}" in
|
||||
#
|
||||
# on Tru64 we need to try ladebug first
|
||||
# because gdb crashes itself...
|
||||
#
|
||||
OSF1)
|
||||
DB_LIST="ladebug ${DB_LIST}"
|
||||
;;
|
||||
esac
|
||||
|
||||
for DB in ${DB_LIST}; do
|
||||
DB_BIN=`which ${DB} 2>/dev/null | grep '^/'`
|
||||
test x"${DB_BIN}" != x"" && {
|
||||
break
|
||||
}
|
||||
done
|
||||
|
||||
test x"${DB_BIN}" = x"" && {
|
||||
echo "${BASENAME}: ERROR: No debugger found."
|
||||
exit 1
|
||||
}
|
||||
|
||||
#
|
||||
# we first try to use /proc/${PID}/exe
|
||||
# then fallback to the binary from the commandline
|
||||
# then we search for the commandline argument with
|
||||
# 'which'
|
||||
#
|
||||
test -f "/proc/${PID}/exe" && BINARY="/proc/${PID}/exe"
|
||||
test x"${BINARY}" = x"" && BINARY="/proc/${PID}/exe"
|
||||
test -f "${BINARY}" || BINARY=`which ${BINARY}`
|
||||
|
||||
test -f "${BINARY}" || {
|
||||
echo "${BASENAME}: ERROR: Cannot find binary '${BINARY}'."
|
||||
exit 1
|
||||
}
|
||||
|
||||
echo "${BASENAME}: Trying to use ${DB_BIN} on ${BINARY} on PID ${PID}"
|
||||
|
||||
BATCHFILE_PRE=/tmp/gdb_backtrace_pre.$$
|
||||
BATCHFILE_MAIN=/tmp/gdb_backtrace_main.$$
|
||||
case "${DB}" in
|
||||
ladebug)
|
||||
cat << EOF > ${BATCHFILE_PRE}
|
||||
set \$stoponattach
|
||||
EOF
|
||||
|
||||
cat << EOF > ${BATCHFILE_MAIN}
|
||||
where
|
||||
quit
|
||||
EOF
|
||||
${DB_BIN} -c "${BATCHFILE_MAIN}" -i "${BATCHFILE_PRE}" -pid "${PID}" "${BINARY}"
|
||||
;;
|
||||
gdb)
|
||||
cat << EOF > ${BATCHFILE_MAIN}
|
||||
set height 1000
|
||||
bt full
|
||||
quit
|
||||
EOF
|
||||
${DB_BIN} -x "${BATCHFILE_MAIN}" "${BINARY}" "${PID}"
|
||||
;;
|
||||
esac
|
||||
/bin/rm -f ${BATCHFILE_PRE} ${BATCHFILE_MAIN}
|
73
ctdb/config/interface_modify.sh
Executable file
73
ctdb/config/interface_modify.sh
Executable file
@ -0,0 +1,73 @@
|
||||
#!/bin/sh
|
||||
#
|
||||
|
||||
OP=$1
|
||||
IFACE=$2
|
||||
IP=$3
|
||||
MASKBITS=$4
|
||||
|
||||
add_ip_to_iface()
|
||||
{
|
||||
local _iface=$1
|
||||
local _ip=$2
|
||||
local _maskbits=$3
|
||||
|
||||
# we make sure the interface is up first
|
||||
/sbin/ip link set $_iface up || {
|
||||
echo "Failed to bringup interface $_iface"
|
||||
return 1;
|
||||
}
|
||||
/sbin/ip addr add $_ip/$_maskbits brd + dev $_iface || {
|
||||
echo "Failed to add $_ip/$_maskbits on dev $_iface"
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
delete_ip_from_iface()
|
||||
{
|
||||
local _iface=$1
|
||||
local _ip=$2
|
||||
local _maskbits=$3
|
||||
|
||||
# the ip tool will delete all secondary IPs if this is the primary. To work around
|
||||
# this _very_ annoying behaviour we have to keep a record of the secondaries and re-add
|
||||
# them afterwards. yuck
|
||||
local _secondaries=""
|
||||
if /sbin/ip addr list dev $_iface primary | grep -q "inet $_ip/$_maskbits " ; then
|
||||
_secondaries=`/sbin/ip addr list dev $_iface secondary | grep " inet " | awk '{print $2}'`
|
||||
fi
|
||||
local _failed=0
|
||||
/sbin/ip addr del $_ip/$_maskbits dev $_iface || _failed=1
|
||||
[ -z "$_secondaries" ] || {
|
||||
local _i=""
|
||||
for _i in $_secondaries; do
|
||||
if /sbin/ip addr list dev $_iface | grep -q "inet $_i" ; then
|
||||
echo "kept secondary $_i on dev $_iface"
|
||||
else
|
||||
echo "re-adding secondary address $_i to dev $_iface"
|
||||
/sbin/ip addr add $_i dev $_iface || _failed=1
|
||||
fi
|
||||
done
|
||||
}
|
||||
[ $_failed = 0 ] || {
|
||||
echo "Failed to del $_ip on dev $_iface"
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
case "$OP" in
|
||||
add)
|
||||
add_ip_to_iface $IFACE $IP $MASKBITS
|
||||
exit $?
|
||||
;;
|
||||
delete)
|
||||
delete_ip_from_iface $IFACE $IP $MASKBITS
|
||||
exit $?
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$0: unknown operation[$OP]"
|
||||
exit 1
|
@ -33,7 +33,12 @@ case $event in
|
||||
# or do something else ...
|
||||
;;
|
||||
startup)
|
||||
# do some extra magic when ctdb has started?
|
||||
# do some extra magic when ctdb has finished the initial
|
||||
# recovery?
|
||||
;;
|
||||
|
||||
init)
|
||||
# do some extra magic when ctdb has started?
|
||||
;;
|
||||
|
||||
esac
|
||||
|
@ -1,13 +1,5 @@
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(ctdb, m4_esyscmd([grep 'Version:' ./packaging/RPM/ctdb.spec 2>/dev/null | head -1 | sed -e 's/[ \t]*Version:[ \t]*\([^ \t]*\)[ \t]*.*/\1/' | tr -d '\n']))
|
||||
AC_DEFUN([AC_CHECK_LIB_EXT], [
|
||||
AC_CHECK_LIB([$1],[$3],[$4],[$5],[$7])
|
||||
ac_cv_lib_ext_$1_$3=$ac_cv_lib_$1_$3
|
||||
])
|
||||
AC_DEFUN([AC_CHECK_FUNC_EXT], [
|
||||
AC_CHECK_FUNC([$1],[$3],[$4])
|
||||
ac_cv_func_ext_$1=$ac_cv_func_$1
|
||||
])
|
||||
AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
|
||||
AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
|
||||
AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
|
||||
@ -68,6 +60,8 @@ m4_include(libtalloc.m4)
|
||||
m4_include(libtdb.m4)
|
||||
m4_include(libevents.m4)
|
||||
m4_include(ib/config.m4)
|
||||
m4_include(lib/util/signal.m4)
|
||||
m4_include(lib/util/fault.m4)
|
||||
|
||||
AC_CHECK_HEADERS(sched.h)
|
||||
AC_CHECK_FUNCS(sched_setscheduler)
|
||||
|
@ -679,7 +679,8 @@ struct ctdb_scripts_wire {
|
||||
|
||||
/* different calls to event scripts. */
|
||||
enum ctdb_eventscript_call {
|
||||
CTDB_EVENT_STARTUP, /* CTDB starting up: no args. */
|
||||
CTDB_EVENT_INIT, /* CTDB starting up: no args */
|
||||
CTDB_EVENT_STARTUP, /* CTDB starting up after initial recovery: no args. */
|
||||
CTDB_EVENT_START_RECOVERY, /* CTDB recovery starting: no args. */
|
||||
CTDB_EVENT_RECOVERED, /* CTDB recovery finished: no args. */
|
||||
CTDB_EVENT_TAKE_IP, /* IP taken: interface, IP address, netmask bits. */
|
||||
@ -689,6 +690,7 @@ enum ctdb_eventscript_call {
|
||||
CTDB_EVENT_STATUS, /* Report service status: no args. */
|
||||
CTDB_EVENT_SHUTDOWN, /* CTDB shutting down: no args. */
|
||||
CTDB_EVENT_RELOAD, /* magic */
|
||||
CTDB_EVENT_UPDATE_IP, /* IP updating: old interface, new interface, IP address, netmask bits. */
|
||||
CTDB_EVENT_MAX
|
||||
};
|
||||
|
||||
|
@ -181,12 +181,14 @@ struct ctdb_client {
|
||||
struct ctdb_client_notify_list *notify;
|
||||
};
|
||||
|
||||
struct ctdb_iface;
|
||||
|
||||
/* state associated with a public ip address */
|
||||
struct ctdb_vnn {
|
||||
struct ctdb_vnn *prev, *next;
|
||||
|
||||
const char *iface;
|
||||
struct ctdb_iface *iface;
|
||||
const char **ifaces;
|
||||
ctdb_sock_addr public_address;
|
||||
uint8_t public_netmask_bits;
|
||||
|
||||
@ -244,7 +246,8 @@ struct ctdb_node {
|
||||
across the nodes. it needs to know which public ip's can be handled
|
||||
by each node.
|
||||
*/
|
||||
struct ctdb_all_public_ips *public_ips;
|
||||
struct ctdb_all_public_ips *known_public_ips;
|
||||
struct ctdb_all_public_ips *available_public_ips;
|
||||
/* used by the recovery dameon to track when a node should be banned */
|
||||
struct ctdb_banning_state *ban_state;
|
||||
};
|
||||
@ -424,6 +427,7 @@ struct ctdb_context {
|
||||
struct ctdb_node **nodes; /* array of nodes in the cluster - indexed by vnn */
|
||||
struct ctdb_vnn *vnn; /* list of public ip addresses and interfaces */
|
||||
struct ctdb_vnn *single_ip_vnn; /* a structure for the single ip */
|
||||
struct ctdb_iface *ifaces; /* list of local interfaces */
|
||||
char *err_msg;
|
||||
const struct ctdb_methods *methods; /* transport methods */
|
||||
const struct ctdb_upcalls *upcalls; /* transport upcalls */
|
||||
@ -634,6 +638,9 @@ enum ctdb_controls {CTDB_CONTROL_PROCESS_EXISTS = 0,
|
||||
CTDB_CONTROL_GET_DB_SEQNUM = 120,
|
||||
CTDB_CONTROL_DB_SET_HEALTHY = 121,
|
||||
CTDB_CONTROL_DB_GET_HEALTH = 122,
|
||||
CTDB_CONTROL_GET_PUBLIC_IP_INFO = 123,
|
||||
CTDB_CONTROL_GET_IFACES = 124,
|
||||
CTDB_CONTROL_SET_IFACE_LINK_STATE = 125,
|
||||
};
|
||||
|
||||
/*
|
||||
@ -841,6 +848,7 @@ struct ctdb_req_control {
|
||||
uint64_t srvid;
|
||||
uint32_t client_id;
|
||||
#define CTDB_CTRL_FLAG_NOREPLY 1
|
||||
#define CTDB_CTRL_FLAG_OPCODE_SPECIFIC 0xFFFF0000
|
||||
uint32_t flags;
|
||||
uint32_t datalen;
|
||||
uint8_t data[1];
|
||||
@ -1301,12 +1309,67 @@ struct ctdb_all_public_ips {
|
||||
int32_t ctdb_control_get_public_ipsv4(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata);
|
||||
int32_t ctdb_control_get_public_ips(struct ctdb_context *ctdb, struct ctdb_req_control *c, TDB_DATA *outdata);
|
||||
int ctdb_ctrl_get_public_ips(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips);
|
||||
struct timeval timeout,
|
||||
uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct ctdb_all_public_ips **ips);
|
||||
#define CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE 0x00010000
|
||||
int ctdb_ctrl_get_public_ips_flags(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
uint32_t flags,
|
||||
struct ctdb_all_public_ips **ips);
|
||||
int ctdb_ctrl_get_public_ipsv4(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx, struct ctdb_all_public_ips **ips);
|
||||
|
||||
#ifdef IFNAMSIZ
|
||||
#define CTDB_IFACE_SIZE IFNAMSIZ
|
||||
#else
|
||||
#define CTDB_IFACE_SIZE 16
|
||||
#endif
|
||||
|
||||
struct ctdb_control_iface_info {
|
||||
char name[CTDB_IFACE_SIZE+2];
|
||||
uint16_t link_state;
|
||||
uint32_t references;
|
||||
};
|
||||
|
||||
struct ctdb_control_public_ip_info {
|
||||
struct ctdb_public_ip ip;
|
||||
uint32_t active_idx;
|
||||
uint32_t num;
|
||||
struct ctdb_control_iface_info ifaces[1];
|
||||
};
|
||||
|
||||
struct ctdb_control_get_ifaces {
|
||||
uint32_t num;
|
||||
struct ctdb_control_iface_info ifaces[1];
|
||||
};
|
||||
|
||||
int32_t ctdb_control_get_public_ip_info(struct ctdb_context *ctdb,
|
||||
struct ctdb_req_control *c,
|
||||
TDB_DATA indata,
|
||||
TDB_DATA *outdata);
|
||||
int32_t ctdb_control_get_ifaces(struct ctdb_context *ctdb,
|
||||
struct ctdb_req_control *c,
|
||||
TDB_DATA *outdata);
|
||||
int32_t ctdb_control_set_iface_link(struct ctdb_context *ctdb,
|
||||
struct ctdb_req_control *c,
|
||||
TDB_DATA indata);
|
||||
int ctdb_ctrl_get_public_ip_info(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const ctdb_sock_addr *addr,
|
||||
struct ctdb_control_public_ip_info **info);
|
||||
int ctdb_ctrl_get_ifaces(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct ctdb_control_get_ifaces **ifaces);
|
||||
int ctdb_ctrl_set_iface_link(struct ctdb_context *ctdb,
|
||||
struct timeval timeout, uint32_t destnode,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
const struct ctdb_control_iface_info *info);
|
||||
|
||||
/* from takeover/system.c */
|
||||
uint32_t uint16_checksum(uint16_t *data, size_t n);
|
||||
@ -1317,6 +1380,9 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
|
||||
uint32_t seq, uint32_t ack, int rst);
|
||||
|
||||
int ctdb_set_public_addresses(struct ctdb_context *ctdb, const char *alist);
|
||||
int ctdb_set_single_public_ip(struct ctdb_context *ctdb,
|
||||
const char *iface,
|
||||
const char *ip);
|
||||
int ctdb_set_event_script(struct ctdb_context *ctdb, const char *script);
|
||||
int ctdb_set_event_script_dir(struct ctdb_context *ctdb, const char *script_dir);
|
||||
int ctdb_set_notification_script(struct ctdb_context *ctdb, const char *script);
|
||||
@ -1564,4 +1630,7 @@ int ctdb_update_persistent_health(struct ctdb_context *ctdb,
|
||||
int num_healthy_nodes);
|
||||
int ctdb_recheck_persistent_health(struct ctdb_context *ctdb);
|
||||
|
||||
void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event);
|
||||
|
||||
void ctdb_fault_setup(void);
|
||||
#endif
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include "tdb.h"
|
||||
#include "idtree.h"
|
||||
#include "ctdb.h"
|
||||
#include "lib/util/debug.h"
|
||||
|
||||
typedef bool BOOL;
|
||||
|
||||
@ -28,9 +27,13 @@ enum debug_level {
|
||||
DEBUG_DEBUG = 4,
|
||||
};
|
||||
|
||||
#define DEBUGLVL(lvl) ((lvl) <= LogLevel)
|
||||
#define DEBUG(lvl, x) do { this_log_level = (lvl); if ((lvl) < DEBUG_DEBUG) { log_ringbuffer x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0)
|
||||
#define DEBUGADD(lvl, x) do { if ((lvl) <= LogLevel) { this_log_level = (lvl); do_debug_add x; }} while (0)
|
||||
|
||||
#define _PUBLIC_
|
||||
#define _NORETURN_
|
||||
#define _PURE_
|
||||
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
@ -53,3 +56,5 @@ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_
|
||||
_PUBLIC_ const char **str_list_add(const char **list, const char *s);
|
||||
_PUBLIC_ int set_blocking(int fd, BOOL set);
|
||||
|
||||
#include "lib/util/debug.h"
|
||||
#include "lib/util/util.h"
|
||||
|
@ -41,14 +41,6 @@ struct epoll_event_context {
|
||||
/* number of registered fd event handlers */
|
||||
int num_fd_events;
|
||||
|
||||
/* this is changed by the destructors for the fd event
|
||||
type. It is used to detect event destruction by event
|
||||
handlers, which means the code that is calling the event
|
||||
handler needs to assume that the linked list is no longer
|
||||
valid
|
||||
*/
|
||||
uint32_t destruction_count;
|
||||
|
||||
/* when using epoll this is the handle from epoll_create */
|
||||
int epoll_fd;
|
||||
|
||||
@ -260,7 +252,6 @@ static int epoll_event_loop(struct epoll_event_context *epoll_ev, struct timeval
|
||||
int ret, i;
|
||||
#define MAXEVENTS 32
|
||||
struct epoll_event events[MAXEVENTS];
|
||||
uint32_t destruction_count = ++epoll_ev->destruction_count;
|
||||
int timeout = -1;
|
||||
|
||||
if (epoll_ev->epoll_fd == -1) return -1;
|
||||
@ -358,7 +349,6 @@ static int epoll_event_fd_destructor(struct fd_event *fde)
|
||||
epoll_check_reopen(epoll_ev);
|
||||
|
||||
epoll_ev->num_fd_events--;
|
||||
epoll_ev->destruction_count++;
|
||||
|
||||
epoll_del_event(epoll_ev, fde);
|
||||
|
||||
|
@ -48,10 +48,6 @@ struct select_event_context {
|
||||
|
||||
/* information for exiting from the event loop */
|
||||
int exit_code;
|
||||
|
||||
/* this is incremented when the loop over events causes something which
|
||||
could change the events yet to be processed */
|
||||
uint32_t destruction_count;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -104,7 +100,6 @@ static int select_event_fd_destructor(struct fd_event *fde)
|
||||
}
|
||||
|
||||
DLIST_REMOVE(select_ev->fd_events, fde);
|
||||
select_ev->destruction_count++;
|
||||
|
||||
if (fde->flags & EVENT_FD_AUTOCLOSE) {
|
||||
close(fde->fd);
|
||||
@ -180,7 +175,6 @@ static int select_event_loop_select(struct select_event_context *select_ev, stru
|
||||
fd_set r_fds, w_fds;
|
||||
struct fd_event *fde;
|
||||
int selrtn;
|
||||
uint32_t destruction_count = ++select_ev->destruction_count;
|
||||
|
||||
/* we maybe need to recalculate the maxfd */
|
||||
if (select_ev->maxfd == EVENT_INVALID_MAXFD) {
|
||||
|
@ -51,14 +51,6 @@ struct std_event_context {
|
||||
/* information for exiting from the event loop */
|
||||
int exit_code;
|
||||
|
||||
/* this is changed by the destructors for the fd event
|
||||
type. It is used to detect event destruction by event
|
||||
handlers, which means the code that is calling the event
|
||||
handler needs to assume that the linked list is no longer
|
||||
valid
|
||||
*/
|
||||
uint32_t destruction_count;
|
||||
|
||||
/* when using epoll this is the handle from epoll_create */
|
||||
int epoll_fd;
|
||||
|
||||
@ -255,7 +247,6 @@ static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tv
|
||||
int ret, i;
|
||||
#define MAXEVENTS 8
|
||||
struct epoll_event events[MAXEVENTS];
|
||||
uint32_t destruction_count = ++std_ev->destruction_count;
|
||||
int timeout = -1;
|
||||
|
||||
if (std_ev->epoll_fd == -1) return -1;
|
||||
@ -316,9 +307,7 @@ static int epoll_event_loop(struct std_event_context *std_ev, struct timeval *tv
|
||||
if (events[i].events & EPOLLOUT) flags |= EVENT_FD_WRITE;
|
||||
if (flags) {
|
||||
fde->handler(std_ev->ev, fde, flags, fde->private_data);
|
||||
if (destruction_count != std_ev->destruction_count) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -388,7 +377,6 @@ static int std_event_fd_destructor(struct fd_event *fde)
|
||||
}
|
||||
|
||||
DLIST_REMOVE(std_ev->fd_events, fde);
|
||||
std_ev->destruction_count++;
|
||||
|
||||
epoll_del_event(std_ev, fde);
|
||||
|
||||
@ -475,7 +463,6 @@ static int std_event_loop_select(struct std_event_context *std_ev, struct timeva
|
||||
fd_set r_fds, w_fds;
|
||||
struct fd_event *fde;
|
||||
int selrtn;
|
||||
uint32_t destruction_count = ++std_ev->destruction_count;
|
||||
|
||||
/* we maybe need to recalculate the maxfd */
|
||||
if (std_ev->maxfd == EVENT_INVALID_MAXFD) {
|
||||
@ -536,9 +523,7 @@ static int std_event_loop_select(struct std_event_context *std_ev, struct timeva
|
||||
if (FD_ISSET(fde->fd, &w_fds)) flags |= EVENT_FD_WRITE;
|
||||
if (flags) {
|
||||
fde->handler(std_ev->ev, fde, flags, fde->private_data);
|
||||
if (destruction_count != std_ev->destruction_count) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -89,10 +89,6 @@ void do_debug_add(const char *format, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#define DEBUGLVL(lvl) ((lvl) <= LogLevel)
|
||||
#define DEBUG(lvl, x) do { this_log_level = (lvl); if ((lvl) < DEBUG_DEBUG) { log_ringbuffer x; } if ((lvl) <= LogLevel) { do_debug x; }} while (0)
|
||||
#define DEBUGADD(lvl, x) do { if ((lvl) <= LogLevel) { this_log_level = (lvl); do_debug_add x; }} while (0)
|
||||
|
||||
static void print_asc(int level, const uint8_t *buf, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
@ -21,4 +21,6 @@ void (*do_debug_v)(const char *, va_list ap);
|
||||
void (*do_debug_add_v)(const char *, va_list ap);
|
||||
void log_ringbuffer(const char *format, ...);
|
||||
void do_debug(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
|
||||
void do_debug_add(const char *format, ...) PRINTF_ATTRIBUTE(1, 2);
|
||||
void dump_data(int level, const uint8_t *buf1, size_t len);
|
||||
|
||||
|
239
ctdb/lib/util/fault.c
Normal file
239
ctdb/lib/util/fault.c
Normal file
@ -0,0 +1,239 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Critical Fault handling
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
|
||||
This program 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/wait.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Fault handling
|
||||
*/
|
||||
|
||||
/* the registered fault handler */
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*fault_handler)(int sig);
|
||||
} fault_handlers;
|
||||
|
||||
static const char *progname;
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#elif HAVE_LIBEXC_H
|
||||
#include <libexc.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write backtrace to debug log
|
||||
*/
|
||||
_PUBLIC_ void call_backtrace(void)
|
||||
{
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
void *backtrace_stack[BACKTRACE_STACK_SIZE];
|
||||
size_t backtrace_size;
|
||||
char **backtrace_strings;
|
||||
|
||||
/* get the backtrace (stack frames) */
|
||||
backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
|
||||
backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
|
||||
(unsigned long)backtrace_size));
|
||||
|
||||
if (backtrace_strings) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < backtrace_size; i++)
|
||||
DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
|
||||
|
||||
/* Leak the backtrace_strings, rather than risk what free() might do */
|
||||
}
|
||||
|
||||
#elif HAVE_LIBEXC
|
||||
|
||||
#define NAMESIZE 32 /* Arbitrary */
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
|
||||
/* The IRIX libexc library provides an API for unwinding the stack. See
|
||||
* libexc(3) for details. Apparantly trace_back_stack leaks memory, but
|
||||
* since we are about to abort anyway, it hardly matters.
|
||||
*
|
||||
* Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
|
||||
* will fail with a nasty message upon failing to open the /proc entry.
|
||||
*/
|
||||
{
|
||||
uint64_t addrs[BACKTRACE_STACK_SIZE];
|
||||
char * names[BACKTRACE_STACK_SIZE];
|
||||
char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
|
||||
|
||||
int i;
|
||||
int levels;
|
||||
|
||||
ZERO_ARRAY(addrs);
|
||||
ZERO_ARRAY(names);
|
||||
ZERO_ARRAY(namebuf);
|
||||
|
||||
for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
|
||||
names[i] = namebuf + (i * NAMESIZE);
|
||||
}
|
||||
|
||||
levels = trace_back_stack(0, addrs, names,
|
||||
BACKTRACE_STACK_SIZE, NAMESIZE);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
|
||||
for (i = 0; i < levels; i++) {
|
||||
DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
|
||||
}
|
||||
}
|
||||
#undef NAMESIZE
|
||||
#else
|
||||
DEBUG(0, ("call_backstrace: not implemented\n"));
|
||||
#error bla
|
||||
#endif
|
||||
}
|
||||
|
||||
_PUBLIC_ const char *panic_action = NULL;
|
||||
_PUBLIC_ void (*pre_panic_action_hook)(void) = NULL;
|
||||
_PUBLIC_ void (*post_panic_action_hook)(void) = NULL;
|
||||
|
||||
/**
|
||||
Something really nasty happened - panic !
|
||||
**/
|
||||
_PUBLIC_ void smb_panic(const char *why)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (panic_action && *panic_action) {
|
||||
char pidstr[20];
|
||||
char cmdstring[200];
|
||||
strlcpy(cmdstring, panic_action, sizeof(cmdstring));
|
||||
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
||||
all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
|
||||
if (progname) {
|
||||
all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
|
||||
}
|
||||
DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
|
||||
|
||||
if (pre_panic_action_hook) {
|
||||
pre_panic_action_hook();
|
||||
}
|
||||
|
||||
result = system(cmdstring);
|
||||
|
||||
if (post_panic_action_hook) {
|
||||
post_panic_action_hook();
|
||||
}
|
||||
|
||||
if (result == -1)
|
||||
DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
|
||||
strerror(errno)));
|
||||
else
|
||||
DEBUG(0, ("smb_panic(): action returned status %d\n",
|
||||
WEXITSTATUS(result)));
|
||||
}
|
||||
DEBUG(0,("PANIC: %s\n", why));
|
||||
|
||||
call_backtrace();
|
||||
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
report a fault
|
||||
**/
|
||||
_NORETURN_ static void fault_report(int sig)
|
||||
{
|
||||
static int counter;
|
||||
|
||||
if (counter) _exit(1);
|
||||
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
DEBUG(0,("INTERNAL ERROR: Signal %d in %s pid %d",sig, progname, (int)getpid()));
|
||||
DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
|
||||
smb_panic("internal error");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
catch serious errors
|
||||
**/
|
||||
_NORETURN_ static void sig_fault(int sig)
|
||||
{
|
||||
if (fault_handlers.fault_handler) {
|
||||
/* we have a fault handler, call it. It may not return. */
|
||||
fault_handlers.fault_handler(sig);
|
||||
}
|
||||
/* If it returns or doesn't exist, use regular reporter */
|
||||
fault_report(sig);
|
||||
}
|
||||
|
||||
/**
|
||||
setup our fault handlers
|
||||
**/
|
||||
_PUBLIC_ void fault_setup(const char *pname)
|
||||
{
|
||||
if (progname == NULL) {
|
||||
progname = pname;
|
||||
}
|
||||
#ifdef SIGSEGV
|
||||
CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGFPE
|
||||
CatchSignal(SIGFPE,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
register a fault handler.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_fault_handler(const char *name,
|
||||
void (*fault_handler)(int sig))
|
||||
{
|
||||
if (fault_handlers.name != NULL) {
|
||||
/* it's already registered! */
|
||||
DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
|
||||
fault_handlers.name, name));
|
||||
return false;
|
||||
}
|
||||
|
||||
fault_handlers.name = name;
|
||||
fault_handlers.fault_handler = fault_handler;
|
||||
|
||||
DEBUG(2,("fault handler '%s' registered\n", name));
|
||||
return true;
|
||||
}
|
15
ctdb/lib/util/fault.m4
Normal file
15
ctdb/lib/util/fault.m4
Normal file
@ -0,0 +1,15 @@
|
||||
AC_CHECK_HEADERS(execinfo.h)
|
||||
AC_SEARCH_LIBS_EXT(backtrace, [execinfo], EXECINFO_LIBS)
|
||||
AC_CHECK_FUNC_EXT(backtrace, $EXECINFO_LIBS)
|
||||
|
||||
|
||||
if test x"$ac_cv_header_execinfo_h" = x"yes" -a x"$ac_cv_func_ext_backtrace" = x"yes";then
|
||||
SMB_ENABLE(EXECINFO, YES)
|
||||
EXECINFO_CFLAGS="$CFLAGS"
|
||||
EXECINFO_CPPFLAGS="$CPPFLAGS"
|
||||
EXECINFO_LDFLAGS="$LDFLAGS"
|
||||
else
|
||||
SMB_ENABLE(EXECINFO,NO)
|
||||
fi
|
||||
|
||||
SMB_EXT_LIB(EXECINFO, [${EXECINFO_LIBS}], [${EXECINFO_CFLAGS}], [${EXECINFO_CPPFLAGS}], [${EXECINFO_LDFLAGS}])
|
144
ctdb/lib/util/signal.c
Normal file
144
ctdb/lib/util/signal.c
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
signal handling functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
This program 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/wait.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Signal handling
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
Catch child exits and reap the child zombie status.
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld(int signum)
|
||||
{
|
||||
while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
|
||||
;
|
||||
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
catch child exits - leave status;
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld_leave_status(int signum)
|
||||
{
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Block sigs.
|
||||
**/
|
||||
|
||||
void BlockSignals(bool block, int signum)
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set,signum);
|
||||
sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
|
||||
#elif defined(HAVE_SIGBLOCK)
|
||||
if (block) {
|
||||
sigblock(sigmask(signum));
|
||||
} else {
|
||||
sigsetmask(siggetmask() & ~sigmask(signum));
|
||||
}
|
||||
#else
|
||||
/* yikes! This platform can't block signals? */
|
||||
static int done;
|
||||
if (!done) {
|
||||
DEBUG(0,("WARNING: No signal blocking available\n"));
|
||||
done=1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Catch a signal. This should implement the following semantics:
|
||||
|
||||
1) The handler remains installed after being called.
|
||||
2) The signal should be blocked during handler execution.
|
||||
**/
|
||||
|
||||
void (*CatchSignal(int signum,void (*handler)(int )))(int)
|
||||
{
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
struct sigaction oldact;
|
||||
|
||||
ZERO_STRUCT(act);
|
||||
|
||||
act.sa_handler = handler;
|
||||
#ifdef SA_RESTART
|
||||
/*
|
||||
* We *want* SIGALRM to interrupt a system call.
|
||||
*/
|
||||
if(signum != SIGALRM)
|
||||
act.sa_flags = SA_RESTART;
|
||||
#endif
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask,signum);
|
||||
sigaction(signum,&act,&oldact);
|
||||
return oldact.sa_handler;
|
||||
#else /* !HAVE_SIGACTION */
|
||||
/* FIXME: need to handle sigvec and systems with broken signal() */
|
||||
return signal(signum, handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Ignore SIGCLD via whatever means is necessary for this OS.
|
||||
**/
|
||||
|
||||
void CatchChild(void)
|
||||
{
|
||||
CatchSignal(SIGCLD, sig_cld);
|
||||
}
|
||||
|
||||
/**
|
||||
Catch SIGCLD but leave the child around so it's status can be reaped.
|
||||
**/
|
||||
|
||||
void CatchChildLeaveStatus(void)
|
||||
{
|
||||
CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
}
|
1
ctdb/lib/util/signal.m4
Normal file
1
ctdb/lib/util/signal.m4
Normal file
@ -0,0 +1 @@
|
||||
AC_CHECK_FUNCS(sigprocmask sigblock sigaction)
|
167
ctdb/lib/util/substitute.c
Normal file
167
ctdb/lib/util/substitute.c
Normal file
@ -0,0 +1,167 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2001
|
||||
Copyright (C) Simo Sorce 2001-2002
|
||||
Copyright (C) Martin Pool 2003
|
||||
Copyright (C) James Peach 2005
|
||||
|
||||
This program 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Substitute utilities.
|
||||
**/
|
||||
|
||||
/**
|
||||
Substitute a string for a pattern in another string. Make sure there is
|
||||
enough room!
|
||||
|
||||
This routine looks for pattern in s and replaces it with
|
||||
insert. It may do multiple replacements.
|
||||
|
||||
Any of " ; ' $ or ` in the insert string are replaced with _
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void string_sub(char *s, const char *pattern, const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls, lp, li, i;
|
||||
|
||||
if (!insert || !pattern || !*pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s, pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
DEBUG(0,("ERROR: string overflow by %d in string_sub(%.50s, %d)\n",
|
||||
(int)(ls + (li-lp) - len),
|
||||
pattern, (int)len));
|
||||
break;
|
||||
}
|
||||
if (li != lp) {
|
||||
memmove(p+li,p+lp,strlen(p+lp)+1);
|
||||
}
|
||||
for (i=0;i<li;i++) {
|
||||
switch (insert[i]) {
|
||||
case '`':
|
||||
case '"':
|
||||
case '\'':
|
||||
case ';':
|
||||
case '$':
|
||||
case '%':
|
||||
case '\r':
|
||||
case '\n':
|
||||
p[i] = '_';
|
||||
break;
|
||||
default:
|
||||
p[i] = insert[i];
|
||||
}
|
||||
}
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Talloc'ed version of string_sub
|
||||
*/
|
||||
_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s,
|
||||
const char *pattern, const char *insert)
|
||||
{
|
||||
const char *p;
|
||||
char *ret;
|
||||
size_t len, alloc_len;
|
||||
|
||||
if (insert == NULL || pattern == NULL || !*pattern || s == NULL)
|
||||
return NULL;
|
||||
|
||||
/* determine length needed */
|
||||
len = strlen(s);
|
||||
|
||||
for (p = strstr(s, pattern); p != NULL;
|
||||
p = strstr(p+strlen(pattern), pattern)) {
|
||||
len += strlen(insert) - strlen(pattern);
|
||||
}
|
||||
|
||||
alloc_len = MAX(len, strlen(s))+1;
|
||||
ret = talloc_array(mem_ctx, char, alloc_len);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
strncpy(ret, s, alloc_len);
|
||||
string_sub(ret, pattern, insert, alloc_len);
|
||||
|
||||
ret = talloc_realloc(mem_ctx, ret, char, len+1);
|
||||
if (ret == NULL)
|
||||
return NULL;
|
||||
|
||||
SMB_ASSERT(ret[len] == '\0');
|
||||
|
||||
talloc_set_name_const(ret, ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Similar to string_sub() but allows for any character to be substituted.
|
||||
Use with caution!
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls,lp,li;
|
||||
|
||||
if (!insert || !pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (!*pattern)
|
||||
return;
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s,pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
DEBUG(0,("ERROR: string overflow by %d in all_string_sub(%.50s, %d)\n",
|
||||
(int)(ls + (li-lp) - len),
|
||||
pattern, (int)len));
|
||||
break;
|
||||
}
|
||||
if (li != lp) {
|
||||
memmove(p+li,p+lp,strlen(p+lp)+1);
|
||||
}
|
||||
memcpy(p, insert, li);
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
658
ctdb/lib/util/util.h
Normal file
658
ctdb/lib/util/util.h
Normal file
@ -0,0 +1,658 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Utility functions for Samba
|
||||
Copyright (C) Andrew Tridgell 1992-1999
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
|
||||
This program 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef _SAMBA_UTIL_H_
|
||||
#define _SAMBA_UTIL_H_
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Helpful macros
|
||||
*/
|
||||
|
||||
struct smbsrv_tcon;
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
extern const char *logfile;
|
||||
#endif
|
||||
extern const char *panic_action;
|
||||
extern void (*pre_panic_action_hook)(void);
|
||||
extern void (*post_panic_action_hook)(void);
|
||||
|
||||
/**
|
||||
* assert macros
|
||||
*/
|
||||
#ifdef DEVELOPER
|
||||
#define SMB_ASSERT(b) do { if (!(b)) { \
|
||||
DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
|
||||
__FILE__, __LINE__, #b)); smb_panic("assert failed: " #b); }} while(0)
|
||||
#else
|
||||
/* redefine the assert macro for non-developer builds */
|
||||
#define SMB_ASSERT(b) do { if (!(b)) { \
|
||||
DEBUG(0,("PANIC: assert failed at %s(%d): %s\n", \
|
||||
__FILE__, __LINE__, #b)); }} while (0)
|
||||
#endif
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
#ifdef VALGRIND
|
||||
#define strlen(x) valgrind_strlen(x)
|
||||
size_t valgrind_strlen(const char *s);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef ABS
|
||||
#define ABS(a) ((a)>0?(a):(-(a)))
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write backtrace to debug log
|
||||
*/
|
||||
_PUBLIC_ void call_backtrace(void);
|
||||
|
||||
/**
|
||||
Something really nasty happened - panic !
|
||||
**/
|
||||
_PUBLIC_ _NORETURN_ void smb_panic(const char *why);
|
||||
|
||||
/**
|
||||
setup our fault handlers
|
||||
**/
|
||||
_PUBLIC_ void fault_setup(const char *pname);
|
||||
|
||||
/**
|
||||
register a fault handler.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_fault_handler(const char *name, void (*fault_handler)(int sig));
|
||||
|
||||
/* The following definitions come from lib/util/signal.c */
|
||||
|
||||
|
||||
/**
|
||||
Block sigs.
|
||||
**/
|
||||
void BlockSignals(bool block, int signum);
|
||||
|
||||
/**
|
||||
Catch a signal. This should implement the following semantics:
|
||||
|
||||
1) The handler remains installed after being called.
|
||||
2) The signal should be blocked during handler execution.
|
||||
**/
|
||||
void (*CatchSignal(int signum,void (*handler)(int )))(int);
|
||||
|
||||
/**
|
||||
Ignore SIGCLD via whatever means is necessary for this OS.
|
||||
**/
|
||||
void CatchChild(void);
|
||||
|
||||
/**
|
||||
Catch SIGCLD but leave the child around so it's status can be reaped.
|
||||
**/
|
||||
void CatchChildLeaveStatus(void);
|
||||
|
||||
|
||||
/* The following definitions come from lib/util/util_str.c */
|
||||
|
||||
|
||||
/**
|
||||
Trim the specified elements off the front and back of a string.
|
||||
**/
|
||||
_PUBLIC_ bool trim_string(char *s, const char *front, const char *back);
|
||||
|
||||
/**
|
||||
Find the number of 'c' chars in a string
|
||||
**/
|
||||
_PUBLIC_ _PURE_ size_t count_chars(const char *s, char c);
|
||||
|
||||
/**
|
||||
Safe string copy into a known length string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength);
|
||||
|
||||
/**
|
||||
Safe string cat into a string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength);
|
||||
|
||||
/**
|
||||
Routine to get hex characters and turn them into a 16 byte array.
|
||||
the array can be variable length, and any non-hex-numeric
|
||||
characters are skipped. "0xnn" or "0Xnn" is specially catered
|
||||
for.
|
||||
|
||||
valid examples: "0A5D15"; "0x15, 0x49, 0xa2"; "59\ta9\te3\n"
|
||||
|
||||
|
||||
**/
|
||||
_PUBLIC_ size_t strhex_to_str(char *p, size_t p_len, const char *strhex, size_t strhex_len);
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
* Parse a hex string and return a data blob.
|
||||
*/
|
||||
_PUBLIC_ _PURE_ DATA_BLOB strhex_to_data_blob(TALLOC_CTX *mem_ctx, const char *strhex) ;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Routine to print a buffer as HEX digits, into an allocated string.
|
||||
*/
|
||||
_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer);
|
||||
|
||||
/**
|
||||
* talloc version of hex_encode()
|
||||
*/
|
||||
_PUBLIC_ char *hex_encode_talloc(TALLOC_CTX *mem_ctx, const unsigned char *buff_in, size_t len);
|
||||
|
||||
/**
|
||||
Substitute a string for a pattern in another string. Make sure there is
|
||||
enough room!
|
||||
|
||||
This routine looks for pattern in s and replaces it with
|
||||
insert. It may do multiple replacements.
|
||||
|
||||
Any of " ; ' $ or ` in the insert string are replaced with _
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
_PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len);
|
||||
|
||||
|
||||
_PUBLIC_ char *string_sub_talloc(TALLOC_CTX *mem_ctx, const char *s,
|
||||
const char *pattern, const char *insert);
|
||||
|
||||
/**
|
||||
Similar to string_sub() but allows for any character to be substituted.
|
||||
Use with caution!
|
||||
if len==0 then the string cannot be extended. This is different from the old
|
||||
use of len==0 which was for no length checks to be done.
|
||||
**/
|
||||
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len);
|
||||
|
||||
/**
|
||||
Unescape a URL encoded string, in place.
|
||||
**/
|
||||
_PUBLIC_ void rfc1738_unescape(char *buf);
|
||||
|
||||
/**
|
||||
format a string into length-prefixed dotted domain format, as used in NBT
|
||||
and in some ADS structures
|
||||
**/
|
||||
_PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s);
|
||||
|
||||
/**
|
||||
* Add a string to an array of strings.
|
||||
*
|
||||
* num should be a pointer to an integer that holds the current
|
||||
* number of elements in strings. It will be updated by this function.
|
||||
*/
|
||||
_PUBLIC_ bool add_string_to_array(TALLOC_CTX *mem_ctx,
|
||||
const char *str, const char ***strings, int *num);
|
||||
|
||||
/**
|
||||
varient of strcmp() that handles NULL ptrs
|
||||
**/
|
||||
_PUBLIC_ int strcmp_safe(const char *s1, const char *s2);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in ASCII format
|
||||
the result includes the null termination
|
||||
limited by 'n' bytes
|
||||
**/
|
||||
_PUBLIC_ size_t ascii_len_n(const char *src, size_t n);
|
||||
|
||||
/**
|
||||
Set a boolean variable from the text value stored in the passed string.
|
||||
Returns true in success, false if the passed string does not correctly
|
||||
represent a boolean.
|
||||
**/
|
||||
_PUBLIC_ bool set_boolean(const char *boolean_string, bool *boolean);
|
||||
|
||||
/**
|
||||
* Parse a string containing a boolean value.
|
||||
*
|
||||
* val will be set to the read value.
|
||||
*
|
||||
* @retval true if a boolean value was parsed, false otherwise.
|
||||
*/
|
||||
_PUBLIC_ bool conv_str_bool(const char * str, bool * val);
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
/**
|
||||
* Convert a size specification like 16K into an integral number of bytes.
|
||||
**/
|
||||
_PUBLIC_ bool conv_str_size(const char * str, uint64_t * val);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Parse a uint64_t value from a string
|
||||
*
|
||||
* val will be set to the value read.
|
||||
*
|
||||
* @retval true if parsing was successful, false otherwise
|
||||
*/
|
||||
_PUBLIC_ bool conv_str_u64(const char * str, uint64_t * val);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in CH_UTF16 format
|
||||
the result includes the null termination
|
||||
**/
|
||||
_PUBLIC_ size_t utf16_len(const void *buf);
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in CH_UTF16 format
|
||||
the result includes the null termination
|
||||
limited by 'n' bytes
|
||||
**/
|
||||
_PUBLIC_ size_t utf16_len_n(const void *src, size_t n);
|
||||
_PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags);
|
||||
|
||||
/**
|
||||
Do a case-insensitive, whitespace-ignoring string compare.
|
||||
**/
|
||||
_PUBLIC_ int strwicmp(const char *psz1, const char *psz2);
|
||||
|
||||
/**
|
||||
String replace.
|
||||
**/
|
||||
_PUBLIC_ void string_replace(char *s, char oldc, char newc);
|
||||
|
||||
/**
|
||||
* Compare 2 strings.
|
||||
*
|
||||
* @note The comparison is case-insensitive.
|
||||
**/
|
||||
_PUBLIC_ bool strequal(const char *s1, const char *s2);
|
||||
|
||||
/* The following definitions come from lib/util/util_strlist.c */
|
||||
#ifdef _SAMBA_BUILD_
|
||||
|
||||
/* separators for lists */
|
||||
#ifndef LIST_SEP
|
||||
#define LIST_SEP " \t,\n\r"
|
||||
#endif
|
||||
|
||||
/**
|
||||
build a null terminated list of strings from a input string and a
|
||||
separator list. The separator list must contain characters less than
|
||||
or equal to 0x2f for this to work correctly on multi-byte strings
|
||||
*/
|
||||
_PUBLIC_ char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
|
||||
|
||||
/**
|
||||
* build a null terminated list of strings from an argv-like input string
|
||||
* Entries are seperated by spaces and can be enclosed by quotes.
|
||||
* Does NOT support escaping
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep);
|
||||
|
||||
/**
|
||||
* join a list back to one string
|
||||
*/
|
||||
_PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator);
|
||||
|
||||
/** join a list back to one (shell-like) string; entries
|
||||
* seperated by spaces, using quotes where necessary */
|
||||
_PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep);
|
||||
|
||||
/**
|
||||
return the number of elements in a string list
|
||||
*/
|
||||
_PUBLIC_ size_t str_list_length(const char * const *list);
|
||||
|
||||
/**
|
||||
copy a string list
|
||||
*/
|
||||
_PUBLIC_ char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list);
|
||||
|
||||
/**
|
||||
Return true if all the elements of the list match exactly.
|
||||
*/
|
||||
_PUBLIC_ bool str_list_equal(const char **list1, const char **list2);
|
||||
|
||||
/**
|
||||
add an entry to a string list
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_add(const char **list, const char *s);
|
||||
|
||||
/**
|
||||
remove an entry from a string list
|
||||
*/
|
||||
_PUBLIC_ void str_list_remove(const char **list, const char *s);
|
||||
|
||||
/**
|
||||
return true if a string is in a list
|
||||
*/
|
||||
_PUBLIC_ bool str_list_check(const char **list, const char *s);
|
||||
|
||||
/**
|
||||
return true if a string is in a list, case insensitively
|
||||
*/
|
||||
_PUBLIC_ bool str_list_check_ci(const char **list, const char *s);
|
||||
#endif
|
||||
|
||||
/* The following definitions come from lib/util/util_file.c */
|
||||
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
read a line from a file with possible \ continuation chars.
|
||||
Blanks at the start or end of a line are stripped.
|
||||
The string will be allocated if s2 is NULL
|
||||
**/
|
||||
_PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Read one line (data until next newline or eof) and allocate it
|
||||
*/
|
||||
_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint);
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
load a file into memory from a fd.
|
||||
**/
|
||||
_PUBLIC_ char *fd_load(int fd, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
|
||||
|
||||
char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
load a file into memory
|
||||
**/
|
||||
_PUBLIC_ char *file_load(const char *fname, size_t *size, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
#endif
|
||||
|
||||
/**
|
||||
mmap (if possible) or read a file
|
||||
**/
|
||||
_PUBLIC_ void *map_file(const char *fname, size_t size);
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
load a file into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free().
|
||||
**/
|
||||
_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
#endif
|
||||
|
||||
/**
|
||||
load a fd into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free(). If convert is true calls unix_to_dos on
|
||||
the list.
|
||||
**/
|
||||
_PUBLIC_ char **fd_lines_load(int fd, int *numlines, size_t maxsize, TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
take a list of lines and modify them to produce a list where \ continues
|
||||
a line
|
||||
**/
|
||||
_PUBLIC_ void file_lines_slashcont(char **lines);
|
||||
|
||||
/**
|
||||
save a lump of data into a file. Mostly used for debugging
|
||||
*/
|
||||
_PUBLIC_ bool file_save(const char *fname, const void *packet, size_t length);
|
||||
_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0);
|
||||
_PUBLIC_ int fdprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3);
|
||||
_PUBLIC_ bool large_file_support(const char *path);
|
||||
|
||||
/* The following definitions come from lib/util/util.c */
|
||||
|
||||
|
||||
/**
|
||||
Find a suitable temporary directory. The result should be copied immediately
|
||||
as it may be overwritten by a subsequent call.
|
||||
**/
|
||||
_PUBLIC_ const char *tmpdir(void);
|
||||
|
||||
/**
|
||||
Check if a file exists - call vfs_file_exist for samba files.
|
||||
**/
|
||||
_PUBLIC_ bool file_exist(const char *fname);
|
||||
|
||||
/**
|
||||
Check a files mod time.
|
||||
**/
|
||||
_PUBLIC_ time_t file_modtime(const char *fname);
|
||||
|
||||
/**
|
||||
Check if a directory exists.
|
||||
**/
|
||||
_PUBLIC_ bool directory_exist(const char *dname);
|
||||
|
||||
/**
|
||||
* Try to create the specified directory if it didn't exist.
|
||||
*
|
||||
* @retval true if the directory already existed and has the right permissions
|
||||
* or was successfully created.
|
||||
*/
|
||||
_PUBLIC_ bool directory_create_or_exist(const char *dname, uid_t uid,
|
||||
mode_t dir_perms);
|
||||
|
||||
/**
|
||||
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
|
||||
else
|
||||
if SYSV use O_NDELAY
|
||||
if BSD use FNDELAY
|
||||
**/
|
||||
_PUBLIC_ int set_blocking(int fd, bool set);
|
||||
|
||||
/**
|
||||
Sleep for a specified number of milliseconds.
|
||||
**/
|
||||
_PUBLIC_ void msleep(unsigned int t);
|
||||
|
||||
/**
|
||||
Get my own name, return in malloc'ed storage.
|
||||
**/
|
||||
_PUBLIC_ char* get_myname(void);
|
||||
|
||||
/**
|
||||
Return true if a string could be a pure IP address.
|
||||
**/
|
||||
_PUBLIC_ bool is_ipaddress(const char *str);
|
||||
|
||||
/**
|
||||
Interpret an internet address or name into an IP address in 4 byte form.
|
||||
**/
|
||||
_PUBLIC_ uint32_t interpret_addr(const char *str);
|
||||
|
||||
/**
|
||||
A convenient addition to interpret_addr().
|
||||
**/
|
||||
_PUBLIC_ struct in_addr interpret_addr2(const char *str);
|
||||
|
||||
/**
|
||||
Check if an IP is the 0.0.0.0.
|
||||
**/
|
||||
_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip);
|
||||
|
||||
/**
|
||||
Are two IPs on the same subnet?
|
||||
**/
|
||||
_PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr mask);
|
||||
|
||||
_PUBLIC_ bool is_ipaddress_v4(const char *str);
|
||||
|
||||
/**
|
||||
Check if a process exists. Does this work on all unixes?
|
||||
**/
|
||||
_PUBLIC_ bool process_exists_by_pid(pid_t pid);
|
||||
|
||||
/**
|
||||
Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
|
||||
is dealt with in posix.c
|
||||
**/
|
||||
_PUBLIC_ bool fcntl_lock(int fd, int op, off_t offset, off_t count, int type);
|
||||
|
||||
/**
|
||||
malloc that aborts with smb_panic on fail or zero size.
|
||||
**/
|
||||
_PUBLIC_ void *smb_xmalloc(size_t size);
|
||||
|
||||
/**
|
||||
Memdup with smb_panic on fail.
|
||||
**/
|
||||
_PUBLIC_ void *smb_xmemdup(const void *p, size_t size);
|
||||
|
||||
/**
|
||||
strdup that aborts on malloc fail.
|
||||
**/
|
||||
_PUBLIC_ char *smb_xstrdup(const char *s);
|
||||
|
||||
char *smb_xstrndup(const char *s, size_t n);
|
||||
|
||||
/**
|
||||
Like strdup but for memory.
|
||||
**/
|
||||
_PUBLIC_ void *memdup(const void *p, size_t size);
|
||||
|
||||
/**
|
||||
* see if a range of memory is all zero. A NULL pointer is considered
|
||||
* to be all zero
|
||||
*/
|
||||
_PUBLIC_ bool all_zero(const uint8_t *ptr, size_t size);
|
||||
|
||||
/**
|
||||
realloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count, bool free_on_fail);
|
||||
|
||||
void *malloc_array(size_t el_size, unsigned int count);
|
||||
|
||||
/* The following definitions come from lib/util/fsusage.c */
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve amount of free disk space.
|
||||
* this does all of the system specific guff to get the free disk space.
|
||||
* It is derived from code in the GNU fileutils package, but has been
|
||||
* considerably mangled for use here
|
||||
*
|
||||
* results are returned in *dfree and *dsize, in 512 byte units
|
||||
*/
|
||||
_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize);
|
||||
|
||||
/* The following definitions come from lib/util/ms_fnmatch.c */
|
||||
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief MS-style Filename matching
|
||||
*/
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
/* protocol types. It assumes that higher protocols include lower protocols
|
||||
as subsets. FIXME: Move to one of the smb-specific headers */
|
||||
enum protocol_types {
|
||||
PROTOCOL_NONE,
|
||||
PROTOCOL_CORE,
|
||||
PROTOCOL_COREPLUS,
|
||||
PROTOCOL_LANMAN1,
|
||||
PROTOCOL_LANMAN2,
|
||||
PROTOCOL_NT1,
|
||||
PROTOCOL_SMB2
|
||||
};
|
||||
|
||||
int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol);
|
||||
|
||||
/** a generic fnmatch function - uses for non-CIFS pattern matching */
|
||||
int gen_fnmatch(const char *pattern, const char *string);
|
||||
#endif
|
||||
|
||||
/* The following definitions come from lib/util/mutex.c */
|
||||
|
||||
|
||||
#ifdef _SAMBA_BUILD_
|
||||
/**
|
||||
register a set of mutex/rwlock handlers.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ bool register_mutex_handlers(const char *name, struct mutex_ops *ops);
|
||||
#endif
|
||||
|
||||
/* The following definitions come from lib/util/idtree.c */
|
||||
|
||||
|
||||
/**
|
||||
initialise a idr tree. The context return value must be passed to
|
||||
all subsequent idr calls. To destroy the idr tree use talloc_free()
|
||||
on this context
|
||||
*/
|
||||
_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx);
|
||||
|
||||
/**
|
||||
allocate the next available id, and assign 'ptr' into its slot.
|
||||
you can retrieve later this pointer using idr_find()
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit);
|
||||
|
||||
/**
|
||||
allocate a new id, giving the first available value greater than or
|
||||
equal to the given starting id
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit);
|
||||
|
||||
/**
|
||||
allocate a new id randomly in the given range
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit);
|
||||
|
||||
/**
|
||||
find a pointer value previously set with idr_get_new given an id
|
||||
*/
|
||||
_PUBLIC_ void *idr_find(struct idr_context *idp, int id);
|
||||
|
||||
/**
|
||||
remove an id from the idr tree
|
||||
*/
|
||||
_PUBLIC_ int idr_remove(struct idr_context *idp, int id);
|
||||
|
||||
/* The following definitions come from lib/util/become_daemon.c */
|
||||
|
||||
#if _SAMBA_BUILD_ == 4
|
||||
/**
|
||||
Become a daemon, discarding the controlling terminal.
|
||||
**/
|
||||
_PUBLIC_ void become_daemon(bool fork);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Load a ini-style file.
|
||||
*/
|
||||
bool pm_process( const char *fileName,
|
||||
bool (*sfunc)(const char *, void *),
|
||||
bool (*pfunc)(const char *, const char *, void *),
|
||||
void *userdata);
|
||||
|
||||
/**
|
||||
* Add-on to talloc_get_type
|
||||
*/
|
||||
_PUBLIC_ void *talloc_check_name_abort(const void *ptr, const char *name);
|
||||
#define talloc_get_type_abort(ptr, type) \
|
||||
(type *)talloc_check_name_abort(ptr, #type)
|
||||
|
||||
bool unmap_file(void *start, size_t size);
|
||||
|
||||
#define CONST_DISCARD(type, ptr) ((type) ((void *) (ptr)))
|
||||
|
||||
#endif /* _SAMBA_UTIL_H_ */
|
@ -95,6 +95,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{_sysconfdir}/ctdb/events.d/00.ctdb
|
||||
%{_sysconfdir}/ctdb/events.d/01.reclock
|
||||
%{_sysconfdir}/ctdb/events.d/10.interface
|
||||
%{_sysconfdir}/ctdb/events.d/13.per_ip_routing
|
||||
%{_sysconfdir}/ctdb/events.d/11.natgw
|
||||
%{_sysconfdir}/ctdb/events.d/11.routing
|
||||
%{_sysconfdir}/ctdb/events.d/20.multipathd
|
||||
@ -107,6 +108,7 @@ rm -rf $RPM_BUILD_ROOT
|
||||
%{_sysconfdir}/ctdb/events.d/70.iscsi
|
||||
%{_sysconfdir}/ctdb/events.d/91.lvs
|
||||
%{_sysconfdir}/ctdb/statd-callout
|
||||
%{_sysconfdir}/ctdb/interface_modify.sh
|
||||
%{_sbindir}/ctdbd
|
||||
%{_bindir}/ctdb
|
||||
%{_bindir}/smnotify
|
||||
|
@ -568,6 +568,18 @@ static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
|
||||
return ctdb_control_db_get_health(ctdb, indata, outdata);
|
||||
|
||||
case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
|
||||
return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata);
|
||||
|
||||
case CTDB_CONTROL_GET_IFACES:
|
||||
CHECK_CONTROL_DATA_SIZE(0);
|
||||
return ctdb_control_get_ifaces(ctdb, c, outdata);
|
||||
|
||||
case CTDB_CONTROL_SET_IFACE_LINK_STATE:
|
||||
CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_iface_info));
|
||||
return ctdb_control_set_iface_link(ctdb, c, indata);
|
||||
|
||||
default:
|
||||
DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
|
||||
return -1;
|
||||
|
@ -781,6 +781,12 @@ int ctdb_start_daemon(struct ctdb_context *ctdb, bool do_fork, bool use_syslog)
|
||||
ctdb_fatal(ctdb, "Failed to get initial freeze\n");
|
||||
}
|
||||
|
||||
ret = ctdb_event_script(ctdb, CTDB_EVENT_INIT);
|
||||
if (ret != 0) {
|
||||
ctdb_fatal(ctdb, "Failed to run init event\n");
|
||||
}
|
||||
ctdb_run_notification_script(ctdb, "init");
|
||||
|
||||
/* now start accepting clients, only can do this once frozen */
|
||||
fde = event_add_fd(ctdb->ev, ctdb, ctdb->daemon.sd,
|
||||
EVENT_FD_READ|EVENT_FD_AUTOCLOSE,
|
||||
|
@ -75,7 +75,7 @@ static int ctdb_run_notification_script_child(struct ctdb_context *ctdb, const c
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event)
|
||||
void ctdb_run_notification_script(struct ctdb_context *ctdb, const char *event)
|
||||
{
|
||||
pid_t child;
|
||||
|
||||
|
@ -64,6 +64,7 @@ struct ctdb_recoverd {
|
||||
TALLOC_CTX *ip_reallocate_ctx;
|
||||
struct ip_reallocate_list *reallocate_callers;
|
||||
TALLOC_CTX *ip_check_disable_ctx;
|
||||
struct ctdb_control_get_ifaces *ifaces;
|
||||
};
|
||||
|
||||
#define CONTROL_TIMEOUT() timeval_current_ofs(ctdb->tunable.recover_timeout, 0)
|
||||
@ -1226,7 +1227,73 @@ static void reload_nodes_file(struct ctdb_context *ctdb)
|
||||
ctdb_load_nodes_file(ctdb);
|
||||
}
|
||||
|
||||
|
||||
static int ctdb_reload_remote_public_ips(struct ctdb_context *ctdb,
|
||||
struct ctdb_node_map *nodemap,
|
||||
uint32_t *culprit)
|
||||
{
|
||||
int j;
|
||||
int ret;
|
||||
|
||||
if (ctdb->num_nodes != nodemap->num) {
|
||||
DEBUG(DEBUG_ERR, (__location__ " ctdb->num_nodes (%d) != nodemap->num (%d) invalid param\n",
|
||||
ctdb->num_nodes, nodemap->num));
|
||||
if (culprit) {
|
||||
*culprit = ctdb->pnn;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (j=0; j<nodemap->num; j++) {
|
||||
/* release any existing data */
|
||||
if (ctdb->nodes[j]->known_public_ips) {
|
||||
talloc_free(ctdb->nodes[j]->known_public_ips);
|
||||
ctdb->nodes[j]->known_public_ips = NULL;
|
||||
}
|
||||
if (ctdb->nodes[j]->available_public_ips) {
|
||||
talloc_free(ctdb->nodes[j]->available_public_ips);
|
||||
ctdb->nodes[j]->available_public_ips = NULL;
|
||||
}
|
||||
|
||||
if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* grab a new shiny list of public ips from the node */
|
||||
ret = ctdb_ctrl_get_public_ips_flags(ctdb,
|
||||
CONTROL_TIMEOUT(),
|
||||
ctdb->nodes[j]->pnn,
|
||||
ctdb->nodes,
|
||||
0,
|
||||
&ctdb->nodes[j]->known_public_ips);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read known public ips from node : %u\n",
|
||||
ctdb->nodes[j]->pnn));
|
||||
if (culprit) {
|
||||
*culprit = ctdb->nodes[j]->pnn;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* grab a new shiny list of public ips from the node */
|
||||
ret = ctdb_ctrl_get_public_ips_flags(ctdb,
|
||||
CONTROL_TIMEOUT(),
|
||||
ctdb->nodes[j]->pnn,
|
||||
ctdb->nodes,
|
||||
CTDB_PUBLIC_IP_FLAGS_ONLY_AVAILABLE,
|
||||
&ctdb->nodes[j]->available_public_ips);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read available public ips from node : %u\n",
|
||||
ctdb->nodes[j]->pnn));
|
||||
if (culprit) {
|
||||
*culprit = ctdb->nodes[j]->pnn;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
we are the recmaster, and recovery is needed - start a recovery run
|
||||
*/
|
||||
@ -1241,6 +1308,7 @@ static int do_recovery(struct ctdb_recoverd *rec,
|
||||
TDB_DATA data;
|
||||
uint32_t *nodes;
|
||||
struct timeval start_time;
|
||||
uint32_t culprit = (uint32_t)-1;
|
||||
|
||||
DEBUG(DEBUG_NOTICE, (__location__ " Starting do_recovery\n"));
|
||||
|
||||
@ -1500,6 +1568,12 @@ static int do_recovery(struct ctdb_recoverd *rec,
|
||||
/*
|
||||
tell nodes to takeover their public IPs
|
||||
*/
|
||||
ret = ctdb_reload_remote_public_ips(ctdb, nodemap, &culprit);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
|
||||
culprit));
|
||||
return -1;
|
||||
}
|
||||
rec->need_takeover_run = false;
|
||||
ret = ctdb_takeover_run(ctdb, nodemap);
|
||||
if (ret != 0) {
|
||||
@ -1880,9 +1954,28 @@ static void process_ipreallocate_requests(struct ctdb_context *ctdb, struct ctdb
|
||||
TDB_DATA result;
|
||||
int32_t ret;
|
||||
struct ip_reallocate_list *callers;
|
||||
uint32_t culprit;
|
||||
|
||||
DEBUG(DEBUG_INFO, ("recovery master forced ip reallocation\n"));
|
||||
ret = ctdb_takeover_run(ctdb, rec->nodemap);
|
||||
|
||||
/* update the list of public ips that a node can handle for
|
||||
all connected nodes
|
||||
*/
|
||||
ret = ctdb_reload_remote_public_ips(ctdb, rec->nodemap, &culprit);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
|
||||
culprit));
|
||||
rec->need_takeover_run = true;
|
||||
}
|
||||
if (ret == 0) {
|
||||
ret = ctdb_takeover_run(ctdb, rec->nodemap);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
|
||||
culprit));
|
||||
rec->need_takeover_run = true;
|
||||
}
|
||||
}
|
||||
|
||||
result.dsize = sizeof(int32_t);
|
||||
result.dptr = (uint8_t *)&ret;
|
||||
|
||||
@ -2326,10 +2419,13 @@ static enum monitor_result verify_recmaster(struct ctdb_recoverd *rec, struct ct
|
||||
static int verify_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd *rec, uint32_t pnn)
|
||||
{
|
||||
TALLOC_CTX *mem_ctx = talloc_new(NULL);
|
||||
struct ctdb_control_get_ifaces *ifaces = NULL;
|
||||
struct ctdb_all_public_ips *ips = NULL;
|
||||
struct ctdb_uptime *uptime1 = NULL;
|
||||
struct ctdb_uptime *uptime2 = NULL;
|
||||
int ret, j;
|
||||
bool need_iface_check = false;
|
||||
bool need_takeover_run = false;
|
||||
|
||||
ret = ctdb_ctrl_uptime(ctdb, mem_ctx, CONTROL_TIMEOUT(),
|
||||
CTDB_CURRENT_NODE, &uptime1);
|
||||
@ -2339,6 +2435,30 @@ static int verify_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/* read the interfaces from the local node */
|
||||
ret = ctdb_ctrl_get_ifaces(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, mem_ctx, &ifaces);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR, ("Unable to get interfaces from local node %u\n", pnn));
|
||||
talloc_free(mem_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!rec->ifaces) {
|
||||
need_iface_check = true;
|
||||
} else if (rec->ifaces->num != ifaces->num) {
|
||||
need_iface_check = true;
|
||||
} else if (memcmp(rec->ifaces, ifaces, talloc_get_size(ifaces)) != 0) {
|
||||
need_iface_check = true;
|
||||
}
|
||||
|
||||
if (need_iface_check) {
|
||||
DEBUG(DEBUG_NOTICE, ("The interfaces status has changed on "
|
||||
"local node %u - force takeover run\n",
|
||||
pnn));
|
||||
need_takeover_run = true;
|
||||
}
|
||||
|
||||
/* read the ip allocation from the local node */
|
||||
ret = ctdb_ctrl_get_public_ips(ctdb, CONTROL_TIMEOUT(), CTDB_CURRENT_NODE, mem_ctx, &ips);
|
||||
if (ret != 0) {
|
||||
@ -2380,6 +2500,9 @@ static int verify_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd
|
||||
return 0;
|
||||
}
|
||||
|
||||
talloc_free(rec->ifaces);
|
||||
rec->ifaces = talloc_steal(rec, ifaces);
|
||||
|
||||
/* verify that we have the ip addresses we should have
|
||||
and we dont have ones we shouldnt have.
|
||||
if we find an inconsistency we set recmode to
|
||||
@ -2389,43 +2512,35 @@ static int verify_ip_allocation(struct ctdb_context *ctdb, struct ctdb_recoverd
|
||||
for (j=0; j<ips->num; j++) {
|
||||
if (ips->ips[j].pnn == pnn) {
|
||||
if (!ctdb_sys_have_ip(&ips->ips[j].addr)) {
|
||||
struct takeover_run_reply rd;
|
||||
TDB_DATA data;
|
||||
|
||||
DEBUG(DEBUG_CRIT,("Public address '%s' is missing and we should serve this ip\n",
|
||||
ctdb_addr_to_str(&ips->ips[j].addr)));
|
||||
|
||||
rd.pnn = ctdb->pnn;
|
||||
rd.srvid = 0;
|
||||
data.dptr = (uint8_t *)&rd;
|
||||
data.dsize = sizeof(rd);
|
||||
|
||||
ret = ctdb_send_message(ctdb, rec->recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Failed to send ipreallocate to recmaster :%d\n", (int)rec->recmaster));
|
||||
}
|
||||
need_takeover_run = true;
|
||||
}
|
||||
} else {
|
||||
if (ctdb_sys_have_ip(&ips->ips[j].addr)) {
|
||||
struct takeover_run_reply rd;
|
||||
TDB_DATA data;
|
||||
|
||||
DEBUG(DEBUG_CRIT,("We are still serving a public address '%s' that we should not be serving.\n",
|
||||
ctdb_addr_to_str(&ips->ips[j].addr)));
|
||||
|
||||
rd.pnn = ctdb->pnn;
|
||||
rd.srvid = 0;
|
||||
data.dptr = (uint8_t *)&rd;
|
||||
data.dsize = sizeof(rd);
|
||||
|
||||
ret = ctdb_send_message(ctdb, rec->recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Failed to send ipreallocate to recmaster :%d\n", (int)rec->recmaster));
|
||||
}
|
||||
need_takeover_run = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (need_takeover_run) {
|
||||
struct takeover_run_reply rd;
|
||||
TDB_DATA data;
|
||||
|
||||
DEBUG(DEBUG_CRIT,("Trigger takeoverrun\n"));
|
||||
|
||||
rd.pnn = ctdb->pnn;
|
||||
rd.srvid = 0;
|
||||
data.dptr = (uint8_t *)&rd;
|
||||
data.dsize = sizeof(rd);
|
||||
|
||||
ret = ctdb_send_message(ctdb, rec->recmaster, CTDB_SRVID_TAKEOVER_RUN, data);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,(__location__ " Failed to send ipreallocate to recmaster :%d\n", (int)rec->recmaster));
|
||||
}
|
||||
}
|
||||
talloc_free(mem_ctx);
|
||||
return 0;
|
||||
}
|
||||
@ -3000,36 +3115,11 @@ again:
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* update the list of public ips that a node can handle for
|
||||
all connected nodes
|
||||
*/
|
||||
if (ctdb->num_nodes != nodemap->num) {
|
||||
DEBUG(DEBUG_ERR, (__location__ " ctdb->num_nodes (%d) != nodemap->num (%d) reloading nodes file\n", ctdb->num_nodes, nodemap->num));
|
||||
reload_nodes_file(ctdb);
|
||||
goto again;
|
||||
}
|
||||
for (j=0; j<nodemap->num; j++) {
|
||||
/* release any existing data */
|
||||
if (ctdb->nodes[j]->public_ips) {
|
||||
talloc_free(ctdb->nodes[j]->public_ips);
|
||||
ctdb->nodes[j]->public_ips = NULL;
|
||||
}
|
||||
|
||||
if (nodemap->nodes[j].flags & NODE_FLAGS_INACTIVE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/* grab a new shiny list of public ips from the node */
|
||||
if (ctdb_ctrl_get_public_ips(ctdb, CONTROL_TIMEOUT(),
|
||||
ctdb->nodes[j]->pnn,
|
||||
ctdb->nodes,
|
||||
&ctdb->nodes[j]->public_ips)) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read public ips from node : %u\n",
|
||||
ctdb->nodes[j]->pnn));
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* verify that all active nodes agree that we are the recmaster */
|
||||
switch (verify_recmaster(rec, nodemap, pnn)) {
|
||||
@ -3256,14 +3346,29 @@ again:
|
||||
|
||||
/* we might need to change who has what IP assigned */
|
||||
if (rec->need_takeover_run) {
|
||||
uint32_t culprit = (uint32_t)-1;
|
||||
|
||||
rec->need_takeover_run = false;
|
||||
|
||||
/* update the list of public ips that a node can handle for
|
||||
all connected nodes
|
||||
*/
|
||||
ret = ctdb_reload_remote_public_ips(ctdb, nodemap, &culprit);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR,("Failed to read public ips from remote node %d\n",
|
||||
culprit));
|
||||
ctdb_set_culprit(rec, culprit);
|
||||
do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* execute the "startrecovery" event script on all nodes */
|
||||
ret = run_startrecovery_eventscript(rec, nodemap);
|
||||
if (ret!=0) {
|
||||
DEBUG(DEBUG_ERR, (__location__ " Unable to run the 'startrecovery' event on cluster\n"));
|
||||
ctdb_set_culprit(rec, ctdb->pnn);
|
||||
do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
|
||||
ret = ctdb_takeover_run(ctdb, nodemap);
|
||||
@ -3271,6 +3376,7 @@ again:
|
||||
DEBUG(DEBUG_ERR, (__location__ " Unable to setup public takeover addresses - starting recovery\n"));
|
||||
ctdb_set_culprit(rec, ctdb->pnn);
|
||||
do_recovery(rec, mem_ctx, pnn, nodemap, vnnmap);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* execute the "recovered" event script on all nodes */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -173,6 +173,7 @@ int main(int argc, const char *argv[])
|
||||
talloc_enable_null_tracking();
|
||||
|
||||
ctdb_block_signal(SIGPIPE);
|
||||
fault_setup("ctdbd");
|
||||
|
||||
ev = event_context_init(NULL);
|
||||
|
||||
@ -281,24 +282,14 @@ int main(int argc, const char *argv[])
|
||||
}
|
||||
|
||||
if (options.single_public_ip) {
|
||||
struct ctdb_vnn *svnn;
|
||||
|
||||
if (options.public_interface == NULL) {
|
||||
DEBUG(DEBUG_ALERT,("--single_public_ip used but --public_interface is not specified. You must specify the public interface when using single public ip. Exiting\n"));
|
||||
exit(10);
|
||||
}
|
||||
|
||||
svnn = talloc_zero(ctdb, struct ctdb_vnn);
|
||||
CTDB_NO_MEMORY(ctdb, svnn);
|
||||
|
||||
ctdb->single_ip_vnn = svnn;
|
||||
svnn->iface = talloc_strdup(svnn, options.public_interface);
|
||||
CTDB_NO_MEMORY(ctdb, svnn->iface);
|
||||
|
||||
if (parse_ip(options.single_public_ip,
|
||||
svnn->iface,
|
||||
0,
|
||||
&svnn->public_address) == 0) {
|
||||
ret = ctdb_set_single_public_ip(ctdb, options.public_interface,
|
||||
options.single_public_ip);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ALERT,("Invalid --single-public-ip argument : %s . This is not a valid ip address. Exiting.\n", options.single_public_ip));
|
||||
exit(10);
|
||||
}
|
||||
|
@ -589,6 +589,7 @@ static bool check_options(enum ctdb_eventscript_call call, const char *options)
|
||||
{
|
||||
switch (call) {
|
||||
/* These all take no arguments. */
|
||||
case CTDB_EVENT_INIT:
|
||||
case CTDB_EVENT_STARTUP:
|
||||
case CTDB_EVENT_START_RECOVERY:
|
||||
case CTDB_EVENT_RECOVERED:
|
||||
@ -603,6 +604,9 @@ static bool check_options(enum ctdb_eventscript_call call, const char *options)
|
||||
case CTDB_EVENT_RELEASE_IP:
|
||||
return count_words(options) == 3;
|
||||
|
||||
case CTDB_EVENT_UPDATE_IP: /* old interface, new interface, IP address, netmask bits. */
|
||||
return count_words(options) == 4;
|
||||
|
||||
default:
|
||||
DEBUG(DEBUG_ERR,(__location__ "Unknown ctdb_eventscript_call %u\n", call));
|
||||
return false;
|
||||
@ -649,7 +653,12 @@ static int ctdb_event_script_callback_v(struct ctdb_context *ctdb,
|
||||
/* we guarantee that only some specifically allowed event scripts are run
|
||||
while in recovery */
|
||||
const enum ctdb_eventscript_call allowed_calls[] = {
|
||||
CTDB_EVENT_START_RECOVERY, CTDB_EVENT_SHUTDOWN, CTDB_EVENT_RELEASE_IP, CTDB_EVENT_STOPPED };
|
||||
CTDB_EVENT_INIT,
|
||||
CTDB_EVENT_START_RECOVERY,
|
||||
CTDB_EVENT_SHUTDOWN,
|
||||
CTDB_EVENT_RELEASE_IP,
|
||||
CTDB_EVENT_STOPPED
|
||||
};
|
||||
int i;
|
||||
for (i=0;i<ARRAY_SIZE(allowed_calls);i++) {
|
||||
if (call == allowed_calls[i]) break;
|
||||
|
@ -16,9 +16,18 @@ case $cmd in
|
||||
exit 0;
|
||||
;;
|
||||
|
||||
init)
|
||||
echo "ctdb init event"
|
||||
exit 0;
|
||||
;;
|
||||
startup)
|
||||
echo "ctdb startup event"
|
||||
exit 0;
|
||||
IFACES=`ctdb ifaces -Y | grep -v '^:Name:LinkStatus:References:'`
|
||||
for I in $IFACES; do
|
||||
IFACE=`echo -n "$I" | cut -d ':' -f2`
|
||||
ctdb setifacelink $IFACE up
|
||||
done
|
||||
exit 0;
|
||||
;;
|
||||
|
||||
takeip)
|
||||
|
@ -239,7 +239,7 @@ sanity_check_output ()
|
||||
|
||||
sanity_check_ips ()
|
||||
{
|
||||
local ips="$1" # Output of "ctdb ip -n all"
|
||||
local ips="$1" # list of "ip node" lines
|
||||
|
||||
echo "Sanity checking IPs..."
|
||||
|
||||
@ -259,9 +259,16 @@ sanity_check_ips ()
|
||||
return 1
|
||||
}
|
||||
|
||||
# This returns a list of "ip node" lines in $out
|
||||
all_ips_on_node()
|
||||
{
|
||||
local node=$@
|
||||
try_command_on_node $node "$CTDB ip -Y -n all | cut -d ':' -f1-3 | sed -e '1d' -e 's@^:@@' -e 's@:@ @g'"
|
||||
}
|
||||
|
||||
select_test_node_and_ips ()
|
||||
{
|
||||
try_command_on_node 0 "$CTDB ip -n all | sed -e '1d'"
|
||||
all_ips_on_node 0
|
||||
|
||||
# When selecting test_node we just want a node that has public
|
||||
# IPs. This will work and is economically semi-random. :-)
|
||||
@ -450,7 +457,7 @@ ips_are_on_nodeglob ()
|
||||
|
||||
local out
|
||||
|
||||
try_command_on_node 1 ctdb ip -n all
|
||||
all_ips_on_node 1
|
||||
|
||||
while read ip pnn ; do
|
||||
for check in $ips ; do
|
||||
|
@ -33,8 +33,20 @@ cluster_is_healthy
|
||||
|
||||
echo "Getting list of public IPs..."
|
||||
try_command_on_node -v 1 $CTDB ip -n all
|
||||
ips=$(echo "$out" | sed -e '1d')
|
||||
colons=$(echo "$ips" | sed -e 's@^@:@' -e 's@$@:@' -e 's@ @:@')
|
||||
ips=$(echo "$out" | sed \
|
||||
-e '1d' \
|
||||
-e 's@ node\[@ @' \
|
||||
-e 's@\].*$@:@')
|
||||
machineout1=":Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:"
|
||||
machineout2=$(echo "$out" | sed \
|
||||
-e '1d' \
|
||||
-e 's@^@:@' \
|
||||
-e 's@ node\[@:@' \
|
||||
-e 's@\] active\[@:@' \
|
||||
-e 's@\] available\[@:@' \
|
||||
-e 's@\] configured\[@:@' \
|
||||
-e 's@\]$@:@')
|
||||
machineout=`echo -e "$machineout1\n$machineout2"`
|
||||
|
||||
while read ip pnn ; do
|
||||
try_command_on_node $pnn "ip addr show"
|
||||
@ -48,14 +60,16 @@ done <<<"$ips" # bashism to avoid problem setting variable in pipeline.
|
||||
|
||||
[ "$testfailures" != 1 ] && echo "Looks good!"
|
||||
|
||||
cmd="$CTDB -Y ip -n all | sed -e '1d'"
|
||||
cmd="$CTDB -Y ip -n all"
|
||||
echo "Checking that \"$cmd\" produces expected output..."
|
||||
|
||||
try_command_on_node 1 "$cmd"
|
||||
if [ "$out" = "$colons" ] ; then
|
||||
if [ "$out" = "$machineout" ] ; then
|
||||
echo "Yep, looks good!"
|
||||
else
|
||||
echo "Nope, it looks like this:"
|
||||
echo "$out"
|
||||
echo "Should be like this:"
|
||||
echo "$machineout"
|
||||
testfailures=1
|
||||
fi
|
||||
|
@ -46,7 +46,7 @@ cluster_is_healthy
|
||||
ctdb_restart_when_done
|
||||
|
||||
echo "Getting list of public IPs..."
|
||||
try_command_on_node 0 "$CTDB ip -n all | sed -e '1d'"
|
||||
all_ips_on_node 0
|
||||
|
||||
# When selecting test_node we just want a node that has public IPs.
|
||||
# This will work and is economically semi-randomly. :-)
|
||||
|
@ -21,7 +21,7 @@ Steps:
|
||||
3. Delete one public IP address being be served by the node, using
|
||||
'ctdb delip'.
|
||||
4. Verify that the delete IP address is no longer listed using the
|
||||
'ctdb ip' command.
|
||||
all_ips_on_node helper function.
|
||||
|
||||
Expected results:
|
||||
|
||||
@ -42,7 +42,7 @@ cluster_is_healthy
|
||||
ctdb_restart_when_done
|
||||
|
||||
echo "Getting list of public IPs..."
|
||||
try_command_on_node -v 0 "$CTDB ip -n all | sed -e '1d'"
|
||||
all_ips_on_node -v 0
|
||||
|
||||
# Select an IP/node to remove.
|
||||
num_ips=$(echo "$out" | wc -l)
|
||||
|
@ -50,7 +50,7 @@ if [ $num_nodes -lt 2 ] ; then
|
||||
fi
|
||||
|
||||
echo "Getting list of public IPs..."
|
||||
try_command_on_node -v 0 "$CTDB ip -n all | sed -e '1d'"
|
||||
all_ips_on_node -v 0
|
||||
|
||||
sanity_check_ips "$out"
|
||||
|
||||
|
@ -502,18 +502,40 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
|
||||
}
|
||||
|
||||
if(options.machinereadable){
|
||||
printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:\n");
|
||||
printf(":Node:IP:Disconnected:Banned:Disabled:Unhealthy:Stopped:Inactive:PartiallyOnline:\n");
|
||||
for(i=0;i<nodemap->num;i++){
|
||||
int partially_online = 0;
|
||||
int j;
|
||||
|
||||
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
|
||||
continue;
|
||||
}
|
||||
printf(":%d:%s:%d:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
|
||||
if (nodemap->nodes[i].flags == 0) {
|
||||
struct ctdb_control_get_ifaces *ifaces;
|
||||
|
||||
ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(),
|
||||
nodemap->nodes[i].pnn,
|
||||
ctdb, &ifaces);
|
||||
if (ret == 0) {
|
||||
for (j=0; j < ifaces->num; j++) {
|
||||
if (ifaces->ifaces[j].link_state != 0) {
|
||||
continue;
|
||||
}
|
||||
partially_online = 1;
|
||||
break;
|
||||
}
|
||||
talloc_free(ifaces);
|
||||
}
|
||||
}
|
||||
printf(":%d:%s:%d:%d:%d:%d:%d:%d:%d:\n", nodemap->nodes[i].pnn,
|
||||
ctdb_addr_to_str(&nodemap->nodes[i].addr),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_BANNED),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED));
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_STOPPED),
|
||||
!!(nodemap->nodes[i].flags&NODE_FLAGS_INACTIVE),
|
||||
partially_online);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -530,6 +552,7 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
|
||||
{ NODE_FLAGS_UNHEALTHY, "UNHEALTHY" },
|
||||
{ NODE_FLAGS_DELETED, "DELETED" },
|
||||
{ NODE_FLAGS_STOPPED, "STOPPED" },
|
||||
{ NODE_FLAGS_INACTIVE, "INACTIVE" },
|
||||
};
|
||||
char *flags_str = NULL;
|
||||
int j;
|
||||
@ -537,6 +560,23 @@ static int control_status(struct ctdb_context *ctdb, int argc, const char **argv
|
||||
if (nodemap->nodes[i].flags & NODE_FLAGS_DELETED) {
|
||||
continue;
|
||||
}
|
||||
if (nodemap->nodes[i].flags == 0) {
|
||||
struct ctdb_control_get_ifaces *ifaces;
|
||||
|
||||
ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(),
|
||||
nodemap->nodes[i].pnn,
|
||||
ctdb, &ifaces);
|
||||
if (ret == 0) {
|
||||
for (j=0; j < ifaces->num; j++) {
|
||||
if (ifaces->ifaces[j].link_state != 0) {
|
||||
continue;
|
||||
}
|
||||
flags_str = talloc_strdup(ctdb, "PARTIALLYONLINE");
|
||||
break;
|
||||
}
|
||||
talloc_free(ifaces);
|
||||
}
|
||||
}
|
||||
for (j=0;j<ARRAY_SIZE(flag_names);j++) {
|
||||
if (nodemap->nodes[i].flags & flag_names[j].flag) {
|
||||
if (flags_str == NULL) {
|
||||
@ -1656,7 +1696,7 @@ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
}
|
||||
|
||||
if (options.machinereadable){
|
||||
printf(":Public IP:Node:\n");
|
||||
printf(":Public IP:Node:ActiveInterface:AvailableInterfaces:ConfiguredInterfaces:\n");
|
||||
} else {
|
||||
if (options.pnn == CTDB_BROADCAST_ALL) {
|
||||
printf("Public IPs on ALL nodes\n");
|
||||
@ -1666,11 +1706,215 @@ static int control_ip(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
}
|
||||
|
||||
for (i=1;i<=ips->num;i++) {
|
||||
if (options.machinereadable){
|
||||
printf(":%s:%d:\n", ctdb_addr_to_str(&ips->ips[ips->num-i].addr), ips->ips[ips->num-i].pnn);
|
||||
struct ctdb_control_public_ip_info *info = NULL;
|
||||
int32_t pnn;
|
||||
char *aciface = NULL;
|
||||
char *avifaces = NULL;
|
||||
char *cifaces = NULL;
|
||||
|
||||
if (options.pnn == CTDB_BROADCAST_ALL) {
|
||||
pnn = ips->ips[ips->num-i].pnn;
|
||||
} else {
|
||||
printf("%s %d\n", ctdb_addr_to_str(&ips->ips[ips->num-i].addr), ips->ips[ips->num-i].pnn);
|
||||
pnn = options.pnn;
|
||||
}
|
||||
|
||||
if (pnn != -1) {
|
||||
ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), pnn, ctdb,
|
||||
&ips->ips[ips->num-i].addr, &info);
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
int j;
|
||||
for (j=0; j < info->num; j++) {
|
||||
if (cifaces == NULL) {
|
||||
cifaces = talloc_strdup(info,
|
||||
info->ifaces[j].name);
|
||||
} else {
|
||||
cifaces = talloc_asprintf_append(cifaces,
|
||||
",%s",
|
||||
info->ifaces[j].name);
|
||||
}
|
||||
|
||||
if (info->active_idx == j) {
|
||||
aciface = info->ifaces[j].name;
|
||||
}
|
||||
|
||||
if (info->ifaces[j].link_state == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (avifaces == NULL) {
|
||||
avifaces = talloc_strdup(info, info->ifaces[j].name);
|
||||
} else {
|
||||
avifaces = talloc_asprintf_append(avifaces,
|
||||
",%s",
|
||||
info->ifaces[j].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (options.machinereadable){
|
||||
printf(":%s:%d:%s:%s:%s:\n",
|
||||
ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
|
||||
ips->ips[ips->num-i].pnn,
|
||||
aciface?aciface:"",
|
||||
avifaces?avifaces:"",
|
||||
cifaces?cifaces:"");
|
||||
} else {
|
||||
printf("%s node[%d] active[%s] available[%s] configured[%s]\n",
|
||||
ctdb_addr_to_str(&ips->ips[ips->num-i].addr),
|
||||
ips->ips[ips->num-i].pnn,
|
||||
aciface?aciface:"",
|
||||
avifaces?avifaces:"",
|
||||
cifaces?cifaces:"");
|
||||
}
|
||||
talloc_free(info);
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
public ip info
|
||||
*/
|
||||
static int control_ipinfo(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int i, ret;
|
||||
ctdb_sock_addr addr;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
|
||||
struct ctdb_control_public_ip_info *info;
|
||||
|
||||
if (argc != 1) {
|
||||
talloc_free(tmp_ctx);
|
||||
usage();
|
||||
}
|
||||
|
||||
if (parse_ip(argv[0], NULL, 0, &addr) == 0) {
|
||||
DEBUG(DEBUG_ERR,("Wrongly formed ip address '%s'\n", argv[0]));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read the public ip info from this node */
|
||||
ret = ctdb_ctrl_get_public_ip_info(ctdb, TIMELIMIT(), options.pnn,
|
||||
tmp_ctx, &addr, &info);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR, ("Unable to get public ip[%s]info from node %u\n",
|
||||
argv[0], options.pnn));
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
printf("Public IP[%s] info on node %u\n",
|
||||
ctdb_addr_to_str(&info->ip.addr),
|
||||
options.pnn);
|
||||
|
||||
printf("IP:%s\nCurrentNode:%d\nNumInterfaces:%u\n",
|
||||
ctdb_addr_to_str(&info->ip.addr),
|
||||
info->ip.pnn, info->num);
|
||||
|
||||
for (i=0; i<info->num; i++) {
|
||||
info->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
|
||||
|
||||
printf("Interface[%u]: Name:%s Link:%s References:%u%s\n",
|
||||
i+1, info->ifaces[i].name,
|
||||
info->ifaces[i].link_state?"up":"down",
|
||||
(unsigned int)info->ifaces[i].references,
|
||||
(i==info->active_idx)?" (active)":"");
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
display interfaces status
|
||||
*/
|
||||
static int control_ifaces(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int i, ret;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
|
||||
struct ctdb_control_get_ifaces *ifaces;
|
||||
|
||||
/* read the public ip list from this node */
|
||||
ret = ctdb_ctrl_get_ifaces(ctdb, TIMELIMIT(), options.pnn,
|
||||
tmp_ctx, &ifaces);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR, ("Unable to get interfaces from node %u\n",
|
||||
options.pnn));
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (options.machinereadable){
|
||||
printf(":Name:LinkStatus:References:\n");
|
||||
} else {
|
||||
printf("Interfaces on node %u\n", options.pnn);
|
||||
}
|
||||
|
||||
for (i=0; i<ifaces->num; i++) {
|
||||
if (options.machinereadable){
|
||||
printf(":%s:%s:%u\n",
|
||||
ifaces->ifaces[i].name,
|
||||
ifaces->ifaces[i].link_state?"1":"0",
|
||||
(unsigned int)ifaces->ifaces[i].references);
|
||||
} else {
|
||||
printf("name:%s link:%s references:%u\n",
|
||||
ifaces->ifaces[i].name,
|
||||
ifaces->ifaces[i].link_state?"up":"down",
|
||||
(unsigned int)ifaces->ifaces[i].references);
|
||||
}
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
set link status of an interface
|
||||
*/
|
||||
static int control_setifacelink(struct ctdb_context *ctdb, int argc, const char **argv)
|
||||
{
|
||||
int ret;
|
||||
TALLOC_CTX *tmp_ctx = talloc_new(ctdb);
|
||||
struct ctdb_control_iface_info info;
|
||||
|
||||
ZERO_STRUCT(info);
|
||||
|
||||
if (argc != 2) {
|
||||
usage();
|
||||
}
|
||||
|
||||
if (strlen(argv[0]) > CTDB_IFACE_SIZE) {
|
||||
DEBUG(DEBUG_ERR, ("interfaces name '%s' too long\n",
|
||||
argv[0]));
|
||||
talloc_free(tmp_ctx);
|
||||
return -1;
|
||||
}
|
||||
strcpy(info.name, argv[0]);
|
||||
|
||||
if (strcmp(argv[1], "up") == 0) {
|
||||
info.link_state = 1;
|
||||
} else if (strcmp(argv[1], "down") == 0) {
|
||||
info.link_state = 0;
|
||||
} else {
|
||||
DEBUG(DEBUG_ERR, ("link state invalid '%s' should be 'up' or 'down'\n",
|
||||
argv[1]));
|
||||
talloc_free(tmp_ctx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* read the public ip list from this node */
|
||||
ret = ctdb_ctrl_set_iface_link(ctdb, TIMELIMIT(), options.pnn,
|
||||
tmp_ctx, &info);
|
||||
if (ret != 0) {
|
||||
DEBUG(DEBUG_ERR, ("Unable to set link state for interfaces %s node %u\n",
|
||||
argv[0], options.pnn));
|
||||
talloc_free(tmp_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
talloc_free(tmp_ctx);
|
||||
@ -4002,6 +4246,9 @@ static const struct {
|
||||
{ "statistics", control_statistics, false, false, "show statistics" },
|
||||
{ "statisticsreset", control_statistics_reset, true, false, "reset statistics"},
|
||||
{ "ip", control_ip, false, false, "show which public ip's that ctdb manages" },
|
||||
{ "ipinfo", control_ipinfo, true, false, "show details about a public ip that ctdb manages", "<ip>" },
|
||||
{ "ifaces", control_ifaces, true, false, "show which interfaces that ctdb manages" },
|
||||
{ "setifacelink", control_setifacelink, true, false, "set interface link status", "<iface> <status>" },
|
||||
{ "process-exists", control_process_exists, true, false, "check if a process exists on a node", "<pid>"},
|
||||
{ "getdbmap", control_getdbmap, true, false, "show the database map" },
|
||||
{ "getdbstatus", control_getdbstatus, true, false, "show the status of a database", "<dbname>" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user