Example #1
0
/*
  process a control request
 */
static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb, 
				     struct ctdb_req_control_old *c,
				     TDB_DATA indata,
				     TDB_DATA *outdata, uint32_t srcnode,
				     const char **errormsg,
				     bool *async_reply)
{
	uint32_t opcode = c->opcode;
	uint64_t srvid = c->srvid;
	uint32_t client_id = c->client_id;

	switch (opcode) {
	case CTDB_CONTROL_PROCESS_EXISTS: {
		CHECK_CONTROL_DATA_SIZE(sizeof(pid_t));
		return ctdb_control_process_exists(ctdb, *(pid_t *)indata.dptr);
	}

	case CTDB_CONTROL_SET_DEBUG: {
		CHECK_CONTROL_DATA_SIZE(sizeof(int32_t));
		DEBUGLEVEL = *(int32_t *)indata.dptr;
		return 0;
	}

	case CTDB_CONTROL_GET_DEBUG: {
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&(DEBUGLEVEL);
		outdata->dsize = sizeof(DEBUGLEVEL);
		return 0;
	}

	case CTDB_CONTROL_STATISTICS: {
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb->statistics.memory_used = talloc_total_size(NULL);
		ctdb->statistics.num_clients = ctdb->num_clients;
		ctdb->statistics.frozen = (ctdb_db_all_frozen(ctdb) ? 1 : 0);
		ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
		ctdb->statistics.statistics_current_time = timeval_current();

		outdata->dptr = (uint8_t *)&ctdb->statistics;
		outdata->dsize = sizeof(ctdb->statistics);
		return 0;
	}

	case CTDB_CONTROL_GET_ALL_TUNABLES: {
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&ctdb->tunable;
		outdata->dsize = sizeof(ctdb->tunable);
		return 0;
	}

	case CTDB_CONTROL_DUMP_MEMORY: {
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_dump_memory(ctdb, outdata);
	}

	case CTDB_CONTROL_STATISTICS_RESET: {
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(0);
		ZERO_STRUCT(ctdb->statistics);
		for (ctdb_db = ctdb->db_list;
		     ctdb_db != NULL;
		     ctdb_db = ctdb_db->next) {
			ctdb_db_statistics_reset(ctdb_db);
		}
		ctdb->statistics.statistics_start_time = timeval_current();
		return 0;
	}

	case CTDB_CONTROL_GETVNNMAP:
		return ctdb_control_getvnnmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_DBMAP:
		return ctdb_control_getdbmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_NODEMAPv4:
		return control_not_implemented("GET_NODEMAPv4", "GET_NODEMAP");

	case CTDB_CONTROL_GET_NODEMAP:
		return ctdb_control_getnodemap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_GET_NODES_FILE:
		return ctdb_control_getnodesfile(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_RELOAD_NODES_FILE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_reload_nodes_file(ctdb, opcode);

	case CTDB_CONTROL_SET_DB_STICKY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_set_db_sticky(ctdb, ctdb_db);
	}

	case CTDB_CONTROL_SETVNNMAP:
		return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata);

	case CTDB_CONTROL_PULL_DB: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb));
		return ctdb_control_pull_db(ctdb, indata, outdata);

	case CTDB_CONTROL_SET_DMASTER: 
		return control_not_implemented("SET_DMASTER", NULL);

	case CTDB_CONTROL_PUSH_DB:
		return ctdb_control_push_db(ctdb, indata);

	case CTDB_CONTROL_GET_RECMODE: {
		return ctdb->recovery_mode;
	}

	case CTDB_CONTROL_SET_RECMASTER: {
		return ctdb_control_set_recmaster(ctdb, opcode, indata);
	}

	case CTDB_CONTROL_GET_RECMASTER:
		return ctdb->recovery_master;

	case CTDB_CONTROL_GET_PID:
		return getpid();

	case CTDB_CONTROL_GET_PNN:
		return ctdb->pnn;

	case CTDB_CONTROL_PING:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb->num_clients;

	case CTDB_CONTROL_GET_RUNSTATE:
		CHECK_CONTROL_DATA_SIZE(0);
		outdata->dptr = (uint8_t *)&ctdb->runstate;
		outdata->dsize = sizeof(uint32_t);
		return 0;


	case CTDB_CONTROL_SET_DB_READONLY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_set_db_readonly(ctdb, ctdb_db);
	}
	case CTDB_CONTROL_GET_DBNAME: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		outdata->dptr = discard_const(ctdb_db->db_name);
		outdata->dsize = strlen(ctdb_db->db_name)+1;
		return 0;
	}

	case CTDB_CONTROL_GETDBPATH: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		outdata->dptr = discard_const(ctdb_db->db_path);
		outdata->dsize = strlen(ctdb_db->db_path)+1;
		return 0;
	}

	case CTDB_CONTROL_DB_ATTACH:
	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false, client_id, c, async_reply);

	case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
	  return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true, client_id, c, async_reply);

	case CTDB_CONTROL_SET_CALL:
		return control_not_implemented("SET_CALL", NULL);

	case CTDB_CONTROL_TRAVERSE_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
		return ctdb_control_traverse_start(ctdb, indata, outdata, srcnode, client_id);

	case CTDB_CONTROL_TRAVERSE_START_EXT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start_ext));
		return ctdb_control_traverse_start_ext(ctdb, indata, outdata, srcnode, client_id);

	case CTDB_CONTROL_TRAVERSE_ALL:
		return ctdb_control_traverse_all(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_ALL_EXT:
		return ctdb_control_traverse_all_ext(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_DATA:
		return ctdb_control_traverse_data(ctdb, indata, outdata);

	case CTDB_CONTROL_TRAVERSE_KILL:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
		return ctdb_control_traverse_kill(ctdb, indata, outdata, srcnode);

	case CTDB_CONTROL_REGISTER_SRVID:
		return daemon_register_message_handler(ctdb, client_id, srvid);

	case CTDB_CONTROL_DEREGISTER_SRVID:
		return daemon_deregister_message_handler(ctdb, client_id, srvid);

	case CTDB_CONTROL_CHECK_SRVIDS:
		return daemon_check_srvids(ctdb, indata, outdata);

	case CTDB_CONTROL_ENABLE_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_ltdb_enable_seqnum(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_UPDATE_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		return ctdb_ltdb_update_seqnum(ctdb, *(uint32_t *)indata.dptr, srcnode);

	case CTDB_CONTROL_FREEZE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_freeze(ctdb, c, async_reply);

	case CTDB_CONTROL_THAW:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_thaw(ctdb, (uint32_t)c->srvid, true);

	case CTDB_CONTROL_SET_RECMODE:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		return ctdb_control_set_recmode(ctdb, c, indata, async_reply, errormsg);

	case CTDB_CONTROL_GET_MONMODE: 
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_monitoring_mode(ctdb);
		
	case CTDB_CONTROL_ENABLE_MONITOR: 
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb_enable_monitoring(ctdb);
		return 0;
	
	case CTDB_CONTROL_RUN_EVENTSCRIPTS: 
		return ctdb_run_eventscripts(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_DISABLE_MONITOR: 
		CHECK_CONTROL_DATA_SIZE(0);
		ctdb_disable_monitoring(ctdb);
		return 0;

	case CTDB_CONTROL_SHUTDOWN:
		DEBUG(DEBUG_NOTICE,("Received SHUTDOWN command.\n"));
		ctdb_shutdown_sequence(ctdb, 0);
		/* In case above returns due to duplicate shutdown */
		return 0;

	case CTDB_CONTROL_TAKEOVER_IPv4:
		return control_not_implemented("TAKEOVER_IPv4", "TAKEOVER_IP");

	case CTDB_CONTROL_TAKEOVER_IP:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
		return ctdb_control_takeover_ip(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_RELEASE_IPv4:
		return control_not_implemented("RELEASE_IPv4", "RELEASE_IP");

	case CTDB_CONTROL_RELEASE_IP:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
		return ctdb_control_release_ip(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_IPREALLOCATED:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_ipreallocated(ctdb, c, async_reply);

	case CTDB_CONTROL_GET_PUBLIC_IPSv4:
		return control_not_implemented("GET_PUBLIC_IPSv4",
					       "GET_PUBLIC_IPS");

	case CTDB_CONTROL_GET_PUBLIC_IPS:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_public_ips(ctdb, c, outdata);

	case CTDB_CONTROL_TCP_CLIENT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_client(ctdb, client_id, indata);

	case CTDB_CONTROL_STARTUP: 
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_startup(ctdb, srcnode);

	case CTDB_CONTROL_TCP_ADD: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_add(ctdb, indata, false);

	case CTDB_CONTROL_TCP_ADD_DELAYED_UPDATE: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_add(ctdb, indata, true);

	case CTDB_CONTROL_TCP_REMOVE: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_tcp_remove(ctdb, indata);

	case CTDB_CONTROL_SET_TUNABLE:
		return ctdb_control_set_tunable(ctdb, indata);

	case CTDB_CONTROL_GET_TUNABLE:
		return ctdb_control_get_tunable(ctdb, indata, outdata);

	case CTDB_CONTROL_LIST_TUNABLES:
		return ctdb_control_list_tunables(ctdb, outdata);

	case CTDB_CONTROL_MODIFY_FLAGS:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_flag_change));
		return ctdb_control_modflags(ctdb, indata);

	case CTDB_CONTROL_KILL_TCP: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_connection));
		return ctdb_control_kill_tcp(ctdb, indata);

	case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
		return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata);

	case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
		/* data size is verified in the called function */
		return ctdb_control_set_tcp_tickle_list(ctdb, indata);

	case CTDB_CONTROL_REGISTER_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_register_server_id(ctdb, client_id, indata);

	case CTDB_CONTROL_UNREGISTER_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_unregister_server_id(ctdb, indata);

	case CTDB_CONTROL_CHECK_SERVER_ID: 
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_id));
		return ctdb_control_check_server_id(ctdb, indata);

	case CTDB_CONTROL_GET_SERVER_ID_LIST:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_server_id_list(ctdb, outdata);

	case CTDB_CONTROL_PERSISTENT_STORE:
		return control_not_implemented("PERSISTENT_STORE", NULL);

	case CTDB_CONTROL_UPDATE_RECORD:
		return ctdb_control_update_record(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_SEND_GRATUITOUS_ARP:
		return ctdb_control_send_gratious_arp(ctdb, indata);

	case CTDB_CONTROL_TRANSACTION_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_transaction_start(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_TRANSACTION_COMMIT:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_WIPE_DATABASE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_wipe_database(ctdb, indata);

	case CTDB_CONTROL_UPTIME:
		return ctdb_control_uptime(ctdb, outdata);

	case CTDB_CONTROL_START_RECOVERY:
		return ctdb_control_start_recovery(ctdb, c, async_reply);

	case CTDB_CONTROL_END_RECOVERY:
		return ctdb_control_end_recovery(ctdb, c, async_reply);

	case CTDB_CONTROL_TRY_DELETE_RECORDS:
		return ctdb_control_try_delete_records(ctdb, indata, outdata);

	case CTDB_CONTROL_ADD_PUBLIC_IP:
		return ctdb_control_add_public_address(ctdb, indata);

	case CTDB_CONTROL_DEL_PUBLIC_IP:
		return ctdb_control_del_public_address(ctdb, c, indata,
						       async_reply);

	case CTDB_CONTROL_GET_CAPABILITIES:
		return ctdb_control_get_capabilities(ctdb, outdata);

	case CTDB_CONTROL_START_PERSISTENT_UPDATE:
		return ctdb_control_start_persistent_update(ctdb, c, indata);

	case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
		return ctdb_control_cancel_persistent_update(ctdb, c, indata);

	case CTDB_CONTROL_TRANS2_COMMIT:
	case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
		return control_not_implemented("TRANS2_COMMIT", "TRANS3_COMMIT");

	case CTDB_CONTROL_TRANS2_ERROR:
		return control_not_implemented("TRANS2_ERROR", NULL);

	case CTDB_CONTROL_TRANS2_FINISHED:
		return control_not_implemented("TRANS2_FINISHED", NULL);

	case CTDB_CONTROL_TRANS2_ACTIVE:
		return control_not_implemented("TRANS2_ACTIVE", NULL);

	case CTDB_CONTROL_TRANS3_COMMIT:
		return ctdb_control_trans3_commit(ctdb, c, indata, async_reply);

	case CTDB_CONTROL_RECD_PING:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_recd_ping(ctdb);

	case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_get_event_script_status(ctdb, *(uint32_t *)indata.dptr, outdata);

	case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
		CHECK_CONTROL_DATA_SIZE(sizeof(double));
		CTDB_UPDATE_RECLOCK_LATENCY(ctdb, "recd reclock", reclock.recd, *((double *)indata.dptr));
		return 0;
	case CTDB_CONTROL_GET_RECLOCK_FILE:
		CHECK_CONTROL_DATA_SIZE(0);
		if (ctdb->recovery_lock_file != NULL) {
			outdata->dptr  = discard_const(ctdb->recovery_lock_file);
			outdata->dsize = strlen(ctdb->recovery_lock_file) + 1;
		}
		return 0;
	case CTDB_CONTROL_SET_RECLOCK_FILE: {
		char *t;

		if (indata.dsize == 0) {
			TALLOC_FREE(ctdb->recovery_lock_file);
			return 0;
		}

		/* Return silent success if unchanged.  Recovery
		 * master updates all nodes on each recovery - we
		 * don't need the extra memory allocation or log
		 * message each time. */
		if (ctdb->recovery_lock_file != NULL &&
		    strcmp(discard_const(indata.dptr),
			   ctdb->recovery_lock_file) == 0) {
			return 0;
		}

		t = talloc_strdup(ctdb, discard_const(indata.dptr));
		if (t == NULL) {
			DEBUG(DEBUG_ERR, ("Out of memory in SET_RECLOCK_FILE\n"));
			return -1;
		}

		talloc_free(ctdb->recovery_lock_file);
		ctdb->recovery_lock_file = t;
		DEBUG(DEBUG_NOTICE, ("Updated recovery lock file to %s\n", t));

		return 0;
	}

	case CTDB_CONTROL_STOP_NODE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_stop_node(ctdb);

	case CTDB_CONTROL_CONTINUE_NODE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_continue_node(ctdb);

	case CTDB_CONTROL_SET_NATGWSTATE:
		return control_not_implemented("SET_NATGWSTATE", NULL);

	case CTDB_CONTROL_SET_LMASTERROLE: {
		uint32_t lmasterrole;

		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		lmasterrole = *(uint32_t *)indata.dptr;
		if (lmasterrole == 0) {
			ctdb->capabilities &= ~CTDB_CAP_LMASTER;
		} else {
			ctdb->capabilities |= CTDB_CAP_LMASTER;
		}
		return 0;
	}

	case CTDB_CONTROL_SET_RECMASTERROLE: {
		uint32_t recmasterrole;

		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));		
		recmasterrole = *(uint32_t *)indata.dptr;
		if (recmasterrole == 0) {
			ctdb->capabilities &= ~CTDB_CAP_RECMASTER;
		} else {
			ctdb->capabilities |= CTDB_CAP_RECMASTER;
		}
		return 0;
	}

	case CTDB_CONTROL_ENABLE_SCRIPT:
		return ctdb_control_enable_script(ctdb, indata);

	case CTDB_CONTROL_DISABLE_SCRIPT:
		return ctdb_control_disable_script(ctdb, indata);

	case CTDB_CONTROL_SET_BAN_STATE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_state));
		return ctdb_control_set_ban_state(ctdb, indata);

	case CTDB_CONTROL_GET_BAN_STATE:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_ban_state(ctdb, outdata);

	case CTDB_CONTROL_SET_DB_PRIORITY:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_db_priority));
		return ctdb_control_set_db_priority(ctdb, indata, client_id);

	case CTDB_CONTROL_GET_DB_PRIORITY: {
		uint32_t db_id;
		struct ctdb_db_context *ctdb_db;

		CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
		db_id = *(uint32_t *)indata.dptr;
		ctdb_db = find_ctdb_db(ctdb, db_id);
		if (ctdb_db == NULL) return -1;
		return ctdb_db->priority;
	}

	case CTDB_CONTROL_TRANSACTION_CANCEL:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_transaction_cancel(ctdb);

	case CTDB_CONTROL_REGISTER_NOTIFY:
		return ctdb_control_register_notify(ctdb, client_id, indata);

	case CTDB_CONTROL_DEREGISTER_NOTIFY:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
		return ctdb_control_deregister_notify(ctdb, client_id, indata);

	case CTDB_CONTROL_GET_LOG:
		return control_not_implemented("GET_LOG", NULL);

	case CTDB_CONTROL_CLEAR_LOG:
		return control_not_implemented("CLEAR_LOG", NULL);

	case CTDB_CONTROL_GET_DB_SEQNUM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
		return ctdb_control_get_db_seqnum(ctdb, indata, outdata);

	case CTDB_CONTROL_DB_SET_HEALTHY:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_set_healthy(ctdb, indata);

	case CTDB_CONTROL_DB_GET_HEALTH:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_get_health(ctdb, indata, outdata);

	case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
		CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
		return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata);

	case CTDB_CONTROL_GET_IFACES:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_ifaces(ctdb, c, outdata);

	case CTDB_CONTROL_SET_IFACE_LINK_STATE:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_iface));
		return ctdb_control_set_iface_link(ctdb, c, indata);

	case CTDB_CONTROL_GET_STAT_HISTORY:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_get_stat_history(ctdb, c, outdata);

	case CTDB_CONTROL_SCHEDULE_FOR_DELETION: {
		struct ctdb_control_schedule_for_deletion *d;
		size_t size = offsetof(struct ctdb_control_schedule_for_deletion, key);
		CHECK_CONTROL_MIN_DATA_SIZE(size);
		d = (struct ctdb_control_schedule_for_deletion *)indata.dptr;
		size += d->keylen;
		CHECK_CONTROL_DATA_SIZE(size);
		return ctdb_control_schedule_for_deletion(ctdb, indata);
	}
	case CTDB_CONTROL_GET_DB_STATISTICS:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_get_db_statistics(ctdb, *(uint32_t *)indata.dptr, outdata);

	case CTDB_CONTROL_RELOAD_PUBLIC_IPS:
		CHECK_CONTROL_DATA_SIZE(0);
		return ctdb_control_reload_public_ips(ctdb, c, async_reply);

	case CTDB_CONTROL_RECEIVE_RECORDS:
		return ctdb_control_receive_records(ctdb, indata, outdata);

	case CTDB_CONTROL_DB_DETACH:
		return ctdb_control_db_detach(ctdb, indata, client_id);

	case CTDB_CONTROL_DB_FREEZE:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_freeze(ctdb, c, *(uint32_t *)indata.dptr,
					      async_reply);

	case CTDB_CONTROL_DB_THAW:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_thaw(ctdb, *(uint32_t *)indata.dptr);

	case CTDB_CONTROL_DB_TRANSACTION_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_db_transaction_start(ctdb, indata);

	case CTDB_CONTROL_DB_TRANSACTION_COMMIT:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_transdb));
		return ctdb_control_db_transaction_commit(ctdb, indata);

	case CTDB_CONTROL_DB_TRANSACTION_CANCEL:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_transaction_cancel(ctdb, indata);

	case CTDB_CONTROL_DB_PULL:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb_ext));
		return ctdb_control_db_pull(ctdb, c, indata, outdata);

	case CTDB_CONTROL_DB_PUSH_START:
		CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_pulldb_ext));
		return ctdb_control_db_push_start(ctdb, indata);

	case CTDB_CONTROL_DB_PUSH_CONFIRM:
		CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
		return ctdb_control_db_push_confirm(ctdb, indata, outdata);

	default:
		DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
		return -1;
	}
}
Example #2
0
/*
  process a control request
 */
static int32_t ctdb_control_dispatch(struct ctdb_context *ctdb,
                                     struct ctdb_req_control *c,
                                     TDB_DATA indata,
                                     TDB_DATA *outdata, uint32_t srcnode,
                                     const char **errormsg,
                                     bool *async_reply)
{
    uint32_t opcode = c->opcode;
    uint64_t srvid = c->srvid;
    uint32_t client_id = c->client_id;

    switch (opcode) {
    case CTDB_CONTROL_PROCESS_EXISTS: {
        CHECK_CONTROL_DATA_SIZE(sizeof(pid_t));
        return ctdb_control_process_exists(ctdb, *(pid_t *)indata.dptr);
    }

    case CTDB_CONTROL_SET_DEBUG: {
        CHECK_CONTROL_DATA_SIZE(sizeof(int32_t));
        LogLevel = *(int32_t *)indata.dptr;
        return 0;
    }

    case CTDB_CONTROL_GET_DEBUG: {
        CHECK_CONTROL_DATA_SIZE(0);
        outdata->dptr = (uint8_t *)&LogLevel;
        outdata->dsize = sizeof(LogLevel);
        return 0;
    }

    case CTDB_CONTROL_STATISTICS: {
        int i;
        CHECK_CONTROL_DATA_SIZE(0);
        ctdb->statistics.memory_used = talloc_total_size(NULL);
        ctdb->statistics.frozen = 0;
        for (i=1; i<= NUM_DB_PRIORITIES; i++) {
            if (ctdb->freeze_mode[i] == CTDB_FREEZE_FROZEN) {
                ctdb->statistics.frozen = 1;
            }
        }
        ctdb->statistics.recovering = (ctdb->recovery_mode == CTDB_RECOVERY_ACTIVE);
        outdata->dptr = (uint8_t *)&ctdb->statistics;
        outdata->dsize = sizeof(ctdb->statistics);
        return 0;
    }

    case CTDB_CONTROL_GET_ALL_TUNABLES: {
        CHECK_CONTROL_DATA_SIZE(0);
        outdata->dptr = (uint8_t *)&ctdb->tunable;
        outdata->dsize = sizeof(ctdb->tunable);
        return 0;
    }

    case CTDB_CONTROL_DUMP_MEMORY: {
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_dump_memory(ctdb, outdata);
    }

    case CTDB_CONTROL_STATISTICS_RESET: {
        CHECK_CONTROL_DATA_SIZE(0);
        ZERO_STRUCT(ctdb->statistics);
        return 0;
    }

    case CTDB_CONTROL_GETVNNMAP:
        return ctdb_control_getvnnmap(ctdb, opcode, indata, outdata);

    case CTDB_CONTROL_GET_DBMAP:
        return ctdb_control_getdbmap(ctdb, opcode, indata, outdata);

    case CTDB_CONTROL_GET_NODEMAPv4:
        return ctdb_control_getnodemapv4(ctdb, opcode, indata, outdata);

    case CTDB_CONTROL_GET_NODEMAP:
        return ctdb_control_getnodemap(ctdb, opcode, indata, outdata);

    case CTDB_CONTROL_RELOAD_NODES_FILE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_reload_nodes_file(ctdb, opcode);

    case CTDB_CONTROL_SETVNNMAP:
        return ctdb_control_setvnnmap(ctdb, opcode, indata, outdata);

    case CTDB_CONTROL_PULL_DB:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_pulldb));
        return ctdb_control_pull_db(ctdb, indata, outdata);

    case CTDB_CONTROL_SET_DMASTER:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_set_dmaster));
        return ctdb_control_set_dmaster(ctdb, indata);

    case CTDB_CONTROL_PUSH_DB:
        return ctdb_control_push_db(ctdb, indata);

    case CTDB_CONTROL_GET_RECMODE: {
        return ctdb->recovery_mode;
    }

    case CTDB_CONTROL_SET_RECMASTER: {
        return ctdb_control_set_recmaster(ctdb, opcode, indata);
    }

    case CTDB_CONTROL_GET_RECMASTER:
        return ctdb->recovery_master;

    case CTDB_CONTROL_GET_PID:
        return getpid();

    case CTDB_CONTROL_GET_PNN:
        return ctdb->pnn;

    case CTDB_CONTROL_PING:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb->statistics.num_clients;

    case CTDB_CONTROL_GET_DBNAME: {
        uint32_t db_id;
        struct ctdb_db_context *ctdb_db;

        CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
        db_id = *(uint32_t *)indata.dptr;
        ctdb_db = find_ctdb_db(ctdb, db_id);
        if (ctdb_db == NULL) return -1;
        outdata->dptr = discard_const(ctdb_db->db_name);
        outdata->dsize = strlen(ctdb_db->db_name)+1;
        return 0;
    }

    case CTDB_CONTROL_GETDBPATH: {
        uint32_t db_id;
        struct ctdb_db_context *ctdb_db;

        CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
        db_id = *(uint32_t *)indata.dptr;
        ctdb_db = find_ctdb_db(ctdb, db_id);
        if (ctdb_db == NULL) return -1;
        outdata->dptr = discard_const(ctdb_db->db_path);
        outdata->dsize = strlen(ctdb_db->db_path)+1;
        return 0;
    }

    case CTDB_CONTROL_DB_ATTACH:
        return ctdb_control_db_attach(ctdb, indata, outdata, srvid, false);

    case CTDB_CONTROL_DB_ATTACH_PERSISTENT:
        return ctdb_control_db_attach(ctdb, indata, outdata, srvid, true);

    case CTDB_CONTROL_SET_CALL: {
        struct ctdb_control_set_call *sc =
            (struct ctdb_control_set_call *)indata.dptr;
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_set_call));
        return ctdb_daemon_set_call(ctdb, sc->db_id, sc->fn, sc->id);
    }

    case CTDB_CONTROL_TRAVERSE_START:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
        return ctdb_control_traverse_start(ctdb, indata, outdata, srcnode, client_id);

    case CTDB_CONTROL_TRAVERSE_ALL:
        return ctdb_control_traverse_all(ctdb, indata, outdata);

    case CTDB_CONTROL_TRAVERSE_DATA:
        return ctdb_control_traverse_data(ctdb, indata, outdata);

    case CTDB_CONTROL_TRAVERSE_KILL:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_traverse_start));
        return ctdb_control_traverse_kill(ctdb, indata, outdata, srcnode);

    case CTDB_CONTROL_REGISTER_SRVID:
        return daemon_register_message_handler(ctdb, client_id, srvid);

    case CTDB_CONTROL_DEREGISTER_SRVID:
        return daemon_deregister_message_handler(ctdb, client_id, srvid);

    case CTDB_CONTROL_ENABLE_SEQNUM:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_ltdb_enable_seqnum(ctdb, *(uint32_t *)indata.dptr);

    case CTDB_CONTROL_UPDATE_SEQNUM:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_ltdb_update_seqnum(ctdb, *(uint32_t *)indata.dptr, srcnode);

    case CTDB_CONTROL_FREEZE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_freeze(ctdb, c, async_reply);

    case CTDB_CONTROL_THAW:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_thaw(ctdb, (uint32_t)c->srvid);

    case CTDB_CONTROL_SET_RECMODE:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_set_recmode(ctdb, c, indata, async_reply, errormsg);

    case CTDB_CONTROL_GET_MONMODE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_monitoring_mode(ctdb);

    case CTDB_CONTROL_ENABLE_MONITOR:
        CHECK_CONTROL_DATA_SIZE(0);
        ctdb_enable_monitoring(ctdb);
        return 0;

    case CTDB_CONTROL_RUN_EVENTSCRIPTS:
        return ctdb_run_eventscripts(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_DISABLE_MONITOR:
        CHECK_CONTROL_DATA_SIZE(0);
        ctdb_disable_monitoring(ctdb);
        return 0;

    case CTDB_CONTROL_SHUTDOWN:
        ctdb_stop_recoverd(ctdb);
        ctdb_stop_keepalive(ctdb);
        ctdb_stop_monitoring(ctdb);
        ctdb_release_all_ips(ctdb);
        if (ctdb->methods != NULL) {
            ctdb->methods->shutdown(ctdb);
        }
        ctdb_event_script(ctdb, CTDB_EVENT_SHUTDOWN);
        DEBUG(DEBUG_NOTICE,("Received SHUTDOWN command. Stopping CTDB daemon.\n"));
        exit(0);

    case CTDB_CONTROL_TAKEOVER_IPv4:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ipv4));
        return ctdb_control_takeover_ipv4(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_TAKEOVER_IP:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
        return ctdb_control_takeover_ip(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_RELEASE_IPv4:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ipv4));
        return ctdb_control_release_ipv4(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_RELEASE_IP:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_public_ip));
        return ctdb_control_release_ip(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_GET_PUBLIC_IPSv4:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_get_public_ipsv4(ctdb, c, outdata);

    case CTDB_CONTROL_GET_PUBLIC_IPS:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_get_public_ips(ctdb, c, outdata);

    case CTDB_CONTROL_TCP_CLIENT:
        return ctdb_control_tcp_client(ctdb, client_id, indata);

    case CTDB_CONTROL_STARTUP:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_startup(ctdb, srcnode);

    case CTDB_CONTROL_TCP_ADD:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_tcp_vnn));
        return ctdb_control_tcp_add(ctdb, indata);

    case CTDB_CONTROL_SET_TUNABLE:
        return ctdb_control_set_tunable(ctdb, indata);

    case CTDB_CONTROL_GET_TUNABLE:
        return ctdb_control_get_tunable(ctdb, indata, outdata);

    case CTDB_CONTROL_LIST_TUNABLES:
        return ctdb_control_list_tunables(ctdb, outdata);

    case CTDB_CONTROL_MODIFY_FLAGS:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_node_flag_change));
        return ctdb_control_modflags(ctdb, indata);

    case CTDB_CONTROL_KILL_TCP:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_killtcp));
        return ctdb_control_kill_tcp(ctdb, indata);

    case CTDB_CONTROL_GET_TCP_TICKLE_LIST:
        CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
        return ctdb_control_get_tcp_tickle_list(ctdb, indata, outdata);

    case CTDB_CONTROL_SET_TCP_TICKLE_LIST:
        /* data size is verified in the called function */
        return ctdb_control_set_tcp_tickle_list(ctdb, indata);

    case CTDB_CONTROL_REGISTER_SERVER_ID:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
        return ctdb_control_register_server_id(ctdb, client_id, indata);

    case CTDB_CONTROL_UNREGISTER_SERVER_ID:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
        return ctdb_control_unregister_server_id(ctdb, indata);

    case CTDB_CONTROL_CHECK_SERVER_ID:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_server_id));
        return ctdb_control_check_server_id(ctdb, indata);

    case CTDB_CONTROL_GET_SERVER_ID_LIST:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_get_server_id_list(ctdb, outdata);

    case CTDB_CONTROL_PERSISTENT_STORE:
        return ctdb_control_persistent_store(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_UPDATE_RECORD:
        return ctdb_control_update_record(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_SEND_GRATIOUS_ARP:
        return ctdb_control_send_gratious_arp(ctdb, indata);

    case CTDB_CONTROL_TRANSACTION_START:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_transaction_start(ctdb, *(uint32_t *)indata.dptr);

    case CTDB_CONTROL_TRANSACTION_COMMIT:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_transaction_commit(ctdb, *(uint32_t *)indata.dptr);

    case CTDB_CONTROL_WIPE_DATABASE:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_wipe_database));
        return ctdb_control_wipe_database(ctdb, indata);

    case CTDB_CONTROL_UPTIME:
        return ctdb_control_uptime(ctdb, outdata);

    case CTDB_CONTROL_START_RECOVERY:
        return ctdb_control_start_recovery(ctdb, c, async_reply);

    case CTDB_CONTROL_END_RECOVERY:
        return ctdb_control_end_recovery(ctdb, c, async_reply);

    case CTDB_CONTROL_TRY_DELETE_RECORDS:
        return ctdb_control_try_delete_records(ctdb, indata, outdata);

    case CTDB_CONTROL_ADD_PUBLIC_IP:
        return ctdb_control_add_public_address(ctdb, indata);

    case CTDB_CONTROL_DEL_PUBLIC_IP:
        return ctdb_control_del_public_address(ctdb, indata);

    case CTDB_CONTROL_GET_CAPABILITIES:
        return ctdb_control_get_capabilities(ctdb, outdata);

    case CTDB_CONTROL_START_PERSISTENT_UPDATE:
        return ctdb_control_start_persistent_update(ctdb, c, indata);

    case CTDB_CONTROL_CANCEL_PERSISTENT_UPDATE:
        return ctdb_control_cancel_persistent_update(ctdb, c, indata);

    case CTDB_CONTROL_TRANS2_COMMIT:
    case CTDB_CONTROL_TRANS2_COMMIT_RETRY:
        return ctdb_control_trans2_commit(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_TRANS2_ERROR:
        return ctdb_control_trans2_error(ctdb, c);

    case CTDB_CONTROL_TRANS2_FINISHED:
        return ctdb_control_trans2_finished(ctdb, c);

    case CTDB_CONTROL_TRANS2_ACTIVE:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_trans2_active(ctdb, c, *(uint32_t *)indata.dptr);

    case CTDB_CONTROL_TRANS3_COMMIT:
        return ctdb_control_trans3_commit(ctdb, c, indata, async_reply);

    case CTDB_CONTROL_RECD_PING:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_recd_ping(ctdb);

    case CTDB_CONTROL_GET_EVENT_SCRIPT_STATUS:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_get_event_script_status(ctdb, *(uint32_t *)indata.dptr, outdata);

    case CTDB_CONTROL_RECD_RECLOCK_LATENCY:
        CHECK_CONTROL_DATA_SIZE(sizeof(double));
        ctdb_reclock_latency(ctdb, "recd reclock", &ctdb->statistics.reclock.recd, *((double *)indata.dptr));
        return 0;
    case CTDB_CONTROL_GET_RECLOCK_FILE:
        CHECK_CONTROL_DATA_SIZE(0);
        if (ctdb->recovery_lock_file != NULL) {
            outdata->dptr  = discard_const(ctdb->recovery_lock_file);
            outdata->dsize = strlen(ctdb->recovery_lock_file) + 1;
        }
        return 0;
    case CTDB_CONTROL_SET_RECLOCK_FILE:
        ctdb->tunable.verify_recovery_lock = 0;
        if (ctdb->recovery_lock_file != NULL) {
            talloc_free(ctdb->recovery_lock_file);
            ctdb->recovery_lock_file = NULL;
        }
        if (indata.dsize > 0) {
            ctdb->recovery_lock_file = talloc_strdup(ctdb, discard_const(indata.dptr));
            ctdb->tunable.verify_recovery_lock = 1;
        }
        return 0;

    case CTDB_CONTROL_STOP_NODE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_stop_node(ctdb, c, async_reply);

    case CTDB_CONTROL_CONTINUE_NODE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_continue_node(ctdb);

    case CTDB_CONTROL_SET_NATGWSTATE: {
        uint32_t natgwstate;

        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        natgwstate = *(uint32_t *)indata.dptr;
        if (natgwstate == 0) {
            ctdb->capabilities &= ~CTDB_CAP_NATGW;
        } else {
            ctdb->capabilities |= CTDB_CAP_NATGW;
        }
        return 0;
    }

    case CTDB_CONTROL_SET_LMASTERROLE: {
        uint32_t lmasterrole;

        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        lmasterrole = *(uint32_t *)indata.dptr;
        if (lmasterrole == 0) {
            ctdb->capabilities &= ~CTDB_CAP_LMASTER;
        } else {
            ctdb->capabilities |= CTDB_CAP_LMASTER;
        }
        return 0;
    }

    case CTDB_CONTROL_SET_RECMASTERROLE: {
        uint32_t recmasterrole;

        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        recmasterrole = *(uint32_t *)indata.dptr;
        if (recmasterrole == 0) {
            ctdb->capabilities &= ~CTDB_CAP_RECMASTER;
        } else {
            ctdb->capabilities |= CTDB_CAP_RECMASTER;
        }
        return 0;
    }

    case CTDB_CONTROL_ENABLE_SCRIPT:
        return ctdb_control_enable_script(ctdb, indata);

    case CTDB_CONTROL_DISABLE_SCRIPT:
        return ctdb_control_disable_script(ctdb, indata);

    case CTDB_CONTROL_SET_BAN_STATE:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_ban_time));
        return ctdb_control_set_ban_state(ctdb, indata);

    case CTDB_CONTROL_GET_BAN_STATE:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_get_ban_state(ctdb, outdata);

    case CTDB_CONTROL_SET_DB_PRIORITY:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_db_priority));
        return ctdb_control_set_db_priority(ctdb, indata);

    case CTDB_CONTROL_GET_DB_PRIORITY: {
        uint32_t db_id;
        struct ctdb_db_context *ctdb_db;

        CHECK_CONTROL_DATA_SIZE(sizeof(db_id));
        db_id = *(uint32_t *)indata.dptr;
        ctdb_db = find_ctdb_db(ctdb, db_id);
        if (ctdb_db == NULL) return -1;
        return ctdb_db->priority;
    }

    case CTDB_CONTROL_TRANSACTION_CANCEL:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_transaction_cancel(ctdb);

    case CTDB_CONTROL_REGISTER_NOTIFY:
        return ctdb_control_register_notify(ctdb, client_id, indata);

    case CTDB_CONTROL_DEREGISTER_NOTIFY:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_client_notify_deregister));
        return ctdb_control_deregister_notify(ctdb, client_id, indata);

    case CTDB_CONTROL_GET_LOG:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_get_log_addr));
        return ctdb_control_get_log(ctdb, indata);

    case CTDB_CONTROL_CLEAR_LOG:
        return ctdb_control_clear_log(ctdb);

    case CTDB_CONTROL_GET_DB_SEQNUM:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint64_t));
        return ctdb_control_get_db_seqnum(ctdb, indata, outdata);

    case CTDB_CONTROL_DB_SET_HEALTHY:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_db_set_healthy(ctdb, indata);

    case CTDB_CONTROL_DB_GET_HEALTH:
        CHECK_CONTROL_DATA_SIZE(sizeof(uint32_t));
        return ctdb_control_db_get_health(ctdb, indata, outdata);

    case CTDB_CONTROL_GET_PUBLIC_IP_INFO:
        CHECK_CONTROL_DATA_SIZE(sizeof(ctdb_sock_addr));
        return ctdb_control_get_public_ip_info(ctdb, c, indata, outdata);

    case CTDB_CONTROL_GET_IFACES:
        CHECK_CONTROL_DATA_SIZE(0);
        return ctdb_control_get_ifaces(ctdb, c, outdata);

    case CTDB_CONTROL_SET_IFACE_LINK_STATE:
        CHECK_CONTROL_DATA_SIZE(sizeof(struct ctdb_control_iface_info));
        return ctdb_control_set_iface_link(ctdb, c, indata);

    default:
        DEBUG(DEBUG_CRIT,(__location__ " Unknown CTDB control opcode %u\n", opcode));
        return -1;
    }
}