lib/util/debug.o common/rb_tree.o @CTDB_SYSTEM_OBJ@ common/system_common.o \
common/ctdb_logging.o common/ctdb_fork.o
-CTDB_LIB_OBJ = libctdb/ctdb.o libctdb/io_elem.o libctdb/local_tdb.o \
- libctdb/messages.o libctdb/sync.o libctdb/control.o \
- libctdb/logging.o $(SOCKET_WRAPPER_OBJ)
-
CTDB_TCP_OBJ = tcp/tcp_connect.o tcp/tcp_io.o tcp/tcp_init.o
CTDB_EXTERNAL_OBJ = $(POPT_OBJ) $(TALLOC_OBJ) $(TDB_OBJ) \
.SUFFIXES: .c .o .h
-all: showflags dirs $(CTDB_VERSION_H) $(CTDB_SERVER_OBJ) $(CTDB_CLIENT_OBJ) $(CTDB_LIB_OBJ) $(BINS) $(SBINS) $(TEST_BINS)
+all: showflags dirs $(CTDB_VERSION_H) $(CTDB_SERVER_OBJ) $(CTDB_CLIENT_OBJ) $(BINS) $(SBINS) $(TEST_BINS)
showflags:
@echo 'ctdb will be compiled with flags:'
@echo Linking $@
$(WRAPPER) $(CC) $(CFLAGS) -o $@ $(CTDB_SERVER_OBJ) $(LIB_FLAGS)
-libctdb/libctdb.a: $(CTDB_LIB_OBJ)
- @echo Linking $@
- -rm -f libctdb.a
- $(WRAPPER) $(AR) $(ARFLAGS) libctdb/libctdb.a $(CTDB_LIB_OBJ)
- $(WRAPPER) $(RANLIB) libctdb/libctdb.a
-
-libctdb/libctdb.so.0: $(CTDB_LIB_OBJ)
- @echo Linking $@
- $(WRAPPER) $(SHLD) -Wl,-soname=libctdb.so.0 $(CTDB_LIB_OBJ)
-
-libctdb/libctdb.so: libctdb/libctdb.so.0
- @echo Creating $@
- $(WRAPPER) rm -f libctdb/libctdb.so
- $(WRAPPER) ln -s libctdb.so.0 libctdb/libctdb.so
-
bin/scsi_io: $(CTDB_CLIENT_OBJ) utils/scsi_io/scsi_io.o
@echo Linking $@
$(WRAPPER) $(CC) $(CFLAGS) -o $@ utils/scsi_io/scsi_io.o $(CTDB_CLIENT_OBJ) $(LIB_FLAGS)
$(INSTALLCMD) -m 755 bin/ping_pong $(DESTDIR)$(bindir)
$(INSTALLCMD) -m 755 bin/ltdbtool $(DESTDIR)$(bindir)
$(INSTALLCMD) -m 755 bin/ctdb_lock_helper $(DESTDIR)$(bindir)
- $(INSTALLCMD) -m 755 libctdb/libctdb.a $(DESTDIR)$(libdir)
${INSTALLCMD} -m 644 include/ctdb.h $(DESTDIR)$(includedir)
${INSTALLCMD} -m 644 include/ctdb_client.h $(DESTDIR)$(includedir)
${INSTALLCMD} -m 644 include/ctdb_protocol.h $(DESTDIR)$(includedir)
+++ /dev/null
-- Use CTDB_CONTROL_GET_DB_PRIORITY to ensure db locking is done in order.
-- Attach tdb's logging to libctdb logging.
-- Threadsafe version.
+++ /dev/null
-/*
- Misc control routines of libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <sys/time.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <ctdb.h>
-#include <ctdb_protocol.h>
-#include "libctdb_private.h"
-
-/* Remove type-safety macros. */
-#undef ctdb_getrecmaster_send
-#undef ctdb_getrecmode_send
-#undef ctdb_getpnn_send
-#undef ctdb_getdbstat_send
-#undef ctdb_check_message_handlers_send
-#undef ctdb_getnodemap_send
-#undef ctdb_getpublicips_send
-#undef ctdb_getdbseqnum_send
-#undef ctdb_getifaces_send
-#undef ctdb_getvnnmap_send
-#undef ctdb_getcapabilities_send
-
-bool ctdb_getrecmaster_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, uint32_t *recmaster)
-{
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMASTER);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getrecmaster_recv: status -1");
- return false;
- }
- /* Note: data is stashed in status - see ctdb_control_dispatch() */
- *recmaster = reply->status;
- return true;
-}
-
-struct ctdb_request *ctdb_getrecmaster_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMASTER,
- destnode, NULL, 0,
- callback, private_data);
-}
-
-bool ctdb_getrecmode_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, uint32_t *recmode)
-{
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_RECMODE);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getrecmode_recv: status -1");
- return false;
- }
- /* Note: data is stashed in status - see ctdb_control_dispatch() */
- *recmode = reply->status;
- return true;
-}
-
-struct ctdb_request *ctdb_getrecmode_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_RECMODE,
- destnode, NULL, 0,
- callback, private_data);
-}
-
-bool ctdb_getpnn_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, uint32_t *pnn)
-{
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_PNN);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
- return false;
- }
- /* Note: data is stashed in status - see ctdb_control_dispatch() */
- *pnn = reply->status;
- return true;
-}
-
-struct ctdb_request *ctdb_getpnn_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PNN, destnode,
- NULL, 0, callback, private_data);
-}
-
-bool ctdb_getdbstat_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- struct ctdb_db_statistics **stat)
-{
- struct ctdb_reply_control *reply;
- struct ctdb_db_statistics *s, *wire;
- int i;
- char *ptr;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_STATISTICS);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getpnn_recv: status -1");
- return false;
- }
- if (reply->datalen < offsetof(struct ctdb_db_statistics, hot_keys_wire)) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getdbstat_recv: returned data is %d bytes but should be >= %d", reply->datalen, (int)sizeof(struct ctdb_db_statistics));
- return false;
- }
-
- wire = (struct ctdb_db_statistics *)reply->data;
-
- s = malloc(sizeof(struct ctdb_db_statistics));
- if (!s) {
- return false;
- }
-
- *s = *wire;
- ptr = &wire->hot_keys_wire[0];
- for (i = 0; i < wire->num_hot_keys; i++) {
- s->hot_keys[i].key.dptr = malloc(s->hot_keys[i].key.dsize);
- memcpy(s->hot_keys[i].key.dptr, ptr, s->hot_keys[i].key.dsize);
- ptr += s->hot_keys[i].key.dsize;
- }
-
- *stat = s;
-
- return true;
-}
-
-struct ctdb_request *ctdb_getdbstat_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- uint32_t db_id,
- ctdb_callback_t callback,
- void *private_data)
-{
- uint32_t indata = db_id;
-
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_STATISTICS, destnode,
- &indata, sizeof(indata), callback, private_data);
-}
-
-void ctdb_free_dbstat(struct ctdb_db_statistics *stat)
-{
- int i;
-
- if (stat == NULL) {
- return;
- }
-
- for (i = 0; i < stat->num_hot_keys; i++) {
- if (stat->hot_keys[i].key.dptr != NULL) {
- free(stat->hot_keys[i].key.dptr);
- }
- }
-
- free(stat);
-}
-
-bool ctdb_getnodemap_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, struct ctdb_node_map **nodemap)
-{
- struct ctdb_reply_control *reply;
-
- *nodemap = NULL;
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_NODEMAP);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: status -1");
- return false;
- }
- if (reply->datalen == 0) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: returned data is 0 bytes");
- return false;
- }
-
- *nodemap = malloc(reply->datalen);
- if (*nodemap == NULL) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getnodemap_recv: failed to malloc buffer");
- return false;
- }
- memcpy(*nodemap, reply->data, reply->datalen);
-
- return true;
-}
-struct ctdb_request *ctdb_getnodemap_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_NODEMAP,
- destnode,
- NULL, 0, callback, private_data);
-}
-
-void ctdb_free_nodemap(struct ctdb_node_map *nodemap)
-{
- if (nodemap == NULL) {
- return;
- }
- free(nodemap);
-}
-
-bool ctdb_getpublicips_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- struct ctdb_all_public_ips **ips)
-{
- struct ctdb_reply_control *reply;
-
- *ips = NULL;
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_PUBLIC_IPS);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: status -1");
- return false;
- }
- if (reply->datalen == 0) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: returned data is 0 bytes");
- return false;
- }
-
- *ips = malloc(reply->datalen);
- if (*ips == NULL) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getpublicips_recv: failed to malloc buffer");
- return false;
- }
- memcpy(*ips, reply->data, reply->datalen);
-
- return true;
-}
-struct ctdb_request *ctdb_getpublicips_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_PUBLIC_IPS,
- destnode,
- NULL, 0, callback, private_data);
-}
-
-void ctdb_free_publicips(struct ctdb_all_public_ips *ips)
-{
- if (ips == NULL) {
- return;
- }
- free(ips);
-}
-
-bool ctdb_getdbseqnum_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, uint64_t *seqnum)
-{
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_DB_SEQNUM);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum_recv: status -1");
- return false;
- }
-
- if (reply->datalen != sizeof(uint64_t)) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getdbseqnum wrong size of data was %d but expected %d bytes", reply->datalen, (int)sizeof(uint64_t));
- return false;
- }
-
- *seqnum = *((uint64_t *)reply->data);
-
- return true;
-}
-
-struct ctdb_request *ctdb_getdbseqnum_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- uint32_t dbid,
- ctdb_callback_t callback,
- void *private_data)
-{
- uint64_t indata;
-
- *((uint32_t *)&indata) = dbid;
-
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_DB_SEQNUM,
- destnode, &indata, sizeof(uint64_t),
- callback, private_data);
-}
-
-bool ctdb_check_message_handlers_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- uint32_t num, uint8_t *result)
-{
- struct ctdb_reply_control *reply;
- int i, count;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_CHECK_SRVIDS);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: status -1");
- return false;
- }
-
- count = (num + 7) / 8;
- if (count != reply->datalen) {
- DEBUG(ctdb, LOG_ERR, "ctdb_check_message_handlers_recv: wrong amount of data returned, expected %d bytes for %d srvids but received %d bytes", count, num, reply->datalen);
- return false;
- }
-
- for (i = 0; i < num; i++) {
- result[i] = !!(reply->data[i / 8] & (1 << (i % 8)));
- }
-
- return true;
-}
-
-struct ctdb_request *
-ctdb_check_message_handlers_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- uint32_t num,
- uint64_t *mhs,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_CHECK_SRVIDS,
- destnode,
- mhs, num * sizeof(uint64_t) ,
- callback, private_data);
-}
-
-
-bool ctdb_getifaces_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- struct ctdb_ifaces_list **ifaces)
-{
- struct ctdb_reply_control *reply;
- struct ctdb_ifaces_list *ifc;
- int i, len;
-
- *ifaces = NULL;
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_IFACES);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: status -1");
- return false;
- }
- if (reply->datalen == 0) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is 0 bytes");
- return false;
- }
-
- len = offsetof(struct ctdb_ifaces_list, ifaces);
- if (len > reply->datalen) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but %d is minimum", reply->datalen, (int)offsetof(struct ctdb_ifaces_list, ifaces));
- return false;
- }
-
- ifc = (struct ctdb_ifaces_list *)(reply->data);
- len += ifc->num * sizeof(struct ctdb_iface_info);
-
- if (len != reply->datalen) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: returned data is %d bytes but should be %d", reply->datalen, len);
- return false;
- }
-
- ifc = malloc(reply->datalen);
- if (ifc == NULL) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getifaces_recv: failed to malloc buffer");
- return false;
- }
- memcpy(ifc, reply->data, reply->datalen);
-
- /* make sure we null terminate the returned strings */
- for (i = 0; i < ifc->num; i++) {
- ifc->ifaces[i].name[CTDB_IFACE_SIZE] = '\0';
- }
-
- *ifaces = ifc;
-
- return true;
-}
-
-void ctdb_free_ifaces(struct ctdb_ifaces_list *ifaces)
-{
- free(ifaces);
-}
-
-struct ctdb_request *ctdb_getifaces_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_IFACES,
- destnode,
- NULL, 0, callback, private_data);
-}
-
-bool ctdb_getvnnmap_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- struct ctdb_vnn_map **vnnmap)
-{
- struct ctdb_reply_control *reply;
- struct ctdb_vnn_map_wire *map;
- struct ctdb_vnn_map *tmap;
- int len;
-
- *vnnmap = NULL;
- reply = unpack_reply_control(req, CTDB_CONTROL_GETVNNMAP);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: status -1");
- return false;
- }
- if (reply->datalen == 0) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is 0 bytes");
- return false;
- }
-
- len = offsetof(struct ctdb_vnn_map_wire, map);
- if (len > reply->datalen) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but %d is minimum", reply->datalen, (int)offsetof(struct ctdb_vnn_map_wire, map));
- return false;
- }
-
- map = (struct ctdb_vnn_map_wire *)(reply->data);
- len += map->size * sizeof(uint32_t);
-
- if (len != reply->datalen) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: returned data is %d bytes but should be %d", reply->datalen, len);
- return false;
- }
-
- tmap = malloc(sizeof(struct ctdb_vnn_map));
- if (tmap == NULL) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
- return false;
- }
-
- tmap->generation = map->generation;
- tmap->size = map->size;
- tmap->map = malloc(sizeof(uint32_t) * map->size);
- if (tmap->map == NULL) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getvnnmap_recv: failed to malloc buffer");
- free(tmap);
- return false;
- }
-
- memcpy(tmap->map, map->map, sizeof(uint32_t)*map->size);
-
- *vnnmap = tmap;
-
- return true;
-}
-
-void ctdb_free_vnnmap(struct ctdb_vnn_map *vnnmap)
-{
- free(vnnmap->map);
- free(vnnmap);
-}
-
-struct ctdb_request *ctdb_getvnnmap_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GETVNNMAP,
- destnode,
- NULL, 0, callback, private_data);
-}
-
-bool ctdb_getcapabilities_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req, uint32_t *capabilities)
-{
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_GET_CAPABILITIES);
- if (!reply) {
- return false;
- }
- if (reply->status == -1) {
- DEBUG(ctdb, LOG_ERR, "ctdb_getcapabilities_recv: status -1");
- return false;
- }
- *capabilities = *((uint32_t *)reply->data);
- return true;
-}
-
-struct ctdb_request *ctdb_getcapabilities_send(struct ctdb_connection *ctdb,
- uint32_t destnode,
- ctdb_callback_t callback,
- void *private_data)
-{
- return new_ctdb_control_request(ctdb, CTDB_CONTROL_GET_CAPABILITIES,
- destnode,
- NULL, 0, callback, private_data);
-}
-
+++ /dev/null
-/*
- core of libctdb
-
- Copyright (C) Rusty Russell 2010
- Copyright (C) Ronnie Sahlberg 2011
-
- 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 "config.h"
-#include <sys/time.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <ctdb.h>
-#include <poll.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/ioctl.h>
-#include <time.h>
-#include "libctdb_private.h"
-#include "io_elem.h"
-#include "local_tdb.h"
-#include "messages.h"
-#include <dlinklist.h>
-#include <ctdb_protocol.h>
-
-/* Remove type-safety macros. */
-#undef ctdb_attachdb_send
-#undef ctdb_readrecordlock_async
-#undef ctdb_readonlyrecordlock_async
-#undef ctdb_connect
-
-struct ctdb_lock {
- struct ctdb_lock *next, *prev;
-
- struct ctdb_db *ctdb_db;
- TDB_DATA key;
-
- /* Is this a request for read-only lock ? */
- bool readonly;
-
- /* This will always be set by the time user sees this. */
- unsigned long held_magic;
- struct ctdb_ltdb_header *hdr;
-
- /* For convenience, we stash original callback here. */
- ctdb_rrl_callback_t callback;
-};
-
-struct ctdb_db {
- struct ctdb_connection *ctdb;
- bool persistent;
- uint32_t tdb_flags;
- uint32_t id;
- struct tdb_context *tdb;
-
- ctdb_callback_t callback;
- void *private_data;
-};
-
-static void remove_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
-{
- DLIST_REMOVE(ctdb->locks, lock);
-}
-
-/* FIXME: for thread safety, need tid info too. */
-static bool holding_lock(struct ctdb_connection *ctdb)
-{
- /* For the moment, you can't ever hold more than 1 lock. */
- return (ctdb->locks != NULL);
-}
-
-static void add_lock(struct ctdb_connection *ctdb, struct ctdb_lock *lock)
-{
- DLIST_ADD(ctdb->locks, lock);
-}
-
-static void cleanup_locks(struct ctdb_connection *ctdb, struct ctdb_db *db)
-{
- struct ctdb_lock *i, *next;
-
- for (i = ctdb->locks; i; i = next) {
- /* Grab next pointer, as release_lock will free i */
- next = i->next;
- if (i->ctdb_db == db) {
- ctdb_release_lock(db, i);
- }
- }
-}
-
-/* FIXME: Could be in shared util code with rest of ctdb */
-static void close_noerr(int fd)
-{
- int olderr = errno;
- close(fd);
- errno = olderr;
-}
-
-/* FIXME: Could be in shared util code with rest of ctdb */
-static void free_noerr(void *p)
-{
- int olderr = errno;
- free(p);
- errno = olderr;
-}
-
-/* FIXME: Could be in shared util code with rest of ctdb */
-static void set_nonblocking(int fd)
-{
- unsigned v;
- v = fcntl(fd, F_GETFL, 0);
- fcntl(fd, F_SETFL, v | O_NONBLOCK);
-}
-
-/* FIXME: Could be in shared util code with rest of ctdb */
-static void set_close_on_exec(int fd)
-{
- unsigned v;
- v = fcntl(fd, F_GETFD, 0);
- fcntl(fd, F_SETFD, v | FD_CLOEXEC);
-}
-
-static void set_pnn(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *unused)
-{
- if (!ctdb_getpnn_recv(ctdb, req, &ctdb->pnn)) {
- DEBUG(ctdb, LOG_CRIT,
- "ctdb_connect(async): failed to get pnn");
- ctdb->broken = true;
- }
- ctdb_request_free(req);
-}
-
-struct ctdb_connection *ctdb_connect(const char *addr,
- ctdb_log_fn_t log_fn, void *log_priv)
-{
- struct ctdb_connection *ctdb;
- struct sockaddr_un sun;
-
- ctdb = malloc(sizeof(*ctdb));
- if (!ctdb) {
- /* With no format string, we hope it doesn't use ap! */
- va_list ap;
- memset(&ap, 0, sizeof(ap));
- errno = ENOMEM;
- log_fn(log_priv, LOG_ERR, "ctdb_connect: no memory", ap);
- goto fail;
- }
- ctdb->pnn = -1;
- ctdb->outq = NULL;
- ctdb->doneq = NULL;
- ctdb->in = NULL;
- ctdb->inqueue = NULL;
- ctdb->message_handlers = NULL;
- ctdb->next_id = 0;
- ctdb->broken = false;
- ctdb->log = log_fn;
- ctdb->log_priv = log_priv;
- ctdb->locks = NULL;
-
- memset(&sun, 0, sizeof(sun));
- sun.sun_family = AF_UNIX;
- if (!addr)
- addr = CTDB_PATH;
- strncpy(sun.sun_path, addr, sizeof(sun.sun_path)-1);
- ctdb->fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if (ctdb->fd < 0)
- goto free_fail;
-
- if (connect(ctdb->fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
- goto close_fail;
-
- set_nonblocking(ctdb->fd);
- set_close_on_exec(ctdb->fd);
-
- /* Immediately queue a request to get our pnn. */
- if (!ctdb_getpnn_send(ctdb, CTDB_CURRENT_NODE, set_pnn, NULL))
- goto close_fail;
-
- return ctdb;
-
-close_fail:
- close_noerr(ctdb->fd);
-free_fail:
- free_noerr(ctdb);
-fail:
- return NULL;
-}
-
-void ctdb_disconnect(struct ctdb_connection *ctdb)
-{
- struct ctdb_request *i;
-
- DEBUG(ctdb, LOG_DEBUG, "ctdb_disconnect");
-
- while ((i = ctdb->outq) != NULL) {
- DLIST_REMOVE(ctdb->outq, i);
- ctdb_request_free(i);
- }
-
- while ((i = ctdb->doneq) != NULL) {
- DLIST_REMOVE(ctdb->doneq, i);
- ctdb_request_free(i);
- }
-
- if (ctdb->in)
- free_io_elem(ctdb->in);
-
- remove_message_handlers(ctdb);
-
- close(ctdb->fd);
- /* Just in case they try to reuse */
- ctdb->fd = -1;
- free(ctdb);
-}
-
-int ctdb_get_fd(struct ctdb_connection *ctdb)
-{
- return ctdb->fd;
-}
-
-int ctdb_which_events(struct ctdb_connection *ctdb)
-{
- int events = POLLIN;
-
- if (ctdb->outq)
- events |= POLLOUT;
- return events;
-}
-
-struct ctdb_request *new_ctdb_request(struct ctdb_connection *ctdb, size_t len,
- ctdb_callback_t cb, void *cbdata)
-{
- struct ctdb_request *req = malloc(sizeof(*req));
- if (!req)
- return NULL;
- req->io = new_io_elem(len);
- if (!req->io) {
- free(req);
- return NULL;
- }
- req->ctdb = ctdb;
- req->hdr.hdr = io_elem_data(req->io, NULL);
- req->reply = NULL;
- req->callback = cb;
- req->priv_data = cbdata;
- req->extra = NULL;
- req->extra_destructor = NULL;
- return req;
-}
-
-void ctdb_request_free(struct ctdb_request *req)
-{
- struct ctdb_connection *ctdb = req->ctdb;
-
- if (req->next || req->prev) {
- DEBUG(ctdb, LOG_ALERT,
- "ctdb_request_free: request not complete! ctdb_cancel? %p (id %u)",
- req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
- ctdb_cancel(ctdb, req);
- return;
- }
- if (req->extra_destructor) {
- req->extra_destructor(ctdb, req);
- }
- if (req->reply) {
- free_io_elem(req->reply);
- }
- free_io_elem(req->io);
- free(req);
-}
-
-/* Sanity-checking wrapper for reply. */
-static struct ctdb_reply_call *unpack_reply_call(struct ctdb_request *req,
- uint32_t callid)
-{
- size_t len;
- struct ctdb_reply_call *inhdr = io_elem_data(req->reply, &len);
-
- /* Library user error if this isn't a reply to a call. */
- if (req->hdr.hdr->operation != CTDB_REQ_CALL) {
- errno = EINVAL;
- DEBUG(req->ctdb, LOG_ALERT,
- "This was not a ctdbd call request: operation %u",
- req->hdr.hdr->operation);
- return NULL;
- }
-
- if (req->hdr.call->callid != callid) {
- errno = EINVAL;
- DEBUG(req->ctdb, LOG_ALERT,
- "This was not a ctdbd %u call request: %u",
- callid, req->hdr.call->callid);
- return NULL;
- }
-
- /* ctdbd or our error if this isn't a reply call. */
- if (len < sizeof(*inhdr) || inhdr->hdr.operation != CTDB_REPLY_CALL) {
- errno = EIO;
- DEBUG(req->ctdb, LOG_CRIT,
- "Invalid ctdbd call reply: len %zu, operation %u",
- len, inhdr->hdr.operation);
- return NULL;
- }
-
- return inhdr;
-}
-
-/* Sanity-checking wrapper for reply. */
-struct ctdb_reply_control *unpack_reply_control(struct ctdb_request *req,
- enum ctdb_controls control)
-{
- size_t len;
- struct ctdb_reply_control *inhdr = io_elem_data(req->reply, &len);
-
- /* Library user error if this isn't a reply to a call. */
- if (len < sizeof(*inhdr)) {
- errno = EINVAL;
- DEBUG(req->ctdb, LOG_ALERT,
- "Short ctdbd control reply: %zu bytes", len);
- return NULL;
- }
- if (req->hdr.hdr->operation != CTDB_REQ_CONTROL) {
- errno = EINVAL;
- DEBUG(req->ctdb, LOG_ALERT,
- "This was not a ctdbd control request: operation %u",
- req->hdr.hdr->operation);
- return NULL;
- }
-
- /* ... or if it was a different control from what we expected. */
- if (req->hdr.control->opcode != control) {
- errno = EINVAL;
- DEBUG(req->ctdb, LOG_ALERT,
- "This was not an opcode %u ctdbd control request: %u",
- control, req->hdr.control->opcode);
- return NULL;
- }
-
- /* ctdbd or our error if this isn't a reply call. */
- if (inhdr->hdr.operation != CTDB_REPLY_CONTROL) {
- errno = EIO;
- DEBUG(req->ctdb, LOG_CRIT,
- "Invalid ctdbd control reply: operation %u",
- inhdr->hdr.operation);
- return NULL;
- }
-
- return inhdr;
-}
-
-static void handle_incoming(struct ctdb_connection *ctdb, struct io_elem *in)
-{
- struct ctdb_req_header *hdr;
- size_t len;
- struct ctdb_request *i;
-
- hdr = io_elem_data(in, &len);
- /* FIXME: use len to check packet! */
-
- if (hdr->operation == CTDB_REQ_MESSAGE) {
- deliver_message(ctdb, hdr);
- return;
- }
-
- for (i = ctdb->doneq; i; i = i->next) {
- if (i->hdr.hdr->reqid == hdr->reqid) {
- DLIST_REMOVE(ctdb->doneq, i);
- i->reply = in;
- i->callback(ctdb, i, i->priv_data);
- return;
- }
- }
- DEBUG(ctdb, LOG_WARNING,
- "Unexpected ctdbd request reply: operation %u reqid %u",
- hdr->operation, hdr->reqid);
- free_io_elem(in);
-}
-
-/* Remove "harmless" errors. */
-static ssize_t real_error(ssize_t ret)
-{
- if (ret < 0 && (errno == EINTR || errno == EWOULDBLOCK))
- return 0;
- return ret;
-}
-
-bool ctdb_service(struct ctdb_connection *ctdb, int revents)
-{
- if (ctdb->broken) {
- return false;
- }
-
- if (holding_lock(ctdb)) {
- DEBUG(ctdb, LOG_ALERT, "Do not block while holding lock!");
- }
-
- if (revents & POLLOUT) {
- while (ctdb->outq) {
- if (real_error(write_io_elem(ctdb->fd,
- ctdb->outq->io)) < 0) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_service: error writing to ctdbd");
- ctdb->broken = true;
- return false;
- }
- if (io_elem_finished(ctdb->outq->io)) {
- struct ctdb_request *done = ctdb->outq;
- DLIST_REMOVE(ctdb->outq, done);
- /* We add at the head: any dead ones
- * sit and end. */
- DLIST_ADD(ctdb->doneq, done);
- }
- }
- }
-
- while (revents & POLLIN) {
- int ret;
- int num_ready = 0;
-
- if (ioctl(ctdb->fd, FIONREAD, &num_ready) != 0) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_service: ioctl(FIONREAD) %d", errno);
- ctdb->broken = true;
- return false;
- }
- if (num_ready == 0) {
- /* the descriptor has been closed or we have all our data */
- break;
- }
-
-
- if (!ctdb->in) {
- ctdb->in = new_io_elem(sizeof(struct ctdb_req_header));
- if (!ctdb->in) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_service: allocating readbuf");
- ctdb->broken = true;
- return false;
- }
- }
-
- ret = read_io_elem(ctdb->fd, ctdb->in);
- if (real_error(ret) < 0 || ret == 0) {
- /* They closed fd? */
- if (ret == 0)
- errno = EBADF;
- DEBUG(ctdb, LOG_ERR,
- "ctdb_service: error reading from ctdbd");
- ctdb->broken = true;
- return false;
- } else if (ret < 0) {
- /* No progress, stop loop. */
- break;
- } else if (io_elem_finished(ctdb->in)) {
- io_elem_queue(ctdb, ctdb->in);
- ctdb->in = NULL;
- }
- }
-
-
- while (ctdb->inqueue != NULL) {
- struct io_elem *io = ctdb->inqueue;
-
- io_elem_dequeue(ctdb, io);
- handle_incoming(ctdb, io);
- }
-
- return true;
-}
-
-/* This is inefficient. We could pull in idtree.c. */
-static bool reqid_used(const struct ctdb_connection *ctdb, uint32_t reqid)
-{
- struct ctdb_request *i;
-
- for (i = ctdb->outq; i; i = i->next) {
- if (i->hdr.hdr->reqid == reqid) {
- return true;
- }
- }
- for (i = ctdb->doneq; i; i = i->next) {
- if (i->hdr.hdr->reqid == reqid) {
- return true;
- }
- }
- return false;
-}
-
-uint32_t new_reqid(struct ctdb_connection *ctdb)
-{
- while (reqid_used(ctdb, ctdb->next_id)) {
- ctdb->next_id++;
- }
- return ctdb->next_id++;
-}
-
-struct ctdb_request *new_ctdb_control_request(struct ctdb_connection *ctdb,
- uint32_t opcode,
- uint32_t destnode,
- const void *extra_data,
- size_t extra,
- ctdb_callback_t callback,
- void *cbdata)
-{
- struct ctdb_request *req;
- struct ctdb_req_control *pkt;
-
- req = new_ctdb_request(
- ctdb, offsetof(struct ctdb_req_control, data) + extra,
- callback, cbdata);
- if (!req)
- return NULL;
-
- io_elem_init_req_header(req->io,
- CTDB_REQ_CONTROL, destnode, new_reqid(ctdb));
-
- pkt = req->hdr.control;
- pkt->pad = 0;
- pkt->opcode = opcode;
- pkt->srvid = 0;
- pkt->client_id = 0;
- pkt->flags = 0;
- pkt->datalen = extra;
- memcpy(pkt->data, extra_data, extra);
- DLIST_ADD(ctdb->outq, req);
- return req;
-}
-
-void ctdb_cancel_callback(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *unused)
-{
- ctdb_request_free(req);
-}
-
-void ctdb_cancel(struct ctdb_connection *ctdb, struct ctdb_request *req)
-{
- if (!req->next && !req->prev) {
- DEBUG(ctdb, LOG_ALERT,
- "ctdb_cancel: request completed! ctdb_request_free? %p (id %u)",
- req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
- ctdb_request_free(req);
- return;
- }
-
- DEBUG(ctdb, LOG_DEBUG, "ctdb_cancel: %p (id %u)",
- req, req->hdr.hdr ? req->hdr.hdr->reqid : 0);
-
- /* FIXME: If it's not sent, we could just free it right now. */
- req->callback = ctdb_cancel_callback;
-}
-
-void ctdb_detachdb(struct ctdb_connection *ctdb, struct ctdb_db *db)
-{
- cleanup_locks(ctdb, db);
- tdb_close(db->tdb);
- free(db);
-}
-
-static void destroy_req_db(struct ctdb_connection *ctdb,
- struct ctdb_request *req);
-static void attachdb_done(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *_db);
-static void attachdb_getdbpath_done(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *_db);
-
-struct ctdb_request *
-ctdb_attachdb_send(struct ctdb_connection *ctdb,
- const char *name, bool persistent, uint32_t tdb_flags,
- ctdb_callback_t callback, void *private_data)
-{
- struct ctdb_request *req;
- struct ctdb_db *db;
- uint32_t opcode;
-
- /* FIXME: Search if db already open. */
- db = malloc(sizeof(*db));
- if (!db) {
- return NULL;
- }
-
- if (persistent) {
- opcode = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
- } else {
- opcode = CTDB_CONTROL_DB_ATTACH;
- }
-
- req = new_ctdb_control_request(ctdb, opcode, CTDB_CURRENT_NODE, name,
- strlen(name) + 1, attachdb_done, db);
- if (!req) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_attachdb_send: failed allocating DB_ATTACH");
- free(db);
- return NULL;
- }
-
- db->ctdb = ctdb;
- db->tdb_flags = tdb_flags;
- db->persistent = persistent;
- db->callback = callback;
- db->private_data = private_data;
-
- req->extra_destructor = destroy_req_db;
- /* This is set non-NULL when we succeed, see ctdb_attachdb_recv */
- req->extra = NULL;
-
- /* Flags get overloaded into srvid. */
- req->hdr.control->srvid = tdb_flags;
- DEBUG(db->ctdb, LOG_DEBUG,
- "ctdb_attachdb_send: DB_ATTACH request %p", req);
- return req;
-}
-
-static void destroy_req_db(struct ctdb_connection *ctdb,
- struct ctdb_request *req)
-{
- /* Incomplete db is in priv_data. */
- free(req->priv_data);
- /* second request is chained off this one. */
- if (req->extra) {
- ctdb_request_free(req->extra);
- }
-}
-
-static void attachdb_done(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *_db)
-{
- struct ctdb_db *db = _db;
- struct ctdb_request *req2;
- struct ctdb_reply_control *reply;
- enum ctdb_controls control = CTDB_CONTROL_DB_ATTACH;
-
- if (db->persistent) {
- control = CTDB_CONTROL_DB_ATTACH_PERSISTENT;
- }
-
- reply = unpack_reply_control(req, control);
- if (!reply || reply->status != 0) {
- if (reply) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_attachdb_send(async): DB_ATTACH status %i",
- reply->status);
- }
- /* We failed. Hand request to user and have them discover it
- * via ctdb_attachdb_recv. */
- db->callback(ctdb, req, db->private_data);
- return;
- }
- db->id = *(uint32_t *)reply->data;
-
- /* Now we do another call, to get the dbpath. */
- req2 = new_ctdb_control_request(db->ctdb, CTDB_CONTROL_GETDBPATH,
- CTDB_CURRENT_NODE,
- &db->id, sizeof(db->id),
- attachdb_getdbpath_done, db);
- if (!req2) {
- DEBUG(db->ctdb, LOG_ERR,
- "ctdb_attachdb_send(async): failed to allocate");
- db->callback(ctdb, req, db->private_data);
- return;
- }
- req->extra = req2;
- req2->extra = req;
- DEBUG(db->ctdb, LOG_DEBUG,
- "ctdb_attachdb_send(async): created getdbpath request");
-}
-
-static void attachdb_getdbpath_done(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *_db)
-{
- struct ctdb_db *db = _db;
-
- /* Do callback on original request. */
- db->callback(ctdb, req->extra, db->private_data);
-}
-
-struct ctdb_db *ctdb_attachdb_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req)
-{
- struct ctdb_request *dbpath_req = req->extra;
- struct ctdb_reply_control *reply;
- struct ctdb_db *db = req->priv_data;
- uint32_t tdb_flags = db->tdb_flags;
- struct tdb_logging_context log;
-
- /* Never sent the dbpath request? We've failed. */
- if (!dbpath_req) {
- /* FIXME: Save errno? */
- errno = EINVAL;
- return NULL;
- }
-
- reply = unpack_reply_control(dbpath_req, CTDB_CONTROL_GETDBPATH);
- if (!reply) {
- return NULL;
- }
- if (reply->status != 0) {
- DEBUG(db->ctdb, LOG_ERR,
- "ctdb_attachdb_recv: reply status %i", reply->status);
- return NULL;
- }
-
- tdb_flags = db->persistent ? TDB_DEFAULT : TDB_NOSYNC;
- tdb_flags |= TDB_DISALLOW_NESTING;
-
- log.log_fn = ctdb_tdb_log_bridge;
- log.log_private = ctdb;
- db->tdb = tdb_open_ex((char *)reply->data, 0, tdb_flags, O_RDWR, 0,
- &log, NULL);
- if (db->tdb == NULL) {
- DEBUG(db->ctdb, LOG_ERR,
- "ctdb_attachdb_recv: failed to tdb_open %s",
- (char *)reply->data);
- return NULL;
- }
-
- /* Finally, separate the db from the request (see destroy_req_db). */
- req->priv_data = NULL;
- DEBUG(db->ctdb, LOG_DEBUG,
- "ctdb_attachdb_recv: db %p, tdb %s", db, (char *)reply->data);
- return db;
-}
-
-static unsigned long lock_magic(struct ctdb_lock *lock)
-{
- /* A non-zero magic specific to this structure. */
- return ((unsigned long)lock->key.dptr
- ^ (((unsigned long)lock->key.dptr) << 16)
- ^ 0xBADC0FFEEBADC0DEULL)
- | 1;
-}
-
-/* This is only called on locks before they're held. */
-static void free_lock(struct ctdb_lock *lock)
-{
- if (lock->held_magic) {
- DEBUG(lock->ctdb_db->ctdb, LOG_ALERT,
- "free_lock invalid lock %p", lock);
- }
- free(lock->hdr);
- free(lock);
-}
-
-
-void ctdb_release_lock(struct ctdb_db *ctdb_db, struct ctdb_lock *lock)
-{
- if (lock->held_magic != lock_magic(lock)) {
- DEBUG(lock->ctdb_db->ctdb, LOG_ALERT,
- "ctdb_release_lock invalid lock %p", lock);
- } else if (lock->ctdb_db != ctdb_db) {
- errno = EBADF;
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_release_lock: wrong ctdb_db.");
- } else {
- tdb_chainunlock(lock->ctdb_db->tdb, lock->key);
- DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
- "ctdb_release_lock %p", lock);
- remove_lock(lock->ctdb_db->ctdb, lock);
- }
- lock->held_magic = 0;
- free_lock(lock);
-}
-
-
-/* We keep the lock if local node is the dmaster. */
-static bool try_readrecordlock(struct ctdb_lock *lock, TDB_DATA *data)
-{
- struct ctdb_ltdb_header *hdr;
-
- if (tdb_chainlock(lock->ctdb_db->tdb, lock->key) != 0) {
- DEBUG(lock->ctdb_db->ctdb, LOG_WARNING,
- "ctdb_readrecordlock_async: failed to chainlock");
- return NULL;
- }
-
- hdr = ctdb_local_fetch(lock->ctdb_db->tdb, lock->key, data);
- if (hdr && lock->readonly && (hdr->flags & CTDB_REC_RO_HAVE_READONLY) ) {
- DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
- "ctdb_readrecordlock_async: got local lock for ro");
- lock->held_magic = lock_magic(lock);
- lock->hdr = hdr;
- add_lock(lock->ctdb_db->ctdb, lock);
- return true;
- }
- if (hdr && hdr->dmaster == lock->ctdb_db->ctdb->pnn) {
- DEBUG(lock->ctdb_db->ctdb, LOG_DEBUG,
- "ctdb_readrecordlock_async: got local lock");
- lock->held_magic = lock_magic(lock);
- lock->hdr = hdr;
- add_lock(lock->ctdb_db->ctdb, lock);
- return true;
- }
-
- /* we dont have the record locally,
- * drop to writelock to force a migration
- */
- if (!hdr && lock->readonly) {
- lock->readonly = false;
- }
-
- tdb_chainunlock(lock->ctdb_db->tdb, lock->key);
- free(hdr);
- return NULL;
-}
-
-/* If they shutdown before we hand them the lock, we free it here. */
-static void destroy_lock(struct ctdb_connection *ctdb,
- struct ctdb_request *req)
-{
- free_lock(req->extra);
-}
-
-static void readrecordlock_retry(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- struct ctdb_lock *lock = req->extra;
- struct ctdb_reply_call *reply;
- TDB_DATA data;
-
- /* OK, we've received reply to fetch migration */
- reply = unpack_reply_call(req, CTDB_FETCH_FUNC);
- if (!reply || reply->status != 0) {
- if (reply) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_readrecordlock_async(async):"
- " FETCH returned %i", reply->status);
- }
- lock->callback(lock->ctdb_db, NULL, tdb_null, private);
- ctdb_request_free(req); /* Also frees lock. */
- return;
- }
-
- /* Can we get lock now? */
- if (try_readrecordlock(lock, &data)) {
- /* Now it's their responsibility to free lock & request! */
- req->extra_destructor = NULL;
- lock->callback(lock->ctdb_db, lock, data, private);
- ctdb_request_free(req);
- return;
- }
-
- /* Retransmit the same request again (we lost race). */
- io_elem_reset(req->io);
- DLIST_ADD(ctdb->outq, req);
-}
-
-static bool
-ctdb_readrecordlock_internal(struct ctdb_db *ctdb_db, TDB_DATA key,
- bool readonly,
- ctdb_rrl_callback_t callback, void *cbdata)
-{
- struct ctdb_request *req;
- struct ctdb_lock *lock;
- TDB_DATA data;
-
- if (holding_lock(ctdb_db->ctdb)) {
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_readrecordlock_async: already holding lock");
- return false;
- }
-
- /* Setup lock */
- lock = malloc(sizeof(*lock) + key.dsize);
- if (!lock) {
- DEBUG(ctdb_db->ctdb, LOG_ERR,
- "ctdb_readrecordlock_async: lock allocation failed");
- return false;
- }
- lock->key.dptr = (void *)(lock + 1);
- memcpy(lock->key.dptr, key.dptr, key.dsize);
- lock->key.dsize = key.dsize;
- lock->ctdb_db = ctdb_db;
- lock->hdr = NULL;
- lock->held_magic = 0;
- lock->readonly = readonly;
-
- /* Fast path. */
- if (try_readrecordlock(lock, &data)) {
- callback(ctdb_db, lock, data, cbdata);
- return true;
- }
-
- /* Slow path: create request. */
- req = new_ctdb_request(
- ctdb_db->ctdb,
- offsetof(struct ctdb_req_call, data) + key.dsize,
- readrecordlock_retry, cbdata);
- if (!req) {
- DEBUG(ctdb_db->ctdb, LOG_ERR,
- "ctdb_readrecordlock_async: allocation failed");
- free_lock(lock);
- return NULL;
- }
- req->extra = lock;
- req->extra_destructor = destroy_lock;
- /* We store the original callback in the lock, and use our own. */
- lock->callback = callback;
-
- io_elem_init_req_header(req->io, CTDB_REQ_CALL, CTDB_CURRENT_NODE,
- new_reqid(ctdb_db->ctdb));
-
- if (lock->readonly) {
- req->hdr.call->flags = CTDB_WANT_READONLY;
- } else {
- req->hdr.call->flags = CTDB_IMMEDIATE_MIGRATION;
- }
- req->hdr.call->db_id = ctdb_db->id;
- req->hdr.call->callid = CTDB_FETCH_FUNC;
- req->hdr.call->hopcount = 0;
- req->hdr.call->keylen = key.dsize;
- req->hdr.call->calldatalen = 0;
- memcpy(req->hdr.call->data, key.dptr, key.dsize);
- DLIST_ADD(ctdb_db->ctdb->outq, req);
- return true;
-}
-
-bool
-ctdb_readrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
- ctdb_rrl_callback_t callback, void *cbdata)
-{
- return ctdb_readrecordlock_internal(ctdb_db, key,
- false,
- callback, cbdata);
-}
-
-bool
-ctdb_readonlyrecordlock_async(struct ctdb_db *ctdb_db, TDB_DATA key,
- ctdb_rrl_callback_t callback, void *cbdata)
-{
- return ctdb_readrecordlock_internal(ctdb_db, key,
- true,
- callback, cbdata);
-}
-
-bool ctdb_writerecord(struct ctdb_db *ctdb_db,
- struct ctdb_lock *lock, TDB_DATA data)
-{
- if (lock->readonly) {
- errno = EBADF;
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_writerecord: Can not write, read-only record.");
- return false;
- }
-
- if (lock->ctdb_db != ctdb_db) {
- errno = EBADF;
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_writerecord: Can not write, wrong ctdb_db.");
- return false;
- }
-
- if (lock->held_magic != lock_magic(lock)) {
- errno = EBADF;
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_writerecord: Can not write. Lock has been released.");
- return false;
- }
-
- if (ctdb_db->persistent) {
- errno = EINVAL;
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_writerecord: cannot write to persistent db");
- return false;
- }
-
- switch (ctdb_local_store(ctdb_db->tdb, lock->key, lock->hdr, data)) {
- case 0:
- DEBUG(ctdb_db->ctdb, LOG_DEBUG,
- "ctdb_writerecord: optimized away noop write.");
- /* fall thru */
- case 1:
- return true;
-
- default:
- switch (errno) {
- case ENOMEM:
- DEBUG(ctdb_db->ctdb, LOG_CRIT,
- "ctdb_writerecord: out of memory.");
- break;
- case EINVAL:
- DEBUG(ctdb_db->ctdb, LOG_ALERT,
- "ctdb_writerecord: record changed under lock?");
- break;
- default: /* TDB already logged. */
- break;
- }
- return false;
- }
-}
-
-
-struct ctdb_traverse_state {
- struct ctdb_request *handle;
- struct ctdb_db *ctdb_db;
- uint64_t srvid;
-
- ctdb_traverse_callback_t callback;
- void *cbdata;
-};
-
-static void traverse_remhnd_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private_data)
-{
- struct ctdb_traverse_state *state = private_data;
-
- if (!ctdb_remove_message_handler_recv(ctdb, state->handle)) {
- DEBUG(ctdb, LOG_ERR,
- "Failed to remove message handler for"
- " traverse.");
- state->callback(state->ctdb_db->ctdb, state->ctdb_db,
- TRAVERSE_STATUS_ERROR,
- tdb_null, tdb_null,
- state->cbdata);
- }
- ctdb_request_free(state->handle);
- state->handle = NULL;
- free(state);
-}
-
-static void msg_h(struct ctdb_connection *ctdb, uint64_t srvid,
- TDB_DATA data, void *private_data)
-{
- struct ctdb_traverse_state *state = private_data;
- struct ctdb_db *ctdb_db = state->ctdb_db;
- struct ctdb_rec_data *d = (struct ctdb_rec_data *)data.dptr;
- TDB_DATA key;
-
- if (data.dsize < sizeof(uint32_t) ||
- d->length != data.dsize) {
- DEBUG(ctdb, LOG_ERR,
- "Bad data size %u in traverse_handler",
- (unsigned)data.dsize);
- state->callback(state->ctdb_db->ctdb, state->ctdb_db,
- TRAVERSE_STATUS_ERROR,
- tdb_null, tdb_null,
- state->cbdata);
- state->handle = ctdb_remove_message_handler_send(
- state->ctdb_db->ctdb, state->srvid,
- msg_h, state,
- traverse_remhnd_cb, state);
- return;
- }
-
- key.dsize = d->keylen;
- key.dptr = &d->data[0];
- data.dsize = d->datalen;
- data.dptr = &d->data[d->keylen];
-
- if (key.dsize == 0 && data.dsize == 0) {
- state->callback(state->ctdb_db->ctdb, state->ctdb_db,
- TRAVERSE_STATUS_FINISHED,
- tdb_null, tdb_null,
- state->cbdata);
- state->handle = ctdb_remove_message_handler_send(
- state->ctdb_db->ctdb, state->srvid,
- msg_h, state,
- traverse_remhnd_cb, state);
- return;
- }
-
- if (data.dsize <= sizeof(struct ctdb_ltdb_header)) {
- /* empty records are deleted records in ctdb */
- return;
- }
-
- data.dsize -= sizeof(struct ctdb_ltdb_header);
- data.dptr += sizeof(struct ctdb_ltdb_header);
-
- if (state->callback(ctdb, ctdb_db,
- TRAVERSE_STATUS_RECORD,
- key, data, state->cbdata) != 0) {
- state->handle = ctdb_remove_message_handler_send(
- state->ctdb_db->ctdb, state->srvid,
- msg_h, state,
- traverse_remhnd_cb, state);
- return;
- }
-}
-
-static void traverse_start_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private_data)
-{
- struct ctdb_traverse_state *state = private_data;
-
- ctdb_request_free(state->handle);
- state->handle = NULL;
-}
-
-static void traverse_msghnd_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private_data)
-{
- struct ctdb_traverse_state *state = private_data;
- struct ctdb_db *ctdb_db = state->ctdb_db;
- struct ctdb_traverse_start t;
-
- if (!ctdb_set_message_handler_recv(ctdb, state->handle)) {
- DEBUG(ctdb, LOG_ERR,
- "Failed to register message handler for"
- " traverse.");
- state->callback(state->ctdb_db->ctdb, state->ctdb_db,
- TRAVERSE_STATUS_ERROR,
- tdb_null, tdb_null,
- state->cbdata);
- ctdb_request_free(state->handle);
- state->handle = NULL;
- free(state);
- return;
- }
- ctdb_request_free(state->handle);
- state->handle = NULL;
-
- t.db_id = ctdb_db->id;
- t.srvid = state->srvid;
- t.reqid = 0;
-
- state->handle = new_ctdb_control_request(ctdb,
- CTDB_CONTROL_TRAVERSE_START,
- CTDB_CURRENT_NODE,
- &t, sizeof(t),
- traverse_start_cb, state);
- if (state->handle == NULL) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_traverse_async:"
- " failed to send traverse_start control");
- state->callback(state->ctdb_db->ctdb, state->ctdb_db,
- TRAVERSE_STATUS_ERROR,
- tdb_null, tdb_null,
- state->cbdata);
- state->handle = ctdb_remove_message_handler_send(
- state->ctdb_db->ctdb, state->srvid,
- msg_h, state,
- traverse_remhnd_cb, state);
- return;
- }
-}
-
-bool ctdb_traverse_async(struct ctdb_db *ctdb_db,
- ctdb_traverse_callback_t callback, void *cbdata)
-{
- struct ctdb_connection *ctdb = ctdb_db->ctdb;
- struct ctdb_traverse_state *state;
- static uint32_t tid = 0;
-
- state = malloc(sizeof(struct ctdb_traverse_state));
- if (state == NULL) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_traverse_async: no memory."
- " allocate state failed");
- return false;
- }
-
- tid++;
- state->srvid = CTDB_SRVID_TRAVERSE_RANGE|tid;
-
- state->callback = callback;
- state->cbdata = cbdata;
- state->ctdb_db = ctdb_db;
-
- state->handle = ctdb_set_message_handler_send(ctdb_db->ctdb,
- state->srvid,
- msg_h, state,
- traverse_msghnd_cb, state);
- if (state->handle == NULL) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_traverse_async:"
- " failed ctdb_set_message_handler_send");
- free(state);
- return false;
- }
-
- return true;
-}
-
-int ctdb_num_out_queue(struct ctdb_connection *ctdb)
-{
- struct ctdb_request *req;
- int i;
-
- for (i = 0, req = ctdb->outq; req; req = req->next, i++)
- ;
-
- return i;
-}
-
-int ctdb_num_in_flight(struct ctdb_connection *ctdb)
-{
- struct ctdb_request *req;
- int i;
-
- for (i = 0, req = ctdb->doneq; req; req = req->next, i++)
- ;
-
- return i;
-}
-
-int ctdb_num_active(struct ctdb_connection *ctdb)
-{
- return ctdb_num_out_queue(ctdb)
- + ctdb_num_in_flight(ctdb);
-}
-
+++ /dev/null
-/*
- Simple queuing of input and output records for libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <sys/types.h>
-#include <sys/socket.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "libctdb_private.h"
-#include "io_elem.h"
-#include <tdb.h>
-#include <netinet/in.h>
-#include <dlinklist.h>
-#include <ctdb_protocol.h> // For CTDB_DS_ALIGNMENT and ctdb_req_header
-
-struct io_elem {
- struct io_elem *next, *prev;
- size_t len, off;
- char *data;
-};
-
-struct io_elem *new_io_elem(size_t len)
-{
- struct io_elem *elem;
- size_t ask = len;
-
- len = (len + (CTDB_DS_ALIGNMENT-1)) & ~(CTDB_DS_ALIGNMENT-1);
-
- elem = malloc(sizeof(*elem));
- if (!elem)
- return NULL;
- elem->data = malloc(len);
- if (!elem->data) {
- free(elem);
- return NULL;
- }
-
- /* stamp out any padding to keep valgrind happy */
- if (ask != len) {
- memset(elem->data + ask, 0, len-ask);
- }
- elem->len = len;
- elem->off = 0;
- elem->next = NULL;
- elem->prev = NULL;
- return elem;
-}
-
-void free_io_elem(struct io_elem *io)
-{
- free(io->data);
- free(io);
-}
-
-bool io_elem_finished(const struct io_elem *io)
-{
- return io->off == io->len;
-}
-
-void io_elem_init_req_header(struct io_elem *io,
- uint32_t operation,
- uint32_t destnode,
- uint32_t reqid)
-{
- struct ctdb_req_header *hdr = io_elem_data(io, NULL);
-
- hdr->length = io->len;
- hdr->ctdb_magic = CTDB_MAGIC;
- hdr->ctdb_version = CTDB_VERSION;
- /* Generation and srcnode only used for inter-ctdbd communication. */
- hdr->generation = 0;
- hdr->destnode = destnode;
- hdr->srcnode = 0;
- hdr->operation = operation;
- hdr->reqid = reqid;
-}
-
-/* Access to raw data: if len is non-NULL it is filled in. */
-void *io_elem_data(const struct io_elem *io, size_t *len)
-{
- if (len)
- *len = io->len;
- return io->data;
-}
-
-/* Returns -1 if we hit an error. Errno will be set. */
-int read_io_elem(int fd, struct io_elem *io)
-{
- ssize_t ret;
-
- ret = read(fd, io->data + io->off, io->len - io->off);
- if (ret < 0)
- return ret;
-
- io->off += ret;
- if (io_elem_finished(io)) {
- struct ctdb_req_header *hdr = (void *)io->data;
-
- /* Finished. But maybe this was just header? */
- if (io->len == sizeof(*hdr) && hdr->length > io->len) {
- int reret;
- void *newdata;
- /* Enlarge and re-read. */
- io->len = hdr->length;
- newdata = realloc(io->data, io->len);
- if (!newdata)
- return -1;
- io->data = newdata;
- /* Try reading again immediately. */
- reret = read_io_elem(fd, io);
- if (reret >= 0)
- reret += ret;
- return reret;
- }
- }
- return ret;
-}
-
-/* Returns -1 if we hit an error. Errno will be set. */
-int write_io_elem(int fd, struct io_elem *io)
-{
- ssize_t ret;
-
- ret = write(fd, io->data + io->off, io->len - io->off);
- if (ret < 0)
- return ret;
-
- io->off += ret;
- return ret;
-}
-
-void io_elem_reset(struct io_elem *io)
-{
- io->off = 0;
-}
-
-void io_elem_queue(struct ctdb_connection *ctdb, struct io_elem *io)
-{
- DLIST_ADD_END(ctdb->inqueue, io, struct io_elem);
-}
-
-void io_elem_dequeue(struct ctdb_connection *ctdb, struct io_elem *io)
-{
- DLIST_REMOVE(ctdb->inqueue, io);
-}
-
+++ /dev/null
-#ifndef _LIBCTDB_IO_ELEM_H
-#define _LIBCTDB_IO_ELEM_H
-#include <stdbool.h>
-
-/* Packets are of form: <u32 length><data>. */
-
-/* Create a new queue element of at least len bytes (for reading or writing).
- * Len may be rounded up for alignment. */
-struct io_elem *new_io_elem(size_t len);
-
-/* Free a queue element. */
-void free_io_elem(struct io_elem *io);
-
-/* If finished, this returns the request header, otherwise NULL. */
-bool io_elem_finished(const struct io_elem *io);
-
-/* Reset an io_elem to the start. */
-void io_elem_reset(struct io_elem *io);
-
-/* Access to raw data: if len is non-NULL it is filled in. */
-void *io_elem_data(const struct io_elem *io, size_t *len);
-
-/* Initialise the struct ctdb_req_header at the front of the I/O. */
-void io_elem_init_req_header(struct io_elem *io,
- uint32_t operation,
- uint32_t destnode,
- uint32_t reqid);
-
-/* Returns -1 if we hit an error. Otherwise bytes read. */
-int read_io_elem(int fd, struct io_elem *io);
-
-/* Returns -1 if we hit an error. Otherwise bytes written. */
-int write_io_elem(int fd, struct io_elem *io);
-
-/* Queues a received io element for later processing */
-void io_elem_queue(struct ctdb_connection *ctdb, struct io_elem *io);
-
-/* Removes an element from the queue */
-void io_elem_dequeue(struct ctdb_connection *ctdb, struct io_elem *io);
-
-#endif /* _LIBCTDB_IO_ELEM_H */
+++ /dev/null
-#ifndef _LIBCTDB_PRIVATE_H
-#define _LIBCTDB_PRIVATE_H
-#include <dlinklist.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <ctdb.h>
-#include <ctdb_protocol.h>
-#include <syslog.h>
-#include <tdb.h>
-#include <stddef.h>
-
-#ifndef offsetof
-#define offsetof(t,f) ((unsigned int)&((t *)0)->f)
-#endif
-
-#ifndef COLD_ATTRIBUTE
-#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
-#define COLD_ATTRIBUTE __attribute__((cold))
-#else
-#define COLD_ATTRIBUTE
-#endif
-#endif /* COLD_ATTRIBUTE */
-
-#define DEBUG(ctdb, lvl, format, args...) do { if (lvl <= ctdb_log_level) { ctdb_do_debug(ctdb, lvl, format , ## args ); }} while(0)
-
-struct message_handler_info;
-struct ctdb_reply_call;
-
-struct ctdb_request {
- struct ctdb_connection *ctdb;
- struct ctdb_request *next, *prev;
- bool cancelled;
-
- struct io_elem *io;
- union {
- struct ctdb_req_header *hdr;
- struct ctdb_req_call *call;
- struct ctdb_req_control *control;
- struct ctdb_req_message *message;
- } hdr;
-
- struct io_elem *reply;
-
- ctdb_callback_t callback;
- void *priv_data;
-
- /* Extra per-request info. */
- void (*extra_destructor)(struct ctdb_connection *,
- struct ctdb_request *);
- void *extra;
-};
-
-struct ctdb_connection {
- /* Socket to ctdbd. */
- int fd;
- /* Currently our failure mode is simple; return -1 from ctdb_service */
- bool broken;
- /* Linked list of pending outgoings. */
- struct ctdb_request *outq;
- /* Finished outgoings (awaiting response) */
- struct ctdb_request *doneq;
-
- /* Current incoming. */
- struct io_elem *in;
- /* Queue of received pdus */
- struct io_elem *inqueue;
-
- /* Guess at a good reqid to try next. */
- uint32_t next_id;
- /* List of messages */
- struct message_handler_info *message_handlers;
- /* PNN of this ctdb: valid by the time we do our first db connection. */
- uint32_t pnn;
- /* Chain of locks we hold. */
- struct ctdb_lock *locks;
- /* Extra logging. */
- ctdb_log_fn_t log;
- void *log_priv;
-};
-
-/* ctdb.c */
-struct ctdb_request *new_ctdb_request(struct ctdb_connection *ctdb, size_t len,
- ctdb_callback_t cb, void *cbdata);
-struct ctdb_request *new_ctdb_control_request(struct ctdb_connection *ctdb,
- uint32_t opcode,
- uint32_t destnode,
- const void *extra_data,
- size_t extra,
- ctdb_callback_t, void *);
-uint32_t new_reqid(struct ctdb_connection *ctdb);
-
-struct ctdb_reply_control *unpack_reply_control(struct ctdb_request *req,
- enum ctdb_controls control);
-void ctdb_cancel_callback(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- void *unused);
-
-/* logging.c */
-void ctdb_tdb_log_bridge(struct tdb_context *tdb,
- enum tdb_debug_level level,
- const char *format, ...) PRINTF_ATTRIBUTE(3, 4);
-
-void ctdb_do_debug(struct ctdb_connection *, int, const char *format, ...)
- PRINTF_ATTRIBUTE(3, 4) COLD_ATTRIBUTE;
-
-#endif /* _LIBCTDB_PRIVATE_H */
+++ /dev/null
-/*
- libctdb local tdb access code
-
- Copyright (C) Andrew Tridgell 2006
- Copyright (C) Rusty Russell 2010
-
- 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 <sys/time.h>
-#include <sys/socket.h>
-#include <ctdb.h>
-#include <tdb.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <errno.h>
-#include <ctdb_protocol.h> // For struct ctdb_ltdb_header
-#include "local_tdb.h"
-
-/*
- fetch a record from the ltdb, separating out the header information
- and returning the body of the record. The caller should free() the
- header when done, rather than the (optional) data->dptr.
-*/
-struct ctdb_ltdb_header *ctdb_local_fetch(struct tdb_context *tdb,
- TDB_DATA key, TDB_DATA *data)
-{
- TDB_DATA rec;
-
- rec = tdb_fetch(tdb, key);
- if (rec.dsize < sizeof(struct ctdb_ltdb_header)) {
- free(rec.dptr);
- return NULL;
- }
-
- if (data) {
- data->dsize = rec.dsize - sizeof(struct ctdb_ltdb_header);
- data->dptr = rec.dptr + sizeof(struct ctdb_ltdb_header);
- }
- return (struct ctdb_ltdb_header *)rec.dptr;
-}
-
-
-/*
- write a record to a normal database: 1 on success, 0 if noop, -1 on fail.
- errno = EIO => tdb error.
-*/
-int ctdb_local_store(struct tdb_context *tdb, TDB_DATA key,
- struct ctdb_ltdb_header *header, TDB_DATA data)
-{
- TDB_DATA rec;
- int ret;
- TDB_DATA old;
-
- old = tdb_fetch(tdb, key);
- if (old.dsize < sizeof(*header)) {
- errno = EIO;
- return -1;
- }
-
- /* Debugging check: we have lock and should not change hdr. */
- if (memcmp(old.dptr, header, sizeof(*header)) != 0) {
- free(old.dptr);
- errno = EINVAL;
- return -1;
- }
-
- /* Optimize out the nothing-changed case. */
- if (old.dsize == sizeof(*header) + data.dsize
- && memcmp(old.dptr+sizeof(*header), data.dptr, data.dsize) == 0) {
- free(old.dptr);
- return 0;
- }
-
- rec.dsize = sizeof(*header) + data.dsize;
- rec.dptr = malloc(rec.dsize);
- if (!rec.dptr) {
- free(old.dptr);
- errno = ENOMEM;
- return -1;
- }
- memcpy(rec.dptr, header, sizeof(*header));
- memcpy(rec.dptr + sizeof(*header), data.dptr, data.dsize);
-
- ret = tdb_store(tdb, key, rec, TDB_REPLACE);
- free(old.dptr);
- free(rec.dptr);
- if (ret != 0) {
- errno = EIO;
- return -1;
- }
- return 1;
-}
+++ /dev/null
-#ifndef _LIBCTDB_LOCAL_TDB_H
-#define _LIBCTDB_LOCAL_TDB_H
-
-struct ctdb_ltdb_header *ctdb_local_fetch(struct tdb_context *tdb,
- TDB_DATA key, TDB_DATA *data);
-
-int ctdb_local_store(struct tdb_context *tdb, TDB_DATA key,
- struct ctdb_ltdb_header *header, TDB_DATA data);
-
-#endif /* _LIBCTDB_LOCAL_TDB_H */
+++ /dev/null
-/*
- logging wrapper for libctdb
-
- Copyright (C) Ronnie Sahlberg 2010
-
- 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 <sys/time.h>
-#include <sys/socket.h>
-#include <stdio.h>
-#include <errno.h>
-#include <ctdb.h>
-#include <string.h>
-#include <tdb.h>
-#include "libctdb_private.h"
-
-int ctdb_log_level = LOG_WARNING;
-
-void ctdb_do_debug(struct ctdb_connection *ctdb,
- int severity, const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- ctdb->log(ctdb->log_priv, severity, format, ap);
- va_end(ap);
-}
-
-/* Attach tdb logging to our ctdb logging. */
-void ctdb_tdb_log_bridge(struct tdb_context *tdb,
- enum tdb_debug_level level,
- const char *format, ...)
-{
- va_list ap;
- int sev;
- struct ctdb_connection *ctdb = tdb_get_logging_private(tdb);
- char *newformat;
-
- switch (level) {
- case TDB_DEBUG_FATAL:
- sev = LOG_CRIT;
- break;
- case TDB_DEBUG_ERROR:
- sev = LOG_ERR;
- break;
- case TDB_DEBUG_WARNING:
- sev = LOG_WARNING;
- break;
- case TDB_DEBUG_TRACE:
- sev = LOG_DEBUG;
- break;
- default:
- sev = LOG_CRIT;
- }
-
- if (sev > ctdb_log_level) {
- return;
- }
-
- newformat = malloc(sizeof("TDB error: ") + strlen(format));
- if (!newformat) {
- DEBUG(ctdb, LOG_ERR,
- "memory allocation failure reporting tdb error %s",
- format);
- return;
- }
-
- /* Prepend TDB error: and remove \n */
- strcpy(newformat, "TDB error: ");
- strcat(newformat, format);
- if (newformat[strlen(newformat)-1] == '\n')
- newformat[strlen(newformat)-1] = '\0';
-
- va_start(ap, format);
- ctdb->log(ctdb->log_priv, sev, newformat, ap);
- va_end(ap);
- free(newformat);
-}
-
-/* Convenient log helper. */
-void ctdb_log_file(FILE *outf, int priority, const char *format, va_list ap)
-{
- fprintf(outf, "%s:",
- priority == LOG_EMERG ? "EMERG" :
- priority == LOG_ALERT ? "ALERT" :
- priority == LOG_CRIT ? "CRIT" :
- priority == LOG_ERR ? "ERR" :
- priority == LOG_WARNING ? "WARNING" :
- priority == LOG_NOTICE ? "NOTICE" :
- priority == LOG_INFO ? "INFO" :
- priority == LOG_DEBUG ? "DEBUG" :
- "Unknown Error Level");
-
- vfprintf(outf, format, ap);
- if (priority == LOG_ERR) {
- fprintf(outf, " (%s)", strerror(errno));
- }
- fprintf(outf, "\n");
-}
+++ /dev/null
-/*
- core of libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <sys/socket.h>
-#include "libctdb_private.h"
-#include "messages.h"
-#include "io_elem.h"
-#include <ctdb.h>
-#include <tdb.h>
-#include <ctdb_protocol.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-/* Remove type-safety macros. */
-#undef ctdb_set_message_handler_send
-#undef ctdb_set_message_handler_recv
-#undef ctdb_remove_message_handler_send
-
-struct message_handler_info {
- struct message_handler_info *next, *prev;
-
- uint64_t srvid;
- ctdb_message_fn_t handler;
- void *handler_data;
-};
-
-void deliver_message(struct ctdb_connection *ctdb, struct ctdb_req_header *hdr)
-{
- struct message_handler_info *i;
- struct ctdb_req_message *msg = (struct ctdb_req_message *)hdr;
- TDB_DATA data;
- bool found;
-
- data.dptr = msg->data;
- data.dsize = msg->datalen;
-
- /* Note: we want to call *every* handler: there may be more than one */
- for (i = ctdb->message_handlers; i; i = i->next) {
- if (i->srvid == msg->srvid) {
- i->handler(ctdb, msg->srvid, data, i->handler_data);
- found = true;
- }
- }
- if (!found) {
- DEBUG(ctdb, LOG_WARNING,
- "ctdb_service: messsage for unregistered srvid %llu",
- (unsigned long long)msg->srvid);
- }
-}
-
-void remove_message_handlers(struct ctdb_connection *ctdb)
-{
- struct message_handler_info *i;
-
- /* ctdbd should unregister automatically when we close fd, so we don't
- need to do that here. */
- while ((i = ctdb->message_handlers) != NULL) {
- DLIST_REMOVE(ctdb->message_handlers, i);
- free(i);
- }
-}
-
-static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req);
-
-struct ctdb_request *
-ctdb_set_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
- ctdb_message_fn_t handler, void *handler_data,
- ctdb_callback_t callback, void *private_data)
-{
- struct message_handler_info *info;
- struct ctdb_request *req;
-
- info = malloc(sizeof(*info));
- if (!info) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_set_message_handler_send: allocating info");
- return NULL;
- }
-
- req = new_ctdb_control_request(ctdb, CTDB_CONTROL_REGISTER_SRVID,
- CTDB_CURRENT_NODE, NULL, 0,
- callback, private_data);
- if (!req) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_set_message_handler_send: allocating request");
- free(info);
- return NULL;
- }
- req->extra = info;
- req->extra_destructor = free_info;
- req->hdr.control->srvid = srvid;
-
- info->srvid = srvid;
- info->handler = handler;
- info->handler_data = handler_data;
-
- DEBUG(ctdb, LOG_DEBUG,
- "ctdb_set_message_handler_send: sending request %u for id %llx",
- req->hdr.hdr->reqid, (unsigned long long)srvid);
- return req;
-}
-
-static void free_info(struct ctdb_connection *ctdb, struct ctdb_request *req)
-{
- free(req->extra);
-}
-
-bool ctdb_set_message_handler_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req)
-{
- struct message_handler_info *info = req->extra;
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_REGISTER_SRVID);
- if (!reply) {
- return false;
- }
- if (reply->status != 0) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_set_message_handler_recv: status %i",
- reply->status);
- return false;
- }
-
- /* Put ourselves in list of handlers. */
- DLIST_ADD(ctdb->message_handlers, info);
- /* Keep safe from destructor */
- req->extra = NULL;
- return true;
-}
-
-struct ctdb_request *
-ctdb_remove_message_handler_send(struct ctdb_connection *ctdb, uint64_t srvid,
- ctdb_message_fn_t handler, void *hdata,
- ctdb_callback_t callback, void *cbdata)
-{
- struct message_handler_info *i;
- struct ctdb_request *req;
-
- for (i = ctdb->message_handlers; i; i = i->next) {
- if (i->srvid == srvid
- && i->handler == handler && i->handler_data == hdata) {
- break;
- }
- }
- if (!i) {
- DEBUG(ctdb, LOG_ALERT,
- "ctdb_remove_message_handler_send: no such handler");
- errno = ENOENT;
- return NULL;
- }
-
- req = new_ctdb_control_request(ctdb, CTDB_CONTROL_DEREGISTER_SRVID,
- CTDB_CURRENT_NODE, NULL, 0,
- callback, cbdata);
- if (!req) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_remove_message_handler_send: allocating request");
- return NULL;
- }
- req->hdr.control->srvid = srvid;
- req->extra = i;
-
- DEBUG(ctdb, LOG_DEBUG,
- "ctdb_set_remove_handler_send: sending request %u for id %llu",
- req->hdr.hdr->reqid, (unsigned long long)srvid);
- return req;
-}
-
-bool ctdb_remove_message_handler_recv(struct ctdb_connection *ctdb,
- struct ctdb_request *req)
-{
- struct message_handler_info *handler = req->extra;
- struct ctdb_reply_control *reply;
-
- reply = unpack_reply_control(req, CTDB_CONTROL_DEREGISTER_SRVID);
- if (!reply) {
- return false;
- }
- if (reply->status != 0) {
- DEBUG(ctdb, LOG_ERR,
- "ctdb_remove_message_handler_recv: status %i",
- reply->status);
- return false;
- }
-
- /* Remove ourselves from list of handlers. */
- DLIST_REMOVE(ctdb->message_handlers, handler);
- free(handler);
- /* Crash if they call this again! */
- req->extra = NULL;
- return true;
-}
-
-bool ctdb_send_message(struct ctdb_connection *ctdb,
- uint32_t pnn, uint64_t srvid,
- TDB_DATA data)
-{
- struct ctdb_request *req;
- struct ctdb_req_message *pkt;
-
- /* We just discard it once it's finished: no reply. */
- req = new_ctdb_request(
- ctdb, offsetof(struct ctdb_req_message, data) + data.dsize,
- ctdb_cancel_callback, NULL);
- if (!req) {
- DEBUG(ctdb, LOG_ERR, "ctdb_set_message: allocating message");
- return false;
- }
-
- io_elem_init_req_header(req->io,
- CTDB_REQ_MESSAGE, pnn, new_reqid(ctdb));
-
- pkt = req->hdr.message;
- pkt->srvid = srvid;
- pkt->datalen = data.dsize;
- memcpy(pkt->data, data.dptr, data.dsize);
- DLIST_ADD_END(ctdb->outq, req, struct ctdb_request);
- return true;
-}
+++ /dev/null
-#ifndef _LIBCTDB_MESSAGE_H
-#define _LIBCTDB_MESSAGE_H
-struct message_handler_info;
-struct ctdb_connection;
-struct ctdb_req_header;
-
-void deliver_message(struct ctdb_connection *ctdb, struct ctdb_req_header *hdr);
-void remove_message_handlers(struct ctdb_connection *ctdb);
-#endif /* _LIBCTDB_MESSAGE_H */
+++ /dev/null
-/*
- synchronous wrappers for libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <sys/time.h>
-#include <sys/socket.h>
-#include <ctdb.h>
-#include <stdbool.h>
-#include <poll.h>
-#include <errno.h>
-#include <stdlib.h>
-#include "libctdb_private.h"
-
-/* Remove type-safety macros. */
-#undef ctdb_set_message_handler
-
-/* On failure, frees req and returns NULL. */
-static struct ctdb_request *synchronous(struct ctdb_connection *ctdb,
- struct ctdb_request *req,
- bool *done)
-{
- struct pollfd fds;
-
- /* Pass through allocation failures. */
- if (!req)
- return NULL;
-
- fds.fd = ctdb_get_fd(ctdb);
- while (!*done) {
- fds.events = ctdb_which_events(ctdb);
- if (poll(&fds, 1, -1) < 0) {
- /* Signalled is OK, other error is bad. */
- if (errno == EINTR)
- continue;
- ctdb_cancel(ctdb, req);
- DEBUG(ctdb, LOG_ERR, "ctdb_synchronous: poll failed");
- return NULL;
- }
- if (!ctdb_service(ctdb, fds.revents)) {
- /* It can have failed after it completed request. */
- if (!*done)
- ctdb_cancel(ctdb, req);
- else
- ctdb_request_free(req);
- return NULL;
- }
- }
- return req;
-}
-
-static void set(struct ctdb_connection *ctdb,
- struct ctdb_request *req, bool *done)
-{
- *done = true;
-}
-
-bool ctdb_getrecmaster(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t *recmaster)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getrecmaster_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getrecmaster_recv(ctdb, req, recmaster);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getrecmode(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t *recmode)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getrecmode_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getrecmode_recv(ctdb, req, recmode);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-struct ctdb_db *ctdb_attachdb(struct ctdb_connection *ctdb,
- const char *name, bool persistent,
- uint32_t tdb_flags)
-{
- struct ctdb_request *req;
- bool done = false;
- struct ctdb_db *ret = NULL;
-
- req = synchronous(ctdb,
- ctdb_attachdb_send(ctdb, name, persistent, tdb_flags,
- set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_attachdb_recv(ctdb, req);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getpnn(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t *pnn)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getpnn_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getpnn_recv(ctdb, req, pnn);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getdbstat(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t db_id,
- struct ctdb_db_statistics **stat)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getdbstat_send(ctdb, destnode, db_id, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getdbstat_recv(ctdb, req, stat);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_check_message_handlers(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t num,
- uint64_t *mhs, uint8_t *result)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_check_message_handlers_send(ctdb, destnode, num, mhs, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_check_message_handlers_recv(ctdb, req, num, result);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getnodemap(struct ctdb_connection *ctdb,
- uint32_t destnode, struct ctdb_node_map **nodemap)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- *nodemap = NULL;
-
- req = synchronous(ctdb,
- ctdb_getnodemap_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getnodemap_recv(ctdb, req, nodemap);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getpublicips(struct ctdb_connection *ctdb,
- uint32_t destnode, struct ctdb_all_public_ips **ips)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- *ips = NULL;
-
- req = synchronous(ctdb,
- ctdb_getpublicips_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getpublicips_recv(ctdb, req, ips);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_set_message_handler(struct ctdb_connection *ctdb, uint64_t srvid,
- ctdb_message_fn_t handler, void *cbdata)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_set_message_handler_send(ctdb, srvid, handler,
- cbdata, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_set_message_handler_recv(ctdb, req);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-struct rrl_info {
- bool done;
- struct ctdb_lock *lock;
- TDB_DATA *data;
-};
-
-static void rrl_callback(struct ctdb_db *ctdb_db,
- struct ctdb_lock *lock,
- TDB_DATA data,
- struct rrl_info *rrl)
-{
- rrl->done = true;
- rrl->lock = lock;
- *rrl->data = data;
-}
-
-struct ctdb_lock *ctdb_readrecordlock(struct ctdb_connection *ctdb,
- struct ctdb_db *ctdb_db, TDB_DATA key,
- TDB_DATA *data)
-{
- struct pollfd fds;
- struct rrl_info rrl;
-
- rrl.done = false;
- rrl.lock = NULL;
- rrl.data = data;
-
- /* Immediate failure is easy. */
- if (!ctdb_readrecordlock_async(ctdb_db, key, rrl_callback, &rrl))
- return NULL;
-
- /* Immediate success is easy. */
- if (!rrl.done) {
- /* Otherwise wait until callback called. */
- fds.fd = ctdb_get_fd(ctdb);
- while (!rrl.done) {
- fds.events = ctdb_which_events(ctdb);
- if (poll(&fds, 1, -1) < 0) {
- /* Signalled is OK, other error is bad. */
- if (errno == EINTR)
- continue;
- DEBUG(ctdb, LOG_ERR,
- "ctdb_readrecordlock: poll failed");
- return NULL;
- }
- if (!ctdb_service(ctdb, fds.revents)) {
- break;
- }
- }
- }
- return rrl.lock;
-}
-
-bool ctdb_getdbseqnum(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t dbid,
- uint64_t *seqnum)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getdbseqnum_send(ctdb, destnode, dbid, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getdbseqnum_recv(ctdb, req, seqnum);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getifaces(struct ctdb_connection *ctdb,
- uint32_t destnode, struct ctdb_ifaces_list **ifaces)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- *ifaces = NULL;
-
- req = synchronous(ctdb,
- ctdb_getifaces_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getifaces_recv(ctdb, req, ifaces);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getvnnmap(struct ctdb_connection *ctdb,
- uint32_t destnode, struct ctdb_vnn_map **vnnmap)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- *vnnmap = NULL;
-
- req = synchronous(ctdb,
- ctdb_getvnnmap_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getvnnmap_recv(ctdb, req, vnnmap);
- ctdb_request_free(req);
- }
- return ret;
-}
-
-bool ctdb_getcapabilities(struct ctdb_connection *ctdb,
- uint32_t destnode, uint32_t *capabilities)
-{
- struct ctdb_request *req;
- bool done = false;
- bool ret = false;
-
- req = synchronous(ctdb,
- ctdb_getcapabilities_send(ctdb, destnode, set, &done),
- &done);
- if (req != NULL) {
- ret = ctdb_getcapabilities_recv(ctdb, req, capabilities);
- ctdb_request_free(req);
- }
- return ret;
-}
-
+++ /dev/null
-CFLAGS=-Wall -g -I../../include/ -I../../lib/talloc/ -I../../lib/tdb/include/ -I../../lib/util/
-LDLIBS=-lreadline
-
-USAGE_SOURCES := $(shell grep -l 'XML Argument' *.c)
-HELP_SOURCES := $(shell grep -l 'XML Help' *.c)
-
-ctdb-test: $(patsubst %.c,%.o,$(wildcard *.c)) generated-usage.o ../../talloc.o ../../common/check.o ../../common/error.o ../../common/freelist.o ../../common/io.o ../../common/lock.o ../../common/open.o ../../common/tdb.o ../../common/transaction.o ../../common/traverse.o
-
-$(patsubst %.c,%.o,$(wildcard *.c)): .help-files
-
-.PHONY: links
-links:
- cd tools && ./create-links
-
-generated-usage.o: generated-usage.c links .help-files
-generated-usage.c: $(USAGE_SOURCES) tools/gen-usage links
- tools/gen-usage $(USAGE_SOURCES) >$@
-
-.help-files: $(HELP_SOURCES) links
- set -e; for f in $(HELP_SOURCES); do tools/gen-help $$f; done; touch .help-files
-
-clean:
- rm -f ctdb-test .help-files generated-* *.o
+++ /dev/null
-#include "utils.h"
-#include "log.h"
-#include "tui.h"
-#include "ctdb-test.h"
-#include <ctdb.h>
-#include <tdb.h>
-#include <talloc.h>
-#include <dlinklist.h>
-#include <errno.h>
-
-static unsigned int db_num;
-static struct db *dbs;
-
-struct db {
- struct db *next, *prev;
- struct ctdb_db *db;
- const char *name;
- unsigned int num;
- bool persistent;
- uint32_t tdb_flags;
-};
-
-struct ctdb_db *find_db_by_id(unsigned int id)
-{
- struct db *db;
-
- for (db = dbs; db; db = db->next) {
- if (db->num == id)
- return db->db;
- }
- return NULL;
-}
-
-static void attachdb_help(int agc, char **argv)
-{
-#include "generated-attachdb-help:attachdb"
-/*** XML Help:
- <section id="c:attachdb">
- <title><command>attachdb</command></title>
- <para>Attach to a ctdb database</para>
- <cmdsynopsis>
- <command>attachdb</command>
- <arg choice="req"><replaceable>name</replaceable></arg>
- <arg choice="req"><replaceable>persistent</replaceable></arg>
- <arg choice="opt"><replaceable>tdb-flags</replaceable></arg>
- </cmdsynopsis>
- <para>Attach to the database of the given <replaceable>name</replaceable>.
- <replaceable>persistent</replaceable> is 'true' or 'false', an
-
- <replaceable>tdb-flags</replaceable> an optional one or more
- comma-separated values:</para>
- <variablelist>
- <varlistentry>
- <term>SEQNUM</term>
- <listitem>
- <para>Use sequence numbers on the tdb</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>It uses a consecutive number for each attached db to
- identify it for other ctdb-test commands, starting with 1.</para>
-
- <para>Without any options, the <command>attachdb</command>
- command lists all databases attached.</para>
- </section>
-*/
-}
-
-static void detachdb_help(int agc, char **argv)
-{
-#include "generated-attachdb-help:detachdb"
-/*** XML Help:
- <section id="c:detachdb">
- <title><command>detachdb</command></title>
- <para>Detach from a ctdb database</para>
- <cmdsynopsis>
- <command>detachdb</command>
- <arg choice="req"><replaceable>number</replaceable></arg>
- </cmdsynopsis>
- <para>Detach from the database returned by <command>attachdb</command>.
- </para>
- </section>
-*/
-}
-static int db_destructor(struct db *db)
-{
- ctdb_detachdb(get_ctdb(), db->db);
- DLIST_REMOVE(dbs, db);
- return 0;
-}
-
-static bool detachdb(int argc, char **argv)
-{
- struct db *db;
-
- if (argc != 2) {
- log_line(LOG_ALWAYS, "Need database number");
- return false;
- }
-
- for (db = dbs; db; db = db->next) {
- if (db->num == atoi(argv[1]))
- break;
- }
- if (!db) {
- log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
- return false;
- }
- talloc_free(db);
- return true;
-}
-
-static bool attachdb(int argc, char **argv)
-{
- struct db *db;
-
- if (!get_ctdb()) {
- log_line(LOG_ALWAYS, "No ctdb connection");
- return false;
- }
-
- if (argc == 1) {
- log_line(LOG_UI, "Databases currently attached:");
- for (db = dbs; db; db = db->next) {
- log_line(LOG_ALWAYS, " %i: %s: %s %u",
- db->num, db->name,
- db->persistent
- ? "persistent" : "not persistent",
- db->tdb_flags);
- }
- return true;
- }
- if (argc != 3 && argc != 4) {
- log_line(LOG_ALWAYS, "Need 2 or 3 args");
- return false;
- }
- db = talloc(working, struct db);
- db->name = talloc_strdup(db, argv[1]);
- if (strcasecmp(argv[2], "true") == 0)
- db->persistent = true;
- else if (strcasecmp(argv[2], "false") == 0)
- db->persistent = false;
- else {
- log_line(LOG_ALWAYS, "persistent should be true or false");
- talloc_free(db);
- return false;
- }
- db->tdb_flags = 0;
- if (argc == 4) {
- if (strcasecmp(argv[3], "seqnum") == 0)
- db->tdb_flags |= TDB_SEQNUM;
- else {
- log_line(LOG_ALWAYS, "invalid tdb-flags");
- talloc_free(db);
- return false;
- }
- }
- db->db = ctdb_attachdb(get_ctdb(), db->name, db->persistent,
- db->tdb_flags);
- if (!db->db) {
- log_line(LOG_UI, "ctdb_attachdb: %s", strerror(errno));
- return false;
- }
- db->num = ++db_num;
- DLIST_ADD(dbs, db);
- talloc_set_destructor(db, db_destructor);
- log_line(LOG_UI, "attached: %u", db->num);
- return true;
-}
-
-static void attachdb_init(void)
-{
- tui_register_command("attachdb", attachdb, attachdb_help);
- tui_register_command("detachdb", detachdb, detachdb_help);
-}
-init_call(attachdb_init);
+++ /dev/null
-/*
- test driver for libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <poll.h>
-#include <talloc.h>
-#include <tdb.h>
-
-/* We replace the following functions, for finer control. */
-#define poll(fds, nfds, timeout) ctdb_test_poll((fds), (nfds), (timeout), __location__)
-#define malloc(size) ctdb_test_malloc((size), __location__)
-#define free(ptr) ctdb_test_free((ptr), __location__)
-#define realloc(ptr, size) ctdb_test_realloc((ptr), (size), __location__)
-#define read(fd, buf, count) ctdb_test_read((fd), (buf), (count), __location__)
-#define write(fd, buf, count) ctdb_test_write((fd), (buf), (count), __location__)
-#define socket(domain, type, protocol) ctdb_test_socket((domain), (type), (protocol), __location__)
-#define connect(sockfd, addr, addrlen) ctdb_test_connect((sockfd), (addr), (addrlen), __location__)
-
-#define tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode, log_ctx, hash_fn) ctdb_test_tdb_open_ex((name), (hash_size), (tdb_flags), (open_flags), (mode), (log_ctx), (hash_fn), __location__)
-#define tdb_fetch(tdb, key) ctdb_test_tdb_fetch((tdb), (key))
-
-/* Implement these if they're ever used. */
-#define calloc ctdb_test_calloc
-#define select ctdb_test_select
-#define epoll_wait ctdb_test_epoll_wait
-#define epoll_ctl ctdb_test_epoll_ctl
-#define tdb_open ctdb_test_tdb_open
-
-static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout, const char *location);
-static void *ctdb_test_malloc(size_t size, const char *location);
-static void ctdb_test_free(void *ptr, const char *location);
-static void *ctdb_test_realloc(void *ptr, size_t size, const char *location);
-static ssize_t ctdb_test_read(int fd, void *buf, size_t count, const char *location);
-static ssize_t ctdb_test_write(int fd, const void *buf, size_t count, const char *location);
-static int ctdb_test_socket(int domain, int type, int protocol, const char *location);
-static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen, const char *location);
-static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
- int hash_size, int tdb_flags,
- int open_flags, mode_t mode,
- const struct tdb_logging_context *log_ctx,
- tdb_hash_func hash_fn, const char *location);
-static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key);
-
-#include "../sync.c"
-#include "../control.c"
-#include "../ctdb.c"
-#include "../io_elem.c"
-#include "../local_tdb.c"
-#include "../logging.c"
-#include "../messages.c"
-
-#undef poll
-#undef malloc
-#undef realloc
-#undef read
-#undef write
-#undef socket
-#undef connect
-#undef tdb_open_ex
-#undef calloc
-#undef select
-#undef epoll_wait
-#undef epoll_ctl
-#undef tdb_open
-#undef tdb_fetch
-
-#include "ctdb-test.h"
-#include "utils.h"
-#include "tui.h"
-#include "log.h"
-#include "failtest.h"
-#include "expect.h"
-#include <err.h>
-
-/* Talloc contexts */
-void *allocations;
-void *working;
-
-static void run_inits(void)
-{
- /* Linker magic creates these to delineate section. */
- extern initcall_t __start_init_call[], __stop_init_call[];
- initcall_t *p;
-
- for (p = __start_init_call; p < __stop_init_call; p++)
- (*p)();
-}
-
-static void print_license(void)
-{
- printf("ctdb-test, Copyright (C) 2010 Jeremy Kerr, Rusty Russell\n"
- "ctdb-test comes with ABSOLUTELY NO WARRANTY; see COPYING.\n"
- "This is free software, and you are welcome to redistribute\n"
- "it under certain conditions; see COPYING for details.\n");
-}
-
-/*** XML Argument:
- <section id="a:echo">
- <title><option>--echo</option>, <option>-x</option></title>
- <subtitle>Echo commands as they are executed</subtitle>
- <para>ctdb-test will echo each command before it is executed. Useful when
- commands are read from a file</para>
- </section>
-*/
-static void cmdline_echo(struct option *opt)
-{
- tui_echo_commands = 1;
-}
-cmdline_opt("echo", 0, 'x', cmdline_echo);
-
-/*** XML Argument:
- <section id="a:quiet">
- <title><option>--quiet</option>, <option>-q</option></title>
- <subtitle>Run quietly</subtitle>
- <para>Causes ctdb-test to reduce its output to the minimum possible - no prompt
- is displayed, and most warning messages are suppressed
- </para>
- </section>
-*/
-static void cmdline_quiet(struct option *opt)
-{
- tui_quiet = 1;
-}
-cmdline_opt("quiet", 0, 'q', cmdline_quiet);
-
-/*** XML Argument:
- <section id="a:exit">
- <title><option>--exit</option>, <option>-e</option></title>
- <subtitle>Exit on error</subtitle>
- <para>If <option>--exit</option> is specified, ctdb-test will exit (with a
- non-zero error code) on the first script error it encounters (eg an
- expect command does not match). This is the default when invoked as a
- non-interactive script.</para>
- </section>
-*/
-static void cmdline_abort_on_fail(struct option *opt)
-{
- tui_abort_on_fail = 1;
-}
-cmdline_opt("exit", 0, 'e', cmdline_abort_on_fail);
-
-/*** XML Argument:
- <section id="a:help">
- <title><option>--help</option></title>
- <subtitle>Print usage information</subtitle>
- <para>Causes ctdb-test to print its command line arguments and then exit</para>
- </section>
-*/
-static void cmdline_help(struct option *opt)
-{
- print_license();
- print_usage();
- exit(EXIT_SUCCESS);
-}
-cmdline_opt("help", 0, 'h', cmdline_help);
-
-extern struct cmdline_option __start_cmdline[], __stop_cmdline[];
-
-static struct cmdline_option *get_cmdline_option(int opt)
-{
- struct cmdline_option *copt;
-
- /* if opt is < '0', we have been passed a long option, which is
- * indexed directly */
- if (opt < '0')
- return __start_cmdline + opt;
-
- /* otherwise search for the short option in the .val member */
- for (copt = __start_cmdline; copt < __stop_cmdline; copt++)
- if (copt->opt.val == opt)
- return copt;
-
- return NULL;
-}
-
-static struct option *get_cmdline_options(void)
-{
- struct cmdline_option *copts;
- struct option *opts;
- unsigned int x, n_opts;
-
- n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
- sizeof(struct cmdline_option);
-
- opts = talloc_zero_array(NULL, struct option, n_opts + 1);
- copts = __start_cmdline;
-
- for (x = 0; x < n_opts; x++) {
- unsigned int y;
-
- if (copts[x].opt.has_arg > 2)
- errx(1, "Bad argument `%s'", copts[x].opt.name);
-
- for (y = 0; y < x; y++)
- if ((copts[x].opt.val && copts[x].opt.val
- == opts[y].val)
- || streq(copts[x].opt.name,
- opts[y].name))
- errx(1, "Conflicting arguments %s = %s\n",
- copts[x].opt.name, opts[y].name);
-
- opts[x] = copts[x].opt;
- opts[x].val = x;
- }
-
- return opts;
-}
-
-static char *get_cmdline_optstr(void)
-{
- struct cmdline_option *copts;
- unsigned int x, n_opts;
- char *optstr, tmpstr[3], *colonstr = "::";
-
- n_opts = ((void *)__stop_cmdline - (void *)__start_cmdline) /
- sizeof(struct cmdline_option);
-
- optstr = talloc_size(NULL, 3 * n_opts * sizeof(*optstr) + 1);
- *optstr = '\0';
-
- copts = __start_cmdline;
-
- for (x = 0; x < n_opts; x++) {
- if (!copts[x].opt.val)
- continue;
- snprintf(tmpstr, 4, "%c%s", copts[x].opt.val,
- colonstr + 2 - copts[x].opt.has_arg);
- strcat(optstr, tmpstr);
- }
- return optstr;
-}
-
-static int ctdb_test_poll(struct pollfd *fds, nfds_t nfds, int timeout,
- const char *location)
-{
- if (should_i_fail("poll", location)) {
- errno = EINVAL;
- return -1;
- }
- return poll(fds, nfds, timeout);
-}
-
-static void *ctdb_test_malloc(size_t size, const char *location)
-{
- if (should_i_fail("malloc", location)) {
- errno = ENOMEM;
- return NULL;
- }
- return talloc_named_const(allocations, size, location);
-}
-
-static void ctdb_test_free(void *ptr, const char *location)
-{
- talloc_free(ptr);
-}
-
-static void *ctdb_test_realloc(void *ptr, size_t size, const char *location)
-{
- if (should_i_fail("realloc", location)) {
- errno = ENOMEM;
- return NULL;
- }
- ptr = _talloc_realloc(allocations, ptr, size, location);
- if (ptr)
- talloc_set_name(ptr, "%s (reallocated to %u at %s)",
- talloc_get_name(ptr), size, location);
- return ptr;
-}
-
-static ssize_t ctdb_test_read(int fd, void *buf, size_t count,
- const char *location)
-{
- if (should_i_fail("read", location)) {
- errno = EBADF;
- return -1;
- }
- /* FIXME: We only let parent read and write.
- * We should have child do short read, at least until whole packet is
- * read. Then we terminate child. */
- if (!am_parent()) {
- log_line(LOG_DEBUG, "Child reading fd");
- return 0;
- }
- return read(fd, buf, count);
-}
-
-static ssize_t ctdb_test_write(int fd, const void *buf, size_t count,
- const char *location)
-{
- if (should_i_fail("write", location)) {
- errno = EBADF;
- return -1;
- }
- /* FIXME: We only let parent read and write.
- * We should have child do short write, at least until whole packet is
- * written, then terminate child. Check that all children and parent
- * write the same data. */
- if (!am_parent()) {
- log_line(LOG_DEBUG, "Child writing fd");
- return 0;
- }
- return write(fd, buf, count);
-}
-
-static int ctdb_test_socket(int domain, int type, int protocol,
- const char *location)
-{
- if (should_i_fail("socket", location)) {
- errno = EINVAL;
- return -1;
- }
- return socket(domain, type, protocol);
-}
-
-static int ctdb_test_connect(int sockfd, const struct sockaddr *addr,
- socklen_t addrlen, const char *location)
-{
- if (should_i_fail("connect", location)) {
- errno = EINVAL;
- return -1;
- }
- return connect(sockfd, addr, addrlen);
-}
-
-static struct tdb_context *ctdb_test_tdb_open_ex(const char *name,
- int hash_size, int tdb_flags,
- int open_flags, mode_t mode,
- const struct tdb_logging_context *log_ctx,
- tdb_hash_func hash_fn,
- const char *location)
-{
- if (should_i_fail("tdb_open_ex", location)) {
- errno = ENOENT;
- return NULL;
- }
- return tdb_open_ex(name, hash_size, tdb_flags, open_flags, mode,
- log_ctx, hash_fn);
-}
-
-/* We don't need to fail this, but as library expects to be able to free()
- dptr, we need to make sure it's talloced (see ctdb_test_free) */
-static TDB_DATA ctdb_test_tdb_fetch(struct tdb_context *tdb, TDB_DATA key)
-{
- TDB_DATA ret = tdb_fetch(tdb, key);
- if (ret.dptr) {
- ret.dptr = talloc_memdup(allocations, ret.dptr, ret.dsize);
- if (!ret.dptr) {
- err(1, "Could not memdup %zu bytes", ret.dsize);
- }
- }
- return ret;
-}
-
-void check_allocations(void)
-{
- talloc_free(working);
-
- if (talloc_total_blocks(allocations) != 1) {
- log_line(LOG_ALWAYS, "Resource leak:");
- talloc_report_full(allocations, stdout);
- exit(1);
- }
-}
-
-/* This version adds one byte (for nul term) */
-void *grab_fd(int fd, size_t *size)
-{
- size_t max = 16384;
- int ret;
- void *buffer = talloc_array(NULL, char, max+1);
-
- *size = 0;
- while ((ret = read(fd, buffer + *size, max - *size)) > 0) {
- *size += ret;
- if (*size == max)
- buffer = talloc_realloc(NULL, buffer, char, max *= 2 + 1);
- }
- if (ret < 0) {
- talloc_free(buffer);
- buffer = NULL;
- }
- return buffer;
-}
-
-int main(int argc, char *argv[])
-{
- int input_fd, c;
- const char *optstr;
- struct option *options;
-
- allocations = talloc_named_const(NULL, 1, "ctdb-test");
- working = talloc_named_const(NULL, 1, "ctdb-test-working");
-
- options = get_cmdline_options();
- optstr = get_cmdline_optstr();
-
- while ((c = getopt_long(argc, argv, optstr, options, NULL)) != EOF) {
- struct cmdline_option *copt = get_cmdline_option(c);
- if (!copt)
- errx(1, "Unknown argument");
-
- copt->parse(&copt->opt);
- }
-
- if (optind == argc) {
- log_line(LOG_DEBUG, "Disabling failtest due to stdin.");
- failtest = false;
- input_fd = STDIN_FILENO;
- } else if (optind + 1 != argc)
- errx(1, "Need a single argument: input filename");
- else {
- input_fd = open(argv[optind], O_RDONLY);
- if (input_fd < 0)
- err(1, "Opening %s", argv[optind]);
- tui_abort_on_fail = true;
- }
-
- run_inits();
- if (!tui_quiet)
- print_license();
-
- log_line(LOG_VERBOSE, "initialisation done");
-
- tui_run(input_fd);
-
- /* Everyone loves a good error haiku! */
- if (expects_remaining())
- errx(1, "Expectations still / "
- "unfulfilled remaining. / "
- "Testing blossoms fail.");
- check_allocations();
- check_databases();
- dump_failinfo();
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-#ifndef __HAVE_CTDB_TEST_H
-#define __HAVE_CTDB_TEST_H
-#include <stdlib.h>
-
-/* We hang all libctdb allocations off this talloc tree. */
-extern void *allocations;
-
-void check_allocations(void);
-
-/* Our own working state gets hung off this tree. */
-extern void *working;
-
-/* The ctdb connection; created by 'connect' command. */
-struct ctdb_connection *get_ctdb(void);
-
-/* Talloc bytes from an fd until EOF. Nul terminate. */
-void *grab_fd(int fd, size_t *size);
-
-/* Check the databases are still ok. */
-void check_databases(void);
-
-/* Save and restore databases, in case children do damage. */
-void *save_databases(void);
-void restore_databases(void *);
-
-struct ctdb_db *find_db_by_id(unsigned int id);
-
-#endif /* __HAVE_CTDB_TEST_H */
+++ /dev/null
-/*
- database code for libctdb
-
- Copyright (C) Rusty Russell 2010
-
- 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 <unistd.h>
-#include <err.h>
-#include <talloc.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <fcntl.h>
-#include "utils.h"
-#include "log.h"
-#include "ctdb-test.h"
-#include <tdb.h>
-#include <ctdb_protocol.h>
-
-/* FIXME */
-#define DB_PATH "/tmp/ctdbd-test/dbs/"
-
-static int check_header(TDB_DATA key, TDB_DATA data, void *unused)
-{
- struct ctdb_ltdb_header *hdr = (void *)data.dptr;
- if (data.dsize < sizeof(*hdr)) {
- log_line(LOG_ALWAYS, "tdb entry '%.*s' is truncated",
- key.dsize, key.dptr);
- return -1;
- }
- /* Currently a single-node cluster. */
- if (hdr->dmaster != 0) {
- log_line(LOG_ALWAYS, "tdb entry '%.*s' dmaster %u",
- key.dsize, key.dptr, hdr->dmaster);
- return -1;
- }
- /* Currently a single-node cluster. */
- if (hdr->laccessor != 0) {
- log_line(LOG_ALWAYS, "tdb entry '%.*s' laccessor %u",
- key.dsize, key.dptr, hdr->laccessor);
- return -1;
- }
- return 0;
-}
-
-static void check_database(const char *name)
-{
- struct tdb_context *tdb = tdb_open(name, 0, TDB_DEFAULT, O_RDWR, 0);
- if (!tdb)
- err(1, "Opening tdb %s", name);
-
- if (tdb_check(tdb, check_header, NULL) != 0) {
- log_line(LOG_ALWAYS, "tdb %s is corrupt", name);
- exit(EXIT_FAILURE);
- }
- tdb_close(tdb);
-}
-
-void check_databases(void)
-{
- struct dirent *ent;
- DIR *d = opendir(DB_PATH);
- if (!d)
- err(1, "Reading directory %s", DB_PATH);
-
- while ((ent = readdir(d)) != NULL) {
- if (strends(ent->d_name, ".tdb.0")) {
- char *fullpath = talloc_asprintf(NULL, "%s/%s",
- DB_PATH, ent->d_name);
- check_database(fullpath);
- talloc_free(fullpath);
- }
- }
- closedir(d);
-}
-
-/* FIXME: We assume we don't need locks here. Not a solid assumption! */
-void *save_databases(void)
-{
- struct tdb_context *tdb = tdb_open(NULL, 0, TDB_INTERNAL, 0, 0);
- struct dirent *ent;
- DIR *d = opendir(DB_PATH);
- if (!d)
- err(1, "Reading directory %s", DB_PATH);
-
- while ((ent = readdir(d)) != NULL) {
- if (strends(ent->d_name, ".tdb.0")) {
- TDB_DATA data, key;
- int fd;
- char *fullpath = talloc_asprintf(NULL, "%s/%s",
- DB_PATH, ent->d_name);
- fd = open(fullpath, O_RDONLY);
- if (fd < 0)
- err(1, "Saving tdb %s", fullpath);
- data.dptr = grab_fd(fd, &data.dsize);
- key.dptr = (void *)fullpath;
- key.dsize = strlen(fullpath) + 1;
- tdb_store(tdb, key, data, TDB_INSERT);
- talloc_free(fullpath);
- close(fd);
- }
- }
- closedir(d);
- return tdb;
-}
-
-void restore_databases(void *_tdb)
-{
- struct tdb_context *tdb = _tdb;
- TDB_DATA key, data;
-
- for (key = tdb_firstkey(tdb); key.dptr; key = tdb_nextkey(tdb, key)) {
- int fd = open((char *)key.dptr, O_WRONLY);
- if (fd < 0)
- err(1, "Restoring tdb %s", (char *)key.dptr);
- data = tdb_fetch(tdb, key);
- write(fd, data.dptr, data.dsize);
- free(data.dptr);
- close(fd);
- }
- tdb_close(tdb);
-}
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "tui.h"
-#include "log.h"
-#include "expect.h"
-#include <fnmatch.h>
-#include <talloc.h>
-#include "utils.h"
-
-/* Expect is used to set up expectations on logging, for automated
- * testing. */
-struct expect {
- struct expect *next;
- int invert;
- int matched;
- char *command;
- char *pattern;
-};
-
-static struct expect *expect;
-struct cmdstack
-{
- struct cmdstack *prev;
- char *command;
-};
-static struct cmdstack *current_command;
-
-/* We don't need to try to match every pattern length: we only need
- * lengths where the next char matches. */
-static unsigned int maybe_skip(char next_char, const char *line)
-{
- char str[2];
-
- /* If next one is *, we can't skip any. */
- if (next_char == '*')
- return 1;
-
- /* No more string? */
- if (*line == '\0')
- return 1;
-
- /* Next one is space, skip up to next space. */
- if (next_char == '\t' || next_char == ' ')
- return strcspn(line+1, "\t ") + 1;
-
- str[0] = next_char;
- str[1] = '\0';
- return strcspn(line+1, str) + 1;
-}
-
-/* Loose match for strings: whitespace can be any number of
- * whitespace, and * matches anything. Approximately. */
-static bool loose_match(const char *pattern, const char *line)
-{
- /* Any whitespace in pattern matches any whitespace in line. */
- if (*pattern == '\t' || *pattern == ' ') {
- int i, j, pat_space, line_space;
-
- pat_space = strspn(pattern, "\t ");
- line_space = strspn(line, "\t ");
-
- for (i = 1; i <= pat_space; i++)
- for (j = 1; j <= line_space; j++)
- if (loose_match(pattern+i, line+j))
- return true;
- return false;
- }
-
- if (*pattern == '*') {
- int i, len = strlen(line);
- for (i = 0; i <= len; i += maybe_skip(pattern[1],line+i))
- if (loose_match(pattern+1, line+i))
- return true;
-
- return false;
- }
-
- if (*pattern == *line) {
- if (*pattern == '\0')
- return true;
- return loose_match(pattern+1, line+1);
- }
-
- return false;
-}
-
-/* Pattern can't have whitespace at start and end, due to our parser.
- * Strip ot here. */
-static bool matches(const char *pattern, const char *line)
-{
- unsigned int len;
-
- line += strspn(line, "\t ");
- len = strlen(line);
- if (len > 0 && (line[len-1] == '\t' || line[len-1] == ' ')) {
- char trimmed[len];
- memcpy(trimmed, line, len);
- while (trimmed[len-1] == '\t' || trimmed[len-1] == ' ') {
- if (len == 1)
- break;
- len--;
- }
- trimmed[len] = '\0';
- return loose_match(pattern, trimmed);
- }
- return loose_match(pattern, line);
-}
-
-bool expect_log_hook(const char *line)
-{
- struct expect *e;
- bool ret = false;
-
- if (current_command == NULL)
- return false;
-
- /* Only allow each pattern to match once, so we can easily
- * expect something to happen twice. */
- for (e = expect; e; e = e->next) {
- if (!e->matched
- && streq(current_command->command, e->command)
- && matches(e->pattern, line)) {
- e->matched = 1;
- ret = true;
- }
- }
- return ret;
-}
-
-bool expects_remaining(void)
-{
- return expect != NULL;
-}
-
-static void expect_pre_command(const char *command)
-{
- struct cmdstack *new = talloc(NULL, struct cmdstack);
- new->prev = current_command;
- new->command = talloc_strdup(new, command);
- current_command = new;
-}
-
-static bool expect_post_command(const char *command)
-{
- struct expect **e, **next, *old;
- bool ret = true;
- struct cmdstack *oldcmd;
-
- for (e = &expect; *e; e = next) {
- next = &(*e)->next;
-
- if (!streq(current_command->command, (*e)->command))
- continue;
-
- if (!(*e)->invert && !(*e)->matched) {
- if (tui_abort_on_fail)
- script_fail("Pattern '%s' did not match",
- (*e)->pattern);
- log_line(LOG_VERBOSE, "Pattern '%s' did not match",
- (*e)->pattern);
- ret = false;
- } else if ((*e)->invert && (*e)->matched) {
- if (tui_abort_on_fail)
- script_fail("Pattern '%s' matched",
- (*e)->pattern);
- log_line(LOG_VERBOSE, "Pattern '%s' matched",
- (*e)->pattern);
- ret = false;
- }
-
- /* Unlink from list and free. */
- old = *e;
- *e = (*e)->next;
- next = e;
-
- talloc_free(old);
- }
-
- oldcmd = current_command;
- current_command = current_command->prev;
- talloc_free(oldcmd);
- return ret;
-}
-
-static bool expect_cmd(int argc, char **argv)
-{
- struct expect *e;
- unsigned int i, len;
- bool invert = false;
-
- if (argc == 1) {
- for (e = expect; e; e = e->next)
- log_line(LOG_UI, "%s: %s\"%s\"",
- e->command,
- e->invert ? "! " : "",
- e->pattern);
- return true;
- }
-
- if (argv[1] && streq(argv[1], "!")) {
- invert = true;
- argv++;
- argc--;
- }
-
- if (argc < 3)
- return false;
-
- if (!tui_is_command(argv[1])) {
- log_line(LOG_ALWAYS, "expect: %s is not a command\n",
- argv[1]);
- return false;
- }
-
- e = talloc(NULL, struct expect);
- e->matched = 0;
- e->invert = invert;
- e->next = expect;
-
- e->command = talloc_strdup(e, argv[1]);
-
- for (len = 0, i = 2; i < argc; i++)
- len += strlen(argv[i])+1;
- e->pattern = talloc_array(e, char, len + 1);
-
- e->pattern[0] = '\0';
- for (i = 2; i < argc; i++) {
- if (i == 2)
- sprintf(e->pattern+strlen(e->pattern), "%s", argv[i]);
- else
- sprintf(e->pattern+strlen(e->pattern), " %s", argv[i]);
- }
- expect = e;
- return true;
-}
-
-static void expect_help(int argc, char **argv)
-{
-#include "generated-expect-help:expect"
-/*** XML Help:
- <section id="c:expect">
- <title><command>expect</command></title>
- <para>Catch logging information for automated testing</para>
- <cmdsynopsis>
- <command>expect</command>
- </cmdsynopsis>
- <cmdsynopsis>
- <command>expect</command>
- <arg choice="opt">!</arg>
- <arg choice="req"><replaceable>command</replaceable></arg>
- <arg choice="req"><replaceable>pattern</replaceable></arg>
- </cmdsynopsis>
- <para><command>expect</command> will set up a set of patterns to expect in
- logging messages for a particular command. If that command finishes
- without matching the specified pattern, the simulator will exit with a
- non-zero return value. After the command is run, all expectations on that
- command are deleted.</para>
- <para><command>expect</command> with no arguments will print out the
- current list of expectations, as a command and a pattern.</para>
- <para><command>expect <replaceable>command pattern</replaceable></command>
- will expect the specified pattern to occur the next time
- <replaceable>command</replaceable> is invoked. If an '!' appears before
- the command, then the expectation is negated - if the pattern appears in
- the output, then the simulator will exit with an error
- </para>
- <para>The pattern itself is similar to a simple shell wildcard,
- except whitespace is loosely matched. The * character will
- match any a string of any length.</para>
- </section>
-*/
-}
-
-static void init(void)
-{
- tui_register_command("expect", expect_cmd, expect_help);
- tui_register_pre_post_hook(expect_pre_command, expect_post_command);
-}
-
-init_call(init);
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef __HAVE_EXPECT_H
-#define __HAVE_EXPECT_H
-
-/* Expect interface */
-void expect_before_command(const char *command);
-bool expect_log_hook(const char *line);
-void expect_after_command(void);
-
-/* Are there any expect commands unresolved? */
-bool expects_remaining(void);
-
-#endif /* __HAVE_EXPECT_H */
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2004 Jeremy Kerr & Rusty Russell
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#include "utils.h"
-#include "tui.h"
-#include "log.h"
-#include "failtest.h"
-#include "ctdb-test.h"
-#include "talloc.h"
-#include "dlinklist.h"
-#include <stdlib.h>
-#include <stdbool.h>
-#include <getopt.h>
-#include <err.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <errno.h>
-
-static unsigned int fails = 0, excessive_fails = 2;
-unsigned int failpoints = 0;
-static const char *failtest_no_report = NULL;
-bool failtest = true;
-
-struct fail_decision {
- struct fail_decision *next, *prev;
- char *location;
- unsigned int tui_line;
- bool failed;
-};
-
-static struct fail_decision *decisions;
-
-/* Failure path to follow (initialized by --failpath). */
-static const char *failpath = NULL, *orig_failpath;
-
-/*** XML Argument:
- <section id="a:failpath">
- <title><option>--failpath
- <replaceable>path</replaceable></option></title>
- <subtitle>Replay a failure path</subtitle>
- <para>Given a failure path, (from <option>--failtest</option>), this will
- replay the sequence of sucesses/failures, allowing debugging. The input
- should be the same as the original which caused the failure.
- </para>
-
- <para>This testing can be slow, but allows for testing of failure
- paths which would otherwise be very difficult to test
- automatically.</para>
- </section>
-*/
-static void cmdline_failpath(struct option *opt)
-{
- extern char *optarg;
- if (!optarg)
- errx(1, "failtest option requires an argument");
- orig_failpath = failpath = optarg;
-}
-cmdline_opt("failpath", 1, 0, cmdline_failpath);
-
-/*** XML Argument:
- <section id="a:failtest-no-report">
- <title><option>--failtest-no-report
- <replaceable>function</replaceable></option></title>
- <subtitle>Exclude a function from excessive failure reports</subtitle>
-
- <para>Sometimes code deliberately ignores the failures of a
- certain function. This suppresses complaints about that for any
- functions containing this name.</para> </section>
-*/
-static void cmdline_failtest_no_report(struct option *opt)
-{
- extern char *optarg;
- if (!optarg)
- errx(1, "failtest-no-report option requires an argument");
- failtest_no_report = optarg;
-}
-cmdline_opt("failtest-no-report", 1, 0, cmdline_failtest_no_report);
-
-/*** XML Argument:
- <section id="a:no-failtest">
- <title><option>--no-failtest</option></title>
- <subtitle>Don't test failure cases</subtitle>
-
- <para>This is the default in interactive mode.</para>
- </section>
-*/
-static void cmdline_no_failtest(struct option *opt)
-{
- failtest = false;
-}
-cmdline_opt("no-failtest", 0, 0, cmdline_no_failtest);
-
-/* Separate function to make .gdbinit easier */
-static bool failpath_fail(void)
-{
- return true;
-}
-
-static bool do_failpath(const char *func)
-{
- if (*failpath == '[') {
- failpath++;
- if (strncmp(failpath, func, strlen(func)) != 0
- || failpath[strlen(func)] != ']')
- errx(1, "Failpath expected %.*s not %s\n",
- strcspn(failpath, "]"), failpath, func);
- failpath += strlen(func) + 1;
- }
-
- if (*failpath == ':') {
- unsigned long line;
- char *after;
- failpath++;
- line = strtoul(failpath, &after, 10);
- if (*after != ':')
- errx(1, "Bad failure path line number %s\n",
- failpath);
- if (line != tui_linenum)
- errx(1, "Unexpected line number %lu vs %u\n",
- line, tui_linenum);
- failpath = after+1;
- }
-
- switch ((failpath++)[0]) {
- case 'F':
- case 'f':
- return failpath_fail();
- case 'S':
- case 's':
- return false;
- case 0:
- failpath = NULL;
- return false;
- default:
- errx(1, "Failpath '%c' failed to path",
- failpath[-1]);
- }
-}
-
-static char *failpath_string_for_line(struct fail_decision *dec)
-{
- char *ret = NULL;
- struct fail_decision *i;
-
- for (i = decisions; i; i = i->next) {
- if (i->tui_line != dec->tui_line)
- continue;
- ret = talloc_asprintf_append(ret, "[%s]%c",
- i->location,
- i->failed ? 'F' : 'S');
- }
- return ret;
-}
-
-static char *failpath_string(void)
-{
- char *ret = NULL;
- struct fail_decision *i;
-
- for (i = decisions; i; i = i->next)
- ret = talloc_asprintf_append(ret, "[%s]:%i:%c",
- i->location, i->tui_line,
- i->failed ? 'F' : 'S');
- return ret;
-}
-
-static void warn_failure(void)
-{
- char *warning;
- struct fail_decision *i;
- int last_warning = 0;
-
- log_line(LOG_ALWAYS, "WARNING: test ignores failures at %s",
- failpath_string());
-
- for (i = decisions; i; i = i->next) {
- if (i->failed && i->tui_line > last_warning) {
- warning = failpath_string_for_line(i);
- log_line(LOG_ALWAYS, " Line %i: %s",
- i->tui_line, warning);
- talloc_free(warning);
- last_warning = i->tui_line;
- }
- }
-}
-
-bool am_parent(void)
-{
- struct fail_decision *i;
-
- for (i = decisions; i; i = i->next) {
- if (i->failed)
- return false;
- }
- return true;
-}
-
-static char *make_location(const char *func, const char *caller)
-{
- const char *afterslash;
-
- afterslash = strrchr(caller, '/');
- if (afterslash)
- afterslash++;
- else
- afterslash = caller;
- return talloc_asprintf(working, "%s(%s)", func, afterslash);
-}
-
-/* Should I fail at this point? Once only: it would be too expensive
- * to fail at every possible call. */
-bool should_i_fail_once(const char *func, const char *caller)
-{
- char *p, *location = make_location(func, caller);
- struct fail_decision *i;
-
- if (failpath) {
- p = strstr(orig_failpath ?: "", location);
- if (p && p <= failpath
- && p[-1] == '[' && p[strlen(location)] == ']')
- return false;
-
- return do_failpath(location);
- }
-
- for (i = decisions; i; i = i->next)
- if (streq(location, i->location))
- return false;
-
- if (should_i_fail(func, caller)) {
- excessive_fails++;
- return true;
- }
- return false;
-}
-
-/* Should I fail at this point? */
-bool should_i_fail(const char *func, const char *caller)
-{
- pid_t child;
- int status, pfd[2];
- struct fail_decision *dec;
- size_t log_size;
- char *log;
- char *location = make_location(func, caller);
- void *databases;
-
- if (failpath)
- return do_failpath(location);
-
- failpoints++;
- if (!failtest)
- return false;
-
- /* If a testcase ignores a spuriously-inserted failure, it's
- * not specific enough, and we risk doing 2^n tests! */
- if (fails > excessive_fails) {
- static bool warned = false;
- if (!warned++)
- warn_failure();
- }
-
- dec = talloc(NULL, struct fail_decision);
- dec->location = talloc_steal(dec, location);
- dec->tui_line = tui_linenum;
-
- DLIST_ADD_END(decisions, dec, struct fail_decision);
-
- if (pipe(pfd) != 0)
- err(1, "pipe failed for failtest!");
-
- databases = save_databases();
-
- fflush(stdout);
- child = fork();
- if (child == -1)
- err(1, "fork failed for failtest!");
-
- /* The child actually fails. The script will screw up at this
- * point, but should not crash. */
- if (child == 0) {
- /* Log to parent (including stderr if things go really bad). */
- close(pfd[0]);
- dup2(pfd[1], STDOUT_FILENO);
- dup2(pfd[1], STDERR_FILENO);
- dec->failed = true;
- if (!failtest_no_report || !strstr(func, failtest_no_report))
- fails++;
- return true;
- }
-
- dec->failed = false;
-
- close(pfd[1]);
- log = grab_fd(pfd[0], &log_size);
-
- while (waitpid(child, &status, 0) < 0) {
- if (errno != EINTR)
- err(1, "failtest waitpid failed for child %i",
- (int)child);
- }
-
- /* If child succeeded, or mere script failure, continue. */
- if (WIFEXITED(status) && (WEXITSTATUS(status) == EXIT_SUCCESS
- || WEXITSTATUS(status) == EXIT_SCRIPTFAIL)) {
- talloc_free(log);
- restore_databases(databases);
- return false;
- }
-
- /* Reproduce child's path: leave databases for post-mortem. */
- dec->failed = true;
-
- log_line(LOG_ALWAYS, "Child %s %i on failure path: %s",
- WIFEXITED(status) ? "exited" : "signalled",
- WIFEXITED(status) ? WEXITSTATUS(status)
- : WTERMSIG(status), failpath_string());
- log_line(LOG_ALWAYS, "Child output:\n%s", log);
- exit(EXIT_FAILURE);
-}
-
-void dump_failinfo(void)
-{
- log_line(LOG_VERBOSE, "Hit %u failpoints: %s",
- failpoints, failpath_string());
-}
+++ /dev/null
-#ifndef FAILTEST_H
-#define FAILTEST_H
-#include <stdbool.h>
-
-bool should_i_fail_once(const char *func, const char *caller);
-bool should_i_fail(const char *func, const char *caller);
-
-bool failtest;
-
-/* Parent never has artificial failures. */
-bool am_parent(void);
-
-void dump_failinfo(void);
-
-#endif /* FAILTEST_H */
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-#include "log.h"
-#include "tui.h"
-#include "utils.h"
-#include "expect.h"
-#include <string.h>
-#include <talloc.h>
-#include <err.h>
-
-static struct {
- enum log_type type;
- char * name;
-} log_names[] = {
- { LOG_WRITE, "write" },
- { LOG_READ, "read" },
- { LOG_LIB, "lib" },
- { LOG_VERBOSE, "verbose" },
-};
-
-static int typemask = ~LOG_VERBOSE;
-
-bool log_line(enum log_type type, const char *format, ...)
-{
- va_list ap;
- char *line;
- bool ret;
-
- va_start(ap, format);
- line = talloc_vasprintf(NULL, format, ap);
- va_end(ap);
-
- if (!type || (type & typemask)) {
- printf("%s\n", line);
- fflush(stdout);
- }
-
- ret = expect_log_hook(line);
- talloc_free(line);
- return ret;
-}
-
-static void log_partial_v(enum log_type type,
- char *buf,
- unsigned bufsize,
- const char *format,
- va_list ap)
-{
- char *ptr;
- int len = strlen(buf);
-
- /* write to the end of buffer */
- if (vsnprintf(buf + len, bufsize - len - 1, format, ap)
- > bufsize - len - 1) {
- errx(1, "log_line_partial buffer is full!");
- }
-
- ptr = buf;
-
- /* print each bit that ends in a newline */
- for (len = strcspn(ptr, "\n"); *(ptr + len);
- ptr += len, len = strcspn(ptr, "\n")) {
- log_line(type, "%.*s", len++, ptr);
- }
-
- /* if we've printed, copy any remaining (non-newlined)
- parts (including the \0) to the front of buf */
- memmove(buf, ptr, strlen(ptr) + 1);
-}
-
-void log_partial(enum log_type type, char *buf, unsigned bufsize,
- const char *format, ...)
-{
- va_list ap;
-
- va_start(ap, format);
- log_partial_v(type, buf, bufsize, format, ap);
- va_end(ap);
-}
-
-static inline int parsetype(const char *type)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(log_names); i++)
- if (streq(log_names[i].name, type))
- return log_names[i].type;
-
- return 0;
-}
-
-static bool log_admin(int argc, char **argv)
-{
- int i;
- int newtypemask = 0;
-
- if (argc == 1) {
- log_line(LOG_UI, "current log types:", typemask);
-
- for (i = 0; i < ARRAY_SIZE(log_names); i++) {
- if (typemask & log_names[i].type)
- log_line(LOG_UI, "\t%s", log_names[i].name);
- }
- return true;
- }
-
- if (argc == 2) {
- log_line(LOG_ALWAYS, "Expected =, + or - then args");
- return false;
- }
-
- for (i = 2; i < argc; i++) {
- int type;
-
- if (!(type = parsetype(argv[i]))) {
- log_line(LOG_ALWAYS, "no such type %s", argv[i]);
- return false;
- }
- newtypemask |= type;
- }
-
- switch (*argv[1]) {
- case '=':
- typemask = newtypemask;
- break;
- case '-':
- typemask &= ~newtypemask;
- break;
- case '+':
- typemask |= newtypemask;
- break;
- default:
- log_line(LOG_ALWAYS, "unknown modifer: %c", *argv[1]);
- return false;
- }
-
- return true;
-}
-
-static void log_admin_help(int agc, char **argv)
-{
-#include "generated-log-help:log"
-/*** XML Help:
- <section id="c:log">
- <title><command>log</command></title>
- <para>Manage logging settings</para>
- <cmdsynopsis>
- <command>log</command>
- <group choice="opt">
- <arg choice="plain">=</arg>
- <arg choice="plain">+</arg>
- <arg choice="plain">-</arg>
- </group>
- <arg choice="req"><replaceable>type, ...</replaceable></arg>
- </cmdsynopsis>
- <para>Each log message is classified into one of the following
- types:</para>
- <varlistentry>
- <term>UI</term>
- <listitem>
- <para>Normal response from command lines.</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>LIB</term>
- <listitem>
- <para>Logging output from libctdb</para>
- </listitem>
- </varlistentry>
- <variablelist>
- <varlistentry>
- <term>READ</term>
- <listitem>
- <para>Messages from ctdbd</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>WRITE</term>
- <listitem>
- <para>Messages to ctdbd</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>VERBOSE</term>
- <listitem>
- <para>Verbose debug output</para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- <para>The <command>log</command> command allows you to select
- which messages are displayed. By default, all messages except
- debug will be shown.</para>
-
- <para>Without any arguments, the current logged types are listed.</para>
-
- <para>With +, - or = character, those types will be added,
- removed or set as the current types of messages to be logged
- (repectively).</para>
-
- <para>Messages generated as a result of user input are always
- logged. </para> </section>
-*/
-}
-
-static void log_init(void)
-{
- if (tui_quiet)
- typemask = 0;
- tui_register_command("log", log_admin, log_admin_help);
-}
-
-init_call(log_init);
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef __HAVE_LOG_H
-#define __HAVE_LOG_H
-#include <stdbool.h>
-
-enum log_type {
- LOG_ALWAYS = 0x00,
- /* Packets that are written to ctdbd. */
- LOG_WRITE = 0x02,
- /* Packets that are read from ctdbd. */
- LOG_READ = 0x04,
- /* Logging from libctdb. */
- LOG_LIB = 0x08,
- /* Logging from normal operations. */
- LOG_UI = 0x10,
- /* Verbose debugging. */
- LOG_VERBOSE = 0x20,
-};
-
-/* Adds a \n for convenient logging. Returns true if it was expected. */
-bool log_line(enum log_type type, const char *format, ...);
-/* Builds up buffer and prints out line at a time. */
-void log_partial(enum log_type type, char *buf, unsigned bufsize,
- const char *format, ...);
-#endif /* __HAVE_LOG_H */
+++ /dev/null
-#include "utils.h"
-#include "log.h"
-#include "tui.h"
-#include "ctdb-test.h"
-#include <ctdb.h>
-#include <tdb.h>
-#include <talloc.h>
-#include <dlinklist.h>
-#include <errno.h>
-
-struct lock {
- struct lock *next, *prev;
- struct ctdb_db *db;
- struct ctdb_lock *lock;
- unsigned int id;
-};
-
-static unsigned int lock_id;
-static struct lock *locks;
-
-static void readrecordlock_help(int argc, char **argv)
-{
-#include "generated-readrecordlock-help:readrecordlock"
-/*** XML Help:
- <section id="c:readrecordlock">
- <title><command>readrecordlock</command></title>
- <para>Read and lock a record in a ctdb database</para>
- <cmdsynopsis>
- <command>readrecordlock</command>
- <arg choice="req"><replaceable>db-id</replaceable></arg>
- <arg choice="req"><replaceable>key</replaceable></arg>
- </cmdsynopsis>
-
- <para>Read and lock a record. Prints the record, and a 1-based
- sequential handle on success, which should be handed to
- <command>releaselock</command>
- </para>
- </section>
-*/
-}
-
-static void releaselock_help(int argc, char **argv)
-{
-#include "generated-readrecordlock-help:releaselock"
-/*** XML Help:
- <section id="c:releaselock">
- <title><command>releaselock</command></title>
- <para>Unlock a record in a ctdb database</para>
- <cmdsynopsis>
- <command>releaselock</command>
- <arg choice="req"><replaceable>db-id</replaceable></arg>
- <arg choice="req"><replaceable>lock-id</replaceable></arg>
- </cmdsynopsis>
-
- <para>Unlock a record successfully locked by
- <command>readrecordlock</command>. </para>
-
- </section>
-*/
-}
-
-static void writerecord_help(int argc, char **argv)
-{
-#include "generated-readrecordlock-help:writerecord"
-/*** XML Help:
- <section id="c:writerecord">
- <title><command>writerecord</command></title>
- <para>Write to a locked record in a ctdb database</para>
- <cmdsynopsis>
- <command>writerecord</command>
- <arg choice="req"><replaceable>db-id</replaceable></arg>
- <arg choice="req"><replaceable>lock-id</replaceable></arg>
- <arg choice="req"><replaceable>data</replaceable></arg>
- </cmdsynopsis>
-
- <para>Once a record is locked with
- <command>readrecordlock</command>, you can write to it. </para>
- </section>
-*/
-}
-
-static int lock_destructor(struct lock *lock)
-{
- ctdb_release_lock(lock->db, lock->lock);
- DLIST_REMOVE(locks, lock);
- return 0;
-}
-
-static bool releaselock(int argc, char **argv)
-{
- struct ctdb_db *db;
- struct lock *lock;
-
- if (argc != 3) {
- log_line(LOG_ALWAYS, "Need database number and lock number");
- return false;
- }
-
- db = find_db_by_id(atoi(argv[1]));
- if (!db) {
- log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
- return false;
- }
-
- for (lock = locks; lock; lock = lock->next) {
- if (lock->id == atoi(argv[2]))
- break;
- }
- if (!lock) {
- log_line(LOG_ALWAYS, "Unknown lock number %s", argv[2]);
- return false;
- }
- talloc_free(lock);
- return true;
-}
-
-static bool writerecord(int argc, char **argv)
-{
- struct ctdb_db *db;
- struct lock *lock;
- TDB_DATA data;
-
- if (argc != 4) {
- log_line(LOG_ALWAYS, "Need db-id, lock-id and data");
- return false;
- }
-
- db = find_db_by_id(atoi(argv[1]));
- if (!db) {
- log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
- return false;
- }
-
- for (lock = locks; lock; lock = lock->next) {
- if (lock->id == atoi(argv[2]))
- break;
- }
- if (!lock) {
- log_line(LOG_ALWAYS, "Unknown lock number %s", argv[2]);
- return false;
- }
-
- data.dptr = (unsigned char *)argv[3];
- data.dsize = strlen(argv[3]);
-
- if (!ctdb_writerecord(db, lock->lock, data)) {
- log_line(LOG_UI, "writerecordlock: failed %s", strerror(errno));
- return false;
- }
- return true;
-}
-
-static bool readrecordlock(int argc, char **argv)
-{
- struct lock *lock = talloc(working, struct lock);
- TDB_DATA key, data;
-
- if (!get_ctdb()) {
- log_line(LOG_ALWAYS, "No ctdb connection");
- return false;
- }
- if (argc != 3) {
- log_line(LOG_ALWAYS, "Need db-id and key");
- return false;
- }
-
- lock->db = find_db_by_id(atoi(argv[1]));
- if (!lock->db) {
- log_line(LOG_ALWAYS, "Unknown db number %s", argv[1]);
- return false;
- }
-
- key.dptr = (unsigned char *)argv[2];
- key.dsize = strlen(argv[2]);
-
- lock->lock = ctdb_readrecordlock(get_ctdb(), lock->db, key, &data);
- if (!lock->lock) {
- log_line(LOG_UI, "readrecordlock: failed %s", strerror(errno));
- return false;
- }
- lock->id = ++lock_id;
- DLIST_ADD(locks, lock);
- talloc_set_destructor(lock, lock_destructor);
-
- log_line(LOG_UI, "lock %u: data '%.*s'",
- lock->id, data.dsize, (char *)data.dptr);
- return true;
-}
-
-static void readrecordlock_init(void)
-{
- tui_register_command("readrecordlock",
- readrecordlock, readrecordlock_help);
- tui_register_command("releaselock", releaselock, releaselock_help);
- tui_register_command("writerecord", writerecord, writerecord_help);
-}
-init_call(readrecordlock_init);
+++ /dev/null
-#! /bin/sh
-
-set -e
-
-CTDBD_DIR=/tmp/ctdbd-test
-VALGRIND="valgrind -q --error-exitcode=111"
-
-if [ x"$1" = x--no-valgrind ]; then
- VALGRIND=""
- shift
-fi
-
-if pidof ctdbd > /dev/null; then
- echo ctdbd already running. Please kill it. >&2
- exit 1
-fi
-
-cleanup()
-{
- killall ctdbd
-}
-
-# Default is to run all tests.
-if [ $# = 0 ]; then
- set tests/*
-fi
-
-# Build ctdb, and build ctdb-test
-make --quiet -C ../..
-echo Building ctdb-test...
-make --quiet
-
-rm -rf $CTDBD_DIR
-mkdir -p $CTDBD_DIR $CTDBD_DIR/dbs $CTDBD_DIR/dbs/persistent $CTDBD_DIR/dbs/state $CTDBD_DIR/event.d
-
-if lsmod | grep -q dummy; then
- :
-else
- echo Installing dummy0 network module...
- sudo modprobe dummy
-fi
-
-echo 10.199.199.1/24 dummy0 > $CTDBD_DIR/addresses
-cat > $CTDBD_DIR/event.d/01.print <<EOF
-#! /bin/sh
-
-echo "Script invoked with args \$@" >> $CTDBD_DIR/eventscripts.log
-EOF
-chmod a+x $CTDBD_DIR/event.d/01.print
-
-echo Running ctdbd with logging to $CTDBD_DIR/log...
-../../bin/ctdbd --logfile=$CTDBD_DIR/log --public-addresses=$CTDBD_DIR/addresses --dbdir=$CTDBD_DIR/dbs --reclock=$CTDBD_DIR/reclock --dbdir-persistent=$CTDBD_DIR/dbs/persistent --dbdir-state=$CTDBD_DIR/dbs/state --event-script-dir=$CTDBD_DIR/event.d
-
-trap cleanup EXIT
-
-echo Waiting for ctdbd to be happy...
-i=0
-while true; do
- ../../bin/ctdb status > $CTDBD_DIR/status
- if ! grep -q UNHEALTHY $CTDBD_DIR/status; then
- break
- fi
- sleep 1
- i=`expr $i + 1`
- if [ $i = 40 ]; then
- echo ctdbd failed to start: >&2
- tail -n 20 $CTDBD_DIR/log >&2
- exit 1
- fi
-done
-
-for test; do
- echo -n Running $test...
- if $VALGRIND ./ctdb-test --quiet $test > $CTDBD_DIR/test-out 2>&1; then
- echo success.
- else
- echo failure:
- cat $CTDBD_DIR/test-out
- exit 1
- fi
-done
-
-echo Success!
+++ /dev/null
-connect
-# This is just a sanity check
-expect attachdb attached: 1
-attachdb test.tdb false
-expect attachdb attached: 2
-attachdb test2.tdb false
-detachdb 2
-detachdb 1
+++ /dev/null
-# Simple connect, disconnect
-connect
-disconnect
+++ /dev/null
-# Simple connect with explicit path, then disconnect
-connect /tmp/ctdb.socket
-disconnect
+++ /dev/null
-connect
-# This is just a sanity check
-expect attachdb attached: 1
-attachdb test.tdb false
-# This is just a sanity check
-expect readrecordlock lock 1: data ''
-readrecordlock 1 testkey
-releaselock 1 1
+++ /dev/null
-connect
-# This is just a sanity check
-expect attachdb attached: 1
-attachdb test.tdb false
-# This is just a sanity check
-expect readrecordlock lock 1: data ''
-readrecordlock 1 testkey
-writerecord 1 1 test-contents
-releaselock 1 1
-
-expect readrecordlock lock 2: data 'test-contents'
-readrecordlock 1 testkey
-releaselock 1 2
+++ /dev/null
-#!/bin/sh
-# Create docbook-xml links
-
-# most things will be under this path.
-DOCB=/usr/share/sgml/docbook
-
-# potential location for xhtml/docbook.xsl
-XSLDIRS="$DOCB/xsl-stylesheets* $DOCB/stylesheet/xsl/nwalsh"
-
-# potential location for docbookx.dtd
-DTDDIRS="$DOCB/xml-dtd* $DOCB/dtd/xml/*"
-
-# look for a file (arg 1) in a set of dirs (arg 2). If it exists, create a link
-# (arg 3), in the current directory to the dir.
-condlink() {
- file=$1
- dirs=$2
- link=$3
-
- for d in $dirs
- do
- if [ -f $d/$file ]
- then
- dir=$d
- break
- fi
- done
-
- if [ -z "$dir" ]
- then
- echo Docbook support not found. See README. Faking it. >&2
- exit 1
- else
- ln -sfn "$dir" "$link"
- fi
-}
-
-condlink "xhtml/docbook.xsl" "$XSLDIRS" "link-xhtml"
-condlink "docbookx.dtd" "$DTDDIRS" "link-dtd"
+++ /dev/null
-#! /bin/sh
-# Extract XML help from .c file.
-
-FILE=$1
-LINE=`expr $2 + 1`
-
-END=`tail -n +$LINE $1 | fgrep -n '*/' | cut -d: -f1 | head -n +1`
-END=`expr $END - 1`
-
-tail -n +$LINE $1 | head -n $END
+++ /dev/null
-#! /bin/bash
-
-# We could have multiple occurances. Create all of them.
-FILE=$1
-
-TMPF=`mktemp /tmp/gen-help.XXXXXX`
-trap "rm -f $TMPF*" EXIT
-cmdsed='s,.*<command>[ ]*\([^ ]*\)[ ]*</command>.*,\1,p'
-
-STARTLINE=1
-for LINE in `fgrep -n '/*** XML Help:' < $FILE | cut -d: -f1`; do
- if [ -L tools/link-dtd ]; then
- echo '<?xml version="1.0"?>' > $TMPF
- echo '<!DOCTYPE article PUBLIC "-//OASIS//DTD Docbook XML V4.1.2//EN"' \
- >> $TMPF
- echo '"'`pwd`'/tools/link-dtd/docbookx.dtd">' >> $TMPF
- echo '<article><section>' >> $TMPF
- tools/extract-help $FILE $LINE >> $TMPF
- echo '</section></article>' >> $TMPF
-
- tr '\n' ' ' < $TMPF | sed -e 's/[[:space:]]\{2,\}/ /g' |
- xsltproc tools/text.xsl - | fold -w80 -s > $TMPF.txt
-
- COMMAND=`sed -n "$cmdsed" < $TMPF | head -n +1`
- COMMAND_FILE=generated-`basename $FILE .c`-help:$COMMAND
- #echo Creating $COMMAND_FILE
-
- # Output description, in quotes.
- echo 'log_line(LOG_ALWAYS,' > $COMMAND_FILE
-
- TXTSTART=`grep -n '^ 1\.1\.' $TMPF.txt | cut -d: -f1`
- tail -n +`expr $TXTSTART + 2` $TMPF.txt | while read -r TXTLINE; do
- echo "$TXTLINE" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' \
- -e 's/$/\\n"/' >> $COMMAND_FILE
- done
- echo ');' >> $COMMAND_FILE
- else
- tools/extract-help $FILE $LINE > $TMPF
-
- COMMAND=`sed -n "$cmdsed" < $TMPF | head -n +1`
- COMMAND_FILE=generated-`basename $FILE .c`-help:$COMMAND
- echo Faking up $COMMAND_FILE
-
- echo 'log_line(LOG_ALWAYS,' > $COMMAND_FILE
- sed 's/<arg [^>]*>/ /;s/<[^>]*>//g' < $TMPF |
- sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$/\\n"/' \
- >> $COMMAND_FILE
- echo ');' >> $COMMAND_FILE
- fi
-
- STARTLINE=$LINE
-done
+++ /dev/null
-#! /bin/sh
-
-# read a list of C files with inline XML usage given on the command line, and
-# write a usage function on stdout
-
-tmpf=`mktemp /tmp/gen-help.XXXXXX`
-trap "rm -f $tmpf*" EXIT
-quote() {
- sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$/\\n"/'
-}
-
-cat <<EOF
-#include <stdio.h>
-#include "utils.h"
-
-void print_usage(void)
-{
- fprintf(stderr,
-"Usage: ctdb-test [options]\n"
-"Options available:\n"
-"\n"
-EOF
-
-for file in "$@"
-do
- for line in `fgrep -n '/*** XML Argument:' < $file | cut -d: -f1`;
- do
- if [ -L tools/link-dtd ]; then
-
- cat > $tmpf <<EOF
-<?xml version="1.0"?>
-<!DOCTYPE article PUBLIC "-//OASIS//DTD Docbook XML V4.1.2//EN"
-"`pwd`/tools/link-dtd/docbookx.dtd">
-<article>
-EOF
- tools/extract-help $file $line >> $tmpf
- echo '</article>' >> $tmpf
-
- tr '\n' ' ' < $tmpf | sed -e 's/[[:space:]]\{2,\}/ /g' |
- xsltproc tools/usage.xsl - | fold -w80 -s > $tmpf.txt
-
- quote < $tmpf.txt
- else
- # if we don't have docbook, just strip out the tags and grab
- # the first two lines
- tools/extract-help $file $line > $tmpf
- sed 's/<arg [^>]*>/ /;s/<[^>]*>//g;' < $tmpf | head -3 | quote
- fi
-
- done
-done
-
-cat <<EOF
-);
-}
-EOF
+++ /dev/null
-<?xml version="1.0"?>
-
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
- <xsl:output method="text"/>
- <xsl:strip-space elements="*"/>
-
- <xsl:template match="/">
- <xsl:apply-templates select="article"/>
- </xsl:template>
-
- <xsl:template match="article">
- <xsl:apply-templates select="section"/><xsl:text>
-</xsl:text>
- </xsl:template>
-
- <xsl:template match="section">
- <xsl:apply-templates select="title|para|cmdsynopsis|section"/>
- </xsl:template>
-
- <xsl:template match="title">
- <xsl:apply-templates/><xsl:text>
-</xsl:text>
- </xsl:template>
-
- <xsl:template match="subtitle">
- <xsl:apply-templates/><xsl:text>
-</xsl:text>
- </xsl:template>
-
- <xsl:template match="command|filename|varname|computeroutput|constant">
- <xsl:apply-templates/>
- </xsl:template>
-
- <xsl:template match="option">
- <xsl:apply-templates/>
- </xsl:template>
-
- <xsl:template match="screen">
- <xsl:text>
-</xsl:text><xsl:apply-templates/><xsl:text>
-</xsl:text>
- </xsl:template>
-
-
- <xsl:template match="arg">
- <xsl:choose>
- <xsl:when test="@choice='opt'">
- <xsl:text> [</xsl:text><xsl:apply-templates/><xsl:text>]</xsl:text>
- </xsl:when>
- <xsl:otherwise>
- <xsl:text> </xsl:text><xsl:apply-templates/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template match="para">
- <xsl:text>
-</xsl:text>
-<xsl:apply-templates/><xsl:text>
-</xsl:text>
-</xsl:template>
-
- <xsl:template match="cmdsynopsis">
- <xsl:text>
-</xsl:text>
- <xsl:apply-templates select="command|sbr|arg"/><xsl:text>
-</xsl:text>
- </xsl:template>
-
- <xsl:template match="synopfragmentref">
- <xsl:variable name="target" select="id(@linkend)"/>
- <xsl:apply-templates select="$target"/>
- </xsl:template>
-
- <xsl:template match="synopfragment">
- <xsl:apply-templates/>
- </xsl:template>
-
- <xsl:template match="group">
- <xsl:text>{ </xsl:text><xsl:for-each select="arg">
- <xsl:apply-templates/>
- <xsl:if test="position() != last()"><xsl:text> | </xsl:text></xsl:if>
- </xsl:for-each><xsl:text> }</xsl:text>
- </xsl:template>
-
-
- <xsl:template match="replaceable">{<xsl:apply-templates/>}</xsl:template>
-
-
- <xsl:template match="sbr">
- <xsl:text>
-</xsl:text>
-</xsl:template>
-
- <xsl:template match="text()"><xsl:value-of select="."/></xsl:template>
-
- <xsl:template match="node()">
- <xsl:message terminate="yes">Unknown node <xsl:value-of select="name()"/>
-</xsl:message>
- </xsl:template>
-
- <xsl:template match="simplelist">
- <xsl:for-each select="member">
- <xsl:apply-templates/>
- <xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
- </xsl:for-each>
- </xsl:template>
-
-
-</xsl:stylesheet>
+++ /dev/null
-<?xml version="1.0"?>
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
- version="1.0">
- <xsl:output method="text"/>
- <xsl:strip-space elements="*"/>
- <xsl:include href="text.xsl"/>
-
- <xsl:template match="section">
- <xsl:apply-templates select="title"/>
- <xsl:text> </xsl:text><xsl:apply-templates select="subtitle"/>
- </xsl:template>
-
- <xsl:template match="para">
- <xsl:apply-templates/>
- </xsl:template>
-
-</xsl:stylesheet>
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#include "tui.h"
-#include "log.h"
-#include "ctdb-test.h"
-#include "utils.h"
-
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <err.h>
-#include <assert.h>
-#include <readline/readline.h>
-#include <readline/history.h>
-#include <talloc.h>
-#include <dlinklist.h>
-
-int tui_echo_commands;
-int tui_abort_on_fail;
-int tui_quiet;
-int tui_linenum = 1;
-char *extension_path;
-static bool stop;
-
-struct command {
- struct command *next, *prev;
- char name[TUI_MAX_CMD_LEN+1];
- bool (*handler)(int, char **);
- void (*helpfn) (int, char **);
-};
-
-struct pre_post_hook {
- struct pre_post_hook *next, *prev;
- void (*pre)(const char *);
- bool (*post)(const char *);
-};
-
-static struct command *commands;
-static struct pre_post_hook *pre_post_hooks;
-
-static bool tui_exit(int argc, char **argv)
-{
- stop = true;
- return true;
-}
-
-static bool tui_argtest(int argc, char **argv)
-{
- int i;
-
- for (i = 0; i < argc; i++)
- log_line(LOG_UI, "argv[%d]: \"%s\"", i, argv[i]);
-
- return true;
-}
-
-static inline struct command *find_command(const char *name)
-{
- struct command *cmd;
- for (cmd = commands; cmd; cmd = cmd->next)
- if (!strcmp(name, cmd->name))
- return cmd;
-
- return NULL;
-}
-
-bool tui_is_command(const char *name)
-{
- return find_command(name) != NULL;
-}
-
-static void do_pre_commands(const char *cmd)
-{
- struct pre_post_hook *i;
- for (i = pre_post_hooks; i; i = i->next)
- if (i->pre)
- i->pre(cmd);
-}
-
-static bool do_post_commands(const char *cmd)
-{
- struct pre_post_hook *i;
- bool ret = true;
-
- for (i = pre_post_hooks; i; i = i->next)
- if (i->post && !i->post(cmd))
- ret = false;
- return ret;
-}
-
-static bool tui_help(int argc, char **argv)
-{
- struct command *cmd;
-
- if (argc == 1) {
- log_line(LOG_UI, "CTDB tester\n"
- "help is available on the folowing commands:");
- for (cmd = commands; cmd; cmd = cmd->next) {
- if (cmd->helpfn)
- log_line(LOG_UI, "\t%s", cmd->name);
- }
- } else {
- if (!(cmd = find_command(argv[1]))) {
- log_line(LOG_ALWAYS, "No such command '%s'", argv[1]);
- return false;
- }
- if (!cmd->helpfn) {
- log_line(LOG_UI, "No help for the '%s' function",
- argv[1]);
- return false;
- }
- cmd->helpfn(argc-1, argv+1);
- }
- return true;
-
-
-}
-
-static void tui_help_help(int argc, char **argv)
-{
-#include "generated-tui-help:help"
-/*** XML Help:
- <section id="c:help">
- <title><command>help</command></title>
- <para>Displays general help, or help for a specified command</para>
- <cmdsynopsis>
- <command>help</command>
- <arg choice="opt">command</arg>
- </cmdsynopsis>
- <para>With no arguments, <command>help</command> will show general system
- help, and list the available commands. If an argument is specified, then
- <command>help</command> will show help for that command, if
- available.</para>
- </section>
-*/
-}
-
-static void tui_exit_help(int argc, char **argv)
-{
-#include "generated-tui-help:exit"
-/*** XML Help:
- <section id="c:exit">
- <title><command>exit</command>,
- <command>quit</command></title>
- <para>Exit the simulator</para>
- <cmdsynopsis>
- <command>exit</command>
- </cmdsynopsis>
- <cmdsynopsis>
- <command>quit</command>
- </cmdsynopsis>
-
- <para>The <command>exit</command> and <command>quit</command>
- commands are synonomous. They both exit the simulator.
- </para>
- </section>
- */
-}
-
-void script_fail(const char *fmt, ...)
-{
- char *str;
- va_list arglist;
-
- log_line(LOG_ALWAYS, "Script failed at line %i: ", tui_linenum);
-
- va_start(arglist, fmt);
- str = talloc_vasprintf(NULL, fmt, arglist);
- va_end(arglist);
-
- log_line(LOG_ALWAYS, "%s", str);
- talloc_free(str);
-
- check_allocations();
- check_databases();
- exit(EXIT_SCRIPTFAIL);
-}
-
-bool tui_do_command(int argc, char *argv[], bool abort)
-{
- struct command *cmd;
- bool ret = true;
-
- if ((cmd = find_command(argv[0]))) {
- do_pre_commands(cmd->name);
- if (!cmd->handler(argc, argv)) {
- /* Abort on UNEXPECTED failure. */
- if (!log_line(LOG_UI, "%s: command failed", argv[0])
- && abort)
- script_fail("%s failed", argv[0]);
- ret = false;
- }
- if (!do_post_commands(cmd->name))
- ret = false;
- return ret;
- }
-
- if (abort)
- script_fail("%s not found", argv[0]);
-
- log_line(LOG_ALWAYS, "%s: command not found", argv[0]);
- return false;
-}
-
-/**
- * backslash-escape a binary data block into a newly allocated
- * string
- *
- * @param src a pointer to the data block
- * @param src_len the length of the data block
- * @return NULL if out of memory, or a pointer to the allocated escaped
- * string, which is terminated with a '\0' character
- */
-static char *escape(const char *src, size_t src_len)
-{
- static const char hexbuf[]= "0123456789abcdef";
- char *dest, *p;
- size_t i;
-
- /* src_len * 4 is always safe, it's the longest escape
- sequence for all characters */
- dest = talloc_array(src, char, src_len * 4 + 1);
- p = dest;
-
- for (i = 0; i < src_len; i++) {
- if (src[i] == '\n') {
- *p++ = '\\';
- *p++ = 'n';
- } else if (src[i] == '\r') {
- *p++ = '\\';
- *p++ = 'r';
- } else if (src[i] == '\0') {
- *p++ = '\\';
- *p++ = '0';
- } else if (src[i] == '\t') {
- *p++ = '\\';
- *p++ = 't';
- } else if (src[i] == '\\') {
- *p++ = '\\';
- *p++ = '\\';
- } else if (src[i] & 0x80 || (src[i] & 0xe0) == 0) {
- *p++ = '\\';
- *p++ = 'x';
- *p++ = hexbuf[(src[i] >> 4) & 0xf];
- *p++ = hexbuf[src[i] & 0xf];
- } else
- *p++ = src[i];
- }
-
- *p++ = 0;
- return dest;
-}
-
-/* Process `command`: update off to point to tail backquote */
-static char *backquote(char *line, unsigned int *off)
-{
- char *end, *cmdstr, *str;
- FILE *cmdfile;
- size_t used, len, i;
- int status;
-
- /* Skip first backquote, look for next one. */
- (*off)++;
- end = strchr(line + *off, '`');
- if (!end)
- script_fail("no matching \"`\" found");
-
- len = end - (line + *off);
- cmdstr = talloc_asprintf(line, "PATH=%s; %.*s",
- extension_path, (int)len, line + *off);
- cmdfile = popen(cmdstr, "r");
- if (!cmdfile)
- script_fail("failed to popen '%s': %s\n",
- cmdstr, strerror(errno));
-
- /* Jump to backquote. */
- *off += len;
-
- /* Read command output. */
- used = 0;
- len = 1024;
- str = talloc_array(line, char, len);
-
- while ((i = fread(str + used, 1, len - used, cmdfile)) != 0) {
- used += i;
- if (used == len) {
- if (len > 1024*1024)
- script_fail("command '%s' output too long\n",
- cmdstr);
- len *= 2;
- str = talloc_realloc(line, str, char, len);
- }
- }
- status = pclose(cmdfile);
- if (status == -1 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
- script_fail("command '%s' failed\n", cmdstr);
-
- return escape(str, used);
-}
-
-static char *append_char(char **argv, unsigned int argc, char c)
-{
- if (!argv[argc])
- return talloc_asprintf(argv, "%c", c);
- return talloc_asprintf_append(argv[argc], "%c", c);
-}
-
-static char *append_string(char **argv, unsigned int argc, const char *str)
-{
- if (!argv[argc])
- return talloc_asprintf(argv, "%s", str);
- return talloc_asprintf_append(argv[argc], "%s", str);
-}
-
-static void process_line(char *line, unsigned int off)
-{
- unsigned int argc, i;
- char **argv;
-
- if (tui_echo_commands)
- printf("%u:%s\n", tui_linenum, line + off);
-
- /* Talloc argv off line so commands can use it for auto-cleanup. */
- argv = talloc_zero_array(line, char *, TUI_MAX_ARGS+1);
- argc = 0;
- for (i = off; line[i]; i++) {
- if (isspace(line[i])) {
- /* If anything in this arg, move to next. */
- if (argv[argc])
- argc++;
- } else if (line[i] == '`') {
- char *inside = backquote(line, &i);
- argv[argc] = append_string(argv, argc, inside);
- } else {
- /* If it is a comment, stop before we process `` */
- if (!argv[0] && line[i] == '#')
- goto out;
-
- argv[argc] = append_char(argv, argc, line[i]);
- }
- }
-
- if (argv[0]) {
- if (argv[argc])
- argv[++argc] = NULL;
- tui_do_command(argc, argv, tui_abort_on_fail);
- }
-
-out:
- tui_linenum++;
- return;
-}
-
-static void readline_process_line(char *line)
-{
- char *talloc_line;
- if (!line) {
- stop = true;
- return;
- }
-
- add_history(line);
-
- /* Readline isn't talloc-aware, so copy string: functions can
- * hang temporary variables off this. */
- talloc_line = talloc_strdup(NULL, line);
- process_line(talloc_line, 0);
- talloc_free(talloc_line);
-}
-
-static void run_whole_file(int fd)
-{
- char *file, *p;
- size_t size, len;
-
- file = grab_fd(fd, &size);
- if (!file)
- err(1, "Grabbing file");
-
- for (p = file; p < file + size; p += len+1) {
- len = strcspn(p, "\n");
- p[len] = '\0';
- process_line(file, p - file);
- }
-}
-
-void tui_run(int fd)
-{
- tui_register_command("exit", tui_exit, tui_exit_help);
- tui_register_command("quit", tui_exit, tui_exit_help);
- tui_register_command("q", tui_exit, tui_exit_help);
- tui_register_command("test", tui_argtest, NULL);
- tui_register_command("help", tui_help, tui_help_help);
-
- if (fd == STDIN_FILENO) {
- stop = false;
- rl_callback_handler_install(tui_quiet ? "" : "> ",
- readline_process_line);
- while (!stop)
- rl_callback_read_char();
- rl_callback_handler_remove();
- if (!tui_quiet)
- printf("\n");
- } else
- run_whole_file(fd);
-}
-
-int tui_register_pre_post_hook(void (*pre)(const char *),
- bool (*post)(const char *))
-{
- struct pre_post_hook *h;
-
- h = talloc(NULL, struct pre_post_hook);
- h->pre = pre;
- h->post = post;
- DLIST_ADD(pre_post_hooks, h);
- return 0;
-}
-
-int tui_register_command(const char *command,
- bool (*handler)(int, char **),
- void (*helpfn)(int, char **))
-{
- struct command *cmd;
-
- assert(strlen(command) < TUI_MAX_CMD_LEN);
-
- cmd = talloc(NULL, struct command);
- strncpy(cmd->name, command, TUI_MAX_CMD_LEN);
- cmd->handler = handler;
- cmd->helpfn = helpfn;
-
- DLIST_ADD(commands, cmd);
-
- return 0;
-}
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Jeremy Kerr & Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef __HAVE_TUI_H
-#define __HAVE_TUI_H
-
-#include <stdbool.h>
-
-#define TUI_MAX_CMD_LEN 1024
-#define TUI_MAX_ARGS 128
-
-int tui_register_command(const char *command,
- bool (*handler)(int argc, char **argv),
- void (*helpfn)(int argc, char **argv));
-
-int tui_register_pre_post_hook(void (*pre)(const char *),
- bool (*post)(const char *));
-
-void tui_run(int fd);
-
-bool tui_do_command(int argc, char *argv[], bool abort);
-
-/* Is this a valid command? Sanity check for expect. */
-bool tui_is_command(const char *name);
-
-/* A script test failed (a command failed with -e, or an expect failed). */
-void script_fail(const char *fmt, ...) __attribute__((noreturn));
-
-extern int tui_echo_commands;
-extern int tui_abort_on_fail;
-extern int tui_quiet;
-extern int tui_linenum;
-
-#endif /* __HAVE_TUI_H */
+++ /dev/null
-/*
-
-This file is taken from nfsim (http://ozlabs.org/~jk/projects/nfsim/)
-
-Copyright (c) 2003,2004 Rusty Russell
-
-This file is part of nfsim.
-
-nfsim is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-nfsim 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 nfsim; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-*/
-
-#ifndef _UTILS_H
-#define _UTILS_H
-#include <stdbool.h>
-#include <string.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <getopt.h>
-
-/* Is A == B ? */
-#define streq(a,b) (strcmp((a),(b)) == 0)
-
-/* Does A start with B ? */
-#define strstarts(a,b) (strncmp((a),(b),strlen(b)) == 0)
-
-/* Does A end in B ? */
-static inline bool strends(const char *a, const char *b)
-{
- if (strlen(a) < strlen(b))
- return false;
-
- return streq(a + strlen(a) - strlen(b), b);
-}
-
-#define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0]))
-
-/* Paste two tokens together. */
-#define ___cat(a,b) a ## b
-#define __cat(a,b) ___cat(a,b)
-
-/* Try to give a unique identifier: this comes close, iff used as static. */
-#define __unique_id(stem) __cat(__cat(__uniq,stem),__LINE__)
-
-enum exitcodes {
- /* EXIT_SUCCESS, EXIT_FAILURE is in stdlib.h */
- EXIT_SCRIPTFAIL = EXIT_FAILURE + 1,
-};
-
-/* init code */
-typedef void (*initcall_t)(void);
-#define init_call(fn) \
- static initcall_t __initcall_##fn \
- __attribute__((__unused__)) \
- __attribute__((__section__("init_call"))) = &fn
-
-/* distributed command line options */
-struct cmdline_option
-{
- struct option opt;
- void (*parse)(struct option *opt);
-} __attribute__((aligned(64))); /* align it to 64 for 64bit arch,
- * <rusty> LaF0rge: space is cheap. A comment might be nice. */
-
-#define cmdline_opt(_name, _has_arg, _c, _fn) \
- static struct cmdline_option __cat(__cmdlnopt_,__unique_id(_fn)) \
- __attribute__((__unused__)) \
- __attribute__((__section__("cmdline"))) \
- = { .opt = { .name = _name, .has_arg = _has_arg, .val = _c }, \
- .parse = _fn }
-
-/* In generated-usage.c */
-void print_usage(void);
-
-#endif /* _UTILS_H */
+++ /dev/null
-/*
- * Example program to demonstrate the libctdb api
- *
- * 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/>.
- */
-
-/*
- * This program needs to be linked with libtdb and libctdb
- * (You need these packages installed: libtdb libtdb-devel
- * ctdb and ctdb-devel)
- *
- * This program can then be compiled using
- * gcc -o tst tst.c -ltdb -lctdb
- *
- *
- */
-#include <stdio.h>
-#include <stdint.h>
-#include <poll.h>
-#include <fcntl.h>
-#include <string.h>
-#include <stdlib.h>
-#include <err.h>
-#include <stdbool.h>
-#include <syslog.h>
-#include <tdb.h>
-#include <ctdb.h>
-#include <ctdb_protocol.h>
-
-TDB_DATA key;
-
-
-char *ctdb_addr_to_str(ctdb_sock_addr *addr)
-{
- static char cip[128] = "";
-
- switch (addr->sa.sa_family) {
- case AF_INET:
- inet_ntop(addr->ip.sin_family, &addr->ip.sin_addr, cip, sizeof(cip));
- break;
- case AF_INET6:
- inet_ntop(addr->ip6.sin6_family, &addr->ip6.sin6_addr, cip, sizeof(cip));
- break;
- default:
- printf("ERROR, unknown family %u\n", addr->sa.sa_family);
- }
-
- return cip;
-}
-
-void print_nodemap(struct ctdb_node_map *nodemap)
-{
- int i;
-
- printf("number of nodes:%d\n", nodemap->num);
- for (i=0;i<nodemap->num;i++) {
- printf("Node:%d Address:%s Flags:%s%s%s%s%s%s\n",
- nodemap->nodes[i].pnn,
- ctdb_addr_to_str(&nodemap->nodes[i].addr),
- nodemap->nodes[i].flags&NODE_FLAGS_DISCONNECTED?"DISCONNECTED ":"",
- nodemap->nodes[i].flags&NODE_FLAGS_UNHEALTHY?"UNHEALTHY ":"",
- nodemap->nodes[i].flags&NODE_FLAGS_PERMANENTLY_DISABLED?"ADMIN DISABLED ":"",
- nodemap->nodes[i].flags&NODE_FLAGS_BANNED?"BANNED ":"",
- nodemap->nodes[i].flags&NODE_FLAGS_DELETED?"DELETED ":"",
- nodemap->nodes[i].flags&NODE_FLAGS_STOPPED?"STOPPED ":"");
- }
-}
-
-void msg_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
-{
- printf("Message received on port %llx : %s\n", srvid, data.dptr);
-}
-
-void rip_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
-{
- printf("RELEASE IP message for %s\n", data.dptr);
-}
-
-void tip_h(struct ctdb_connection *ctdb, uint64_t srvid, TDB_DATA data, void *private_data)
-{
- printf("TAKE IP message for %s\n", data.dptr);
-}
-
-static void gnm_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- bool status;
- struct ctdb_node_map *nodemap;
-
- status = ctdb_getnodemap_recv(ctdb, req, &nodemap);
- ctdb_request_free(req);
- if (!status) {
- printf("Error reading NODEMAP\n");
- return;
- }
- printf("ASYNC response to getnodemap:\n");
- print_nodemap(nodemap);
- ctdb_free_nodemap(nodemap);
-}
-
-void print_ips(struct ctdb_all_public_ips *ips)
-{
- int i;
-
- printf("Num public ips:%d\n", ips->num);
- for (i=0; i<ips->num;i++) {
- printf("%s hosted on node %d\n",
- ctdb_addr_to_str(&ips->ips[i].addr),
- ips->ips[i].pnn);
- }
-}
-
-static void ips_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- bool status;
- struct ctdb_all_public_ips *ips;
-
- status = ctdb_getpublicips_recv(ctdb, req, &ips);
- ctdb_request_free(req);
- if (!status) {
- printf("Error reading PUBLIC IPS\n");
- return;
- }
- printf("ASYNC response to getpublicips:\n");
- print_ips(ips);
- ctdb_free_publicips(ips);
-}
-
-static void pnn_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- bool status;
- uint32_t pnn;
-
- status = ctdb_getpnn_recv(ctdb, req, &pnn);
- ctdb_request_free(req);
- if (!status) {
- printf("Error reading PNN\n");
- return;
- }
- printf("ASYNC RESPONSE TO GETPNN: pnn:%d\n", pnn);
-}
-
-static void rm_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- bool status;
- uint32_t rm;
-
- status = ctdb_getrecmaster_recv(ctdb, req, &rm);
- ctdb_request_free(req);
- if (!status) {
- printf("Error reading RECMASTER\n");
- return;
- }
-
- printf("GETRECMASTER ASYNC: recmaster:%d\n", rm);
-}
-
-/*
- * example on how to first read(non-existing recortds are implicitely created
- * on demand) a record and change it in the callback.
- * This forms the atom for the read-modify-write cycle.
- *
- * Pure read, or pure write are just special cases of this cycle.
- */
-static void rrl_cb(struct ctdb_db *ctdb_db,
- struct ctdb_lock *lock, TDB_DATA outdata, void *private)
-{
- TDB_DATA data;
- char tmp[256];
- bool *rrl_cb_called = private;
-
- *rrl_cb_called = true;
-
- if (!lock) {
- printf("rrl_cb returned error\n");
- return;
- }
-
- printf("rrl size:%d data:%.*s\n", outdata.dsize,
- outdata.dsize, outdata.dptr);
- if (outdata.dsize == 0) {
- tmp[0] = 0;
- } else {
- strcpy(tmp, outdata.dptr);
- }
- strcat(tmp, "*");
-
- data.dptr = tmp;
- data.dsize = strlen(tmp) + 1;
- if (!ctdb_writerecord(ctdb_db, lock, data))
- printf("Error writing data!\n");
-
- /* Release the lock as quickly as possible */
- ctdb_release_lock(ctdb_db, lock);
-
- printf("Wrote new record : %s\n", tmp);
-
-}
-
-static bool registered = false;
-void message_handler_cb(struct ctdb_connection *ctdb,
- struct ctdb_request *req, void *private)
-{
- if (!ctdb_set_message_handler_recv(ctdb, req)) {
- err(1, "registering message");
- }
- ctdb_request_free(req);
- printf("Message handler registered\n");
- registered = true;
-}
-
-static int traverse_callback(struct ctdb_connection *ctdb_connection, struct ctdb_db *ctdb_db, int status, TDB_DATA key, TDB_DATA data, void *private_data)
-{
- if (status == TRAVERSE_STATUS_FINISHED) {
- printf("Traverse finished\n");
- return 0;
- }
- if (status == TRAVERSE_STATUS_ERROR) {
- printf("Traverse failed\n");
- return 1;
- }
-
- printf("traverse callback status:%d\n", status);
- printf("key: %d [%s]\n", key.dsize, key.dptr);
- printf("data:%d [%s]\n", data.dsize, data.dptr);
-
- return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
- struct ctdb_connection *ctdb_connection;
- struct ctdb_request *handle;
- struct ctdb_db *ctdb_db_context;
- struct ctdb_node_map *nodemap;
- struct pollfd pfd;
- uint32_t recmaster;
- TDB_DATA msg;
- bool rrl_cb_called = false;
- uint64_t srvid;
-
- ctdb_log_level = LOG_DEBUG;
- ctdb_connection = ctdb_connect("/tmp/ctdb.socket",
- ctdb_log_file, stderr);
- if (!ctdb_connection)
- err(1, "Connecting to /tmp/ctdb.socket");
-
- pfd.fd = ctdb_get_fd(ctdb_connection);
-
- srvid = CTDB_SRVID_TEST_RANGE|55;
- handle = ctdb_set_message_handler_send(ctdb_connection, srvid,
- msg_h, NULL,
- message_handler_cb, &srvid);
- if (handle == NULL) {
- printf("Failed to register message port\n");
- exit(10);
- }
-
- /* Hack for testing: this makes sure registrations went out. */
- while (!registered) {
- ctdb_service(ctdb_connection, POLLIN|POLLOUT);
- }
-
- handle = ctdb_set_message_handler_send(ctdb_connection,
- CTDB_SRVID_RELEASE_IP,
- rip_h, NULL,
- message_handler_cb, NULL);
- if (handle == NULL) {
- printf("Failed to register message port for RELEASE IP\n");
- exit(10);
- }
-
- handle = ctdb_set_message_handler_send(ctdb_connection,
- CTDB_SRVID_TAKE_IP,
- tip_h, NULL,
- message_handler_cb, NULL);
- if (handle == NULL) {
- printf("Failed to register message port for TAKE IP\n");
- exit(10);
- }
-
- msg.dptr="HelloWorld";
- msg.dsize = strlen(msg.dptr);
-
- srvid = CTDB_SRVID_TEST_RANGE|55;
- if (!ctdb_send_message(ctdb_connection, 0, srvid, msg)) {
- printf("Failed to send message. Aborting\n");
- exit(10);
- }
-
- handle = ctdb_getrecmaster_send(ctdb_connection, 0, rm_cb, NULL);
- if (handle == NULL) {
- printf("Failed to send get_recmaster control\n");
- exit(10);
- }
-
- ctdb_db_context = ctdb_attachdb(ctdb_connection, "test_test.tdb",
- false, 0);
- if (!ctdb_db_context) {
- printf("Failed to attach to database\n");
- exit(10);
- }
-
- /*
- * SYNC call with callback to read the recmaster
- * calls the blocking sync function.
- * Avoid this mode for performance critical tasks
- */
- if (!ctdb_getrecmaster(ctdb_connection, CTDB_CURRENT_NODE, &recmaster)) {
- printf("Failed to receive response to getrecmaster\n");
- exit(10);
- }
- printf("GETRECMASTER SYNC: recmaster:%d\n", recmaster);
-
-
- handle = ctdb_getpnn_send(ctdb_connection, CTDB_CURRENT_NODE,
- pnn_cb, NULL);
- if (handle == NULL) {
- printf("Failed to send get_pnn control\n");
- exit(10);
- }
-
- /* In the non-contended case the callback might be invoked
- * immediately, before ctdb_readrecordlock_async() returns.
- * In the contended case the callback will be invoked later.
- *
- * Normally an application would not care whether the callback
- * has already been invoked here or not, but if the application
- * needs to know, it can use the *private_data pointer
- * to pass data through to the callback and back.
- */
- if (!ctdb_readrecordlock_async(ctdb_db_context, key,
- rrl_cb, &rrl_cb_called)) {
- printf("Failed to send READRECORDLOCK\n");
- exit(10);
- }
- if (!rrl_cb_called) {
- printf("READRECORDLOCK is async\n");
- }
-
- /*
- * Read the nodemap from a node (async)
- */
- handle = ctdb_getnodemap_send(ctdb_connection, CTDB_CURRENT_NODE,
- gnm_cb, NULL);
- if (handle == NULL) {
- printf("Failed to send get_nodemap control\n");
- exit(10);
- }
-
- /*
- * Read the list of public ips from a node (async)
- */
- handle = ctdb_getpublicips_send(ctdb_connection, CTDB_CURRENT_NODE,
- ips_cb, NULL);
- if (handle == NULL) {
- printf("Failed to send getpublicips control\n");
- exit(10);
- }
-
- /*
- * Read the nodemap from a node (sync)
- */
- if (!ctdb_getnodemap(ctdb_connection, CTDB_CURRENT_NODE,
- &nodemap)) {
- printf("Failed to receive response to getrecmaster\n");
- exit(10);
- }
- printf("SYNC response to getnodemap:\n");
- print_nodemap(nodemap);
- ctdb_free_nodemap(nodemap);
-
- printf("Traverse the test_test.tdb database\n");
- ctdb_traverse_async(ctdb_db_context, traverse_callback, NULL);
-
- for (;;) {
-
- pfd.events = ctdb_which_events(ctdb_connection);
- if (poll(&pfd, 1, -1) < 0) {
- printf("Poll failed");
- exit(10);
- }
- if (ctdb_service(ctdb_connection, pfd.revents) < 0) {
- err(1, "Failed to service");
- }
- }
-
- return 0;
-}
%{_includedir}/ctdb_protocol.h
%{_includedir}/ctdb_private.h
%{_includedir}/ctdb_typesafe_cb.h
-%{_libdir}/libctdb.a
%package tests
Summary: CTDB test suite