blob: ed63d78cc6e3b0764cd9fd94c08f05516f15ef5b [file] [log] [blame]
#ifndef DRBDADM_H
#define DRBDADM_H
#include <stdbool.h>
#include <sys/utsname.h>
#include <sys/types.h>
#include <net/if.h>
#include <stdint.h>
#include <stdarg.h>
#include <fcntl.h>
#ifndef O_CLOEXEC
#warning "O_CLOEXEC undefined, redefining to 0"
#define O_CLOEXEC 0
#endif
#include "config.h"
#include "shared_main.h"
#define API_VERSION 1
struct d_name
{
char *name;
struct d_name *next;
};
struct d_proxy_info
{
struct d_name *on_hosts;
char* inside_addr;
char* inside_port;
char* inside_af;
char* outside_addr;
char* outside_port;
char* outside_af;
struct d_option *options; /* named proxy_options in other places */
struct d_option *plugins; /* named proxy_plugins in other places */
};
struct d_volume
{
unsigned vnr;
char* device;
unsigned device_minor;
char* disk;
char* meta_disk;
char* meta_index;
int meta_major;
int meta_minor;
struct d_volume *next;
struct d_option* disk_options; /* Additional per volume options */
/* Do not dump an explicit volume section */
unsigned int implicit :1 ;
/* flags for "drbdadm adjust" */
unsigned int adj_del_minor :1;
unsigned int adj_add_minor :1;
unsigned int adj_detach :1;
unsigned int adj_attach :1;
unsigned int adj_resize :1;
unsigned int adj_disk_opts :1;
};
struct d_host_info
{
struct d_name *on_hosts;
struct d_volume *volumes;
char* address;
char* port;
char* address_family;
char* alt_address;
char* alt_port;
char* alt_address_family;
struct d_proxy_info *proxy;
struct d_host_info* next;
struct d_resource* lower; /* for device stacking */
char *lower_name; /* for device stacking, before bind_stacked_res() */
int config_line;
unsigned int by_address:1; /* Match to machines by address, not by names (=on_hosts) */
struct d_option* res_options; /* Additional per host options */
};
struct d_option
{
char* name;
char* value;
struct d_option* next;
unsigned int mentioned :1 ; // for the adjust command.
unsigned int is_escaped :1 ;
unsigned int adj_skip :1;
};
struct d_resource
{
char* name;
struct d_volume *volumes; /* gets propagated to host_info sections later. */
struct d_host_info* me;
struct d_host_info* peer;
struct d_host_info* all_hosts;
struct d_option* net_options;
struct d_option* disk_options;
struct d_option* res_options;
struct d_option* startup_options;
struct d_option* handlers;
struct d_option* proxy_options;
struct d_option* proxy_plugins;
struct d_resource* next;
struct d_name *become_primary_on;
char *config_file; /* The config file this resource is define in.*/
int start_line;
unsigned int stacked_timeouts:1;
unsigned int ignore:1;
unsigned int stacked:1; /* Stacked on this node */
unsigned int stacked_on_one:1; /* Stacked either on me or on peer */
/* if a prerequisite command failed, don't try any further commands.
* see run_deferred_cmds() */
unsigned int skip_further_deferred_command:1;
};
struct adm_cmd;
struct cfg_ctx {
/* res == NULL: does not care for resources, or iterates over all
* resources in the global "struct d_resource *config" */
struct d_resource *res;
/* vol == NULL: operate on the resource itself, or iterates over all
* volumes in res */
struct d_volume *vol;
const char *arg;
};
extern char *canonify_path(char *path);
extern int adm_adjust(struct cfg_ctx *);
extern int adm_new_minor(struct cfg_ctx *ctx);
extern int adm_new_resource(struct cfg_ctx *);
extern int adm_res_options(struct cfg_ctx *);
extern int adm_set_default_res_options(struct cfg_ctx *);
extern int adm_attach(struct cfg_ctx *);
extern int adm_disk_options(struct cfg_ctx *);
extern int adm_set_default_disk_options(struct cfg_ctx *);
extern int adm_resize(struct cfg_ctx *);
extern int adm_connect(struct cfg_ctx *);
extern int adm_net_options(struct cfg_ctx *);
extern int adm_set_default_net_options(struct cfg_ctx *);
extern int adm_disconnect(struct cfg_ctx *);
extern int adm_generic_s(struct cfg_ctx *);
extern int adm_create_md(struct cfg_ctx *);
extern int _admm_generic(struct cfg_ctx *, int flags);
extern struct d_option* find_opt(struct d_option*,char*);
extern void validate_resource(struct d_resource *, enum pp_flags);
/* stages of configuration, as performed on "drbdadm up"
* or "drbdadm adjust":
*/
enum drbd_cfg_stage {
/* prerequisite stage: create objects, start daemons, ... */
CFG_PREREQ,
/* run time changeable settings of resources */
CFG_RESOURCE,
/* detach/attach local disks, */
CFG_DISK_PREREQ,
CFG_DISK,
/* The stage to discard network configuration, during adjust.
* This is after the DISK stage, because we don't want to cut access to
* good data while in primary role. And before the SETTINGS stage, as
* some proxy or syncer settings may cause side effects and additional
* handshakes while we have an established connection.
*/
CFG_NET_PREREQ,
/* discard/set connection parameters */
CFG_NET,
__CFG_LAST
};
extern void schedule_deferred_cmd( int (*function)(struct cfg_ctx *),
struct cfg_ctx *ctx,
const char *arg,
enum drbd_cfg_stage stage);
extern int version_code_kernel(void);
extern int version_code_userland(void);
extern void warn_on_version_mismatch(void);
extern void maybe_exec_drbdadm_83(char **argv);
extern void uc_node(enum usage_count_type type);
extern void convert_discard_opt(struct d_resource* res);
extern void convert_after_option(struct d_resource* res);
extern int have_ip(const char *af, const char *ip);
enum pr_flags {
NoneHAllowed = 4,
PARSE_FOR_ADJUST = 8
};
extern struct d_resource* parse_resource_for_adjust(struct cfg_ctx *ctx);
extern struct d_resource* parse_resource(char*, enum pr_flags);
extern void post_parse(struct d_resource *config, enum pp_flags);
extern struct d_option *new_opt(char *name, char *value);
extern int name_in_names(char *name, struct d_name *names);
extern char *_names_to_str(char* buffer, struct d_name *names);
extern char *_names_to_str_c(char* buffer, struct d_name *names, char c);
#define NAMES_STR_SIZE 255
#define names_to_str(N) _names_to_str(alloca(NAMES_STR_SIZE+1), N)
#define names_to_str_c(N, C) _names_to_str_c(alloca(NAMES_STR_SIZE+1), N, C)
extern void free_names(struct d_name *names);
extern void set_me_in_resource(struct d_resource* res, int match_on_proxy);
extern void set_peer_in_resource(struct d_resource* res, int peer_required);
extern void set_on_hosts_in_res(struct d_resource *res);
extern void set_disk_in_res(struct d_resource *res);
extern int _proxy_connect_name_len(struct d_resource *res);
extern char *_proxy_connection_name(char *conn_name, struct d_resource *res);
#define proxy_connection_name(RES) \
_proxy_connection_name(alloca(_proxy_connect_name_len(RES)), RES)
int parse_proxy_options_section(struct d_resource *res);
/* conn_name is optional and mostly for compatibility with dcmd */
int do_proxy_conn_up(struct cfg_ctx *ctx);
int do_proxy_conn_down(struct cfg_ctx *ctx);
int do_proxy_conn_plugins(struct cfg_ctx *ctx);
extern char *config_file;
extern char *config_save;
extern int config_valid;
extern struct d_resource* config;
extern struct d_resource* common;
extern int line, fline;
extern struct hsearch_data global_htable;
extern int no_tty;
extern int dry_run;
extern int verbose;
extern char* drbdsetup;
extern char* drbd_proxy_ctl;
extern char* drbdadm_83;
extern char ss_buffer[1024];
extern struct utsname nodeinfo;
extern char* connect_to_host;
struct setup_option {
bool explicit;
char *option;
};
struct setup_option *setup_options;
extern void add_setup_option(bool explicit, char *option);
/* ssprintf() places the result of the printf in the current stack
frame and sets ptr to the resulting string. If the current stack
frame is destroyed (=function returns), the allocated memory is
freed automatically */
/*
// This is the nicer version, that does not need the ss_buffer.
// But it only works with very new glibcs.
#define ssprintf(...) \
({ int _ss_size = snprintf(0, 0, ##__VA_ARGS__); \
char *_ss_ret = __builtin_alloca(_ss_size+1); \
snprintf(_ss_ret, _ss_size+1, ##__VA_ARGS__); \
_ss_ret; })
*/
#define ssprintf(ptr,...) \
ptr=strcpy(alloca(snprintf(ss_buffer,sizeof(ss_buffer),##__VA_ARGS__)+1),ss_buffer)
/* CAUTION: arguments may not have side effects! */
#define for_each_resource(res,tmp,config) \
for (res = (config); res && (tmp = res->next, 1); res = tmp)
#define for_each_volume(v_,volumes_) \
for (v_ = volumes_; v_; v_ = v_->next)
#define APPEND(LIST,ITEM) ({ \
typeof((LIST)) _l = (LIST); \
typeof((ITEM)) _i = (ITEM); \
typeof((ITEM)) _t; \
_i->next = NULL; \
if (_l == NULL) { _l = _i; } \
else { \
for (_t = _l; _t->next; _t = _t->next); \
_t->next = _i; \
}; \
_l; \
})
#define INSERT_SORTED(LIST,ITEM,SORT) ({ \
typeof((LIST)) _l = (LIST); \
typeof((ITEM)) _i = (ITEM); \
typeof((ITEM)) _t, _p = NULL; \
for (_t = _l; _t && _t->SORT <= _i->SORT; _p = _t, _t = _t->next); \
if (_p) \
_p->next = _i; \
else \
_l = _i; \
_i->next = _t; \
_l; \
})
#define SPLICE(LIST,ITEMS) ({ \
typeof((LIST)) _l = (LIST); \
typeof((ITEMS)) _i = (ITEMS); \
typeof((ITEMS)) _t; \
if (_l == NULL) { _l = _i; } \
else { \
for (_t = _l; _t->next; _t = _t->next); \
_t->next = _i; \
}; \
_l; \
})
#endif