*.a
*.gz
*.d
+\#*
+cscope.files
+cscope.out
kpartx/kpartx
multipath/multipath
multipathd/multipathd
libdmmp/test/libdmmp_speed_test
tests/*-test
tests/*.out
+tests/*.vgr
libmultipath/nvme-ioctl.c
libmultipath/nvme-ioctl.h
STACKPROT := $(call TEST_CC_OPTION,-fstack-protector-strong,-fstack-protector)
ERROR_DISCARDED_QUALIFIERS := $(call TEST_CC_OPTION,-Werror=discarded-qualifiers,)
WNOCLOBBERED := $(call TEST_CC_OPTION,-Wno-clobbered -Wno-error=clobbered,)
+WFORMATOVERFLOW := $(call TEST_CC_OPTION,-Wformat-overflow=2,)
OPTFLAGS := -O2 -g $(STACKPROT) --param=ssp-buffer-size=4
-WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 -Werror=implicit-int \
+WARNFLAGS := -Werror -Wall -Wextra -Wformat=2 $(WFORMATOVERFLOW) -Werror=implicit-int \
-Werror=implicit-function-declaration -Werror=format-security \
$(WNOCLOBBERED) -Werror=cast-qual $(ERROR_DISCARDED_QUALIFIERS)
-CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
+CPPFLAGS := -Wp,-D_FORTIFY_SOURCE=2
CFLAGS := --std=gnu99 $(CFLAGS) $(OPTFLAGS) $(WARNFLAGS) -pipe \
-DBIN_DIR=\"$(bindir)\" -DLIB_STRING=\"${LIB}\" -DRUN_DIR=\"${RUN}\" \
-MMD -MP
- EMC CLARiiON/VNX:
"Failover Mode" should be changed to "4" or "Active-Active mode(ALUA)-failover mode 4"
-- HPE 3PAR:
+- HPE 3PAR, Primera, and Alletra 9000:
"Host:" should be changed to "Generic-ALUA Persona 2 (UARepLun, SESLun, ALUA)".
- Promise VTrak/Vess:
if (read(fd, bp->block, secsz) != secsz) {
fprintf(stderr, "read error, sector %d\n", secnr);
blockhead = bp->next;
+ free(bp->block);
+ free(bp);
return NULL;
}
docs/man/dmmp_strerror.3: $(HEADERS)
TEMPFILE=$(shell mktemp); \
cat $^ | perl docs/doc-preclean.pl >$$TEMPFILE; \
+ LC_ALL=C \
+ KBUILD_BUILD_TIMESTAMP=`git log -n1 --pretty=%cd --date=iso -- $^` \
perl docs/kernel-doc -man $$TEMPFILE | \
perl docs/split-man.pl docs/man; \
rm -f $$TEMPFILE
-.TH "dmmp_context_free" 3 "dmmp_context_free" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_free" 3 "dmmp_context_free" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_free \- Release the memory of struct dmmp_context.
.SH SYNOPSIS
-.TH "dmmp_context_log_func_set" 3 "dmmp_context_log_func_set" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_log_func_set" 3 "dmmp_context_log_func_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_log_func_set \- Set log handler function.
.SH SYNOPSIS
-.TH "dmmp_context_log_priority_get" 3 "dmmp_context_log_priority_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_log_priority_get" 3 "dmmp_context_log_priority_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_log_priority_get \- Get log priority.
.SH SYNOPSIS
-.TH "dmmp_context_log_priority_set" 3 "dmmp_context_log_priority_set" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_log_priority_set" 3 "dmmp_context_log_priority_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_log_priority_set \- Set log priority.
.SH SYNOPSIS
-.TH "dmmp_context_new" 3 "dmmp_context_new" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_new" 3 "dmmp_context_new" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_new \- Create struct dmmp_context.
.SH SYNOPSIS
-.TH "dmmp_context_timeout_get" 3 "dmmp_context_timeout_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_timeout_get" 3 "dmmp_context_timeout_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_timeout_get \- Get IPC timeout.
.SH SYNOPSIS
-.TH "dmmp_context_timeout_set" 3 "dmmp_context_timeout_set" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_timeout_set" 3 "dmmp_context_timeout_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_timeout_set \- Set IPC timeout.
.SH SYNOPSIS
-.TH "dmmp_context_userdata_get" 3 "dmmp_context_userdata_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_userdata_get" 3 "dmmp_context_userdata_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_userdata_get \- Get user data pointer.
.SH SYNOPSIS
-.TH "dmmp_context_userdata_set" 3 "dmmp_context_userdata_set" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_context_userdata_set" 3 "dmmp_context_userdata_set" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_context_userdata_set \- Set user data pointer.
.SH SYNOPSIS
-.TH "dmmp_flush_mpath" 3 "dmmp_flush_mpath" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_flush_mpath" 3 "dmmp_flush_mpath" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_flush_mpath \- Flush specified multipath device map if unused.
.SH SYNOPSIS
-.TH "dmmp_last_error_msg" 3 "dmmp_last_error_msg" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_last_error_msg" 3 "dmmp_last_error_msg" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_last_error_msg \- Retrieves the last error message.
.SH SYNOPSIS
-.TH "dmmp_log_priority_str" 3 "dmmp_log_priority_str" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_log_priority_str" 3 "dmmp_log_priority_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_log_priority_str \- Convert log priority to string.
.SH SYNOPSIS
-.TH "dmmp_mpath_array_free" 3 "dmmp_mpath_array_free" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_mpath_array_free" 3 "dmmp_mpath_array_free" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_mpath_array_free \- Free 'struct dmmp_mpath' pointer array.
.SH SYNOPSIS
-.TH "dmmp_mpath_array_get" 3 "dmmp_mpath_array_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_mpath_array_get" 3 "dmmp_mpath_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_mpath_array_get \- Query all existing multipath devices.
.SH SYNOPSIS
-.TH "dmmp_mpath_kdev_name_get" 3 "dmmp_mpath_kdev_name_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_mpath_kdev_name_get" 3 "dmmp_mpath_kdev_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_mpath_kdev_name_get \- Retrieve kernel DEVNAME of certain mpath.
.SH SYNOPSIS
-.TH "dmmp_mpath_name_get" 3 "dmmp_mpath_name_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_mpath_name_get" 3 "dmmp_mpath_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_mpath_name_get \- Retrieve name(alias) of certain mpath.
.SH SYNOPSIS
-.TH "dmmp_mpath_wwid_get" 3 "dmmp_mpath_wwid_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_mpath_wwid_get" 3 "dmmp_mpath_wwid_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_mpath_wwid_get \- Retrieve WWID of certain mpath.
.SH SYNOPSIS
-.TH "dmmp_path_array_get" 3 "dmmp_path_array_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_array_get" 3 "dmmp_path_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_array_get \- Retrieve path pointer array.
.SH SYNOPSIS
-.TH "dmmp_path_blk_name_get" 3 "dmmp_path_blk_name_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_blk_name_get" 3 "dmmp_path_blk_name_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_blk_name_get \- Retrieve block name.
.SH SYNOPSIS
-.TH "dmmp_path_group_array_get" 3 "dmmp_path_group_array_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_array_get" 3 "dmmp_path_group_array_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_array_get \- Retrieve path groups pointer array.
.SH SYNOPSIS
-.TH "dmmp_path_group_id_get" 3 "dmmp_path_group_id_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_id_get" 3 "dmmp_path_group_id_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_id_get \- Retrieve path group ID.
.SH SYNOPSIS
-.TH "dmmp_path_group_priority_get" 3 "dmmp_path_group_priority_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_priority_get" 3 "dmmp_path_group_priority_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_priority_get \- Retrieve path group priority.
.SH SYNOPSIS
-.TH "dmmp_path_group_selector_get" 3 "dmmp_path_group_selector_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_selector_get" 3 "dmmp_path_group_selector_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_selector_get \- Retrieve path group selector.
.SH SYNOPSIS
-.TH "dmmp_path_group_status_get" 3 "dmmp_path_group_status_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_status_get" 3 "dmmp_path_group_status_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_status_get \- Retrieve path group status.
.SH SYNOPSIS
-.TH "dmmp_path_group_status_str" 3 "dmmp_path_group_status_str" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_group_status_str" 3 "dmmp_path_group_status_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_group_status_str \- Convert path group status to string.
.SH SYNOPSIS
-.TH "dmmp_path_status_get" 3 "dmmp_path_status_get" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_status_get" 3 "dmmp_path_status_get" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_status_get \- Retrieve the path status.
.SH SYNOPSIS
-.TH "dmmp_path_status_str" 3 "dmmp_path_status_str" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_path_status_str" 3 "dmmp_path_status_str" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_path_status_str \- Convert path status to string.
.SH SYNOPSIS
-.TH "dmmp_reconfig" 3 "dmmp_reconfig" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_reconfig" 3 "dmmp_reconfig" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_reconfig \- Instruct multipathd daemon to do reconfiguration.
.SH SYNOPSIS
-.TH "dmmp_strerror" 3 "dmmp_strerror" "March 2021" "Device Mapper Multipath API - libdmmp Manual"
+.TH "dmmp_strerror" 3 "dmmp_strerror" "March 2018" "Device Mapper Multipath API - libdmmp Manual"
.SH NAME
dmmp_strerror \- Convert error code to string.
.SH SYNOPSIS
if (update_multipath_table(mpp, pathvec, DI_CHECKER) != DMP_OK ||
update_mpp_paths(mpp, pathvec)) {
condlog(1, "error parsing map %s", mpp->wwid);
- remove_map(mpp, pathvec, curmp, PURGE_VEC);
+ remove_map(mpp, pathvec, curmp);
i--;
} else
extract_hwe_from_path(mpp);
return ret ;
}
}
- return MPATH_PR_SUCCESS;
+ condlog (0, "%s: no path available", mpp->wwid);
+ return MPATH_PR_DMMP_ERROR;
}
int send_prout_activepath(char * dev, int rq_servact, int rq_scope,
active_pathcount = count_active_paths(mpp);
+ if (active_pathcount == 0) {
+ condlog (0, "%s: no path available", mpp->wwid);
+ return MPATH_PR_DMMP_ERROR;
+ }
+
struct threadinfo thread[active_pathcount];
memset(thread, 0, sizeof(thread));
for (i = 0; i < active_pathcount; i++){
log.o configure.o structs_vec.o sysfs.o prio.o checkers.o \
lock.o file.o wwids.o prioritizers/alua_rtpg.o prkey.o \
io_err_stat.o dm-generic.o generic.o foreign.o nvme-lib.o \
- libsg.o valid.o
+ libsg.o valid.o strbuf.o
all: $(DEVLIB)
#include "util.h"
#include "errno.h"
#include "devmapper.h"
-
+#include "strbuf.h"
/*
* significant parts of this file were taken from iscsi-bindings.c of the
return 1;
}
-
-static int
-format_devname(char *name, int id, int len, const char *prefix)
+static int format_devname(struct strbuf *buf, int id)
{
- int pos;
- int prefix_len = strlen(prefix);
+ /*
+ * We need: 7 chars for 32bit integers, 14 chars for 64bit integers
+ */
+ char devname[2 * sizeof(int)];
+ int pos = sizeof(devname) - 1, rc;
- if (len <= prefix_len + 1 || id <= 0)
+ if (id <= 0)
return -1;
- memset(name, 0, len);
- strcpy(name, prefix);
- name[len - 1] = '\0';
- for (pos = len - 2; pos >= prefix_len; pos--) {
- id--;
- name[pos] = 'a' + id % 26;
- if (id < 26)
- break;
- id /= 26;
- }
- if (pos < prefix_len)
- return -1;
+ devname[pos] = '\0';
+ for (; id >= 1; id /= 26)
+ devname[--pos] = 'a' + --id % 26;
- memmove(name + prefix_len, name + pos, len - pos);
- return (prefix_len + len - pos - 1);
+ rc = append_strbuf_str(buf, devname + pos);
+ return rc >= 0 ? rc : -1;
}
static int
static int
id_already_taken(int id, const char *prefix, const char *map_wwid)
{
- char alias[LINE_MAX];
+ STRBUF_ON_STACK(buf);
+ const char *alias;
- if (format_devname(alias, id, LINE_MAX, prefix) < 0)
+ if (append_strbuf_str(&buf, prefix) < 0 ||
+ format_devname(&buf, id) < 0)
return 0;
+ alias = get_strbuf_str(&buf);
if (dm_map_present(alias)) {
char wwid[WWID_SIZE];
static char *
allocate_binding(int fd, const char *wwid, int id, const char *prefix)
{
- char buf[LINE_MAX];
+ STRBUF_ON_STACK(buf);
off_t offset;
+ ssize_t len;
char *alias, *c;
- int i;
if (id <= 0) {
condlog(0, "%s: cannot allocate new binding for id %d",
return NULL;
}
- i = format_devname(buf, id, LINE_MAX, prefix);
- if (i == -1)
+ if (append_strbuf_str(&buf, prefix) < 0 ||
+ format_devname(&buf, id) == -1)
return NULL;
- c = buf + i;
- if (snprintf(c, LINE_MAX - i, " %s\n", wwid) >= LINE_MAX - i) {
- condlog(1, "%s: line too long for %s\n", __func__, wwid);
+ if (print_strbuf(&buf, " %s\n", wwid) < 0)
return NULL;
- }
- buf[LINE_MAX - 1] = '\0';
offset = lseek(fd, 0, SEEK_END);
if (offset < 0){
strerror(errno));
return NULL;
}
- if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)){
+
+ len = get_strbuf_len(&buf);
+ alias = steal_strbuf_str(&buf);
+
+ if (write(fd, alias, len) != len) {
condlog(0, "Cannot write binding to bindings file : %s",
strerror(errno));
/* clear partial write */
if (ftruncate(fd, offset))
condlog(0, "Cannot truncate the header : %s",
strerror(errno));
+ free(alias);
return NULL;
}
- c = strchr(buf, ' ');
+ c = strchr(alias, ' ');
if (c)
*c = '\0';
- condlog(3, "Created new binding [%s] for WWID [%s]", buf, wwid);
- alias = strdup(buf);
- if (alias == NULL)
- condlog(0, "cannot copy new alias from bindings file: out of memory");
-
+ condlog(3, "Created new binding [%s] for WWID [%s]", alias, wwid);
return alias;
}
static int write_bindings_file(const Bindings *bindings, int fd)
{
struct binding *bnd;
- char line[LINE_MAX];
+ STRBUF_ON_STACK(line);
int i;
if (write(fd, BINDINGS_FILE_HEADER, sizeof(BINDINGS_FILE_HEADER) - 1)
vector_foreach_slot(bindings, bnd, i) {
int len;
- len = snprintf(line, sizeof(line), "%s %s\n",
- bnd->alias, bnd->wwid);
-
- if (len < 0 || (size_t)len >= sizeof(line)) {
- condlog(1, "%s: line overflow", __func__);
+ if ((len = print_strbuf(&line, "%s %s\n",
+ bnd->alias, bnd->wwid)) < 0)
return -1;
- }
-
- if (write(fd, line, len) != len)
+ if (write(fd, get_strbuf_str(&line), len) != len)
return -1;
+ truncate_strbuf(&line, 0);
}
return 0;
}
#include "blacklist.h"
#include "structs_vec.h"
#include "print.h"
+#include "strbuf.h"
char *check_invert(char *str, bool *invert)
{
filter_protocol(const struct _vector *blist, const struct _vector *elist,
const struct path *pp)
{
- char buf[PROTOCOL_BUF_SIZE];
+ STRBUF_ON_STACK(buf);
+ const char *prot;
int r = MATCH_NOTHING;
if (pp) {
- snprint_path_protocol(buf, sizeof(buf), pp);
+ snprint_path_protocol(&buf, pp);
+ prot = get_strbuf_str(&buf);
- if (match_reglist(elist, buf))
+ if (match_reglist(elist, prot))
r = MATCH_PROTOCOL_BLIST_EXCEPT;
- else if (match_reglist(blist, buf))
+ else if (match_reglist(blist, prot))
r = MATCH_PROTOCOL_BLIST;
+ log_filter(pp->dev, NULL, NULL, NULL, NULL, prot, r, 3);
}
- log_filter(pp->dev, NULL, NULL, NULL, NULL, buf, r, 3);
return r;
}
{
struct checker_class *cls = arg;
- (void)checker_class_unref(cls);
+ free_checker_class(cls);
rcu_unregister_thread();
}
return n_pending;
}
-int setup_map(struct multipath *mpp, char *params, int params_size,
- struct vectors *vecs)
+int setup_map(struct multipath *mpp, char **params, struct vectors *vecs)
{
struct pathgroup * pgp;
struct config *conf;
start_io_err_stat_thread(vecs);
n_paths = VECTOR_SIZE(mpp->paths);
- /*
+ /*
* assign paths to path groups -- start with no groups and all paths
* in mpp->paths
*/
* transform the mp->pg vector of vectors of paths
* into a mp->params strings to feed the device-mapper
*/
- if (assemble_map(mpp, params, params_size)) {
+ if (assemble_map(mpp, params)) {
condlog(0, "%s: problem assembing map", mpp->alias);
return 1;
}
remove_feature(&mpp_feat, "retain_attached_hw_handler");
remove_feature(&cmpp_feat, "queue_if_no_path");
remove_feature(&cmpp_feat, "retain_attached_hw_handler");
- if (strncmp(mpp_feat, cmpp_feat, PARAMS_SIZE)) {
+ if (strcmp(mpp_feat, cmpp_feat)) {
select_reload_action(mpp, "features change");
FREE(cmpp_feat);
FREE(mpp_feat);
return DOMAP_FAIL;
}
-static int
-deadmap (struct multipath * mpp)
-{
- int i, j;
- struct pathgroup * pgp;
- struct path * pp;
-
- if (!mpp->pg)
- return 1;
-
- vector_foreach_slot (mpp->pg, pgp, i) {
- if (!pgp->paths)
- continue;
-
- vector_foreach_slot (pgp->paths, pp, j)
- if (strlen(pp->dev))
- return 0; /* alive */
- }
-
- return 1; /* dead */
-}
-
-int check_daemon(void)
+extern int
+check_daemon(void)
{
int fd;
char *reply;
int ret = CP_FAIL;
int k, i, r;
int is_daemon = (cmd == CMD_NONE) ? 1 : 0;
- char params[PARAMS_SIZE];
+ char *params __attribute__((cleanup(cleanup_charp))) = NULL;
struct multipath * mpp;
- struct path * pp1;
+ struct path * pp1 = NULL;
struct path * pp2;
vector curmp = vecs->mpvec;
vector pathvec = vecs->pathvec;
vector newmp;
- struct config *conf;
+ struct config *conf = NULL;
int allow_queueing;
struct bitfield *size_mismatch_seen;
if (!mpp->paths) {
condlog(0, "%s: skip coalesce (no paths)", mpp->alias);
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
+ remove_map(mpp, vecs->pathvec, NULL);
continue;
}
}
verify_paths(mpp);
- params[0] = '\0';
- if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
+ if (setup_map(mpp, ¶ms, vecs)) {
+ remove_map(mpp, vecs->pathvec, NULL);
continue;
}
force_reload == FORCE_RELOAD_YES ? 1 : 0);
r = domap(mpp, params, is_daemon);
+ free(params);
+ params = NULL;
if (r == DOMAP_FAIL || r == DOMAP_RETRY) {
condlog(3, "%s: domap (%u) failure "
condlog(2, "%s: %s map",
mpp->alias, (mpp->action == ACT_CREATE)?
"ignoring" : "removing");
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
+ remove_map(mpp, vecs->pathvec, NULL);
continue;
} else /* if (r == DOMAP_RETRY && !is_daemon) */ {
ret = CP_RETRY;
}
if (r == DOMAP_DRY) {
if (!vector_alloc_slot(newmp)) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
+ remove_map(mpp, vecs->pathvec, NULL);
goto out;
}
vector_set_slot(newmp, mpp);
if (mpp->action != ACT_REJECT) {
if (!vector_alloc_slot(newmp)) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
+ remove_map(mpp, vecs->pathvec, NULL);
goto out;
}
vector_set_slot(newmp, mpp);
}
else
- remove_map(mpp, vecs->pathvec, vecs->mpvec,
- KEEP_VEC);
- }
- /*
- * Flush maps with only dead paths (ie not in sysfs)
- * Keep maps with only failed paths
- */
- if (mpvec) {
- vector_foreach_slot (newmp, mpp, i) {
- char alias[WWID_SIZE];
-
- if (!deadmap(mpp))
- continue;
-
- strlcpy(alias, mpp->alias, WWID_SIZE);
-
- vector_del_slot(newmp, i);
- i--;
- remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC);
-
- if (dm_flush_map(alias))
- condlog(2, "%s: remove failed (dead)",
- alias);
- else
- condlog(2, "%s: remove (dead)", alias);
- }
+ remove_map(mpp, vecs->pathvec, NULL);
}
ret = CP_OK;
out:
struct vectors;
-int setup_map (struct multipath * mpp, char * params, int params_size,
- struct vectors *vecs );
+int setup_map (struct multipath * mpp, char **params, struct vectors *vecs);
void select_action (struct multipath *mpp, const struct _vector *curmp,
int force_reload);
int domap (struct multipath * mpp, char * params, int is_daemon);
void trigger_paths_udev_change(struct multipath *mpp, bool is_mpath);
void trigger_partitions_udev_change(struct udev_device *dev, const char *action,
int len);
+int check_daemon(void);
#ifdef LIBDM_API_DEFERRED
static int dm_cancel_remove_partmaps(const char * mapname);
+#define __DR_UNUSED__ /* empty */
+#else
+#define __DR_UNUSED__ __attribute__((unused))
#endif
static int do_foreach_partmaps(const char * mapname,
#define do_deferred(x) ((x) == DEFERRED_REMOVE_ON || (x) == DEFERRED_REMOVE_IN_PROGRESS)
static int
-dm_simplecmd (int task, const char *name, int no_flush, int need_sync, uint16_t udev_flags, int deferred_remove) {
+dm_simplecmd (int task, const char *name, int no_flush, int need_sync,
+ uint16_t udev_flags, int deferred_remove __DR_UNUSED__) {
int r = 0;
int udev_wait_flag = ((need_sync || udev_flags) &&
(task == DM_DEVICE_RESUME ||
return r;
/* If the resume failed, dm will leave the device suspended, and
- * drop the new table, so doing a second resume will try using
- * the original table */
+ * drop the new table, so doing a second resume will try using
+ * the original table */
if (dm_is_suspended(mpp->alias))
dm_simplecmd(DM_DEVICE_RESUME, mpp->alias, !flush, 1,
udev_flags, 0);
return (do_get_info(str, &info) == 0);
}
-int dm_get_map(const char *name, unsigned long long *size, char *outparams)
+int dm_get_map(const char *name, unsigned long long *size, char **outparams)
{
int r = DMP_ERR;
struct dm_task *dmt;
if (size)
*size = length;
- if (!outparams) {
+ if (!outparams)
r = DMP_OK;
- goto out;
+ else {
+ *outparams = strdup(params);
+ r = *outparams ? DMP_OK : DMP_ERR;
}
- if (snprintf(outparams, PARAMS_SIZE, "%s", params) <= PARAMS_SIZE)
- r = DMP_OK;
+
out:
dm_task_destroy(dmt);
return r;
return 0;
}
-int dm_get_status(const char *name, char *outstatus)
+int dm_get_status(const char *name, char **outstatus)
{
int r = DMP_ERR;
struct dm_task *dmt;
goto out;
}
- if (snprintf(outstatus, PARAMS_SIZE, "%s", status) <= PARAMS_SIZE)
+ if (!outstatus)
r = DMP_OK;
+ else {
+ *outstatus = strdup(status);
+ r = *outstatus ? DMP_OK : DMP_ERR;
+ }
out:
if (r != DMP_OK)
condlog(0, "%s: error getting map status string", name);
int queue_if_no_path = 0;
int udev_flags = 0;
unsigned long long mapsize;
- char params[PARAMS_SIZE] = {0};
+ char *params = NULL;
if (dm_is_mpath(mapname) != 1)
return 0; /* nothing to do */
return 1;
if (need_suspend &&
- dm_get_map(mapname, &mapsize, params) == DMP_OK &&
+ dm_get_map(mapname, &mapsize, ¶ms) == DMP_OK &&
strstr(params, "queue_if_no_path")) {
if (!dm_queue_if_no_path(mapname, 0))
queue_if_no_path = 1;
/* Leave queue_if_no_path alone if unset failed */
queue_if_no_path = -1;
}
+ free(params);
+ params = NULL;
if (dm_remove_partmaps(mapname, need_sync, deferred_remove))
return 1;
#else
int
-dm_flush_map_nopaths(const char * mapname, int deferred_remove)
+dm_flush_map_nopaths(const char * mapname,
+ int deferred_remove __attribute__((unused)))
{
return _dm_flush_map(mapname, 1, 0, 0, 0);
}
struct dm_task *dmt;
struct dm_names *names;
unsigned next = 0;
- char params[PARAMS_SIZE];
+ char *params = NULL;
unsigned long long size;
char dev_t[32];
int r = 1;
/*
* and we can fetch the map table from the kernel
*/
- dm_get_map(names->name, &size, ¶ms[0]) == DMP_OK &&
+ dm_get_map(names->name, &size, ¶ms) == DMP_OK &&
/*
* and the table maps over the multipath map
goto out;
}
+ free(params);
+ params = NULL;
next = names->next;
names = (void *) names + next;
} while (next);
r = 0;
out:
+ free(params);
dm_task_destroy (dmt);
return r;
}
#else
int
-dm_cancel_deferred_remove (struct multipath *mpp)
+dm_cancel_deferred_remove (struct multipath *mpp __attribute__((unused)))
{
return 0;
}
static int
rename_partmap (const char *name, void *data)
{
- char buff[PARAMS_SIZE];
+ char *buff = NULL;
int offset;
struct rename_data *rd = (struct rename_data *)data;
if (strncmp(name, rd->old, strlen(rd->old)) != 0)
return 0;
for (offset = strlen(rd->old); name[offset] && !(isdigit(name[offset])); offset++); /* do nothing */
- snprintf(buff, PARAMS_SIZE, "%s%s%s", rd->new, rd->delim,
- name + offset);
- dm_rename(name, buff, rd->delim, SKIP_KPARTX_OFF);
- condlog(4, "partition map %s renamed", name);
+ if (asprintf(&buff, "%s%s%s", rd->new, rd->delim, name + offset) >= 0) {
+ dm_rename(name, buff, rd->delim, SKIP_KPARTX_OFF);
+ free(buff);
+ condlog(4, "partition map %s renamed", name);
+ } else
+ condlog(1, "failed to rename partition map %s", name);
return 0;
}
int dm_addmap_reload (struct multipath *mpp, char *params, int flush);
int dm_map_present (const char *);
int dm_map_present_by_uuid(const char *uuid);
-int dm_get_map(const char *, unsigned long long *, char *);
-int dm_get_status(const char *, char *);
+int dm_get_map(const char *, unsigned long long *, char **);
+int dm_get_status(const char *, char **);
int dm_type(const char *, char *);
int dm_is_mpath(const char *);
int _dm_flush_map (const char *, int, int, int, int);
#include <mpath_persist.h>
#include "mpath_cmd.h"
#include "dict.h"
+#include "strbuf.h"
static int
set_int(vector strvec, void *ptr)
return 0;
}
-static int
-print_int (char *buff, int len, long v)
+static int print_int(struct strbuf *buff, long v)
{
- return snprintf(buff, len, "%li", v);
+ return print_strbuf(buff, "%li", v);
}
-static int
-print_nonzero (char *buff, int len, long v)
+static int print_nonzero(struct strbuf *buff, long v)
{
if (!v)
return 0;
- return snprintf(buff, len, "%li", v);
+ return print_strbuf(buff, "%li", v);
}
-static int
-print_str (char *buff, int len, const char *ptr)
+static int print_str(struct strbuf *buff, const char *ptr)
{
- char *p;
- char *last;
- const char *q;
+ int ret = append_strbuf_quoted(buff, ptr);
- if (!ptr || len <= 0)
- return 0;
-
- q = strchr(ptr, '"');
- if (q == NULL)
- return snprintf(buff, len, "\"%s\"", ptr);
-
- last = buff + len - 1;
- p = buff;
- if (p >= last)
- goto out;
- *p++ = '"';
- if (p >= last)
- goto out;
- for (; q; q = strchr(ptr, '"')) {
- if (q + 1 - ptr < last - p)
- p = mempcpy(p, ptr, q + 1 - ptr);
- else {
- p = mempcpy(p, ptr, last - p);
- goto out;
- }
- *p++ = '"';
- if (p >= last)
- goto out;
- ptr = q + 1;
- }
- p += strlcpy(p, ptr, last - p);
- if (p >= last)
- goto out;
- *p++ = '"';
- *p = '\0';
- return p - buff;
-out:
- *p = '\0';
- return len;
+ /*
+ * -EINVAL aka (ptr == NULL) means "not set".
+ * Returning an error here breaks unit tests
+ * (logic in snprint_keyword()).
+ */
+ return ret == -EINVAL ? 0 : ret;
}
-static int
-print_ignored (char *buff, int len)
+static int print_ignored(struct strbuf *buff)
{
- return snprintf(buff, len, "ignored");
+ return append_strbuf_quoted(buff, "ignored");
}
-static int
-print_yes_no (char *buff, int len, long v)
+static int print_yes_no(struct strbuf *buff, long v)
{
- return snprintf(buff, len, "\"%s\"",
- (v == YN_NO)? "no" : "yes");
+ return append_strbuf_quoted(buff, v == YN_NO ? "no" : "yes");
}
-static int
-print_yes_no_undef (char *buff, int len, long v)
+static int print_yes_no_undef(struct strbuf *buff, long v)
{
if (!v)
return 0;
- return snprintf(buff, len, "\"%s\"",
- (v == YNU_NO)? "no" : "yes");
+ return append_strbuf_quoted(buff, v == YNU_NO? "no" : "yes");
}
#define declare_def_handler(option, function) \
#define declare_def_snprint(option, function) \
static int \
-snprint_def_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
- return function (buff, len, conf->option); \
+ return function(buff, conf->option); \
}
#define declare_def_snprint_defint(option, function, value) \
static int \
-snprint_def_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
int i = value; \
if (!conf->option) \
- return function (buff, len, i); \
- return function (buff, len, conf->option); \
+ return function(buff, i); \
+ return function (buff, conf->option); \
}
#define declare_def_snprint_defstr(option, function, value) \
static int \
-snprint_def_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
static const char *s = value; \
if (!conf->option) \
- return function (buff, len, s); \
- return function (buff, len, conf->option); \
+ return function(buff, s); \
+ return function(buff, conf->option); \
}
#define declare_hw_handler(option, function) \
#define declare_hw_snprint(option, function) \
static int \
-snprint_hw_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_hw_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
const struct hwentry * hwe = (const struct hwentry *)data; \
- return function (buff, len, hwe->option); \
+ return function(buff, hwe->option); \
}
#define declare_ovr_handler(option, function) \
#define declare_ovr_snprint(option, function) \
static int \
-snprint_ovr_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_ovr_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
- return function (buff, len, conf->overrides->option); \
+ return function (buff, conf->overrides->option); \
}
#define declare_mp_handler(option, function) \
#define declare_mp_snprint(option, function) \
static int \
-snprint_mp_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_mp_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
const struct mpentry * mpe = (const struct mpentry *)data; \
- return function (buff, len, mpe->option); \
+ return function(buff, mpe->option); \
}
static int checkint_handler(struct config *conf, vector strvec)
return 0;
}
-static int snprint_def_partition_delim(struct config *conf, char *buff,
- int len, const void *data)
+static int snprint_def_partition_delim(struct config *conf, struct strbuf *buff,
+ const void *data)
{
if (default_partition_delim == NULL || conf->partition_delim != NULL)
- return print_str(buff, len, conf->partition_delim);
+ return print_str(buff, conf->partition_delim);
else
- return print_str(buff, len, UNSET_PARTITION_DELIM);
+ return print_str(buff, UNSET_PARTITION_DELIM);
}
static const char * const find_multipaths_optvals[] = {
}
static int
-snprint_def_find_multipaths(struct config *conf, char *buff, int len,
+snprint_def_find_multipaths(struct config *conf, struct strbuf *buff,
const void *data)
{
- return print_str(buff, len,
+ return append_strbuf_quoted(buff,
find_multipaths_optvals[conf->find_multipaths]);
}
declare_mp_handler(selector, set_str)
declare_mp_snprint(selector, print_str)
-static int snprint_uid_attrs(struct config *conf, char *buff, int len,
+static int snprint_uid_attrs(struct config *conf, struct strbuf *buff,
const void *dummy)
{
- char *p = buff;
- int n, j;
+ int j, ret, total = 0;
const char *att;
vector_foreach_slot(&conf->uid_attrs, att, j) {
- n = snprintf(p, len, "%s%s", j == 0 ? "" : " ", att);
- if (n >= len)
- return (p - buff) + n;
- p += n;
- len -= n;
+ ret = print_strbuf(buff, "%s%s", j == 0 ? "" : " ", att);
+ if (ret < 0)
+ return ret;
+ total += ret;
}
- return p - buff;
+ return total;
}
static int uid_attrs_handler(struct config *conf, vector strvec)
declare_def_handler(queue_without_daemon, set_yes_no)
static int
-snprint_def_queue_without_daemon (struct config *conf,
- char * buff, int len, const void * data)
+snprint_def_queue_without_daemon(struct config *conf, struct strbuf *buff,
+ const void * data)
{
+ const char *qwd = "unknown";
+
switch (conf->queue_without_daemon) {
case QUE_NO_DAEMON_OFF:
- return snprintf(buff, len, "\"no\"");
+ qwd = "no";
+ break;
case QUE_NO_DAEMON_ON:
- return snprintf(buff, len, "\"yes\"");
+ qwd = "yes";
+ break;
case QUE_NO_DAEMON_FORCE:
- return snprintf(buff, len, "\"forced\"");
+ qwd = "forced";
+ break;
}
- return 0;
+ return append_strbuf_quoted(buff, qwd);
}
declare_def_handler(checker_timeout, set_int)
{
return 0;
}
-static int snprint_def_disable_changed_wwids(struct config *conf, char *buff,
- int len, const void *data)
+static int snprint_def_disable_changed_wwids(struct config *conf,
+ struct strbuf *buff,
+ const void *data)
{
- return print_ignored(buff, len);
+ return print_ignored(buff);
}
declare_def_handler(remove_retries, set_int)
#define declare_def_attr_snprint(option, function) \
static int \
-snprint_def_ ## option (struct config *conf, char * buff, int len, \
- const void * data) \
+snprint_def_ ## option (struct config *conf, struct strbuf *buff, \
+ const void *data) \
{ \
- return function (buff, len, conf->option, \
- conf->attribute_flags); \
+ return function(buff, conf->option, conf->attribute_flags); \
}
#define declare_mp_attr_handler(option, function) \
#define declare_mp_attr_snprint(option, function) \
static int \
-snprint_mp_ ## option (struct config *conf, char * buff, int len, \
+snprint_mp_ ## option (struct config *conf, struct strbuf *buff, \
const void * data) \
{ \
const struct mpentry * mpe = (const struct mpentry *)data; \
- return function (buff, len, mpe->option, \
- mpe->attribute_flags); \
+ return function(buff, mpe->option, mpe->attribute_flags); \
}
static int
}
static int
-print_mode(char * buff, int len, long v, int flags)
+print_mode(struct strbuf *buff, long v, int flags)
{
mode_t mode = (mode_t)v;
if ((flags & (1 << ATTR_MODE)) == 0)
return 0;
- return snprintf(buff, len, "0%o", mode);
+ return print_strbuf(buff, "0%o", mode);
}
static int
-print_uid(char * buff, int len, long v, int flags)
+print_uid(struct strbuf *buff, long v, int flags)
{
uid_t uid = (uid_t)v;
if ((flags & (1 << ATTR_UID)) == 0)
return 0;
- return snprintf(buff, len, "0%o", uid);
+ return print_strbuf(buff, "0%o", uid);
}
static int
-print_gid(char * buff, int len, long v, int flags)
+print_gid(struct strbuf *buff, long v, int flags)
{
gid_t gid = (gid_t)v;
if ((flags & (1 << ATTR_GID)) == 0)
return 0;
- return snprintf(buff, len, "0%o", gid);
+ return print_strbuf(buff, "0%o", gid);
}
declare_def_attr_handler(mode, set_mode)
return 0;
}
-int
-print_undef_off_zero(char * buff, int len, long v)
+int print_undef_off_zero(struct strbuf *buff, long v)
{
if (v == UOZ_UNDEF)
return 0;
if (v == UOZ_OFF)
- return snprintf(buff, len, "\"off\"");
+ return append_strbuf_str(buff, "off");
if (v == UOZ_ZERO)
- return snprintf(buff, len, "0");
- return snprintf(buff, len, "%ld", v);
+ return append_strbuf_str(buff, "0");
+ return print_int(buff, v);
}
declare_def_handler(fast_io_fail, set_undef_off_zero)
}
int
-print_dev_loss(char * buff, int len, unsigned long v)
+print_dev_loss(struct strbuf *buff, unsigned long v)
{
if (v == DEV_LOSS_TMO_UNSET)
return 0;
if (v >= MAX_DEV_LOSS_TMO)
- return snprintf(buff, len, "\"infinity\"");
- return snprintf(buff, len, "%lu", v);
+ return append_strbuf_quoted(buff, "infinity");
+ return print_strbuf(buff, "%lu", v);
}
declare_def_handler(dev_loss, set_dev_loss)
}
int
-print_pgpolicy(char * buff, int len, long pgpolicy)
+print_pgpolicy(struct strbuf *buff, long pgpolicy)
{
char str[POLICY_NAME_SIZE];
get_pgpolicy_name(str, POLICY_NAME_SIZE, pgpolicy);
- return snprintf(buff, len, "\"%s\"", str);
+ return append_strbuf_quoted(buff, str);
}
declare_def_handler(pgpolicy, set_pgpolicy)
}
static int
-snprint_max_fds (struct config *conf, char * buff, int len, const void * data)
+snprint_max_fds (struct config *conf, struct strbuf *buff, const void *data)
{
int r = 0, max_fds;
r = get_sys_max_fds(&max_fds);
if (!r && conf->max_fds >= max_fds)
- return snprintf(buff, len, "\"max\"");
+ return append_strbuf_quoted(buff, "max");
else
- return snprintf(buff, len, "%d", conf->max_fds);
+ return print_int(buff, conf->max_fds);
}
static int
}
int
-print_rr_weight (char * buff, int len, long v)
+print_rr_weight (struct strbuf *buff, long v)
{
if (!v)
return 0;
if (v == RR_WEIGHT_PRIO)
- return snprintf(buff, len, "\"priorities\"");
+ return append_strbuf_quoted(buff, "priorities");
if (v == RR_WEIGHT_NONE)
- return snprintf(buff, len, "\"uniform\"");
+ return append_strbuf_quoted(buff, "uniform");
return 0;
}
}
int
-print_pgfailback (char * buff, int len, long v)
+print_pgfailback (struct strbuf *buff, long v)
{
switch(v) {
case FAILBACK_UNDEF:
return 0;
case -FAILBACK_MANUAL:
- return snprintf(buff, len, "\"manual\"");
+ return append_strbuf_quoted(buff, "manual");
case -FAILBACK_IMMEDIATE:
- return snprintf(buff, len, "\"immediate\"");
+ return append_strbuf_quoted(buff, "immediate");
case -FAILBACK_FOLLOWOVER:
- return snprintf(buff, len, "\"followover\"");
+ return append_strbuf_quoted(buff, "followover");
default:
- return snprintf(buff, len, "%li", v);
+ return print_int(buff, v);
}
}
}
int
-print_no_path_retry(char * buff, int len, long v)
+print_no_path_retry(struct strbuf *buff, long v)
{
switch(v) {
case NO_PATH_RETRY_UNDEF:
return 0;
case NO_PATH_RETRY_FAIL:
- return snprintf(buff, len, "\"fail\"");
+ return append_strbuf_quoted(buff, "fail");
case NO_PATH_RETRY_QUEUE:
- return snprintf(buff, len, "\"queue\"");
+ return append_strbuf_quoted(buff, "queue");
default:
- return snprintf(buff, len, "%li", v);
+ return print_int(buff, v);
}
}
}
static int
-snprint_def_log_checker_err (struct config *conf, char * buff, int len,
- const void * data)
+snprint_def_log_checker_err(struct config *conf, struct strbuf *buff,
+ const void * data)
{
if (conf->log_checker_err == LOG_CHKR_ERR_ONCE)
- return snprintf(buff, len, "once");
- return snprintf(buff, len, "always");
+ return append_strbuf_quoted(buff, "once");
+ return append_strbuf_quoted(buff, "always");
}
static int
}
int
-print_reservation_key(char * buff, int len, struct be64 key, uint8_t flags,
- int source)
+print_reservation_key(struct strbuf *buff,
+ struct be64 key, uint8_t flags, int source)
{
char *flagstr = "";
if (source == PRKEY_SOURCE_NONE)
return 0;
if (source == PRKEY_SOURCE_FILE)
- return snprintf(buff, len, "file");
+ return append_strbuf_quoted(buff, "file");
if (flags & MPATH_F_APTPL_MASK)
flagstr = ":aptpl";
- return snprintf(buff, len, "0x%" PRIx64 "%s", get_be64(key),
- flagstr);
+ return print_strbuf(buff, "0x%" PRIx64 "%s", get_be64(key), flagstr);
}
static int
}
static int
-snprint_def_reservation_key (struct config *conf, char * buff, int len,
+snprint_def_reservation_key (struct config *conf, struct strbuf *buff,
const void * data)
{
- return print_reservation_key(buff, len, conf->reservation_key,
- conf->sa_flags,
- conf->prkey_source);
+ return print_reservation_key(buff, conf->reservation_key,
+ conf->sa_flags, conf->prkey_source);
}
static int
}
static int
-snprint_mp_reservation_key (struct config *conf, char * buff, int len,
- const void * data)
+snprint_mp_reservation_key (struct config *conf, struct strbuf *buff,
+ const void *data)
{
const struct mpentry * mpe = (const struct mpentry *)data;
- return print_reservation_key(buff, len, mpe->reservation_key,
- mpe->sa_flags,
- mpe->prkey_source);
+ return print_reservation_key(buff, mpe->reservation_key,
+ mpe->sa_flags, mpe->prkey_source);
}
static int
}
int
-print_off_int_undef(char * buff, int len, long v)
+print_off_int_undef(struct strbuf *buff, long v)
{
switch(v) {
case NU_UNDEF:
return 0;
case NU_NO:
- return snprintf(buff, len, "\"no\"");
+ return append_strbuf_quoted(buff, "no");
default:
- return snprintf(buff, len, "%li", v);
+ return print_int(buff, v);
}
}
}
static int
-snprint_hw_vpd_vendor(struct config *conf, char * buff, int len,
+snprint_hw_vpd_vendor(struct config *conf, struct strbuf *buff,
const void * data)
{
const struct hwentry * hwe = (const struct hwentry *)data;
if (hwe->vpd_vendor_id > 0 && hwe->vpd_vendor_id < VPD_VP_ARRAY_SIZE)
- return snprintf(buff, len, "%s",
+ return append_strbuf_quoted(buff,
vpd_vendor_pages[hwe->vpd_vendor_id].name);
return 0;
}
declare_ble_handler(elist_protocol)
static int
-snprint_def_uxsock_timeout(struct config *conf, char * buff, int len,
- const void * data)
+snprint_def_uxsock_timeout(struct config *conf, struct strbuf *buff,
+ const void *data)
{
- return snprintf(buff, len, "%u", conf->uxsock_timeout);
+ return print_strbuf(buff, "%u", conf->uxsock_timeout);
}
static int
-snprint_ble_simple (struct config *conf, char * buff, int len,
- const void * data)
+snprint_ble_simple (struct config *conf, struct strbuf *buff, const void *data)
{
- const struct blentry * ble = (const struct blentry *)data;
+ const struct blentry *ble = (const struct blentry *)data;
- return snprintf(buff, len, "\"%s\"", ble->str);
+ return print_str(buff, ble->str);
}
static int
declare_ble_device_handler(product, blist_device, NULL, buff)
declare_ble_device_handler(product, elist_device, NULL, buff)
-static int
-snprint_bled_vendor (struct config *conf, char * buff, int len,
- const void * data)
+static int snprint_bled_vendor(struct config *conf, struct strbuf *buff,
+ const void * data)
{
const struct blentry_device * bled =
(const struct blentry_device *)data;
- return snprintf(buff, len, "\"%s\"", bled->vendor);
+ return print_str(buff, bled->vendor);
}
-static int
-snprint_bled_product (struct config *conf, char * buff, int len,
- const void * data)
+static int snprint_bled_product(struct config *conf, struct strbuf *buff,
+ const void *data)
{
const struct blentry_device * bled =
(const struct blentry_device *)data;
- return snprintf(buff, len, "\"%s\"", bled->product);
+ return print_str(buff, bled->product);
}
/*
}
static int
-snprint_deprecated (struct config *conf, char * buff, int len,
- const void * data)
+snprint_deprecated (struct config *conf, struct strbuf *buff, const void * data)
{
return 0;
}
#endif
#include "byteorder.h"
+struct strbuf;
void init_keywords(vector keywords);
int get_sys_max_fds(int *);
-int print_rr_weight(char *buff, int len, long v);
-int print_pgfailback(char *buff, int len, long v);
-int print_pgpolicy(char *buff, int len, long v);
-int print_no_path_retry(char *buff, int len, long v);
-int print_undef_off_zero(char *buff, int len, long v);
-int print_dev_loss(char *buff, int len, unsigned long v);
-int print_reservation_key(char * buff, int len, struct be64 key, uint8_t
- flags, int source);
-int print_off_int_undef(char *buff, int len, long v);
+int print_rr_weight(struct strbuf *buff, long v);
+int print_pgfailback(struct strbuf *buff, long v);
+int print_pgpolicy(struct strbuf *buff, long v);
+int print_no_path_retry(struct strbuf *buff, long v);
+int print_undef_off_zero(struct strbuf *buff, long v);
+int print_dev_loss(struct strbuf *buff, unsigned long v);
+int print_reservation_key(struct strbuf *buff,
+ struct be64 key, uint8_t flags, int source);
+int print_off_int_undef(struct strbuf *buff, long v);
#endif /* _DICT_H */
#include "foreign.h"
#include "configure.h"
#include "print.h"
+#include "strbuf.h"
struct vpd_vendor_page vpd_vendor_pages[VPD_VP_ARRAY_SIZE] = {
[VPD_VP_UNDEF] = { 0x00, "undef" },
{
struct udev_device *rport_dev = NULL;
char value[16], *eptr;
- char rport_id[32];
+ char rport_id[42];
unsigned int tmo;
int ret;
}
if (err_path) {
- char proto_buf[32];
+ STRBUF_ON_STACK(proto_buf);
- snprint_path_protocol(proto_buf, sizeof(proto_buf), err_path);
+ snprint_path_protocol(&proto_buf, err_path);
condlog(2, "%s: setting dev_loss_tmo is unsupported for protocol %s",
- mpp->alias, proto_buf);
+ mpp->alias, get_strbuf_str(&proto_buf));
}
return 0;
}
attr_path = udev_device_get_sysname(parent);
if (!attr_path)
break;
- if (sscanf(attr_path, "%i:%i:%i:%i",
+ if (sscanf(attr_path, "%i:%i:%i:%" SCNu64,
&pp->sg_id.host_no,
&pp->sg_id.channel,
&pp->sg_id.scsi_id,
/*
* host / bus / target / lun
*/
- condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+ condlog(3, "%s: h:b:t:l = %i:%i:%i:%" PRIu64,
pp->dev,
pp->sg_id.host_no,
pp->sg_id.channel,
&pp->sg_id.host_no,
&pp->sg_id.channel,
&pp->sg_id.scsi_id) == 3) {
- condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+ condlog(3, "%s: h:b:t:l = %i:%i:%i:%" PRIu64,
pp->dev,
pp->sg_id.host_no,
pp->sg_id.channel,
*/
pp->sg_id.lun = 0;
pp->sg_id.channel = 0;
- condlog(3, "%s: h:b:t:l = %i:%i:%i:%i",
+ condlog(3, "%s: h:b:t:l = %i:%i:%i:%" PRIu64,
pp->dev,
pp->sg_id.host_no,
pp->sg_id.channel,
attr_path = udev_device_get_sysname(parent);
if (!attr_path)
break;
- if (sscanf(attr_path, "%i:%i:%i:%i",
+ if (sscanf(attr_path, "%i:%i:%i:%" SCNu64,
&pp->sg_id.host_no,
&pp->sg_id.channel,
&pp->sg_id.scsi_id,
* It's likely that this path is not fit for
* multipath use.
*/
- char buf[16];
+ STRBUF_ON_STACK(buf);
- snprint_path(buf, sizeof(buf), "%T", pp, 0);
+ snprint_path(&buf, "%T", pp, 0);
condlog(1, "%s: no WWID in state \"%s\", giving up",
- pp->dev, buf);
+ pp->dev, get_strbuf_str(&buf));
return PATHINFO_SKIPPED;
}
return PATHINFO_OK;
#include "util.h"
#include "debug.h"
#include "dmparser.h"
+#include "strbuf.h"
#define WORD_SIZE 64
return 0;
}
-#define APPEND(p, end, args...) \
-({ \
- int ret; \
- \
- ret = snprintf(p, end - p, ##args); \
- if (ret < 0) { \
- condlog(0, "%s: conversion error", mp->alias); \
- goto err; \
- } \
- p += ret; \
- if (p >= end) { \
- condlog(0, "%s: params too small", mp->alias); \
- goto err; \
- } \
-})
-
/*
* Transforms the path group vector into a proper device map string
*/
-int
-assemble_map (struct multipath * mp, char * params, int len)
+int assemble_map(struct multipath *mp, char **params)
{
+ static const char no_path_retry[] = "queue_if_no_path";
+ static const char retain_hwhandler[] = "retain_attached_hw_handler";
int i, j;
int minio;
int nr_priority_groups, initial_pg_nr;
- char * p;
- const char *const end = params + len;
- char no_path_retry[] = "queue_if_no_path";
- char retain_hwhandler[] = "retain_attached_hw_handler";
+ STRBUF_ON_STACK(buff);
struct pathgroup * pgp;
struct path * pp;
minio = mp->minio;
- p = params;
nr_priority_groups = VECTOR_SIZE(mp->pg);
initial_pg_nr = (nr_priority_groups ? mp->bestpg : 0);
get_linux_version_code() < KERNEL_VERSION(4, 3, 0))
add_feature(&mp->features, retain_hwhandler);
- /* mp->features must not be NULL */
- APPEND(p, end, "%s %s %i %i", mp->features, mp->hwhandler,
- nr_priority_groups, initial_pg_nr);
+ if (print_strbuf(&buff, "%s %s %i %i", mp->features, mp->hwhandler,
+ nr_priority_groups, initial_pg_nr) < 0)
+ goto err;
vector_foreach_slot (mp->pg, pgp, i) {
pgp = VECTOR_SLOT(mp->pg, i);
- APPEND(p, end, " %s %i 1", mp->selector,
- VECTOR_SIZE(pgp->paths));
+ if (print_strbuf(&buff, " %s %i 1", mp->selector,
+ VECTOR_SIZE(pgp->paths)) < 0)
+ goto err;
vector_foreach_slot (pgp->paths, pp, j) {
int tmp_minio = minio;
condlog(0, "dev_t not set for '%s'", pp->dev);
goto err;
}
- APPEND(p, end, " %s %d", pp->dev_t, tmp_minio);
+ if (print_strbuf(&buff, " %s %d", pp->dev_t, tmp_minio) < 0)
+ goto err;
}
}
- condlog(4, "%s: assembled map [%s]", mp->alias, params);
+ *params = steal_strbuf_str(&buff);
+ condlog(4, "%s: assembled map [%s]", mp->alias, *params);
return 0;
err:
return 1;
}
-#undef APPEND
-
/*
* Caution callers: If this function encounters yet unkown path devices, it
* adds them uninitialized to the mpp.
-int assemble_map (struct multipath *, char *, int);
+int assemble_map (struct multipath *, char **);
int disassemble_map (const struct _vector *, const char *, struct multipath *);
int disassemble_status (const char *, struct multipath *);
#include "structs.h"
#include "structs_vec.h"
#include "print.h"
+#include "strbuf.h"
static vector foreigns;
pthread_cleanup_pop(1);
}
-int snprint_foreign_topology(char *buf, int len, int verbosity)
+int snprint_foreign_topology(struct strbuf *buf, int verbosity)
{
struct foreign *fgn;
int i;
- char *c = buf;
+ size_t initial_len = get_strbuf_len(buf);
rdlock_foreigns();
if (foreigns == NULL) {
vec = fgn->get_multipaths(fgn->context);
if (vec != NULL) {
vector_foreach_slot(vec, gm, j) {
-
- c += _snprint_multipath_topology(gm, c,
- buf + len - c,
- verbosity);
- if (c >= buf + len - 1)
+ if (_snprint_multipath_topology(
+ gm, buf, verbosity) < 0)
break;
}
- if (c >= buf + len - 1)
- break;
}
fgn->release_multipaths(fgn->context, vec);
pthread_cleanup_pop(1);
}
pthread_cleanup_pop(1);
- return c - buf;
+ return get_strbuf_len(buf) - initial_len;
}
void print_foreign_topology(int verbosity)
{
- int buflen = MAX_LINE_LEN * MAX_LINES;
- char *buf = NULL, *tmp = NULL;
-
- buf = calloc(1, buflen);
-
- while (buf != NULL) {
- char *c = buf;
-
- c += snprint_foreign_topology(buf, buflen,
- verbosity);
- if (c < buf + buflen - 1)
- break;
-
- buflen *= 2;
- tmp = buf;
- buf = realloc(buf, buflen);
- }
+ STRBUF_ON_STACK(buf);
- if (buf == NULL && tmp != NULL)
- buf = tmp;
-
- if (buf != NULL) {
- printf("%s", buf);
- free(buf);
- }
+ snprint_foreign_topology(&buf, verbosity);
+ printf("%s", get_strbuf_str(&buf));
}
-int snprint_foreign_paths(char *buf, int len, const char *style, int pretty)
+int snprint_foreign_paths(struct strbuf *buf, const char *style, int pretty)
{
struct foreign *fgn;
int i;
- char *c = buf;
+ size_t initial_len = get_strbuf_len(buf);
rdlock_foreigns();
if (foreigns == NULL) {
vector_foreach_slot(foreigns, fgn, i) {
const struct _vector *vec;
const struct gen_path *gp;
- int j;
+ int j, ret = 0;
fgn->lock(fgn->context);
pthread_cleanup_push(fgn->unlock, fgn->context);
vec = fgn->get_paths(fgn->context);
if (vec != NULL) {
vector_foreach_slot(vec, gp, j) {
- c += _snprint_path(gp, c, buf + len - c,
- style, pretty);
- if (c >= buf + len - 1)
+ ret = _snprint_path(gp, buf, style, pretty);
+ if (ret < 0)
break;
}
- if (c >= buf + len - 1)
- break;
}
fgn->release_paths(fgn->context, vec);
pthread_cleanup_pop(1);
+ if (ret < 0)
+ break;
}
pthread_cleanup_pop(1);
- return c - buf;
+ return get_strbuf_len(buf) - initial_len;
}
-int snprint_foreign_multipaths(char *buf, int len,
+int snprint_foreign_multipaths(struct strbuf *buf,
const char *style, int pretty)
{
struct foreign *fgn;
int i;
- char *c = buf;
+ size_t initial_len = get_strbuf_len(buf);
rdlock_foreigns();
if (foreigns == NULL) {
vector_foreach_slot(foreigns, fgn, i) {
const struct _vector *vec;
const struct gen_multipath *gm;
- int j;
+ int j, ret = 0;
fgn->lock(fgn->context);
pthread_cleanup_push(fgn->unlock, fgn->context);
vec = fgn->get_multipaths(fgn->context);
if (vec != NULL) {
vector_foreach_slot(vec, gm, j) {
- c += _snprint_multipath(gm, c, buf + len - c,
- style, pretty);
- if (c >= buf + len - 1)
+ ret = _snprint_multipath(gm, buf,
+ style, pretty);
+ if (ret < 0)
break;
}
- if (c >= buf + len - 1)
- break;
}
fgn->release_multipaths(fgn->context, vec);
pthread_cleanup_pop(1);
+ if (ret < 0)
+ break;
}
pthread_cleanup_pop(1);
- return c - buf;
+ return get_strbuf_len(buf) - initial_len;
}
#define _FOREIGN_H
#include <stdbool.h>
#include <libudev.h>
+#define LIBMP_FOREIGN_API ((1 << 8) | 1)
-#define LIBMP_FOREIGN_API ((1 << 8) | 0)
-
+struct strbuf;
struct context;
/* return codes of functions below returning "int" */
* prints topology information from foreign libraries into buffer,
* '\0' - terminated.
* @param buf: output buffer
- * @param len: size of output buffer
* @param verbosity: verbosity level
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_topology(char *buf, int len, int verbosity);
+int snprint_foreign_topology(struct strbuf *buf, int verbosity);
/**
* snprint_foreign_paths(buf, len, style, pad);
* prints formatted path information from foreign libraries into buffer,
* '\0' - terminated.
* @param buf: output buffer
- * @param len: size of output buffer
* @param style: format string
* @param pad: whether to pad field width
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_paths(char *buf, int len, const char *style, int pad);
+int snprint_foreign_paths(struct strbuf *buf, const char *style, int pad);
/**
* snprint_foreign_multipaths(buf, len, style, pad);
* prints formatted map information from foreign libraries into buffer,
* '\0' - terminated.
* @param buf: output buffer
- * @param len: size of output buffer
* @param style: format string
* @param pad: whether to pad field width
* @returns: number of printed characters excluding trailing '\0'.
*/
-int snprint_foreign_multipaths(char *buf, int len,
+int snprint_foreign_multipaths(struct strbuf *buf,
const char *style, int pretty);
/**
#include "debug.h"
#include "structs.h"
#include "sysfs.h"
+#include "strbuf.h"
static const char nvme_vendor[] = "NVMe";
static const char N_A[] = "n/a";
}
static int snprint_nvme_map(const struct gen_multipath *gmp,
- char *buff, int len, char wildcard)
+ struct strbuf *buff, char wildcard)
{
const struct nvme_map *nvm = const_gen_mp_to_nvme(gmp);
char fld[NAME_LEN];
switch (wildcard) {
case 'd':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysname(nvm->udev));
case 'n':
- return snprintf(buff, len, "%s:nsid.%s",
+ return print_strbuf(buff, "%s:nsid.%s",
udev_device_get_sysattr_value(nvm->subsys,
"subsysnqn"),
udev_device_get_sysattr_value(nvm->udev,
"nsid"));
case 'w':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysattr_value(nvm->udev,
"wwid"));
case 'N':
- return snprintf(buff, len, "%u", nvm->nr_live);
+ return print_strbuf(buff, "%u", nvm->nr_live);
case 'S':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysattr_value(nvm->udev,
"size"));
case 'v':
- return snprintf(buff, len, "%s", nvme_vendor);
+ return append_strbuf_str(buff, nvme_vendor);
case 's':
case 'p':
snprintf(fld, sizeof(fld), "%s",
"model"));
rstrip(fld);
if (wildcard == 'p')
- return snprintf(buff, len, "%s", fld);
- return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
+ return append_strbuf_str(buff, fld);
+ return print_strbuf(buff, "%s,%s,%s", nvme_vendor, fld,
udev_device_get_sysattr_value(nvm->subsys,
"firmware_rev"));
case 'e':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysattr_value(nvm->subsys,
"firmware_rev"));
case 'r':
val = udev_device_get_sysattr_value(nvm->udev, "ro");
if (val[0] == 1)
- return snprintf(buff, len, "%s", "ro");
+ return append_strbuf_str(buff, "ro");
else
- return snprintf(buff, len, "%s", "rw");
+ return append_strbuf_str(buff, "rw");
case 'G':
- return snprintf(buff, len, "%s", THIS);
+ return append_strbuf_str(buff, THIS);
case 'h':
if (nvm->ana_supported == YNU_YES)
- return snprintf(buff, len, "ANA");
+ return append_strbuf_str(buff, "ANA");
default:
break;
}
- return snprintf(buff, len, N_A);
+ return append_strbuf_str(buff, N_A);
}
static const struct _vector*
/* empty */
}
-static int snprint_hcil(const struct nvme_path *np, char *buf, int len)
+static int snprint_hcil(const struct nvme_path *np, struct strbuf *buf)
{
unsigned int nvmeid, ctlid, nsid;
int rc;
rc = sscanf(sysname, "nvme%uc%un%u", &nvmeid, &ctlid, &nsid);
if (rc != 3) {
condlog(1, "%s: failed to scan %s", __func__, sysname);
- rc = snprintf(buf, len, "(ERR:%s)", sysname);
+ return print_strbuf(buf, "(ERR:%s)", sysname);
} else
- rc = snprintf(buf, len, "%u:%u:%u", nvmeid, ctlid, nsid);
- return (rc < len ? rc : len);
+ return print_strbuf(buf, "%u:%u:%u", nvmeid, ctlid, nsid);
}
static int snprint_nvme_path(const struct gen_path *gp,
- char *buff, int len, char wildcard)
+ struct strbuf *buff, char wildcard)
{
const struct nvme_path *np = const_gen_path_to_nvme(gp);
dev_t devt;
switch (wildcard) {
case 'w':
- return snprintf(buff, len, "%s",
- udev_device_get_sysattr_value(np->udev,
- "wwid"));
+ return print_strbuf(buff, "%s",
+ udev_device_get_sysattr_value(np->udev,
+ "wwid"));
case 'd':
- return snprintf(buff, len, "%s",
- udev_device_get_sysname(np->udev));
+ return print_strbuf(buff, "%s",
+ udev_device_get_sysname(np->udev));
case 'i':
- return snprint_hcil(np, buff, len);
+ return snprint_hcil(np, buff);
case 'D':
devt = udev_device_get_devnum(np->udev);
- return snprintf(buff, len, "%u:%u", major(devt), minor(devt));
+ return print_strbuf(buff, "%u:%u", major(devt), minor(devt));
case 'o':
if (sysfs_attr_get_value(np->ctl, "state",
fld, sizeof(fld)) > 0)
- return snprintf(buff, len, "%s", fld);
+ return append_strbuf_str(buff, fld);
break;
case 'T':
if (sysfs_attr_get_value(np->udev, "ana_state", fld,
sizeof(fld)) > 0)
- return snprintf(buff, len, "%s", fld);
+ return append_strbuf_str(buff, fld);
break;
case 'p':
if (sysfs_attr_get_value(np->udev, "ana_state", fld,
sizeof(fld)) > 0) {
rstrip(fld);
if (!strcmp(fld, "optimized"))
- return snprintf(buff, len, "%d", 50);
+ return print_strbuf(buff, "%d", 50);
else if (!strcmp(fld, "non-optimized"))
- return snprintf(buff, len, "%d", 10);
+ return print_strbuf(buff, "%d", 10);
else
- return snprintf(buff, len, "%d", 0);
+ return print_strbuf(buff, "%d", 0);
}
break;
case 's':
udev_device_get_sysattr_value(np->ctl,
"model"));
rstrip(fld);
- return snprintf(buff, len, "%s,%s,%s", nvme_vendor, fld,
- udev_device_get_sysattr_value(np->ctl,
+ return print_strbuf(buff, "%s,%s,%s", nvme_vendor, fld,
+ udev_device_get_sysattr_value(np->ctl,
"firmware_rev"));
case 'S':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysattr_value(np->udev,
"size"));
case 'z':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysattr_value(np->ctl,
"serial"));
case 'm':
- return snprintf(buff, len, "%s",
+ return append_strbuf_str(buff,
udev_device_get_sysname(np->map->udev));
case 'N':
case 'R':
- return snprintf(buff, len, "%s:%s",
+ return print_strbuf(buff, "%s:%s",
udev_device_get_sysattr_value(np->ctl,
"transport"),
udev_device_get_sysattr_value(np->ctl,
"address"));
case 'G':
- return snprintf(buff, len, "[%s]", THIS);
+ return print_strbuf(buff, "[%s]", THIS);
case 'a':
pci = udev_device_get_parent_with_subsystem_devtype(np->ctl,
"pci",
NULL);
if (pci != NULL)
- return snprintf(buff, len, "PCI:%s",
- udev_device_get_sysname(pci));
+ return print_strbuf(buff, "PCI:%s",
+ udev_device_get_sysname(pci));
/* fall through */
default:
break;
}
- return snprintf(buff, len, "%s", N_A);
- return 0;
+ return append_strbuf_str(buff, N_A);
}
static int snprint_nvme_pg(const struct gen_pathgroup *gmp,
- char *buff, int len, char wildcard)
+ struct strbuf *buff, char wildcard)
{
const struct nvme_pathgroup *pg = const_gen_pg_to_nvme(gmp);
const struct nvme_path *path = nvme_pg_to_path(pg);
switch (wildcard) {
case 't':
return snprint_nvme_path(nvme_path_to_gen(path),
- buff, len, 'T');
+ buff, 'T');
case 'p':
return snprint_nvme_path(nvme_path_to_gen(path),
- buff, len, 'p');
+ buff, 'p');
default:
- return snprintf(buff, len, N_A);
+ return append_strbuf_str(buff, N_A);
}
}
static int nvme_style(__attribute__((unused)) const struct gen_multipath* gm,
- char *buf, int len,
- __attribute__((unused)) int verbosity)
+ struct strbuf *buf, __attribute__((unused)) int verbosity)
{
- int n = snprintf(buf, len, "%%w [%%G]:%%d %%s");
-
- return (n < len ? n : len - 1);
+ return append_strbuf_str(buf, "%%w [%%G]:%%d %%s");
}
static const struct gen_multipath_ops nvme_map_ops = {
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
-
-#include <string.h>
#include "generic.h"
#include "structs.h"
+#include "util.h"
+#include "strbuf.h"
-int generic_style(const struct gen_multipath* gm,
- char *buf, int len, __attribute__((unused)) int verbosity)
+int generic_style(const struct gen_multipath* gm, struct strbuf *buf,
+ __attribute__((unused)) int verbosity)
{
- char alias_buf[WWID_SIZE];
- char wwid_buf[WWID_SIZE];
- int n = 0;
-
- gm->ops->snprint(gm, alias_buf, sizeof(alias_buf), 'n');
- gm->ops->snprint(gm, wwid_buf, sizeof(wwid_buf), 'w');
+ STRBUF_ON_STACK(tmp);
+ char *alias_buf __attribute__((cleanup(cleanup_charp)));
+ const char *wwid_buf;
- n += snprintf(buf, len, "%%n %s[%%G]:%%d %%s",
- strcmp(alias_buf, wwid_buf) ? "(%w) " : "");
+ gm->ops->snprint(gm, &tmp, 'n');
+ alias_buf = steal_strbuf_str(&tmp);
+ gm->ops->snprint(gm, &tmp, 'w');
+ wwid_buf = get_strbuf_str(&tmp);
- return (n < len ? n : len - 1);
+ return print_strbuf(buf, "%%n %s[%%G]:%%d %%s",
+ strcmp(alias_buf, wwid_buf) ? "(%w) " : "");
}
#define _GENERIC_H
#include "vector.h"
+struct strbuf;
struct gen_multipath;
struct gen_pathgroup;
struct gen_path;
* 0-terminated, no more than "len" characters including trailing '\0'.
*
* @param gmp: generic multipath object to act on
- * @param buf: output buffer
- * @param buflen: buffer size
+ * @param buf: output struct strbuf
* @param wildcard: the multipath wildcard (see print.c)
* @returns the number of characters printed (without trailing '\0').
*/
int (*snprint)(const struct gen_multipath*,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
/**
* method: style(gmp, buf, len, verbosity)
* returns the format string to be used for the multipath object,
* defined with the wildcards as defined in print.c
* generic_style() should work well in most cases.
* @param gmp: generic multipath object to act on
- * @param buf: output buffer
- * @param buflen: buffer size
+ * @param buf: output strbuf
* @param verbosity: verbosity level
* @returns number of format chars printed
*/
int (*style)(const struct gen_multipath*,
- char *buf, int len, int verbosity);
+ struct strbuf *buf, int verbosity);
};
/**
* see gen_multipath_ops->snprint() above
*/
int (*snprint)(const struct gen_pathgroup*,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
};
struct gen_path_ops {
* see gen_multipath_ops->snprint() above
*/
int (*snprint)(const struct gen_path*,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
};
struct gen_multipath {
* foreign libraries.
*/
int generic_style(const struct gen_multipath*,
- char *buf, int len, int verbosity);
+ struct strbuf *buf, int verbosity);
#endif /* _GENERIC_H */
* HPE
*/
{
- /* 3PAR / Primera */
+ /* 3PAR / Primera / Alletra 9000 */
.vendor = "3PARdata",
.product = "VV",
.pgpolicy = GROUP_BY_PRIO,
.prio_name = PRIO_ALUA,
},
{
- /* Nimble Storage */
+ /* Nimble Storage / HPE Alletra 6000 */
.vendor = "Nimble",
.product = "Server",
.hwhandler = "1 alua",
.pgpolicy = MULTIBUS,
},
{
- /* Storwize family / SAN Volume Controller / Flex System V7000 / FlashSystem V840/V9000/9100 */
+ // Storwize V5000 and V7000 lines / SAN Volume Controller (SVC) / Flex System V7000 /
+ // FlashSystem V840/V9000/5000/5100/5200/7200/9100/9200/9200R
.vendor = "IBM",
.product = "^2145",
.no_path_retry = NO_PATH_RETRY_QUEUE,
* Huawei
*/
{
- /* OceanStor V3 */
+ /* OceanStor V3-V6 */
+ // This config works with multibus and ALUA
+ // ALUA is required by HyperMetro
.vendor = "HUAWEI",
.product = "XSG1",
.pgpolicy = GROUP_BY_PRIO,
- .prio_name = PRIO_ALUA,
+ .pgfailback = -FAILBACK_IMMEDIATE,
+ .no_path_retry = 15,
},
/*
* Kove
* The new version inherits the previous ones.
*/
-LIBMULTIPATH_5.0.0 {
+LIBMULTIPATH_9.0.0 {
global:
/* symbols referenced by multipath and multipathd */
add_foreign;
count_active_paths;
delete_all_foreign;
delete_foreign;
- disassemble_map;
- disassemble_status;
dlog;
dm_cancel_deferred_remove;
dm_enablegroup;
dm_geteventnr;
dm_get_info;
dm_get_major_minor;
- dm_get_map;
dm_get_maps;
dm_get_multipath;
- dm_get_status;
dm_get_uuid;
dm_is_mpath;
dm_mapname;
/* added in 4.5.0 */
get_vpd_sgio;
trigger_partitions_udev_change;
+
+ /* added in 7.0.0 */
+ cleanup_charp;
+
+ /* added in 8.1.0 */
+ reset_strbuf;
+ append_strbuf_str;
+ get_strbuf_len;
+ get_strbuf_str;
+ steal_strbuf_str;
+ fill_strbuf;
+ print_strbuf;
+ truncate_strbuf;
+
+ /* added in 8.2.0 */
+ check_daemon;
+
local:
*;
};
#include "parser.h"
#include "memory.h"
#include "debug.h"
+#include "strbuf.h"
/* local vars */
static int sublevel = 0;
int
keyword_alloc(vector keywords, char *string,
int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int, const void*),
+ print_fn *print,
int unique)
{
struct keyword *keyword;
int
_install_keyword(vector keywords, char *string,
int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int, const void*),
+ print_fn *print,
int unique)
{
int i = 0;
}
int
-snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+snprint_keyword(struct strbuf *buff, const char *fmt, struct keyword *kw,
const void *data)
{
int r;
- int fwd = 0;
- char *f = fmt;
+ char *f;
struct config *conf;
+ STRBUF_ON_STACK(sbuf);
if (!kw || !kw->print)
return 0;
do {
- if (fwd == len || *f == '\0')
- break;
- if (*f != '%') {
- *(buff + fwd) = *f;
- fwd++;
- continue;
+ f = strchr(fmt, '%');
+ if (f == NULL) {
+ r = append_strbuf_str(&sbuf, fmt);
+ goto out;
}
- f++;
- switch(*f) {
+ if (f != fmt &&
+ (r = __append_strbuf_str(&sbuf, fmt, f - fmt)) < 0)
+ goto out;
+ fmt = f + 1;
+ switch(*fmt) {
case 'k':
- fwd += snprintf(buff + fwd, len - fwd, "%s", kw->string);
+ if ((r = append_strbuf_str(&sbuf, kw->string)) < 0)
+ goto out;
break;
case 'v':
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- r = kw->print(conf, buff + fwd, len - fwd, data);
+ r = kw->print(conf, &sbuf, data);
pthread_cleanup_pop(1);
- if (!r) { /* no output if no value */
- buff[0] = '\0';
- return 0;
+ if (r < 0)
+ goto out;
+ else if (r == 0) {/* no output if no value */
+ reset_strbuf(&sbuf);
+ goto out;
}
- fwd += r;
break;
}
- if (fwd > len)
- fwd = len;
- } while (*f++);
- return fwd;
+ } while (*fmt++);
+out:
+ return __append_strbuf_str(buff, get_strbuf_str(&sbuf),
+ get_strbuf_len(&sbuf));
}
static const char quote_marker[] = { '\0', '"', '\0' };
/* local includes */
#include "vector.h"
#include "config.h"
+struct strbuf;
/* Global definitions */
#define EOB "}"
#define MAXBUF 1024
-/* ketword definition */
+
+/* keyword definition */
+typedef int print_fn(struct config *, struct strbuf *, const void *);
+
struct keyword {
char *string;
int (*handler) (struct config *, vector);
- int (*print) (struct config *, char *, int, const void *);
+ print_fn *print;
vector sub;
int unique;
};
/* Prototypes */
extern int keyword_alloc(vector keywords, char *string,
int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int,
- const void *),
+ print_fn *print,
int unique);
#define install_keyword_root(str, h) keyword_alloc(keywords, str, h, NULL, 1)
extern void install_sublevel(void);
extern void install_sublevel_end(void);
+
extern int _install_keyword(vector keywords, char *string,
int (*handler) (struct config *, vector),
- int (*print) (struct config *, char *, int,
- const void *),
+ print_fn *print,
int unique);
#define install_keyword(str, vec, pri) _install_keyword(keywords, str, vec, pri, 1)
#define install_keyword_multi(str, vec, pri) _install_keyword(keywords, str, vec, pri, 0)
extern void *set_value(vector strvec);
extern int process_file(struct config *conf, const char *conf_file);
extern struct keyword * find_keyword(vector keywords, vector v, char * name);
-int snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw,
+int snprint_keyword(struct strbuf *buff, const char *fmt, struct keyword *kw,
const void *data);
bool is_quote(const char* token);
#include <unistd.h>
#include <string.h>
#include <errno.h>
+#include <assert.h>
#include <libudev.h>
#include "checkers.h"
#include "discovery.h"
#include "util.h"
#include "foreign.h"
+#include "strbuf.h"
+
+#define PRINT_PATH_LONG "%w %i %d %D %p %t %T %s %o"
+#define PRINT_PATH_INDENT "%i %d %D %t %T %o"
+#define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r"
+#define PRINT_PG_INDENT "policy='%s' prio=%p status=%t"
+
+#define PRINT_JSON_MULTIPLIER 5
+#define PRINT_JSON_MAJOR_VERSION 0
+#define PRINT_JSON_MINOR_VERSION 1
+#define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \
+ " \"minor_version\": %d,\n"
+#define PRINT_JSON_START_ELEM "{\n"
+#define PRINT_JSON_START_MAP " \"map\":"
+#define PRINT_JSON_START_MAPS "\"maps\": ["
+#define PRINT_JSON_START_PATHS "\"paths\": ["
+#define PRINT_JSON_START_GROUPS "\"path_groups\": ["
+#define PRINT_JSON_END_ELEM "},"
+#define PRINT_JSON_END_LAST_ELEM "}"
+#define PRINT_JSON_END_LAST "}\n"
+#define PRINT_JSON_END_ARRAY "]\n"
+#define PRINT_JSON_INDENT_N 3
+#define PRINT_JSON_MAP "{\n" \
+ " \"name\" : \"%n\",\n" \
+ " \"uuid\" : \"%w\",\n" \
+ " \"sysfs\" : \"%d\",\n" \
+ " \"failback\" : \"%F\",\n" \
+ " \"queueing\" : \"%Q\",\n" \
+ " \"paths\" : %N,\n" \
+ " \"write_prot\" : \"%r\",\n" \
+ " \"dm_st\" : \"%t\",\n" \
+ " \"features\" : \"%f\",\n" \
+ " \"hwhandler\" : \"%h\",\n" \
+ " \"action\" : \"%A\",\n" \
+ " \"path_faults\" : %0,\n" \
+ " \"vend\" : \"%v\",\n" \
+ " \"prod\" : \"%p\",\n" \
+ " \"rev\" : \"%e\",\n" \
+ " \"switch_grp\" : %1,\n" \
+ " \"map_loads\" : %2,\n" \
+ " \"total_q_time\" : %3,\n" \
+ " \"q_timeouts\" : %4,"
+
+#define PRINT_JSON_GROUP "{\n" \
+ " \"selector\" : \"%s\",\n" \
+ " \"pri\" : %p,\n" \
+ " \"dm_st\" : \"%t\",\n" \
+ " \"marginal_st\" : \"%M\","
+
+#define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n"
+
+#define PRINT_JSON_PATH "{\n" \
+ " \"dev\" : \"%d\",\n"\
+ " \"dev_t\" : \"%D\",\n" \
+ " \"dm_st\" : \"%t\",\n" \
+ " \"dev_st\" : \"%o\",\n" \
+ " \"chk_st\" : \"%T\",\n" \
+ " \"checker\" : \"%c\",\n" \
+ " \"pri\" : %p,\n" \
+ " \"host_wwnn\" : \"%N\",\n" \
+ " \"target_wwnn\" : \"%n\",\n" \
+ " \"host_wwpn\" : \"%R\",\n" \
+ " \"target_wwpn\" : \"%r\",\n" \
+ " \"host_adapter\" : \"%a\",\n" \
+ " \"marginal_st\" : \"%M\""
+
+#define PROGRESS_LEN 10
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
#define MIN(x,y) (((x) > (y)) ? (y) : (x))
-#define TAIL (line + len - 1 - c)
-#define NOPAD s = c
-#define PAD(x) \
-do { \
- while (c < (s + x) && (c < (line + len - 1))) \
- *c++ = ' '; \
- s = c; \
-} while (0)
-
-static char *
-__endline(char *line, size_t len, char *c)
-{
- if (c > line) {
- if (c >= line + len)
- c = line + len - 1;
- *(c - 1) = '\n';
- *c = '\0';
- }
- return c;
-}
-
-#define PRINT(var, size, format, args...) \
-do { \
- fwd = snprintf(var, size, format, ##args); \
- c += (fwd >= size) ? size : fwd; \
-} while (0)
-
/*
* information printing helpers
*/
static int
-snprint_str (char * buff, size_t len, const char * str)
+snprint_str(struct strbuf *buff, const char *str)
{
- return snprintf(buff, len, "%s", str);
+ return append_strbuf_str(buff, str);
}
static int
-snprint_int (char * buff, size_t len, int val)
+snprint_int (struct strbuf *buff, int val)
{
- return snprintf(buff, len, "%i", val);
+ return print_strbuf(buff, "%i", val);
}
static int
-snprint_uint (char * buff, size_t len, unsigned int val)
+snprint_uint (struct strbuf *buff, unsigned int val)
{
- return snprintf(buff, len, "%u", val);
+ return print_strbuf(buff, "%u", val);
}
static int
-snprint_size (char * buff, size_t len, unsigned long long size)
+snprint_size (struct strbuf *buff, unsigned long long size)
{
float s = (float)(size >> 1); /* start with KB */
char units[] = {'K','M','G','T','P'};
u++;
}
- return snprintf(buff, len, "%.*f%c", s < 10, s, *u);
+ return print_strbuf(buff, "%.*f%c", s < 10, s, *u);
}
/*
* multipath info printing functions
*/
static int
-snprint_name (char * buff, size_t len, const struct multipath * mpp)
+snprint_name (struct strbuf *buff, const struct multipath * mpp)
{
if (mpp->alias)
- return snprintf(buff, len, "%s", mpp->alias);
+ return append_strbuf_str(buff, mpp->alias);
else
- return snprintf(buff, len, "%s", mpp->wwid);
+ return append_strbuf_str(buff, mpp->wwid);
}
static int
-snprint_sysfs (char * buff, size_t len, const struct multipath * mpp)
+snprint_sysfs (struct strbuf *buff, const struct multipath * mpp)
{
if (mpp->dmi)
- return snprintf(buff, len, "dm-%i", mpp->dmi->minor);
+ return print_strbuf(buff, "dm-%i", mpp->dmi->minor);
else
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
}
static int
-snprint_ro (char * buff, size_t len, const struct multipath * mpp)
+snprint_ro (struct strbuf *buff, const struct multipath * mpp)
{
if (!mpp->dmi)
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
if (mpp->dmi->read_only)
- return snprintf(buff, len, "ro");
+ return append_strbuf_str(buff, "ro");
else
- return snprintf(buff, len, "rw");
+ return append_strbuf_str(buff, "rw");
}
static int
-snprint_progress (char * buff, size_t len, int cur, int total)
+snprint_progress (struct strbuf *buff, int cur, int total)
{
- char * c = buff;
- char * end = buff + len;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc;
if (total > 0) {
int i = PROGRESS_LEN * cur / total;
int j = PROGRESS_LEN - i;
- while (i-- > 0) {
- c += snprintf(c, len, "X");
- if ((len = (end - c)) <= 1) goto out;
- }
-
- while (j-- > 0) {
- c += snprintf(c, len, ".");
- if ((len = (end - c)) <= 1) goto out;
+ if ((rc = fill_strbuf(buff, 'X', i)) < 0 ||
+ (rc = fill_strbuf(buff, '.', j) < 0)) {
+ truncate_strbuf(buff, initial_len);
+ return rc;
}
}
- c += snprintf(c, len, " %i/%i", cur, total);
-
-out:
- buff[c - buff + 1] = '\0';
- return (c - buff + 1);
+ if ((rc = print_strbuf(buff, " %i/%i", cur, total)) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
static int
-snprint_failback (char * buff, size_t len, const struct multipath * mpp)
+snprint_failback (struct strbuf *buff, const struct multipath * mpp)
{
if (mpp->pgfailback == -FAILBACK_IMMEDIATE)
- return snprintf(buff, len, "immediate");
+ return append_strbuf_str(buff, "immediate");
if (mpp->pgfailback == -FAILBACK_FOLLOWOVER)
- return snprintf(buff, len, "followover");
+ return append_strbuf_str(buff, "followover");
if (!mpp->failback_tick)
- return snprintf(buff, len, "-");
+ return append_strbuf_str(buff, "-");
else
- return snprint_progress(buff, len, mpp->failback_tick,
+ return snprint_progress(buff, mpp->failback_tick,
mpp->pgfailback);
}
static int
-snprint_queueing (char * buff, size_t len, const struct multipath * mpp)
+snprint_queueing (struct strbuf *buff, const struct multipath * mpp)
{
if (mpp->no_path_retry == NO_PATH_RETRY_FAIL)
- return snprintf(buff, len, "off");
+ return append_strbuf_str(buff, "off");
else if (mpp->no_path_retry == NO_PATH_RETRY_QUEUE)
- return snprintf(buff, len, "on");
+ return append_strbuf_str(buff, "on");
else if (mpp->no_path_retry == NO_PATH_RETRY_UNDEF)
- return snprintf(buff, len, "-");
+ return append_strbuf_str(buff, "-");
else if (mpp->no_path_retry > 0) {
if (mpp->retry_tick > 0)
- return snprintf(buff, len, "%i sec",
- mpp->retry_tick);
+ return print_strbuf(buff, "%i sec", mpp->retry_tick);
else if (mpp->retry_tick == 0 && count_active_paths(mpp) > 0)
- return snprintf(buff, len, "%i chk",
- mpp->no_path_retry);
+ return print_strbuf(buff, "%i chk",
+ mpp->no_path_retry);
else
- return snprintf(buff, len, "off");
+ return append_strbuf_str(buff, "off");
}
return 0;
}
static int
-snprint_nb_paths (char * buff, size_t len, const struct multipath * mpp)
+snprint_nb_paths (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_int(buff, len, count_active_paths(mpp));
+ return snprint_int(buff, count_active_paths(mpp));
}
static int
-snprint_dm_map_state (char * buff, size_t len, const struct multipath * mpp)
+snprint_dm_map_state (struct strbuf *buff, const struct multipath * mpp)
{
if (mpp->dmi && mpp->dmi->suspended)
- return snprintf(buff, len, "suspend");
+ return append_strbuf_str(buff, "suspend");
else
- return snprintf(buff, len, "active");
+ return append_strbuf_str(buff, "active");
}
static int
-snprint_multipath_size (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_size (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_size(buff, len, mpp->size);
+ return snprint_size(buff, mpp->size);
}
static int
-snprint_features (char * buff, size_t len, const struct multipath * mpp)
+snprint_features (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_str(buff, len, mpp->features);
+ return snprint_str(buff, mpp->features);
}
static int
-snprint_hwhandler (char * buff, size_t len, const struct multipath * mpp)
+snprint_hwhandler (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_str(buff, len, mpp->hwhandler);
+ return snprint_str(buff, mpp->hwhandler);
}
static int
-snprint_path_faults (char * buff, size_t len, const struct multipath * mpp)
+snprint_path_faults (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_path_failures);
+ return snprint_uint(buff, mpp->stat_path_failures);
}
static int
-snprint_switch_grp (char * buff, size_t len, const struct multipath * mpp)
+snprint_switch_grp (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_switchgroup);
+ return snprint_uint(buff, mpp->stat_switchgroup);
}
static int
-snprint_map_loads (char * buff, size_t len, const struct multipath * mpp)
+snprint_map_loads (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_map_loads);
+ return snprint_uint(buff, mpp->stat_map_loads);
}
static int
-snprint_total_q_time (char * buff, size_t len, const struct multipath * mpp)
+snprint_total_q_time (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_total_queueing_time);
+ return snprint_uint(buff, mpp->stat_total_queueing_time);
}
static int
-snprint_q_timeouts (char * buff, size_t len, const struct multipath * mpp)
+snprint_q_timeouts (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_queueing_timeouts);
+ return snprint_uint(buff, mpp->stat_queueing_timeouts);
}
static int
-snprint_map_failures (char * buff, size_t len, const struct multipath * mpp)
+snprint_map_failures (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_uint(buff, len, mpp->stat_map_failures);
+ return snprint_uint(buff, mpp->stat_map_failures);
}
static int
-snprint_multipath_uuid (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_uuid (struct strbuf *buff, const struct multipath * mpp)
{
- return snprint_str(buff, len, mpp->wwid);
+ return snprint_str(buff, mpp->wwid);
}
static int
-snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_vpr (struct strbuf *buff, const struct multipath * mpp)
{
struct pathgroup * pgp;
struct path * pp;
vector_foreach_slot(mpp->pg, pgp, i) {
vector_foreach_slot(pgp->paths, pp, j) {
if (strlen(pp->vendor_id) && strlen(pp->product_id))
- return snprintf(buff, len, "%s,%s",
- pp->vendor_id, pp->product_id);
+ return print_strbuf(buff, "%s,%s",
+ pp->vendor_id, pp->product_id);
}
}
- return snprintf(buff, len, "##,##");
+ return append_strbuf_str(buff, "##,##");
}
static int
-snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_vend (struct strbuf *buff, const struct multipath * mpp)
{
struct pathgroup * pgp;
struct path * pp;
vector_foreach_slot(mpp->pg, pgp, i) {
vector_foreach_slot(pgp->paths, pp, j) {
if (strlen(pp->vendor_id))
- return snprintf(buff, len, "%s", pp->vendor_id);
+ return append_strbuf_str(buff, pp->vendor_id);
}
}
- return snprintf(buff, len, "##");
+ return append_strbuf_str(buff, "##");
}
static int
-snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_prod (struct strbuf *buff, const struct multipath * mpp)
{
struct pathgroup * pgp;
struct path * pp;
vector_foreach_slot(mpp->pg, pgp, i) {
vector_foreach_slot(pgp->paths, pp, j) {
if (strlen(pp->product_id))
- return snprintf(buff, len, "%s", pp->product_id);
+ return append_strbuf_str(buff, pp->product_id);
}
}
- return snprintf(buff, len, "##");
+ return append_strbuf_str(buff, "##");
}
static int
-snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp)
+snprint_multipath_rev (struct strbuf *buff, const struct multipath * mpp)
{
struct pathgroup * pgp;
struct path * pp;
vector_foreach_slot(mpp->pg, pgp, i) {
vector_foreach_slot(pgp->paths, pp, j) {
if (strlen(pp->rev))
- return snprintf(buff, len, "%s", pp->rev);
+ return append_strbuf_str(buff, pp->rev);
}
}
- return snprintf(buff, len, "##");
+ return append_strbuf_str(buff, "##");
}
static int
-snprint_multipath_foreign (char * buff, size_t len,
+snprint_multipath_foreign (struct strbuf *buff,
__attribute__((unused)) const struct multipath * pp)
{
- return snprintf(buff, len, "%s", "--");
+ return append_strbuf_str(buff, "--");
}
static int
-snprint_action (char * buff, size_t len, const struct multipath * mpp)
+snprint_action (struct strbuf *buff, const struct multipath * mpp)
{
switch (mpp->action) {
case ACT_REJECT:
- return snprint_str(buff, len, ACT_REJECT_STR);
+ return snprint_str(buff, ACT_REJECT_STR);
case ACT_RENAME:
- return snprint_str(buff, len, ACT_RENAME_STR);
+ return snprint_str(buff, ACT_RENAME_STR);
case ACT_RELOAD:
- return snprint_str(buff, len, ACT_RELOAD_STR);
+ return snprint_str(buff, ACT_RELOAD_STR);
case ACT_CREATE:
- return snprint_str(buff, len, ACT_CREATE_STR);
+ return snprint_str(buff, ACT_CREATE_STR);
case ACT_SWITCHPG:
- return snprint_str(buff, len, ACT_SWITCHPG_STR);
+ return snprint_str(buff, ACT_SWITCHPG_STR);
default:
return 0;
}
}
static int
-snprint_multipath_vpd_data(char * buff, size_t len,
+snprint_multipath_vpd_data(struct strbuf *buff,
const struct multipath * mpp)
{
struct pathgroup * pgp;
vector_foreach_slot(mpp->pg, pgp, i)
vector_foreach_slot(pgp->paths, pp, j)
if (pp->vpd_data)
- return snprintf(buff, len, "%s", pp->vpd_data);
- return snprintf(buff, len, "[undef]");
+ return append_strbuf_str(buff, pp->vpd_data);
+ return append_strbuf_str(buff, "[undef]");
}
/*
* path info printing functions
*/
static int
-snprint_path_uuid (char * buff, size_t len, const struct path * pp)
+snprint_path_uuid (struct strbuf *buff, const struct path * pp)
{
- return snprint_str(buff, len, pp->wwid);
+ return snprint_str(buff, pp->wwid);
}
static int
-snprint_hcil (char * buff, size_t len, const struct path * pp)
+snprint_hcil (struct strbuf *buff, const struct path * pp)
{
if (!pp || pp->sg_id.host_no < 0)
- return snprintf(buff, len, "#:#:#:#");
+ return append_strbuf_str(buff, "#:#:#:#");
- return snprintf(buff, len, "%i:%i:%i:%i",
+ return print_strbuf(buff, "%i:%i:%i:%" PRIu64,
pp->sg_id.host_no,
pp->sg_id.channel,
pp->sg_id.scsi_id,
}
static int
-snprint_dev (char * buff, size_t len, const struct path * pp)
+snprint_dev (struct strbuf *buff, const struct path * pp)
{
if (!pp || !strlen(pp->dev))
- return snprintf(buff, len, "-");
+ return append_strbuf_str(buff, "-");
else
- return snprint_str(buff, len, pp->dev);
+ return snprint_str(buff, pp->dev);
}
static int
-snprint_dev_t (char * buff, size_t len, const struct path * pp)
+snprint_dev_t (struct strbuf *buff, const struct path * pp)
{
if (!pp || !strlen(pp->dev))
- return snprintf(buff, len, "#:#");
+ return append_strbuf_str(buff, "#:#");
else
- return snprint_str(buff, len, pp->dev_t);
+ return snprint_str(buff, pp->dev_t);
}
static int
-snprint_offline (char * buff, size_t len, const struct path * pp)
+snprint_offline (struct strbuf *buff, const struct path * pp)
{
if (!pp || !pp->mpp)
- return snprintf(buff, len, "unknown");
+ return append_strbuf_str(buff, "unknown");
else if (pp->offline)
- return snprintf(buff, len, "offline");
+ return append_strbuf_str(buff, "offline");
else
- return snprintf(buff, len, "running");
+ return append_strbuf_str(buff, "running");
}
static int
-snprint_chk_state (char * buff, size_t len, const struct path * pp)
+snprint_chk_state (struct strbuf *buff, const struct path * pp)
{
if (!pp || !pp->mpp)
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
switch (pp->state) {
case PATH_UP:
- return snprintf(buff, len, "ready");
+ return append_strbuf_str(buff, "ready");
case PATH_DOWN:
- return snprintf(buff, len, "faulty");
+ return append_strbuf_str(buff, "faulty");
case PATH_SHAKY:
- return snprintf(buff, len, "shaky");
+ return append_strbuf_str(buff, "shaky");
case PATH_GHOST:
- return snprintf(buff, len, "ghost");
+ return append_strbuf_str(buff, "ghost");
case PATH_PENDING:
- return snprintf(buff, len, "i/o pending");
+ return append_strbuf_str(buff, "i/o pending");
case PATH_TIMEOUT:
- return snprintf(buff, len, "i/o timeout");
+ return append_strbuf_str(buff, "i/o timeout");
case PATH_DELAYED:
- return snprintf(buff, len, "delayed");
+ return append_strbuf_str(buff, "delayed");
default:
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
}
}
static int
-snprint_dm_path_state (char * buff, size_t len, const struct path * pp)
+snprint_dm_path_state (struct strbuf *buff, const struct path * pp)
{
if (!pp)
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
switch (pp->dmstate) {
case PSTATE_ACTIVE:
- return snprintf(buff, len, "active");
+ return append_strbuf_str(buff, "active");
case PSTATE_FAILED:
- return snprintf(buff, len, "failed");
+ return append_strbuf_str(buff, "failed");
default:
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
}
}
static int
-snprint_vpr (char * buff, size_t len, const struct path * pp)
+snprint_vpr (struct strbuf *buff, const struct path * pp)
{
- return snprintf(buff, len, "%s,%s",
- pp->vendor_id, pp->product_id);
+ return print_strbuf(buff, "%s,%s", pp->vendor_id, pp->product_id);
}
static int
-snprint_next_check (char * buff, size_t len, const struct path * pp)
+snprint_next_check (struct strbuf *buff, const struct path * pp)
{
if (!pp || !pp->mpp)
- return snprintf(buff, len, "orphan");
+ return append_strbuf_str(buff, "orphan");
- return snprint_progress(buff, len, pp->tick, pp->checkint);
+ return snprint_progress(buff, pp->tick, pp->checkint);
}
static int
-snprint_pri (char * buff, size_t len, const struct path * pp)
+snprint_pri (struct strbuf *buff, const struct path * pp)
{
- return snprint_int(buff, len, pp ? pp->priority : -1);
+ return snprint_int(buff, pp ? pp->priority : -1);
}
static int
-snprint_pg_selector (char * buff, size_t len, const struct pathgroup * pgp)
+snprint_pg_selector (struct strbuf *buff, const struct pathgroup * pgp)
{
const char *s = pgp->mpp->selector;
- return snprint_str(buff, len, s ? s : "");
+ return snprint_str(buff, s ? s : "");
}
static int
-snprint_pg_pri (char * buff, size_t len, const struct pathgroup * pgp)
+snprint_pg_pri (struct strbuf *buff, const struct pathgroup * pgp)
{
- return snprint_int(buff, len, pgp->priority);
+ return snprint_int(buff, pgp->priority);
}
static int
-snprint_pg_state (char * buff, size_t len, const struct pathgroup * pgp)
+snprint_pg_state (struct strbuf *buff, const struct pathgroup * pgp)
{
switch (pgp->status) {
case PGSTATE_ENABLED:
- return snprintf(buff, len, "enabled");
+ return append_strbuf_str(buff, "enabled");
case PGSTATE_DISABLED:
- return snprintf(buff, len, "disabled");
+ return append_strbuf_str(buff, "disabled");
case PGSTATE_ACTIVE:
- return snprintf(buff, len, "active");
+ return append_strbuf_str(buff, "active");
default:
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
}
}
static int
-snprint_pg_marginal (char * buff, size_t len, const struct pathgroup * pgp)
+snprint_pg_marginal (struct strbuf *buff, const struct pathgroup * pgp)
{
if (pgp->marginal)
- return snprintf(buff, len, "marginal");
- return snprintf(buff, len, "normal");
+ return append_strbuf_str(buff, "marginal");
+ return append_strbuf_str(buff, "normal");
}
static int
-snprint_path_size (char * buff, size_t len, const struct path * pp)
+snprint_path_size (struct strbuf *buff, const struct path * pp)
{
- return snprint_size(buff, len, pp->size);
+ return snprint_size(buff, pp->size);
}
int
-snprint_path_serial (char * buff, size_t len, const struct path * pp)
+snprint_path_serial (struct strbuf *buff, const struct path * pp)
{
- return snprint_str(buff, len, pp->serial);
+ return snprint_str(buff, pp->serial);
}
static int
-snprint_path_mpp (char * buff, size_t len, const struct path * pp)
+snprint_path_mpp (struct strbuf *buff, const struct path * pp)
{
if (!pp->mpp)
- return snprintf(buff, len, "[orphan]");
+ return append_strbuf_str(buff, "[orphan]");
if (!pp->mpp->alias)
- return snprintf(buff, len, "[unknown]");
- return snprint_str(buff, len, pp->mpp->alias);
+ return append_strbuf_str(buff, "[unknown]");
+ return snprint_str(buff, pp->mpp->alias);
}
static int
-snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr)
+snprint_host_attr (struct strbuf *buff, const struct path * pp, char *attr)
{
struct udev_device *host_dev = NULL;
char host_id[32];
int ret;
if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
- return snprintf(buff, len, "[undef]");
+ return append_strbuf_str(buff, "[undef]");
sprintf(host_id, "host%d", pp->sg_id.host_no);
host_dev = udev_device_new_from_subsystem_sysname(udev, "fc_host",
host_id);
}
value = udev_device_get_sysattr_value(host_dev, attr);
if (value)
- ret = snprint_str(buff, len, value);
+ ret = snprint_str(buff, value);
udev_device_unref(host_dev);
out:
if (!value)
- ret = snprintf(buff, len, "[unknown]");
+ ret = append_strbuf_str(buff, "[unknown]");
return ret;
}
int
-snprint_host_wwnn (char * buff, size_t len, const struct path * pp)
+snprint_host_wwnn (struct strbuf *buff, const struct path * pp)
{
- return snprint_host_attr(buff, len, pp, "node_name");
+ return snprint_host_attr(buff, pp, "node_name");
}
int
-snprint_host_wwpn (char * buff, size_t len, const struct path * pp)
+snprint_host_wwpn (struct strbuf *buff, const struct path * pp)
{
- return snprint_host_attr(buff, len, pp, "port_name");
+ return snprint_host_attr(buff, pp, "port_name");
}
int
-snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp)
+snprint_tgt_wwpn (struct strbuf *buff, const struct path * pp)
{
struct udev_device *rport_dev = NULL;
- char rport_id[32];
+ char rport_id[42];
const char *value = NULL;
int ret;
if (pp->sg_id.proto_id != SCSI_PROTOCOL_FCP)
- return snprintf(buff, len, "[undef]");
+ return append_strbuf_str(buff, "[undef]");
sprintf(rport_id, "rport-%d:%d-%d",
pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.transport_id);
rport_dev = udev_device_new_from_subsystem_sysname(udev,
}
value = udev_device_get_sysattr_value(rport_dev, "port_name");
if (value)
- ret = snprint_str(buff, len, value);
+ ret = snprint_str(buff, value);
udev_device_unref(rport_dev);
out:
if (!value)
- ret = snprintf(buff, len, "[unknown]");
+ ret = append_strbuf_str(buff, "[unknown]");
return ret;
}
int
-snprint_tgt_wwnn (char * buff, size_t len, const struct path * pp)
+snprint_tgt_wwnn (struct strbuf *buff, const struct path * pp)
{
if (pp->tgt_node_name[0] == '\0')
- return snprintf(buff, len, "[undef]");
- return snprint_str(buff, len, pp->tgt_node_name);
+ return append_strbuf_str(buff, "[undef]");
+ return snprint_str(buff, pp->tgt_node_name);
}
static int
-snprint_host_adapter (char * buff, size_t len, const struct path * pp)
+snprint_host_adapter (struct strbuf *buff, const struct path * pp)
{
char adapter[SLOT_NAME_SIZE];
if (sysfs_get_host_adapter_name(pp, adapter))
- return snprintf(buff, len, "[undef]");
- return snprint_str(buff, len, adapter);
+ return append_strbuf_str(buff, "[undef]");
+ return snprint_str(buff, adapter);
}
static int
-snprint_path_checker (char * buff, size_t len, const struct path * pp)
+snprint_path_checker (struct strbuf *buff, const struct path * pp)
{
const struct checker * c = &pp->checker;
- return snprint_str(buff, len, checker_name(c));
+ return snprint_str(buff, checker_name(c));
}
static int
-snprint_path_foreign (char * buff, size_t len,
+snprint_path_foreign (struct strbuf *buff,
__attribute__((unused)) const struct path * pp)
{
- return snprintf(buff, len, "%s", "--");
+ return append_strbuf_str(buff, "--");
}
static int
-snprint_path_failures(char * buff, size_t len, const struct path * pp)
+snprint_path_failures(struct strbuf *buff, const struct path * pp)
{
- return snprint_int(buff, len, pp->failcount);
+ return snprint_int(buff, pp->failcount);
}
/* if you add a protocol string bigger than "scsi:unspec" you must
* also change PROTOCOL_BUF_SIZE */
int
-snprint_path_protocol(char * buff, size_t len, const struct path * pp)
+snprint_path_protocol(struct strbuf *buff, const struct path * pp)
{
switch (pp->bus) {
case SYSFS_BUS_SCSI:
switch (pp->sg_id.proto_id) {
case SCSI_PROTOCOL_FCP:
- return snprintf(buff, len, "scsi:fcp");
+ return append_strbuf_str(buff, "scsi:fcp");
case SCSI_PROTOCOL_SPI:
- return snprintf(buff, len, "scsi:spi");
+ return append_strbuf_str(buff, "scsi:spi");
case SCSI_PROTOCOL_SSA:
- return snprintf(buff, len, "scsi:ssa");
+ return append_strbuf_str(buff, "scsi:ssa");
case SCSI_PROTOCOL_SBP:
- return snprintf(buff, len, "scsi:sbp");
+ return append_strbuf_str(buff, "scsi:sbp");
case SCSI_PROTOCOL_SRP:
- return snprintf(buff, len, "scsi:srp");
+ return append_strbuf_str(buff, "scsi:srp");
case SCSI_PROTOCOL_ISCSI:
- return snprintf(buff, len, "scsi:iscsi");
+ return append_strbuf_str(buff, "scsi:iscsi");
case SCSI_PROTOCOL_SAS:
- return snprintf(buff, len, "scsi:sas");
+ return append_strbuf_str(buff, "scsi:sas");
case SCSI_PROTOCOL_ADT:
- return snprintf(buff, len, "scsi:adt");
+ return append_strbuf_str(buff, "scsi:adt");
case SCSI_PROTOCOL_ATA:
- return snprintf(buff, len, "scsi:ata");
+ return append_strbuf_str(buff, "scsi:ata");
case SCSI_PROTOCOL_USB:
- return snprintf(buff, len, "scsi:usb");
+ return append_strbuf_str(buff, "scsi:usb");
case SCSI_PROTOCOL_UNSPEC:
default:
- return snprintf(buff, len, "scsi:unspec");
+ return append_strbuf_str(buff, "scsi:unspec");
}
case SYSFS_BUS_CCW:
- return snprintf(buff, len, "ccw");
+ return append_strbuf_str(buff, "ccw");
case SYSFS_BUS_CCISS:
- return snprintf(buff, len, "cciss");
+ return append_strbuf_str(buff, "cciss");
case SYSFS_BUS_NVME:
- return snprintf(buff, len, "nvme");
+ return append_strbuf_str(buff, "nvme");
case SYSFS_BUS_UNDEF:
default:
- return snprintf(buff, len, "undef");
+ return append_strbuf_str(buff, "undef");
}
}
int
-snprint_path_marginal(char * buff, size_t len, const struct path * pp)
+snprint_path_marginal(struct strbuf *buff, const struct path * pp)
{
if (pp->marginal)
- return snprintf(buff, len, "marginal");
- return snprintf(buff, len, "normal");
+ return append_strbuf_str(buff, "marginal");
+ return append_strbuf_str(buff, "normal");
}
static int
-snprint_path_vpd_data(char * buff, size_t len, const struct path * pp)
+snprint_path_vpd_data(struct strbuf *buff, const struct path * pp)
{
if (pp->vpd_data)
- return snprintf(buff, len, "%s", pp->vpd_data);
- return snprintf(buff, len, "[undef]");
+ return append_strbuf_str(buff, pp->vpd_data);
+ return append_strbuf_str(buff, "[undef]");
}
struct multipath_data mpd[] = {
{0, NULL, 0 , NULL}
};
-int
-snprint_wildcards (char * buff, int len)
+int snprint_wildcards(struct strbuf *buff)
{
- int i, fwd = 0;
+ int initial_len = get_strbuf_len(buff);
+ int i, rc;
- fwd += snprintf(buff + fwd, len - fwd, "multipath format wildcards:\n");
+ if ((rc = append_strbuf_str(buff, "multipath format wildcards:\n")) < 0)
+ return rc;
for (i = 0; mpd[i].header; i++)
- fwd += snprintf(buff + fwd, len - fwd, "%%%c %s\n",
- mpd[i].wildcard, mpd[i].header);
- fwd += snprintf(buff + fwd, len - fwd, "\npath format wildcards:\n");
+ if ((rc = print_strbuf(buff, "%%%c %s\n",
+ mpd[i].wildcard, mpd[i].header)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "\npath format wildcards:\n")) < 0)
+ return rc;
for (i = 0; pd[i].header; i++)
- fwd += snprintf(buff + fwd, len - fwd, "%%%c %s\n",
- pd[i].wildcard, pd[i].header);
- fwd += snprintf(buff + fwd, len - fwd, "\npathgroup format wildcards:\n");
+ if ((rc = print_strbuf(buff, "%%%c %s\n",
+ pd[i].wildcard, pd[i].header)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "\npathgroup format wildcards:\n")) < 0)
+ return rc;
for (i = 0; pgd[i].header; i++)
- fwd += snprintf(buff + fwd, len - fwd, "%%%c %s\n",
- pgd[i].wildcard, pgd[i].header);
- return fwd;
+ if ((rc = print_strbuf(buff, "%%%c %s\n",
+ pgd[i].wildcard, pgd[i].header)) < 0)
+ return rc;
+
+ return get_strbuf_len(buff) - initial_len;
}
void
_get_path_layout (const struct _vector *gpvec, enum layout_reset reset)
{
int i, j;
- char buff[MAX_FIELD_LEN];
const struct gen_path *gp;
for (j = 0; pd[j].header; j++) {
+ STRBUF_ON_STACK(buff);
reset_width(&pd[j].width, reset, pd[j].header);
continue;
vector_foreach_slot (gpvec, gp, i) {
- gp->ops->snprint(gp, buff, MAX_FIELD_LEN,
- pd[j].wildcard);
- pd[j].width = MAX(pd[j].width, strlen(buff));
+ gp->ops->snprint(gp, &buff, pd[j].wildcard);
+ pd[j].width = MAX(pd[j].width, get_strbuf_len(&buff));
+ truncate_strbuf(&buff, 0);
}
}
}
enum layout_reset reset)
{
int i, j;
- char buff[MAX_FIELD_LEN];
const struct gen_multipath * gm;
for (j = 0; mpd[j].header; j++) {
+ STRBUF_ON_STACK(buff);
reset_width(&mpd[j].width, reset, mpd[j].header);
continue;
vector_foreach_slot (gmvec, gm, i) {
- gm->ops->snprint(gm, buff, MAX_FIELD_LEN,
- mpd[j].wildcard);
- mpd[j].width = MAX(mpd[j].width, strlen(buff));
+ gm->ops->snprint(gm, &buff, mpd[j].wildcard);
+ mpd[j].width = MAX(mpd[j].width, get_strbuf_len(&buff));
+ truncate_strbuf(&buff, 0);
}
condlog(4, "%s: width %d", mpd[j].header, mpd[j].width);
}
}
int snprint_multipath_attr(const struct gen_multipath* gm,
- char *buf, int len, char wildcard)
+ struct strbuf *buf, char wildcard)
{
const struct multipath *mpp = gen_multipath_to_dm(gm);
struct multipath_data *mpd = mpd_lookup(wildcard);
if (mpd == NULL)
return 0;
- return mpd->snprint(buf, len, mpp);
+ return mpd->snprint(buf, mpp);
}
static struct path_data *
}
int snprint_path_attr(const struct gen_path* gp,
- char *buf, int len, char wildcard)
+ struct strbuf *buf, char wildcard)
{
const struct path *pp = gen_path_to_dm(gp);
struct path_data *pd = pd_lookup(wildcard);
if (pd == NULL)
return 0;
- return pd->snprint(buf, len, pp);
+ return pd->snprint(buf, pp);
}
static struct pathgroup_data *
}
int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
- char *buf, int len, char wildcard)
+ struct strbuf *buf, char wildcard)
{
const struct pathgroup *pg = gen_pathgroup_to_dm(gpg);
struct pathgroup_data *pdg = pgd_lookup(wildcard);
if (pdg == NULL)
return 0;
- return pdg->snprint(buf, len, pg);
+ return pdg->snprint(buf, pg);
}
-int
-snprint_multipath_header (char * line, int len, const char * format)
+int snprint_multipath_header(struct strbuf *line, const char *format)
{
- char * c = line; /* line cursor */
- char * s = line; /* for padding */
- const char * f = format; /* format string cursor */
- int fwd;
+ int initial_len = get_strbuf_len(line);
+ const char *f;
struct multipath_data * data;
+ int rc;
- do {
- if (TAIL <= 0)
- break;
-
- if (*f != '%') {
- *c++ = *f;
- NOPAD;
- continue;
- }
- f++;
+ for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
+ return rc;
- if (!(data = mpd_lookup(*f)))
+ format = f + 1;
+ if (!(data = mpd_lookup(*format)))
continue; /* unknown wildcard */
- PRINT(c, TAIL, "%s", data->header);
- PAD(data->width);
- } while (*f++);
+ if ((rc = append_strbuf_str(line, data->header)) < 0)
+ return rc;
+ else if ((unsigned int)rc < data->width)
+ if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ return rc;
+ }
- __endline(line, len, c);
- return (c - line);
+ if ((rc = print_strbuf(line, "%s\n", format)) < 0)
+ return rc;
+ return get_strbuf_len(line) - initial_len;
}
-int
-_snprint_multipath (const struct gen_multipath * gmp,
- char * line, int len, const char * format, int pad)
+int _snprint_multipath(const struct gen_multipath *gmp,
+ struct strbuf *line, const char *format, int pad)
{
- char * c = line; /* line cursor */
- char * s = line; /* for padding */
- const char * f = format; /* format string cursor */
- int fwd;
+ int initial_len = get_strbuf_len(line);
+ const char *f;
struct multipath_data * data;
- char buff[MAX_FIELD_LEN] = {};
-
- do {
- if (TAIL <= 0)
- break;
+ int rc;
- if (*f != '%') {
- *c++ = *f;
- NOPAD;
- continue;
- }
- f++;
+ for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
+ return rc;
- if (!(data = mpd_lookup(*f)))
- continue;
+ format = f + 1;
+ if (!(data = mpd_lookup(*format)))
+ continue; /* unknown wildcard */
- gmp->ops->snprint(gmp, buff, MAX_FIELD_LEN, *f);
- PRINT(c, TAIL, "%s", buff);
- if (pad)
- PAD(data->width);
- buff[0] = '\0';
- } while (*f++);
+ if ((rc = gmp->ops->snprint(gmp, line, *format)) < 0)
+ return rc;
+ else if (pad && (unsigned int)rc < data->width)
+ if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ return rc;
+ }
- __endline(line, len, c);
- return (c - line);
+ if ((rc = print_strbuf(line, "%s\n", format)) < 0)
+ return rc;
+ return get_strbuf_len(line) - initial_len;
}
-int
-snprint_path_header (char * line, int len, const char * format)
+int snprint_path_header(struct strbuf *line, const char *format)
{
- char * c = line; /* line cursor */
- char * s = line; /* for padding */
- const char * f = format; /* format string cursor */
- int fwd;
- struct path_data * data;
+ int initial_len = get_strbuf_len(line);
+ const char *f;
+ struct path_data *data;
+ int rc;
- do {
- if (TAIL <= 0)
- break;
+ for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
+ return rc;
- if (*f != '%') {
- *c++ = *f;
- NOPAD;
- continue;
- }
- f++;
-
- if (!(data = pd_lookup(*f)))
+ format = f + 1;
+ if (!(data = pd_lookup(*format)))
continue; /* unknown wildcard */
- PRINT(c, TAIL, "%s", data->header);
- PAD(data->width);
- } while (*f++);
+ if ((rc = append_strbuf_str(line, data->header)) < 0)
+ return rc;
+ else if ((unsigned int)rc < data->width)
+ if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ return rc;
+ }
- __endline(line, len, c);
- return (c - line);
+ if ((rc = print_strbuf(line, "%s\n", format)) < 0)
+ return rc;
+ return get_strbuf_len(line) - initial_len;
}
-int
-_snprint_path (const struct gen_path * gp, char * line, int len,
- const char * format, int pad)
+int _snprint_path(const struct gen_path *gp, struct strbuf *line,
+ const char *format, int pad)
{
- char * c = line; /* line cursor */
- char * s = line; /* for padding */
- const char * f = format; /* format string cursor */
- int fwd;
+ int initial_len = get_strbuf_len(line);
+ const char *f;
struct path_data * data;
- char buff[MAX_FIELD_LEN];
+ int rc;
- do {
- if (TAIL <= 0)
- break;
-
- if (*f != '%') {
- *c++ = *f;
- NOPAD;
- continue;
- }
- f++;
+ for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
+ return rc;
- if (!(data = pd_lookup(*f)))
- continue;
+ format = f + 1;
+ if (!(data = pd_lookup(*format)))
+ continue; /* unknown wildcard */
- gp->ops->snprint(gp, buff, MAX_FIELD_LEN, *f);
- PRINT(c, TAIL, "%s", buff);
- if (pad)
- PAD(data->width);
- } while (*f++);
+ if ((rc = gp->ops->snprint(gp, line, *format)) < 0)
+ return rc;
+ else if (pad && (unsigned int)rc < data->width)
+ if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ return rc;
+ }
- __endline(line, len, c);
- return (c - line);
+ if ((rc = print_strbuf(line, "%s\n", format)) < 0)
+ return rc;
+ return get_strbuf_len(line) - initial_len;
}
-int
-_snprint_pathgroup (const struct gen_pathgroup * ggp, char * line, int len,
- char * format)
-{
- char * c = line; /* line cursor */
- char * s = line; /* for padding */
- char * f = format; /* format string cursor */
- int fwd;
- struct pathgroup_data * data;
- char buff[MAX_FIELD_LEN];
-
- do {
- if (TAIL <= 0)
- break;
+int _snprint_pathgroup(const struct gen_pathgroup *ggp, struct strbuf *line,
+ const char *format)
+{
+ int initial_len = get_strbuf_len(line);
+ const char *f;
+ struct pathgroup_data *data;
+ int rc;
- if (*f != '%') {
- *c++ = *f;
- NOPAD;
- continue;
- }
- f++;
+ for (f = strchr(format, '%'); f; f = strchr(++format, '%')) {
+ if ((rc = __append_strbuf_str(line, format, f - format)) < 0)
+ return rc;
- if (!(data = pgd_lookup(*f)))
- continue;
+ format = f + 1;
+ if (!(data = pgd_lookup(*format)))
+ continue; /* unknown wildcard */
- ggp->ops->snprint(ggp, buff, MAX_FIELD_LEN, *f);
- PRINT(c, TAIL, "%s", buff);
- PAD(data->width);
- } while (*f++);
+ if ((rc = ggp->ops->snprint(ggp, line, *format)) < 0)
+ return rc;
+ else if ((unsigned int)rc < data->width)
+ if ((rc = fill_strbuf(line, ' ', data->width - rc)) < 0)
+ return rc;
+ }
- __endline(line, len, c);
- return (c - line);
+ if ((rc = print_strbuf(line, "%s\n", format)) < 0)
+ return rc;
+ return get_strbuf_len(line) - initial_len;
}
-#define snprint_pathgroup(line, len, fmt, pgp) \
- _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, len, fmt)
+
+#define snprint_pathgroup(line, fmt, pgp) \
+ _snprint_pathgroup(dm_pathgroup_to_gen(pgp), line, fmt)
void _print_multipath_topology(const struct gen_multipath *gmp, int verbosity)
{
- int resize;
- char *buff = NULL;
- char *old = NULL;
- int len, maxlen = MAX_LINE_LEN * MAX_LINES;
-
- buff = MALLOC(maxlen);
- do {
- if (!buff) {
- if (old)
- FREE(old);
- condlog(0, "couldn't allocate memory for list: %s\n",
- strerror(errno));
- return;
- }
+ STRBUF_ON_STACK(buff);
- len = _snprint_multipath_topology(gmp, buff, maxlen, verbosity);
- resize = (len == maxlen - 1);
-
- if (resize) {
- maxlen *= 2;
- old = buff;
- buff = REALLOC(buff, maxlen);
- }
- } while (resize);
- printf("%s", buff);
- FREE(buff);
+ _snprint_multipath_topology(gmp, &buff, verbosity);
+ printf("%s", get_strbuf_str(&buff));
}
-int
-snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len,
- int verbosity)
+int snprint_multipath_style(const struct gen_multipath *gmp,
+ struct strbuf *style, int verbosity)
{
- int n;
const struct multipath *mpp = gen_multipath_to_dm(gmp);
bool need_action = (verbosity > 1 &&
mpp->action != ACT_NOTHING &&
mpp->action != ACT_IMPOSSIBLE);
bool need_wwid = (strncmp(mpp->alias, mpp->wwid, WWID_SIZE));
- n = snprintf(style, len, "%s%s%s%s",
- need_action ? "%A: " : "", "%n",
- need_wwid ? " (%w)" : "", " %d %s");
- return MIN(n, len - 1);
+ return print_strbuf(style, "%s%s%s%s",
+ need_action ? "%A: " : "", "%n",
+ need_wwid ? " (%w)" : "", " %d %s");
}
int _snprint_multipath_topology(const struct gen_multipath *gmp,
- char *buff, int len, int verbosity)
+ struct strbuf *buff, int verbosity)
{
- int j, i, fwd = 0;
+ int j, i, rc;
const struct _vector *pgvec;
const struct gen_pathgroup *gpg;
- char style[64];
- char * c = style;
- char fmt[64];
- char * f;
+ STRBUF_ON_STACK(style);
+ size_t initial_len = get_strbuf_len(buff);
if (verbosity <= 0)
- return fwd;
+ return 0;
reset_multipath_layout();
if (verbosity == 1)
- return _snprint_multipath(gmp, buff, len, "%n", 1);
-
- if(isatty(1))
- c += sprintf(c, "%c[%dm", 0x1B, 1); /* bold on */
+ return _snprint_multipath(gmp, buff, "%n", 1);
- c += gmp->ops->style(gmp, c, sizeof(style) - (c - style),
- verbosity);
- if(isatty(1))
- c += sprintf(c, "%c[%dm", 0x1B, 0); /* bold off */
+ if(isatty(1) &&
+ (rc = print_strbuf(&style, "%c[%dm", 0x1B, 1)) < 0) /* bold on */
+ return rc;
+ if ((rc = gmp->ops->style(gmp, &style, verbosity)) < 0)
+ return rc;
+ if(isatty(1) &&
+ (rc = print_strbuf(&style, "%c[%dm", 0x1B, 0)) < 0) /* bold off */
+ return rc;
- fwd += _snprint_multipath(gmp, buff + fwd, len - fwd, style, 1);
- if (fwd >= len)
- return len;
- fwd += _snprint_multipath(gmp, buff + fwd, len - fwd,
- PRINT_MAP_PROPS, 1);
- if (fwd >= len)
- return len;
+ if ((rc = _snprint_multipath(gmp, buff, get_strbuf_str(&style), 1)) < 0
+ || (rc = _snprint_multipath(gmp, buff, PRINT_MAP_PROPS, 1)) < 0)
+ return rc;
pgvec = gmp->ops->get_pathgroups(gmp);
if (pgvec == NULL)
- return fwd;
+ goto out;
vector_foreach_slot (pgvec, gpg, j) {
const struct _vector *pathvec;
struct gen_path *gp;
+ bool last_group = j + 1 == VECTOR_SIZE(pgvec);
- f=fmt;
-
- if (j + 1 < VECTOR_SIZE(pgvec)) {
- strcpy(f, "|-+- " PRINT_PG_INDENT);
- } else
- strcpy(f, "`-+- " PRINT_PG_INDENT);
- fwd += _snprint_pathgroup(gpg, buff + fwd, len - fwd, fmt);
-
- if (fwd >= len) {
- fwd = len;
- break;
- }
+ if ((rc = print_strbuf(buff, "%c-+- ",
+ last_group ? '`' : '|')) < 0 ||
+ (rc = _snprint_pathgroup(gpg, buff, PRINT_PG_INDENT)) < 0)
+ return rc;
pathvec = gpg->ops->get_paths(gpg);
if (pathvec == NULL)
continue;
vector_foreach_slot (pathvec, gp, i) {
- f=fmt;
- if (*f != '|')
- *f=' ';
- f++;
- if (i + 1 < VECTOR_SIZE(pathvec))
- strcpy(f, " |- " PRINT_PATH_INDENT);
- else
- strcpy(f, " `- " PRINT_PATH_INDENT);
- fwd += _snprint_path(gp, buff + fwd, len - fwd, fmt, 1);
- if (fwd >= len) {
- fwd = len;
- break;
- }
+ if ((rc = print_strbuf(buff, "%c %c- ",
+ last_group ? ' ' : '|',
+ i + 1 == VECTOR_SIZE(pathvec) ?
+ '`': '|')) < 0 ||
+ (rc = _snprint_path(gp, buff,
+ PRINT_PATH_INDENT, 1)) < 0)
+ return rc;
}
gpg->ops->rel_paths(gpg, pathvec);
-
- if (fwd == len)
- break;
}
+
gmp->ops->rel_pathgroups(gmp, pgvec);
- return fwd;
+out:
+ return get_strbuf_len(buff) - initial_len;
}
static int
-snprint_json (char * buff, int len, int indent, char *json_str)
+snprint_json(struct strbuf *buff, int indent, const char *json_str)
{
- int fwd = 0, i;
+ int rc;
- for (i = 0; i < indent; i++) {
- fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
- if (fwd >= len)
- return fwd;
- }
+ if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
+ return rc;
- fwd += snprintf(buff + fwd, len - fwd, "%s", json_str);
- return fwd;
+ return append_strbuf_str(buff, json_str);
}
-static int
-snprint_json_header (char * buff, int len)
+static int snprint_json_header(struct strbuf *buff)
{
- int fwd = 0;
-
- fwd += snprint_json(buff, len, 0, PRINT_JSON_START_ELEM);
- if (fwd >= len)
- return fwd;
+ int rc;
- fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_START_VERSION,
- PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
- return fwd;
+ if ((rc = snprint_json(buff, 0, PRINT_JSON_START_ELEM)) < 0)
+ return rc;
+ return print_strbuf(buff, PRINT_JSON_START_VERSION,
+ PRINT_JSON_MAJOR_VERSION, PRINT_JSON_MINOR_VERSION);
}
-static int
-snprint_json_elem_footer (char * buff, int len, int indent, int last)
+static int snprint_json_elem_footer(struct strbuf *buff, int indent, bool last)
{
- int fwd = 0, i;
+ int rc;
- for (i = 0; i < indent; i++) {
- fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_INDENT);
- if (fwd >= len)
- return fwd;
- }
+ if ((rc = fill_strbuf(buff, ' ', indent * PRINT_JSON_INDENT_N)) < 0)
+ return rc;
- if (last == 1)
- fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_LAST_ELEM);
+ if (last)
+ return append_strbuf_str(buff, PRINT_JSON_END_LAST_ELEM);
else
- fwd += snprintf(buff + fwd, len - fwd, "%s", PRINT_JSON_END_ELEM);
- return fwd;
+ return append_strbuf_str(buff, PRINT_JSON_END_ELEM);
}
-static int
-snprint_multipath_fields_json (char * buff, int len,
- const struct multipath * mpp, int last)
+static int snprint_multipath_fields_json(struct strbuf *buff,
+ const struct multipath *mpp, int last)
{
- int i, j, fwd = 0;
+ int i, j, rc;
struct path *pp;
struct pathgroup *pgp;
+ size_t initial_len = get_strbuf_len(buff);
- fwd += snprint_multipath(buff, len, PRINT_JSON_MAP, mpp, 0);
- if (fwd >= len)
- return fwd;
-
- fwd += snprint_json(buff + fwd, len - fwd, 2, PRINT_JSON_START_GROUPS);
- if (fwd >= len)
- return fwd;
+ if ((rc = snprint_multipath(buff, PRINT_JSON_MAP, mpp, 0)) < 0 ||
+ (rc = snprint_json(buff, 2, PRINT_JSON_START_GROUPS)) < 0)
+ return rc;
vector_foreach_slot (mpp->pg, pgp, i) {
- fwd += snprint_pathgroup(buff + fwd, len - fwd, PRINT_JSON_GROUP, pgp);
- if (fwd >= len)
- return fwd;
-
- fwd += snprintf(buff + fwd, len - fwd, PRINT_JSON_GROUP_NUM, i + 1);
- if (fwd >= len)
- return fwd;
-
- fwd += snprint_json(buff + fwd, len - fwd, 3, PRINT_JSON_START_PATHS);
- if (fwd >= len)
- return fwd;
+ if ((rc = snprint_pathgroup(buff, PRINT_JSON_GROUP, pgp)) < 0 ||
+ (rc = print_strbuf(buff, PRINT_JSON_GROUP_NUM, i + 1)) < 0 ||
+ (rc = snprint_json(buff, 3, PRINT_JSON_START_PATHS)) < 0)
+ return rc;
vector_foreach_slot (pgp->paths, pp, j) {
- fwd += snprint_path(buff + fwd, len - fwd, PRINT_JSON_PATH, pp, 0);
- if (fwd >= len)
- return fwd;
-
- fwd += snprint_json_elem_footer(buff + fwd,
- len - fwd, 3, j + 1 == VECTOR_SIZE(pgp->paths));
- if (fwd >= len)
- return fwd;
+ if ((rc = snprint_path(buff, PRINT_JSON_PATH,
+ pp, 0)) < 0 ||
+ (rc = snprint_json_elem_footer(
+ buff, 3,
+ j + 1 == VECTOR_SIZE(pgp->paths))) < 0)
+ return rc;
}
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd >= len)
- return fwd;
-
- fwd += snprint_json_elem_footer(buff + fwd,
- len - fwd, 2, i + 1 == VECTOR_SIZE(mpp->pg));
- if (fwd >= len)
- return fwd;
+ if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
+ (rc = snprint_json_elem_footer(
+ buff, 2, i + 1 == VECTOR_SIZE(mpp->pg))) < 0)
+ return rc;
}
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd >= len)
- return fwd;
+ if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
+ (rc = snprint_json_elem_footer(buff, 1, last)) < 0)
+ return rc;
- fwd += snprint_json_elem_footer(buff + fwd, len - fwd, 1, last);
- return fwd;
+ return get_strbuf_len(buff) - initial_len;
}
-int
-snprint_multipath_map_json (char * buff, int len, const struct multipath * mpp)
+int snprint_multipath_map_json(struct strbuf *buff, const struct multipath * mpp)
{
- int fwd = 0;
-
- fwd += snprint_json_header(buff, len);
- if (fwd >= len)
- return len;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc;
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_START_MAP);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_json_header(buff)) < 0 ||
+ (rc = snprint_json(buff, 0, PRINT_JSON_START_MAP)) < 0)
+ return rc;
- fwd += snprint_multipath_fields_json(buff + fwd, len - fwd, mpp, 1);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_multipath_fields_json(buff, mpp, 1)) < 0)
+ return rc;
- fwd += snprint_json(buff + fwd, len - fwd, 0, "\n");
- if (fwd >= len)
- return len;
+ if ((rc = snprint_json(buff, 0, "\n")) < 0 ||
+ (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
+ return rc;
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
- if (fwd >= len)
- return len;
- return fwd;
+ return get_strbuf_len(buff) - initial_len;
}
-int
-snprint_multipath_topology_json (char * buff, int len, const struct vectors * vecs)
+int snprint_multipath_topology_json (struct strbuf *buff,
+ const struct vectors * vecs)
{
- int i, fwd = 0;
+ int i;
struct multipath * mpp;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc;
- fwd += snprint_json_header(buff, len);
- if (fwd >= len)
- return len;
-
- fwd += snprint_json(buff + fwd, len - fwd, 1, PRINT_JSON_START_MAPS);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_json_header(buff)) < 0 ||
+ (rc = snprint_json(buff, 1, PRINT_JSON_START_MAPS)) < 0)
+ return rc;
vector_foreach_slot(vecs->mpvec, mpp, i) {
- fwd += snprint_multipath_fields_json(buff + fwd, len - fwd,
- mpp, i + 1 == VECTOR_SIZE(vecs->mpvec));
- if (fwd >= len)
- return len;
+ if ((rc = snprint_multipath_fields_json(
+ buff, mpp, i + 1 == VECTOR_SIZE(vecs->mpvec))) < 0)
+ return rc;
}
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_ARRAY);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_json(buff, 0, PRINT_JSON_END_ARRAY)) < 0 ||
+ (rc = snprint_json(buff, 0, PRINT_JSON_END_LAST)) < 0)
+ return rc;
- fwd += snprint_json(buff + fwd, len - fwd, 0, PRINT_JSON_END_LAST);
- if (fwd >= len)
- return len;
- return fwd;
+ return get_strbuf_len(buff) - initial_len;
}
static int
snprint_hwentry (const struct config *conf,
- char * buff, int len, const struct hwentry * hwe)
+ struct strbuf *buff, const struct hwentry * hwe)
{
- int i;
- int fwd = 0;
+ int i, rc;
struct keyword * kw;
struct keyword * rootkw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "devices");
-
- if (!rootkw || !rootkw->sub)
- return 0;
-
+ assert(rootkw && rootkw->sub);
rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
+ assert(rootkw);
- if (!rootkw)
- return 0;
+ if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0)
+ return rc;
- fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd >= len)
- return len;
iterate_sub_keywords(rootkw, kw, i) {
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, hwe);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, hwe)) < 0)
+ return rc;
}
- fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd >= len)
- return len;
- return fwd;
+ if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
-static int snprint_hwtable(const struct config *conf,
- char *buff, int len,
+static int snprint_hwtable(const struct config *conf, struct strbuf *buff,
const struct _vector *hwtable)
{
- int fwd = 0;
- int i;
+ int i, rc;
struct hwentry * hwe;
struct keyword * rootkw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "devices");
- if (!rootkw)
- return 0;
+ assert(rootkw);
+
+ if ((rc = append_strbuf_str(buff, "devices {\n")) < 0)
+ return rc;
- fwd += snprintf(buff + fwd, len - fwd, "devices {\n");
- if (fwd >= len)
- return len;
vector_foreach_slot (hwtable, hwe, i) {
- fwd += snprint_hwentry(conf, buff + fwd, len - fwd, hwe);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_hwentry(conf, buff, hwe)) < 0)
+ return rc;
}
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+
+ return get_strbuf_len(buff) - initial_len;
}
static int
-snprint_mpentry (const struct config *conf, char * buff, int len,
+snprint_mpentry (const struct config *conf, struct strbuf *buff,
const struct mpentry * mpe, const struct _vector *mpvec)
{
- int i;
- int fwd = 0;
+ int i, rc;
struct keyword * kw;
struct keyword * rootkw;
struct multipath *mpp = NULL;
+ size_t initial_len = get_strbuf_len(buff);
if (mpvec != NULL && (mpp = find_mp_by_wwid(mpvec, mpe->wwid)) == NULL)
return 0;
rootkw = find_keyword(conf->keywords, NULL, "multipath");
- if (!rootkw)
- return 0;
+ assert(rootkw);
+
+ if ((rc = append_strbuf_str(buff, "\tmultipath {\n")) < 0)
+ return rc;
- fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n");
- if (fwd >= len)
- return len;
iterate_sub_keywords(rootkw, kw, i) {
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, mpe);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, mpe)) < 0)
+ return rc;
}
/*
* This mpp doesn't have alias defined. Add the alias in a comment.
*/
- if (mpp != NULL && strcmp(mpp->alias, mpp->wwid)) {
- fwd += snprintf(buff + fwd, len - fwd, "\t\t# alias \"%s\"\n",
- mpp->alias);
- if (fwd >= len)
- return len;
- }
- fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd >= len)
- return len;
- return fwd;
+ if (mpp != NULL && strcmp(mpp->alias, mpp->wwid) &&
+ (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n", mpp->alias)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
+ return rc;
+
+ return get_strbuf_len(buff) - initial_len;
}
-static int snprint_mptable(const struct config *conf,
- char *buff, int len, const struct _vector *mpvec)
+static int snprint_mptable(const struct config *conf, struct strbuf *buff,
+ const struct _vector *mpvec)
{
- int fwd = 0;
- int i;
+ int i, rc;
struct mpentry * mpe;
struct keyword * rootkw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "multipaths");
- if (!rootkw)
- return 0;
+ assert(rootkw);
+
+ if ((rc = append_strbuf_str(buff, "multipaths {\n")) < 0)
+ return rc;
- fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n");
- if (fwd >= len)
- return len;
vector_foreach_slot (conf->mptable, mpe, i) {
- fwd += snprint_mpentry(conf, buff + fwd, len - fwd, mpe, mpvec);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_mpentry(conf, buff, mpe, mpvec)) < 0)
+ return rc;
}
if (mpvec != NULL) {
struct multipath *mpp;
if (find_mpe(conf->mptable, mpp->wwid) != NULL)
continue;
- fwd += snprintf(buff + fwd, len - fwd,
- "\tmultipath {\n");
- if (fwd >= len)
- return len;
- fwd += snprintf(buff + fwd, len - fwd,
- "\t\twwid \"%s\"\n", mpp->wwid);
- if (fwd >= len)
- return len;
+ if ((rc = print_strbuf(buff,
+ "\tmultipath {\n\t\twwid \"%s\"\n",
+ mpp->wwid)) < 0)
+ return rc;
/*
* This mpp doesn't have alias defined in
* multipath.conf - otherwise find_mpe would have
* found it. Add the alias in a comment.
*/
- if (strcmp(mpp->alias, mpp->wwid)) {
- fwd += snprintf(buff + fwd, len - fwd,
- "\t\t# alias \"%s\"\n",
- mpp->alias);
- if (fwd >= len)
- return len;
- }
- fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd >= len)
- return len;
+ if (strcmp(mpp->alias, mpp->wwid) &&
+ (rc = print_strbuf(buff, "\t\t# alias \"%s\"\n",
+ mpp->alias)) < 0)
+ return rc;
+ if ((rc = append_strbuf_str(buff, "\t}\n")) < 0)
+ return rc;
}
}
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
-static int snprint_overrides(const struct config *conf, char * buff, int len,
+static int snprint_overrides(const struct config *conf, struct strbuf *buff,
const struct hwentry *overrides)
{
- int fwd = 0;
- int i;
+ int i, rc;
struct keyword *rootkw;
struct keyword *kw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "overrides");
- if (!rootkw)
- return 0;
+ assert(rootkw);
- fwd += snprintf(buff + fwd, len - fwd, "overrides {\n");
- if (fwd >= len)
- return len;
+ if ((rc = append_strbuf_str(buff, "overrides {\n")) < 0)
+ return rc;
if (!overrides)
goto out;
+
iterate_sub_keywords(rootkw, kw, i) {
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, NULL);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
+ return rc;
}
out:
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
-static int snprint_defaults(const struct config *conf, char *buff, int len)
+static int snprint_defaults(const struct config *conf, struct strbuf *buff)
{
- int fwd = 0;
- int i;
+ int i, rc;
struct keyword *rootkw;
struct keyword *kw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "defaults");
- if (!rootkw)
- return 0;
+ assert(rootkw);
- fwd += snprintf(buff + fwd, len - fwd, "defaults {\n");
- if (fwd >= len)
- return len;
+ if ((rc = append_strbuf_str(buff, "defaults {\n")) < 0)
+ return rc;
iterate_sub_keywords(rootkw, kw, i) {
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, NULL);
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, NULL)) < 0)
+ return rc;
}
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
-static int
-snprint_blacklist_group (char *buff, int len, int *fwd, vector *vec)
+static int snprint_blacklist_group(struct strbuf *buff, vector *vec)
{
- int threshold = MAX_LINE_LEN;
struct blentry * ble;
- int pos;
- int i;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc, i;
- pos = *fwd;
if (!VECTOR_SIZE(*vec)) {
- if ((len - pos - threshold) <= 0)
- return 0;
- pos += snprintf(buff + pos, len - pos, " <empty>\n");
+ if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
+ return rc;
} else vector_foreach_slot (*vec, ble, i) {
- if ((len - pos - threshold) <= 0)
- return 0;
- if (ble->origin == ORIGIN_CONFIG)
- pos += snprintf(buff + pos, len - pos, " (config file rule) ");
- else if (ble->origin == ORIGIN_DEFAULT)
- pos += snprintf(buff + pos, len - pos, " (default rule) ");
- pos += snprintf(buff + pos, len - pos, "%s\n", ble->str);
+ rc = print_strbuf(buff, " %s %s\n",
+ ble->origin == ORIGIN_CONFIG ?
+ "(config file rule)" :
+ "(default rule) ", ble->str);
+ if (rc < 0)
+ return rc;
}
- *fwd = pos;
- return pos;
+ return get_strbuf_len(buff) - initial_len;
}
static int
-snprint_blacklist_devgroup (char *buff, int len, int *fwd, vector *vec)
+snprint_blacklist_devgroup (struct strbuf *buff, vector *vec)
{
- int threshold = MAX_LINE_LEN;
struct blentry_device * bled;
- int pos;
- int i;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc, i;
- pos = *fwd;
if (!VECTOR_SIZE(*vec)) {
- if ((len - pos - threshold) <= 0)
- return 0;
- pos += snprintf(buff + pos, len - pos, " <empty>\n");
+ if ((rc = append_strbuf_str(buff, " <empty>\n")) < 0)
+ return rc;
} else vector_foreach_slot (*vec, bled, i) {
- if ((len - pos - threshold) <= 0)
- return 0;
- if (bled->origin == ORIGIN_CONFIG)
- pos += snprintf(buff + pos, len - pos, " (config file rule) ");
- else if (bled->origin == ORIGIN_DEFAULT)
- pos += snprintf(buff + pos, len - pos, " (default rule) ");
- pos += snprintf(buff + pos, len - pos, "%s:%s\n", bled->vendor, bled->product);
+ rc = print_strbuf(buff, " %s %s:%s\n",
+ bled->origin == ORIGIN_CONFIG ?
+ "(config file rule)" :
+ "(default rule) ",
+ bled->vendor, bled->product);
+ if (rc < 0)
+ return rc;
}
- *fwd = pos;
- return pos;
-}
-
-int snprint_blacklist_report(struct config *conf, char *buff, int len)
-{
- int threshold = MAX_LINE_LEN;
- int fwd = 0;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "device node rules:\n"
- "- blacklist:\n");
- if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_devnode))
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
- if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_devnode) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "udev property rules:\n"
- "- blacklist:\n");
- if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_property))
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
- if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_property) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "protocol rules:\n"
- "- blacklist:\n");
- if (!snprint_blacklist_group(buff, len, &fwd, &conf->blist_protocol))
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
- if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_protocol) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "wwid rules:\n"
- "- blacklist:\n");
- if (snprint_blacklist_group(buff, len, &fwd, &conf->blist_wwid) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
- if (snprint_blacklist_group(buff, len, &fwd, &conf->elist_wwid) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "device rules:\n"
- "- blacklist:\n");
- if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->blist_device) == 0)
- return len;
-
- if ((len - fwd - threshold) <= 0)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "- exceptions:\n");
- if (snprint_blacklist_devgroup(buff, len, &fwd, &conf->elist_device) == 0)
- return len;
-
- if (fwd > len)
- return len;
- return fwd;
-}
-
-static int snprint_blacklist(const struct config *conf, char *buff, int len)
+ return get_strbuf_len(buff) - initial_len;
+}
+
+int snprint_blacklist_report(struct config *conf, struct strbuf *buff)
{
- int i;
+ size_t initial_len = get_strbuf_len(buff);
+ int rc;
+
+ if ((rc = append_strbuf_str(buff, "device node rules:\n- blacklist:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->blist_devnode)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->elist_devnode)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "udev property rules:\n- blacklist:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->blist_property)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->elist_property)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "protocol rules:\n- blacklist:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->blist_protocol)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->elist_protocol)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "wwid rules:\n- blacklist:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->blist_wwid)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_group(buff, &conf->elist_wwid)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "device rules:\n- blacklist:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_devgroup(buff, &conf->blist_device)) < 0)
+ return rc;
+
+ if ((rc = append_strbuf_str(buff, "- exceptions:\n")) < 0)
+ return rc;
+ if ((rc = snprint_blacklist_devgroup(buff, &conf->elist_device)) < 0)
+ return rc;
+
+ return get_strbuf_len(buff) - initial_len;
+}
+
+static int snprint_blacklist(const struct config *conf, struct strbuf *buff)
+{
+ int i, rc;
struct blentry * ble;
struct blentry_device * bled;
- int fwd = 0;
struct keyword *rootkw;
- struct keyword *kw;
+ struct keyword *kw, *pkw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "blacklist");
- if (!rootkw)
- return 0;
+ assert(rootkw);
- fwd += snprintf(buff + fwd, len - fwd, "blacklist {\n");
- if (fwd >= len)
- return len;
+ if ((rc = append_strbuf_str(buff, "blacklist {\n")) < 0)
+ return rc;
vector_foreach_slot (conf->blist_devnode, ble, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ble);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
+ return rc;
}
vector_foreach_slot (conf->blist_wwid, ble, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ble);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
+ return rc;
}
vector_foreach_slot (conf->blist_property, ble, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "property");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ble);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
+ return rc;
}
vector_foreach_slot (conf->blist_protocol, ble, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ble);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ble)) < 0)
+ return rc;
}
+
rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
- if (!rootkw)
- return 0;
+ assert(rootkw);
+ kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
+ pkw = find_keyword(conf->keywords, rootkw->sub, "product");
+ assert(kw && pkw);
vector_foreach_slot (conf->blist_device, bled, i) {
- fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd >= len)
- return len;
- kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, bled);
- if (fwd >= len)
- return len;
- kw = find_keyword(conf->keywords, rootkw->sub, "product");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, bled);
- if (fwd >= len)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
+ kw, bled)) < 0)
+ return rc;
+ if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
+ pkw, bled)) < 0)
+ return rc;
}
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
static int snprint_blacklist_except(const struct config *conf,
- char *buff, int len)
+ struct strbuf *buff)
{
- int i;
+ int i, rc;
struct blentry * ele;
struct blentry_device * eled;
- int fwd = 0;
struct keyword *rootkw;
- struct keyword *kw;
+ struct keyword *kw, *pkw;
+ size_t initial_len = get_strbuf_len(buff);
rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions");
- if (!rootkw)
- return 0;
+ assert(rootkw);
- fwd += snprintf(buff + fwd, len - fwd, "blacklist_exceptions {\n");
- if (fwd >= len)
- return len;
+ if ((rc = append_strbuf_str(buff, "blacklist_exceptions {\n")) < 0)
+ return rc;
vector_foreach_slot (conf->elist_devnode, ele, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "devnode");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ele);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
+ return rc;
}
vector_foreach_slot (conf->elist_wwid, ele, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "wwid");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ele);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
+ return rc;
}
vector_foreach_slot (conf->elist_property, ele, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "property");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ele);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
+ return rc;
}
vector_foreach_slot (conf->elist_protocol, ele, i) {
kw = find_keyword(conf->keywords, rootkw->sub, "protocol");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t%k %v\n",
- kw, ele);
- if (fwd >= len)
- return len;
+ assert(kw);
+ if ((rc = snprint_keyword(buff, "\t%k %v\n", kw, ele)) < 0)
+ return rc;
}
+
rootkw = find_keyword(conf->keywords, rootkw->sub, "device");
- if (!rootkw)
- return 0;
+ assert(rootkw);
+ kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
+ pkw = find_keyword(conf->keywords, rootkw->sub, "product");
+ assert(kw && pkw);
vector_foreach_slot (conf->elist_device, eled, i) {
- fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n");
- if (fwd >= len)
- return len;
- kw = find_keyword(conf->keywords, rootkw->sub, "vendor");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, eled);
- if (fwd >= len)
- return len;
- kw = find_keyword(conf->keywords, rootkw->sub, "product");
- if (!kw)
- return 0;
- fwd += snprint_keyword(buff + fwd, len - fwd, "\t\t%k %v\n",
- kw, eled);
- if (fwd >= len)
- return len;
- fwd += snprintf(buff + fwd, len - fwd, "\t}\n");
- if (fwd >= len)
- return len;
+ if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n",
+ kw, eled)) < 0)
+ return rc;
+ if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n",
+ pkw, eled)) < 0)
+ return rc;
}
- fwd += snprintf(buff + fwd, len - fwd, "}\n");
- if (fwd >= len)
- return len;
- return fwd;
+
+ if ((rc = append_strbuf_str(buff, "}\n")) < 0)
+ return rc;
+ return get_strbuf_len(buff) - initial_len;
}
char *snprint_config(const struct config *conf, int *len,
const struct _vector *hwtable, const struct _vector *mpvec)
{
+ STRBUF_ON_STACK(buff);
char *reply;
- /* built-in config is >20kB already */
- unsigned int maxlen = 32768;
-
- for (reply = NULL; maxlen <= UINT_MAX/2; maxlen *= 2) {
- char *c, *tmp = reply;
-
- reply = REALLOC(reply, maxlen);
- if (!reply) {
- if (tmp)
- free(tmp);
+ int rc;
+
+ if ((rc = snprint_defaults(conf, &buff)) < 0 ||
+ (rc = snprint_blacklist(conf, &buff)) < 0 ||
+ (rc = snprint_blacklist_except(conf, &buff)) < 0 ||
+ (rc = snprint_hwtable(conf, &buff,
+ hwtable ? hwtable : conf->hwtable)) < 0 ||
+ (rc = snprint_overrides(conf, &buff, conf->overrides)) < 0)
+ return NULL;
+ if (VECTOR_SIZE(conf->mptable) > 0 ||
+ (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
+ if ((rc = snprint_mptable(conf, &buff, mpvec)) < 0)
return NULL;
- }
-
- c = reply + snprint_defaults(conf, reply, maxlen);
- if (c == reply + maxlen)
- continue;
-
- c += snprint_blacklist(conf, c, reply + maxlen - c);
- if (c == reply + maxlen)
- continue;
-
- c += snprint_blacklist_except(conf, c, reply + maxlen - c);
- if (c == reply + maxlen)
- continue;
-
- c += snprint_hwtable(conf, c, reply + maxlen - c,
- hwtable ? hwtable : conf->hwtable);
- if (c == reply + maxlen)
- continue;
- c += snprint_overrides(conf, c, reply + maxlen - c,
- conf->overrides);
- if (c == reply + maxlen)
- continue;
-
- if (VECTOR_SIZE(conf->mptable) > 0 ||
- (mpvec != NULL && VECTOR_SIZE(mpvec) > 0))
- c += snprint_mptable(conf, c, reply + maxlen - c,
- mpvec);
+ if (len)
+ *len = get_strbuf_len(&buff);
+ reply = steal_strbuf_str(&buff);
- if (c < reply + maxlen) {
- if (len)
- *len = c - reply;
- return reply;
- }
- }
-
- free(reply);
- return NULL;
+ return reply;
}
-int snprint_status(char *buff, int len, const struct vectors *vecs)
+int snprint_status(struct strbuf *buff, const struct vectors *vecs)
{
- int fwd = 0;
- int i;
+ int i, rc;
unsigned int count[PATH_MAX_STATE] = {0};
+ int monitored_count = 0;
struct path * pp;
+ size_t initial_len = get_strbuf_len(buff);
vector_foreach_slot (vecs->pathvec, pp, i) {
count[pp->state]++;
}
- fwd += snprintf(buff + fwd, len - fwd, "path checker states:\n");
- for (i=0; i<PATH_MAX_STATE; i++) {
+ if ((rc = append_strbuf_str(buff, "path checker states:\n")) < 0)
+ return rc;
+ for (i = 0; i < PATH_MAX_STATE; i++) {
if (!count[i])
continue;
- fwd += snprintf(buff + fwd, len - fwd, "%-20s%u\n",
- checker_state_name(i), count[i]);
+ if ((rc = print_strbuf(buff, "%-20s%u\n",
+ checker_state_name(i), count[i])) < 0)
+ return rc;
}
- int monitored_count = 0;
-
vector_foreach_slot(vecs->pathvec, pp, i)
if (pp->fd >= 0)
monitored_count++;
- fwd += snprintf(buff + fwd, len - fwd, "\npaths: %d\nbusy: %s\n",
- monitored_count, is_uevent_busy()? "True" : "False");
+ if ((rc = print_strbuf(buff, "\npaths: %d\nbusy: %s\n",
+ monitored_count,
+ is_uevent_busy()? "True" : "False")) < 0)
+ return rc;
- if (fwd >= len)
- return len;
- return fwd;
+ return get_strbuf_len(buff) - initial_len;
}
-int snprint_devices(struct config *conf, char *buff, size_t len,
+int snprint_devices(struct config *conf, struct strbuf *buff,
const struct vectors *vecs)
{
- size_t fwd = 0;
int r;
struct udev_enumerate *enm;
struct udev_list_entry *item, *first;
-
struct path * pp;
+ size_t initial_len = get_strbuf_len(buff);
enm = udev_enumerate_new(udev);
if (!enm)
return 1;
udev_enumerate_add_match_subsystem(enm, "block");
- fwd += snprintf(buff + fwd, len - fwd, "available block devices:\n");
+ if ((r = append_strbuf_str(buff, "available block devices:\n")) < 0)
+ goto out;
r = udev_enumerate_scan_devices(enm);
if (r < 0)
goto out;
continue;
}
- fwd += snprintf(buff + fwd, len - fwd, " %s", devname);
- if (fwd >= len)
- break;
-
pp = find_path_by_dev(vecs->pathvec, devname);
if (!pp) {
const char *hidden;
} else
status = " devnode whitelisted, monitored";
- fwd += snprintf(buff + fwd, len - fwd, " %s\n", status);
+ r = print_strbuf(buff, " %s %s\n", devname, status);
udev_device_unref(u_dev);
- if (fwd >= len)
+ if (r < 0)
break;
}
out:
udev_enumerate_unref(enm);
+ if (r < 0)
+ return r;
- if (fwd >= len)
- return len;
- return fwd;
+ return get_strbuf_len(buff) - initial_len;
}
/*
* stdout printing helpers
*/
-void print_path(struct path *pp, char *style)
-{
- char line[MAX_LINE_LEN];
-
- memset(&line[0], 0, MAX_LINE_LEN);
- snprint_path(&line[0], MAX_LINE_LEN, style, pp, 1);
- printf("%s", line);
-}
-
-void print_all_paths(vector pathvec, int banner)
-{
- print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
-}
-
-void print_all_paths_custo(vector pathvec, int banner, char *fmt)
+static void print_all_paths_custo(vector pathvec, int banner, const char *fmt)
{
int i;
struct path * pp;
- char line[MAX_LINE_LEN];
+ STRBUF_ON_STACK(line);
if (!VECTOR_SIZE(pathvec)) {
if (banner)
}
if (banner)
- fprintf(stdout, "===== paths list =====\n");
+ append_strbuf_str(&line, "===== paths list =====\n");
get_path_layout(pathvec, 1);
- snprint_path_header(line, MAX_LINE_LEN, fmt);
- fprintf(stdout, "%s", line);
+ snprint_path_header(&line, fmt);
vector_foreach_slot (pathvec, pp, i)
- print_path(pp, fmt);
+ snprint_path(&line, fmt, pp, 1);
+
+ printf("%s", get_strbuf_str(&line));
+}
+
+void print_all_paths(vector pathvec, int banner)
+{
+ print_all_paths_custo(pathvec, banner, PRINT_PATH_LONG);
}
#define _PRINT_H
#include "dm-generic.h"
-#define PRINT_PATH_LONG "%w %i %d %D %p %t %T %s %o"
-#define PRINT_PATH_INDENT "%i %d %D %t %T %o"
#define PRINT_PATH_CHECKER "%i %d %D %p %t %T %o %C"
#define PRINT_MAP_STATUS "%n %F %Q %N %t %r"
#define PRINT_MAP_STATS "%n %0 %1 %2 %3 %4"
#define PRINT_MAP_NAMES "%n %d %w"
-#define PRINT_MAP_PROPS "size=%S features='%f' hwhandler='%h' wp=%r"
-#define PRINT_PG_INDENT "policy='%s' prio=%p status=%t"
-#define PRINT_JSON_MULTIPLIER 5
-#define PRINT_JSON_MAJOR_VERSION 0
-#define PRINT_JSON_MINOR_VERSION 1
-#define PRINT_JSON_START_VERSION " \"major_version\": %d,\n" \
- " \"minor_version\": %d,\n"
-#define PRINT_JSON_START_ELEM "{\n"
-#define PRINT_JSON_START_MAP " \"map\":"
-#define PRINT_JSON_START_MAPS "\"maps\": ["
-#define PRINT_JSON_START_PATHS "\"paths\": ["
-#define PRINT_JSON_START_GROUPS "\"path_groups\": ["
-#define PRINT_JSON_END_ELEM "},"
-#define PRINT_JSON_END_LAST_ELEM "}"
-#define PRINT_JSON_END_LAST "}\n"
-#define PRINT_JSON_END_ARRAY "]\n"
-#define PRINT_JSON_INDENT " "
-#define PRINT_JSON_MAP "{\n" \
- " \"name\" : \"%n\",\n" \
- " \"uuid\" : \"%w\",\n" \
- " \"sysfs\" : \"%d\",\n" \
- " \"failback\" : \"%F\",\n" \
- " \"queueing\" : \"%Q\",\n" \
- " \"paths\" : %N,\n" \
- " \"write_prot\" : \"%r\",\n" \
- " \"dm_st\" : \"%t\",\n" \
- " \"features\" : \"%f\",\n" \
- " \"hwhandler\" : \"%h\",\n" \
- " \"action\" : \"%A\",\n" \
- " \"path_faults\" : %0,\n" \
- " \"vend\" : \"%v\",\n" \
- " \"prod\" : \"%p\",\n" \
- " \"rev\" : \"%e\",\n" \
- " \"switch_grp\" : %1,\n" \
- " \"map_loads\" : %2,\n" \
- " \"total_q_time\" : %3,\n" \
- " \"q_timeouts\" : %4,"
-
-#define PRINT_JSON_GROUP "{\n" \
- " \"selector\" : \"%s\",\n" \
- " \"pri\" : %p,\n" \
- " \"dm_st\" : \"%t\",\n" \
- " \"marginal_st\" : \"%M\","
-
-#define PRINT_JSON_GROUP_NUM " \"group\" : %d,\n"
-
-#define PRINT_JSON_PATH "{\n" \
- " \"dev\" : \"%d\",\n"\
- " \"dev_t\" : \"%D\",\n" \
- " \"dm_st\" : \"%t\",\n" \
- " \"dev_st\" : \"%o\",\n" \
- " \"chk_st\" : \"%T\",\n" \
- " \"checker\" : \"%c\",\n" \
- " \"pri\" : %p,\n" \
- " \"host_wwnn\" : \"%N\",\n" \
- " \"target_wwnn\" : \"%n\",\n" \
- " \"host_wwpn\" : \"%R\",\n" \
- " \"target_wwpn\" : \"%r\",\n" \
- " \"host_adapter\" : \"%a\",\n" \
- " \"marginal_st\" : \"%M\""
-
-#define MAX_LINE_LEN 80
-#define MAX_LINES 64
-#define MAX_FIELD_LEN 128
-#define PROGRESS_LEN 10
+struct strbuf;
struct path_data {
char wildcard;
char * header;
unsigned int width;
- int (*snprint)(char * buff, size_t len, const struct path * pp);
+ int (*snprint)(struct strbuf *, const struct path * pp);
};
struct multipath_data {
char wildcard;
char * header;
unsigned int width;
- int (*snprint)(char * buff, size_t len, const struct multipath * mpp);
+ int (*snprint)(struct strbuf *, const struct multipath * mpp);
};
struct pathgroup_data {
char wildcard;
char * header;
unsigned int width;
- int (*snprint)(char * buff, size_t len, const struct pathgroup * pgp);
+ int (*snprint)(struct strbuf *, const struct pathgroup * pgp);
};
enum layout_reset {
void get_path_layout (vector pathvec, int header);
void _get_multipath_layout (const struct _vector *gmvec, enum layout_reset);
void get_multipath_layout (vector mpvec, int header);
-int snprint_path_header (char *, int, const char *);
-int snprint_multipath_header (char *, int, const char *);
-int _snprint_path (const struct gen_path *, char *, int, const char *, int);
-#define snprint_path(buf, len, fmt, pp, v) \
- _snprint_path(dm_path_to_gen(pp), buf, len, fmt, v)
-int _snprint_multipath (const struct gen_multipath *, char *, int,
+int snprint_path_header(struct strbuf *, const char *);
+int snprint_multipath_header(struct strbuf *, const char *);
+int _snprint_path (const struct gen_path *, struct strbuf *, const char *, int);
+#define snprint_path(buf, fmt, pp, v) \
+ _snprint_path(dm_path_to_gen(pp), buf, fmt, v)
+int _snprint_multipath (const struct gen_multipath *, struct strbuf *,
const char *, int);
-#define snprint_multipath(buf, len, fmt, mp, v) \
- _snprint_multipath(dm_multipath_to_gen(mp), buf, len, fmt, v)
-int _snprint_multipath_topology (const struct gen_multipath *, char *, int,
+#define snprint_multipath(buf, fmt, mp, v) \
+ _snprint_multipath(dm_multipath_to_gen(mp), buf, fmt, v)
+int _snprint_multipath_topology (const struct gen_multipath *, struct strbuf *,
int verbosity);
-#define snprint_multipath_topology(buf, len, mpp, v) \
- _snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, len, v)
-int snprint_multipath_topology_json (char * buff, int len,
- const struct vectors * vecs);
+#define snprint_multipath_topology(buf, mpp, v) \
+ _snprint_multipath_topology (dm_multipath_to_gen(mpp), buf, v)
+int snprint_multipath_topology_json(struct strbuf *, const struct vectors *vecs);
char *snprint_config(const struct config *conf, int *len,
const struct _vector *hwtable,
const struct _vector *mpvec);
-int snprint_multipath_map_json (char * buff, int len,
- const struct multipath * mpp);
-int snprint_blacklist_report (struct config *, char *, int);
-int snprint_wildcards (char *, int);
-int snprint_status (char *, int, const struct vectors *);
-int snprint_devices (struct config *, char *, size_t, const struct vectors *);
-int snprint_path_serial (char *, size_t, const struct path *);
-int snprint_host_wwnn (char *, size_t, const struct path *);
-int snprint_host_wwpn (char *, size_t, const struct path *);
-int snprint_tgt_wwnn (char *, size_t, const struct path *);
-int snprint_tgt_wwpn (char *, size_t, const struct path *);
+int snprint_multipath_map_json(struct strbuf *, const struct multipath *mpp);
+int snprint_blacklist_report(struct config *, struct strbuf *);
+int snprint_wildcards(struct strbuf *);
+int snprint_status(struct strbuf *, const struct vectors *);
+int snprint_devices(struct config *, struct strbuf *, const struct vectors *);
+int snprint_path_serial(struct strbuf *, const struct path *);
+int snprint_host_wwnn(struct strbuf *, const struct path *);
+int snprint_host_wwpn(struct strbuf *, const struct path *);
+int snprint_tgt_wwnn(struct strbuf *, const struct path *);
+int snprint_tgt_wwpn(struct strbuf *, const struct path *);
#define PROTOCOL_BUF_SIZE sizeof("scsi:unspec")
-int snprint_path_protocol(char *, size_t, const struct path *);
+int snprint_path_protocol(struct strbuf *, const struct path *);
void _print_multipath_topology (const struct gen_multipath * gmp,
int verbosity);
_print_multipath_topology(dm_multipath_to_gen(mpp), v)
void print_all_paths (vector pathvec, int banner);
-void print_all_paths_custo (vector pathvec, int banner, char *fmt);
int snprint_path_attr(const struct gen_path* gp,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
int snprint_pathgroup_attr(const struct gen_pathgroup* gpg,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
int snprint_multipath_attr(const struct gen_multipath* gm,
- char *buf, int len, char wildcard);
+ struct strbuf *buf, char wildcard);
int snprint_multipath_style(const struct gen_multipath *gmp,
- char *style, int len, int verbosity);
+ struct strbuf *style, int verbosity);
#endif /* _PRINT_H */
#include "structs_vec.h"
#include "print.h"
#include "util.h"
-
-#define CHECK_LEN \
-do { \
- if ((p - str) >= (len - 1)) { \
- condlog(0, "%s: %s - buffer size too small", pp->dev, pp->prio.name); \
- return -1; \
- } \
-} while(0)
+#include "strbuf.h"
static int
-build_serial_path(struct path *pp, char *str, int len)
+build_serial_path(struct path *pp, struct strbuf *buf)
{
- char *p = str;
+ int rc = snprint_path_serial(buf, pp);
- p += snprint_path_serial(p, str + len - p, pp);
- CHECK_LEN;
- return 0;
+ return rc < 0 ? rc : 0;
}
static int
-build_wwn_path(struct path *pp, char *str, int len)
+build_wwn_path(struct path *pp, struct strbuf *buf)
{
- char *p = str;
-
- p += snprint_host_wwnn(p, str + len - p, pp);
- CHECK_LEN;
- p += snprintf(p, str + len - p, ":");
- CHECK_LEN;
- p += snprint_host_wwpn(p, str + len - p, pp);
- CHECK_LEN;
- p += snprintf(p, str + len - p, ":");
- CHECK_LEN;
- p += snprint_tgt_wwnn(p, str + len - p, pp);
- CHECK_LEN;
- p += snprintf(p, str + len - p, ":");
- CHECK_LEN;
- p += snprint_tgt_wwpn(p, str + len - p, pp);
- CHECK_LEN;
+ int rc;
+
+ if ((rc = snprint_host_wwnn(buf, pp)) < 0 ||
+ (rc = fill_strbuf(buf, ':', 1)) < 0 ||
+ (rc = snprint_host_wwpn(buf, pp)) < 0 ||
+ (rc = fill_strbuf(buf, ':', 1)) < 0 ||
+ (rc = snprint_tgt_wwnn(buf, pp) < 0) ||
+ (rc = fill_strbuf(buf, ':', 1) < 0) ||
+ (rc = snprint_tgt_wwpn(buf, pp) < 0))
+ return rc;
return 0;
}
/* main priority routine */
int prio_path_weight(struct path *pp, char *prio_args)
{
- char path[FILE_NAME_SIZE];
- char *arg;
+ STRBUF_ON_STACK(path);
+ char *arg __attribute__((cleanup(cleanup_charp))) = NULL;
char *temp, *regex, *prio;
char split_char[] = " \t";
int priority = DEFAULT_PRIORITY, path_found = 0;
}
if (!strcmp(regex, HBTL)) {
- sprintf(path, "%d:%d:%d:%d", pp->sg_id.host_no,
- pp->sg_id.channel, pp->sg_id.scsi_id, pp->sg_id.lun);
+ if (print_strbuf(&path, "%d:%d:%d:%" PRIu64, pp->sg_id.host_no,
+ pp->sg_id.channel, pp->sg_id.scsi_id,
+ pp->sg_id.lun) < 0)
+ return priority;
} else if (!strcmp(regex, DEV_NAME)) {
- strcpy(path, pp->dev);
+ if (append_strbuf_str(&path, pp->dev) < 0)
+ return priority;
} else if (!strcmp(regex, SERIAL)) {
- if (build_serial_path(pp, path, FILE_NAME_SIZE) != 0) {
- FREE(arg);
+ if (build_serial_path(pp, &path) != 0)
return priority;
- }
} else if (!strcmp(regex, WWN)) {
- if (build_wwn_path(pp, path, FILE_NAME_SIZE) != 0) {
- FREE(arg);
+ if (build_wwn_path(pp, &path) != 0)
return priority;
- }
} else {
condlog(0, "%s: %s - Invalid arguments", pp->dev,
pp->prio.name);
- FREE(arg);
return priority;
}
break;
if (!regcomp(&pathe, regex, REG_EXTENDED|REG_NOSUB)) {
- if (!regexec(&pathe, path, 0, NULL, 0)) {
+ if (!regexec(&pathe, get_strbuf_str(&path), 0,
+ NULL, 0)) {
path_found = 1;
priority = atoi(prio);
}
}
}
- FREE(arg);
return priority;
}
#include "prioritizers/alua_rtpg.h"
#include "prkey.h"
#include "propsel.h"
+#include "strbuf.h"
#include <inttypes.h>
#include <libudev.h>
int select_rr_weight(struct config *conf, struct multipath * mp)
{
const char *origin;
- char buff[13];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(rr_weight);
mp_set_ovr(rr_weight);
mp_set_conf(rr_weight);
mp_set_default(rr_weight, DEFAULT_RR_WEIGHT);
out:
- print_rr_weight(buff, 13, mp->rr_weight);
- condlog(3, "%s: rr_weight = %s %s", mp->alias, buff, origin);
+ print_rr_weight(&buff, mp->rr_weight);
+ condlog(3, "%s: rr_weight = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
int select_pgfailback(struct config *conf, struct multipath * mp)
{
const char *origin;
- char buff[13];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(pgfailback);
mp_set_ovr(pgfailback);
mp_set_conf(pgfailback);
mp_set_default(pgfailback, DEFAULT_FAILBACK);
out:
- print_pgfailback(buff, 13, mp->pgfailback);
- condlog(3, "%s: failback = %s %s", mp->alias, buff, origin);
+ print_pgfailback(&buff, mp->pgfailback);
+ condlog(3, "%s: failback = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
{
static const char q_i_n_p[] = "queue_if_no_path";
static const char r_a_h_h[] = "retain_attached_hw_handler";
- char buff[12];
+ STRBUF_ON_STACK(buff);
if (*features == NULL)
return;
id, q_i_n_p);
if (*no_path_retry == NO_PATH_RETRY_UNDEF) {
*no_path_retry = NO_PATH_RETRY_QUEUE;
- print_no_path_retry(buff, sizeof(buff),
- *no_path_retry);
+ print_no_path_retry(&buff, *no_path_retry);
condlog(3, "%s: no_path_retry = %s (inherited setting from feature '%s')",
- id, buff, q_i_n_p);
+ id, get_strbuf_str(&buff), q_i_n_p);
};
/* Warn only if features string is overridden */
if (*no_path_retry != NO_PATH_RETRY_QUEUE) {
- print_no_path_retry(buff, sizeof(buff),
- *no_path_retry);
+ print_no_path_retry(&buff, *no_path_retry);
condlog(2, "%s: ignoring feature '%s' because no_path_retry is set to '%s'",
- id, q_i_n_p, buff);
+ id, q_i_n_p, get_strbuf_str(&buff));
}
remove_feature(features, q_i_n_p);
}
int select_no_path_retry(struct config *conf, struct multipath *mp)
{
const char *origin = NULL;
- char buff[12];
+ STRBUF_ON_STACK(buff);
if (mp->disable_queueing) {
condlog(0, "%s: queueing disabled", mp->alias);
mp_set_hwe(no_path_retry);
mp_set_conf(no_path_retry);
out:
- print_no_path_retry(buff, 12, mp->no_path_retry);
+ print_no_path_retry(&buff, mp->no_path_retry);
if (origin)
- condlog(3, "%s: no_path_retry = %s %s", mp->alias, buff,
- origin);
+ condlog(3, "%s: no_path_retry = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
else
condlog(3, "%s: no_path_retry = undef %s",
mp->alias, default_origin);
int select_fast_io_fail(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_ovr(fast_io_fail);
mp_set_hwe(fast_io_fail);
mp_set_conf(fast_io_fail);
mp_set_default(fast_io_fail, DEFAULT_FAST_IO_FAIL);
out:
- print_undef_off_zero(buff, 12, mp->fast_io_fail);
- condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias, buff, origin);
+ print_undef_off_zero(&buff, mp->fast_io_fail);
+ condlog(3, "%s: fast_io_fail_tmo = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
int select_dev_loss(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_ovr(dev_loss);
mp_set_hwe(dev_loss);
mp->dev_loss = DEV_LOSS_TMO_UNSET;
return 0;
out:
- print_dev_loss(buff, 12, mp->dev_loss);
- condlog(3, "%s: dev_loss_tmo = %s %s", mp->alias, buff, origin);
+ print_dev_loss(&buff, mp->dev_loss);
+ condlog(3, "%s: dev_loss_tmo = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
int select_eh_deadline(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_ovr(eh_deadline);
mp_set_hwe(eh_deadline);
/* not changing sysfs in default cause, so don't print anything */
return 0;
out:
- print_undef_off_zero(buff, 12, mp->eh_deadline);
- condlog(3, "%s: eh_deadline = %s %s", mp->alias, buff, origin);
+ print_undef_off_zero(&buff, mp->eh_deadline);
+ condlog(3, "%s: eh_deadline = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
int select_reservation_key(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[PRKEY_SIZE];
+ STRBUF_ON_STACK(buff);
char *from_file = "";
uint64_t prkey = 0;
else
put_be64(mp->reservation_key, prkey);
}
- print_reservation_key(buff, PRKEY_SIZE, mp->reservation_key,
+ print_reservation_key(&buff, mp->reservation_key,
mp->sa_flags, mp->prkey_source);
- condlog(3, "%s: reservation_key = %s %s%s", mp->alias, buff, origin,
- from_file);
+ condlog(3, "%s: reservation_key = %s %s%s", mp->alias,
+ get_strbuf_str(&buff), origin, from_file);
return 0;
}
{
int value = NU_UNDEF;
const char *origin = default_origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
do_set(delay_watch_checks, mp->mpe, value, multipaths_origin);
do_set(delay_watch_checks, conf->overrides, value, overrides_origin);
do_set_from_hwe(delay_watch_checks, mp, value, hwe_origin);
do_set(delay_watch_checks, conf, value, conf_origin);
out:
- if (print_off_int_undef(buff, 12, value) != 0)
- condlog(3, "%s: delay_watch_checks = %s %s", mp->alias, buff,
- origin);
+ if (print_off_int_undef(&buff, value) > 0)
+ condlog(3, "%s: delay_watch_checks = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return value;
}
{
int value = NU_UNDEF;
const char *origin = default_origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
do_set(delay_wait_checks, mp->mpe, value, multipaths_origin);
do_set(delay_wait_checks, conf->overrides, value, overrides_origin);
do_set_from_hwe(delay_wait_checks, mp, value, hwe_origin);
do_set(delay_wait_checks, conf, value, conf_origin);
out:
- if (print_off_int_undef(buff, 12, value) != 0)
- condlog(3, "%s: delay_wait_checks = %s %s", mp->alias, buff,
- origin);
+ if (print_off_int_undef(&buff, value) > 0)
+ condlog(3, "%s: delay_wait_checks = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return value;
}
int select_delay_checks(struct config *conf, struct multipath *mp)
{
int watch_checks, wait_checks;
- char buff[12];
+ STRBUF_ON_STACK(buff);
watch_checks = use_delay_watch_checks(conf, mp);
wait_checks = use_delay_wait_checks(conf, mp);
(watch_checks > 0)? delay_watch_origin : delay_wait_origin);
if (watch_checks > 0) {
mp->san_path_err_forget_rate = watch_checks;
- print_off_int_undef(buff, 12, mp->san_path_err_forget_rate);
+ print_off_int_undef(&buff, mp->san_path_err_forget_rate);
condlog(3, "%s: san_path_err_forget_rate = %s %s", mp->alias,
- buff, delay_watch_origin);
+ get_strbuf_str(&buff), delay_watch_origin);
+ reset_strbuf(&buff);
}
if (wait_checks > 0) {
mp->san_path_err_recovery_time = wait_checks *
conf->max_checkint;
- print_off_int_undef(buff, 12, mp->san_path_err_recovery_time);
+ print_off_int_undef(&buff, mp->san_path_err_recovery_time);
condlog(3, "%s: san_path_err_recovery_time = %s %s", mp->alias,
- buff, delay_wait_origin);
+ get_strbuf_str(&buff), delay_wait_origin);
}
return 0;
}
int select_san_path_err_threshold(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
if (marginal_path_check_enabled(mp)) {
mp->san_path_err_threshold = NU_NO;
mp_set_conf(san_path_err_threshold);
mp_set_default(san_path_err_threshold, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12, mp->san_path_err_threshold) != 0)
+ if (print_off_int_undef(&buff, mp->san_path_err_threshold) > 0)
condlog(3, "%s: san_path_err_threshold = %s %s",
- mp->alias, buff, origin);
+ mp->alias, get_strbuf_str(&buff), origin);
warn_san_path_deprecated(mp, san_path_err_threshold);
return 0;
}
int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
if (marginal_path_check_enabled(mp)) {
mp->san_path_err_forget_rate = NU_NO;
mp_set_conf(san_path_err_forget_rate);
mp_set_default(san_path_err_forget_rate, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12, mp->san_path_err_forget_rate) != 0)
- condlog(3, "%s: san_path_err_forget_rate = %s %s", mp->alias,
- buff, origin);
+ if (print_off_int_undef(&buff, mp->san_path_err_forget_rate) > 0)
+ condlog(3, "%s: san_path_err_forget_rate = %s %s",
+ mp->alias, get_strbuf_str(&buff), origin);
warn_san_path_deprecated(mp, san_path_err_forget_rate);
return 0;
int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
if (marginal_path_check_enabled(mp)) {
mp->san_path_err_recovery_time = NU_NO;
mp_set_conf(san_path_err_recovery_time);
mp_set_default(san_path_err_recovery_time, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12, mp->san_path_err_recovery_time) != 0)
+ if (print_off_int_undef(&buff, mp->san_path_err_recovery_time) != 0)
condlog(3, "%s: san_path_err_recovery_time = %s %s", mp->alias,
- buff, origin);
+ get_strbuf_str(&buff), origin);
warn_san_path_deprecated(mp, san_path_err_recovery_time);
return 0;
int select_marginal_path_err_sample_time(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(marginal_path_err_sample_time);
mp_set_ovr(marginal_path_err_sample_time);
mp->alias, 2 * IOTIMEOUT_SEC);
mp->marginal_path_err_sample_time = 2 * IOTIMEOUT_SEC;
}
- if (print_off_int_undef(buff, 12, mp->marginal_path_err_sample_time)
- != 0)
+ if (print_off_int_undef(&buff, mp->marginal_path_err_sample_time) > 0)
condlog(3, "%s: marginal_path_err_sample_time = %s %s",
- mp->alias, buff, origin);
+ mp->alias, get_strbuf_str(&buff), origin);
return 0;
}
int select_marginal_path_err_rate_threshold(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(marginal_path_err_rate_threshold);
mp_set_ovr(marginal_path_err_rate_threshold);
mp_set_conf(marginal_path_err_rate_threshold);
mp_set_default(marginal_path_err_rate_threshold, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12, mp->marginal_path_err_rate_threshold)
- != 0)
+ if (print_off_int_undef(&buff, mp->marginal_path_err_rate_threshold) > 0)
condlog(3, "%s: marginal_path_err_rate_threshold = %s %s",
- mp->alias, buff, origin);
+ mp->alias, get_strbuf_str(&buff), origin);
return 0;
}
int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(marginal_path_err_recheck_gap_time);
mp_set_ovr(marginal_path_err_recheck_gap_time);
mp_set_conf(marginal_path_err_recheck_gap_time);
mp_set_default(marginal_path_err_recheck_gap_time, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12,
- mp->marginal_path_err_recheck_gap_time) != 0)
+ if (print_off_int_undef(&buff,
+ mp->marginal_path_err_recheck_gap_time) > 0)
condlog(3, "%s: marginal_path_err_recheck_gap_time = %s %s",
- mp->alias, buff, origin);
+ mp->alias, get_strbuf_str(&buff), origin);
return 0;
}
int select_marginal_path_double_failed_time(struct config *conf, struct multipath *mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(marginal_path_double_failed_time);
mp_set_ovr(marginal_path_double_failed_time);
mp_set_conf(marginal_path_double_failed_time);
mp_set_default(marginal_path_double_failed_time, DEFAULT_ERR_CHECKS);
out:
- if (print_off_int_undef(buff, 12, mp->marginal_path_double_failed_time)
- != 0)
+ if (print_off_int_undef(&buff, mp->marginal_path_double_failed_time) > 0)
condlog(3, "%s: marginal_path_double_failed_time = %s %s",
- mp->alias, buff, origin);
+ mp->alias, get_strbuf_str(&buff), origin);
return 0;
}
int select_ghost_delay (struct config *conf, struct multipath * mp)
{
const char *origin;
- char buff[12];
+ STRBUF_ON_STACK(buff);
mp_set_mpe(ghost_delay);
mp_set_ovr(ghost_delay);
mp_set_conf(ghost_delay);
mp_set_default(ghost_delay, DEFAULT_GHOST_DELAY);
out:
- if (print_off_int_undef(buff, 12, mp->ghost_delay) != 0)
- condlog(3, "%s: ghost_delay = %s %s", mp->alias, buff, origin);
+ if (print_off_int_undef(&buff, mp->ghost_delay) != 0)
+ condlog(3, "%s: ghost_delay = %s %s", mp->alias,
+ get_strbuf_str(&buff), origin);
return 0;
}
--- /dev/null
+/*
+ * Copyright (c) 2021 SUSE LLC
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+#include <inttypes.h>
+#include <stdint.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <assert.h>
+#include "strbuf.h"
+
+static const char empty_str[] = "";
+
+const char *get_strbuf_str(const struct strbuf *buf)
+{
+ return buf->buf ? buf->buf : empty_str;
+}
+
+char *steal_strbuf_str(struct strbuf *buf)
+{
+ char *p = buf->buf;
+
+ buf->buf = NULL;
+ buf->size = buf->offs = 0;
+ return p;
+}
+
+size_t get_strbuf_len(const struct strbuf *buf)
+{
+ return buf->offs;
+}
+
+static bool strbuf_is_sane(const struct strbuf *buf)
+{
+ return buf && ((!buf->buf && !buf->size && !buf->offs) ||
+ (buf->buf && buf->size && buf->size > buf->offs));
+}
+
+void reset_strbuf(struct strbuf *buf)
+{
+ free(buf->buf);
+ buf->buf = NULL;
+ buf->size = buf->offs = 0;
+}
+
+void free_strbuf(struct strbuf *buf)
+{
+ if (!buf)
+ return;
+ reset_strbuf(buf);
+ free(buf);
+}
+
+struct strbuf *new_strbuf(void)
+{
+ return calloc(1, sizeof(struct strbuf));
+}
+
+int truncate_strbuf(struct strbuf *buf, size_t offs)
+{
+ if (!buf->buf)
+ return -EFAULT;
+ if (offs > buf->offs)
+ return -ERANGE;
+
+ buf->offs = offs;
+ buf->buf[offs] = '\0';
+ return 0;
+}
+
+#define BUF_CHUNK 64
+
+static int expand_strbuf(struct strbuf *buf, int addsz)
+{
+ size_t add;
+ char *tmp;
+
+ assert(strbuf_is_sane(buf));
+ if (addsz < 0)
+ return -EINVAL;
+ if (buf->size - buf->offs >= (size_t)addsz + 1)
+ return 0;
+
+ add = ((addsz - (buf->size - buf->offs)) / BUF_CHUNK + 1)
+ * BUF_CHUNK;
+
+ if (buf->size >= SIZE_MAX - add) {
+ add = SIZE_MAX - buf->size;
+ if (add < (size_t)addsz + 1)
+ return -EOVERFLOW;
+ }
+
+ tmp = realloc(buf->buf, buf->size + add);
+ if (!tmp)
+ return -ENOMEM;
+
+ buf->buf = tmp;
+ buf->size += add;
+ buf->buf[buf->offs] = '\0';
+
+ return 0;
+}
+
+int __append_strbuf_str(struct strbuf *buf, const char *str, int slen)
+{
+ int ret;
+
+ if ((ret = expand_strbuf(buf, slen)) < 0)
+ return ret;
+
+ memcpy(buf->buf + buf->offs, str, slen);
+ buf->offs += slen;
+ buf->buf[buf->offs] = '\0';
+
+ return slen;
+}
+
+int append_strbuf_str(struct strbuf *buf, const char *str)
+{
+ size_t slen;
+
+ if (!str)
+ return -EINVAL;
+
+ slen = strlen(str);
+ if (slen > INT_MAX)
+ return -ERANGE;
+
+ return __append_strbuf_str(buf, str, slen);
+}
+
+int fill_strbuf(struct strbuf *buf, char c, int slen)
+{
+ int ret;
+
+ if ((ret = expand_strbuf(buf, slen)) < 0)
+ return ret;
+
+ memset(buf->buf + buf->offs, c, slen);
+ buf->offs += slen;
+ buf->buf[buf->offs] = '\0';
+
+ return slen;
+}
+
+int append_strbuf_quoted(struct strbuf *buff, const char *ptr)
+{
+ char *quoted, *q;
+ const char *p;
+ unsigned n_quotes, i;
+ size_t qlen;
+ int ret;
+
+ if (!ptr)
+ return -EINVAL;
+
+ for (n_quotes = 0, p = strchr(ptr, '"'); p; p = strchr(++p, '"'))
+ n_quotes++;
+
+ /* leading + trailing quote, 1 extra quote for every quote in ptr */
+ qlen = strlen(ptr) + 2 + n_quotes;
+ if (qlen > INT_MAX)
+ return -ERANGE;
+ if ((ret = expand_strbuf(buff, qlen)) < 0)
+ return ret;
+
+ quoted = &(buff->buf[buff->offs]);
+ *quoted++ = '"';
+ for (p = ptr, q = quoted, i = 0; i < n_quotes; i++) {
+ char *q1 = memccpy(q, p, '"', qlen - 2 - (q - quoted));
+
+ assert(q1 != NULL);
+ p += q1 - q;
+ *q1++ = '"';
+ q = q1;
+ }
+ q = mempcpy(q, p, qlen - 2 - (q - quoted));
+ *q++ = '"';
+ *q = '\0';
+ ret = q - &(buff->buf[buff->offs]);
+ buff->offs += ret;
+ return ret;
+}
+
+__attribute__((format(printf, 2, 3)))
+int print_strbuf(struct strbuf *buf, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+ char *tail;
+
+ va_start(ap, fmt);
+ ret = vasprintf(&tail, fmt, ap);
+ va_end(ap);
+
+ if (ret < 0)
+ return -ENOMEM;
+
+ ret = __append_strbuf_str(buf, tail, ret);
+
+ free(tail);
+ return ret;
+}
--- /dev/null
+/*
+ * Copyright (c) 2021 SUSE LLC
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+#ifndef _STRBUF_H
+#define _STRBUF_H
+#include <errno.h>
+#include <string.h>
+
+struct strbuf {
+ char *buf;
+ size_t size;
+ size_t offs;
+};
+
+/**
+ * reset_strbuf(): prepare strbuf for new content
+ * @param strbuf: string buffer to reset
+ *
+ * Frees internal buffer and resets size and offset to 0.
+ * Can be used to cleanup a struct strbuf on stack.
+ */
+void reset_strbuf(struct strbuf *buf);
+
+/**
+ * free_strbuf(): free resources
+ * @param strbuf: string buffer to discard
+ *
+ * Frees all memory occupied by a struct strbuf.
+ */
+void free_strbuf(struct strbuf *buf);
+
+/**
+ * macro: STRBUF_INIT
+ *
+ * Use this to initialize a local struct strbuf on the stack,
+ * or in a global/static variable.
+ */
+#define STRBUF_INIT { .buf = NULL, }
+
+/**
+ * macro: STRBUF_ON_STACK
+ *
+ * Define and initialize a local struct @strbuf to be cleaned up when
+ * the current scope is left
+ */
+#define STRBUF_ON_STACK(__x) \
+ struct strbuf __attribute__((cleanup(reset_strbuf))) (__x) = STRBUF_INIT;
+
+/**
+ * new_strbuf(): allocate a struct strbuf on the heap
+ *
+ * @returns: pointer to allocated struct, or NULL in case of error.
+ */
+struct strbuf *new_strbuf(void);
+
+/**
+ * get_strbuf_str(): retrieve string from strbuf
+ * @param buf: a struct strbuf
+ * @returns: pointer to the string written to the strbuf so far.
+ *
+ * If @strbuf was never written to, the function returns a zero-
+ * length string. The return value of this function must not be
+ * free()d.
+ */
+const char *get_strbuf_str(const struct strbuf *buf);
+
+/**
+ * steal_strbuf_str(): retrieve string from strbuf and reset
+ * @param buf: a struct strbuf
+ * @returns: pointer to the string written to @strbuf, or NULL
+ *
+ * After calling this function, the @strbuf is empty as if freshly
+ * initialized. The caller is responsible to free() the returned pointer.
+ * If @strbuf was never written to (not even an empty string was appended),
+ * the function returns NULL.
+ */
+char *steal_strbuf_str(struct strbuf *buf);
+
+/**
+ * get_strbuf_len(): retrieve string length from strbuf
+ * @param buf: a struct strbuf
+ * @returns: the length of the string written to @strbuf so far.
+ */
+size_t get_strbuf_len(const struct strbuf *buf);
+
+/**
+ * truncate_strbuf(): shorten the buffer
+ * @param buf: struct strbuf to truncate
+ * @param offs: new buffer position / offset
+ * @returns: 0 on success, negative error code otherwise.
+ *
+ * If @strbuf is freshly allocated/reset (never written to), -EFAULT
+ * is returned. if @offs must be higher than the current offset as returned
+ * by get_strbuf_len(), -ERANGE is returned. The allocated size of the @strbuf
+ * remains unchanged.
+ */
+int truncate_strbuf(struct strbuf *buf, size_t offs);
+
+/**
+ * __append_strbuf_str(): append string of known length
+ * @param buf: the struct strbuf to write to
+ * @param str: the string to append, not necessarily 0-terminated
+ * @param slen: max number of characters to append, must be non-negative
+ * @returns: @slen = number of appended characters if successful (excluding
+ * terminating '\0'); negative error code otherwise.
+ *
+ * Notes: a 0-byte is always appended to the output buffer after @slen characters.
+ * 0-bytes possibly contained in the first @slen characters are copied into
+ * the output. If the function returns an error, @strbuf is unchanged.
+ */
+int __append_strbuf_str(struct strbuf *buf, const char *str, int slen);
+
+/**
+ * append_strbuf_str(): append string
+ * @param buf: the struct strbuf to write to
+ * @param str: the string to append, 0-terminated
+ * @returns: number of appended characters if successful (excluding
+ * terminating '\0'); negative error code otherwise
+ *
+ * Appends the given 0-terminated string to @strbuf, expanding @strbuf's size
+ * as necessary. If the function returns an error, @strbuf is unchanged.
+ */
+int append_strbuf_str(struct strbuf *buf, const char *str);
+
+/**
+ * fill_strbuf_str(): pad strbuf with a character
+ * @param buf: the struct strbuf to write to
+ * @param c: the character used for filling
+ * @param slen: max number of characters to append, must be non-negative
+ * @returns: number of appended characters if successful (excluding
+ * terminating '\0'); negative error code otherwise
+ *
+ * Appends the given character @slen times to @strbuf, expanding @strbuf's size
+ * as necessary. If the function returns an error, @strbuf is unchanged.
+ */
+int fill_strbuf(struct strbuf *buf, char c, int slen);
+
+/**
+ * append_strbuf_quoted(): append string in double quotes, escaping quotes in string
+ * @param buf: the struct strbuf to write to
+ * @param str: the string to append, 0-terminated
+ * @returns: number of appended characters if successful (excluding
+ * terminating '\0'); negative error code otherwise
+ *
+ * Appends the given string to @strbuf, with leading and trailing double
+ * quotes (") added, expanding @strbuf's size as necessary. Any double quote
+ * characters (") in the string are transformed to double double quotes ("").
+ * If the function returns an error, @strbuf is unchanged.
+ */
+int append_strbuf_quoted(struct strbuf *buf, const char *str);
+
+/**
+ * print_strbuf(): print to strbuf, formatted
+ * @param buf: the struct strbuf to print to
+ * @param fmt: printf()-like format string
+ * @returns: number of appended characters if successful, (excluding
+ * terminating '\0'); negative error code otherwise
+ *
+ * Appends the the arguments following @fmt, formatted as in printf(), to
+ * @strbuf, expanding @strbuf's size as necessary. The function makes sure that
+ * the output @strbuf is always 0-terminated.
+ * If the function returns an error, @strbuf is unchanged.
+ */
+__attribute__((format(printf, 2, 3)))
+int print_strbuf(struct strbuf *buf, const char *fmt, ...);
+
+#endif
pp->sg_id.host_no = -1;
pp->sg_id.channel = -1;
pp->sg_id.scsi_id = -1;
- pp->sg_id.lun = -1;
+ pp->sg_id.lun = SCSI_INVALID_LUN;
pp->sg_id.proto_id = SCSI_PROTOCOL_UNSPEC;
pp->fd = -1;
pp->tpgs = TPGS_UNDEF;
#define SERIAL_SIZE 128
#define NODE_NAME_SIZE 224
#define PATH_STR_SIZE 16
-#define PARAMS_SIZE 4096
#define FILE_NAME_SIZE 256
#define CALLOUT_MAX_SIZE 256
#define BLK_DEV_SIZE 33
SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */
};
+#define SCSI_INVALID_LUN ~0ULL
+
enum no_undef_states {
NU_NO = -1,
NU_UNDEF = 0,
int host_no;
int channel;
int scsi_id;
- int lun;
+ uint64_t lun;
short h_cmd_per_lun;
short d_queue_depth;
enum scsi_protocol proto_id;
/*
* Avoid adding removed paths to the map again
- * when we reload it. Such paths may exist if
- * domap fails in ev_remove_path().
+ * when we reload it. Such paths may exist in
+ * ev_remove_paths() or if it returns failure.
*/
pp1 = find_path_by_devt(pathvec, pp->dev_t);
if (pp1 && pp->initialized != INIT_REMOVED &&
}
void
-remove_map(struct multipath *mpp, vector pathvec, vector mpvec, int purge_vec)
+remove_map(struct multipath *mpp, vector pathvec, vector mpvec)
{
int i;
*/
orphan_paths(pathvec, mpp, "map removed internally");
- if (purge_vec &&
+ if (mpvec &&
(i = find_slot(mpvec, (void *)mpp)) != -1)
vector_del_slot(mpvec, i);
}
void
-remove_map_by_alias(const char *alias, struct vectors * vecs, int purge_vec)
+remove_map_by_alias(const char *alias, struct vectors * vecs)
{
struct multipath * mpp = find_mp_by_alias(vecs->mpvec, alias);
if (mpp) {
condlog(2, "%s: removing map by alias", alias);
- remove_map(mpp, vecs->pathvec, vecs->mpvec, purge_vec);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
}
}
return;
vector_foreach_slot (vecs->mpvec, mpp, i) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
i--;
}
update_multipath_table (struct multipath *mpp, vector pathvec, int flags)
{
int r = DMP_ERR;
- char params[PARAMS_SIZE] = {0};
+ char *params = NULL;
if (!mpp)
return r;
- r = dm_get_map(mpp->alias, &mpp->size, params);
+ r = dm_get_map(mpp->alias, &mpp->size, ¶ms);
if (r != DMP_OK) {
condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting table" : "map not present");
return r;
if (disassemble_map(pathvec, params, mpp)) {
condlog(2, "%s: cannot disassemble map", mpp->alias);
+ free(params);
return DMP_ERR;
}
- *params = '\0';
- if (dm_get_status(mpp->alias, params) != DMP_OK)
+ free(params);
+ params = NULL;
+ if (dm_get_status(mpp->alias, ¶ms) != DMP_OK)
condlog(2, "%s: %s", mpp->alias, (r == DMP_ERR)? "error getting status" : "map not present");
else if (disassemble_status(params, mpp))
condlog(2, "%s: cannot disassemble status", mpp->alias);
+ free(params);
/* FIXME: we should deal with the return value here */
update_pathvec_from_dm(pathvec, mpp, flags);
return mpp;
out:
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
return NULL;
}
int update_multipath_strings (struct multipath *mpp, vector pathvec);
void extract_hwe_from_path(struct multipath * mpp);
-enum {
- KEEP_VEC,
- PURGE_VEC,
-};
-
-void remove_map (struct multipath *mpp, vector pathvec, vector mpvec,
- int purge_vec);
-void remove_map_by_alias(const char *alias, struct vectors * vecs,
- int purge_vec);
+void remove_map (struct multipath *mpp, vector pathvec, vector mpvec);
+void remove_map_by_alias(const char *alias, struct vectors * vecs);
void remove_maps (struct vectors * vecs);
void sync_map_state (struct multipath *);
strchop(pp->wwid);
}
}
- } else if (nr < 0)
+ } else if (nr < 0)
condlog(1, "%s: error reading from %s: %m",
__func__, pathbuf);
}
pthread_cleanup_push(monitor_cleanup, monitor);
#ifdef LIBUDEV_API_RECVBUF
- if (udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024))
+ if (udev_monitor_set_receive_buffer_size(monitor, 128 * 1024 * 1024) < 0)
condlog(2, "failed to increase buffer size");
#endif
fd = udev_monitor_get_fd(monitor);
ret = pthread_attr_init(attr);
assert(ret == 0);
- if (stacksize < PTHREAD_STACK_MIN)
- stacksize = PTHREAD_STACK_MIN;
+ if (PTHREAD_STACK_MIN > 0 && stacksize < (size_t)PTHREAD_STACK_MIN)
+ stacksize = (size_t)PTHREAD_STACK_MIN;
ret = pthread_attr_setstacksize(attr, stacksize);
assert(ret == 0);
if (detached) {
{
return 0;
}
+
+void cleanup_charp(char **p)
+{
+ free(*p);
+}
___p; \
})
+void cleanup_charp(char **p);
#endif /* _UTIL_H */
#ifndef _VERSION_H
#define _VERSION_H
-#define VERSION_CODE 0x000806
-#define DATE_CODE 0x040115
+#define VERSION_CODE 0x000807
+#define DATE_CODE 0x090815
#define PROG "multipath-tools"
if (refwwid && strlen(refwwid) &&
strncmp(mpp->wwid, refwwid, WWID_SIZE)) {
condlog(3, "skip map %s: out of scope", mpp->alias);
- remove_map(mpp, pathvec, curmp, PURGE_VEC);
+ remove_map(mpp, pathvec, curmp);
i--;
continue;
}
if (update_multipath_table(mpp, pathvec, flags) != DMP_OK) {
condlog(1, "error parsing map %s", mpp->wwid);
- remove_map(mpp, pathvec, curmp, PURGE_VEC);
+ remove_map(mpp, pathvec, curmp);
i--;
continue;
}
{
vector curmp = NULL;
vector pathvec = NULL;
+ vector newmp = NULL;
int r = RTVL_FAIL, rc;
int di_flag = 0;
char * refwwid = NULL;
*/
curmp = vector_alloc();
pathvec = vector_alloc();
- atexit(cleanup_vecs);
+ newmp = vector_alloc();
- if (!curmp || !pathvec) {
+ if (!curmp || !pathvec || !newmp) {
condlog(0, "can not allocate memory");
goto out;
}
/*
* core logic entry point
*/
- rc = coalesce_paths(&vecs, NULL, refwwid,
+ rc = coalesce_paths(&vecs, newmp, refwwid,
conf->force_reload, cmd);
r = rc == CP_RETRY ? RTVL_RETRY : rc == CP_OK ? RTVL_OK : RTVL_FAIL;
out:
+ if (r == RTVL_OK &&
+ (cmd == CMD_LIST_SHORT || cmd == CMD_LIST_LONG ||
+ cmd == CMD_CREATE) &&
+ (VECTOR_SIZE(curmp) > 0 || VECTOR_SIZE(newmp) > 0) &&
+ !check_daemon())
+ condlog(2, "Warning: multipath devices exist, but multipathd service is not running");
+
if (refwwid)
FREE(refwwid);
+ free_multipathvec(curmp, KEEP_PATHS);
+ vecs.mpvec = NULL;
+ free_multipathvec(newmp, KEEP_PATHS);
+ free_pathvec(pathvec, FREE_PATHS);
+ vecs.pathvec = NULL;
+
return r;
}
conf = get_multipath_config();
conf->retrigger_tries = 0;
conf->force_sync = 1;
+ atexit(cleanup_vecs);
while ((arg = getopt(argc, argv, ":adDcChl::eFfM:v:p:b:BrR:itTquUwW")) != EOF ) {
switch(arg) {
case 1: printf("optarg : %s\n",optarg);
.TP
.B \-e
Enable all foreign libraries. This overrides the
-.I enable_foreign
+.I enable_foreign
option from \fBmultipath.conf(5)\fR.
.
.TP
Sets the number of seconds that multipath will wait after creating a device
with only ghost paths before marking it ready for use in systemd. This gives
the active paths time to appear before the multipath runs the hardware handler
-to switch the ghost paths to active ones. Setting this to \fI0\fR or \fIon\fR
+to switch the ghost paths to active ones. Setting this to \fI0\fR or \fIno\fR
makes multipath immediately mark a device with only ghost paths as ready.
.RS
.TP
LIBDEPS += -L$(multipathdir) -lmultipath -L$(mpathpersistdir) -lmpathpersist \
-L$(mpathcmddir) -lmpathcmd -ludev -ldl -lurcu -lpthread \
-ldevmapper -lreadline
+CFLAGS += $(shell $(PKGCONFIG) --modversion liburcu 2>/dev/null | \
+ awk -F. '{ printf("-DURCU_VERSION=0x%06x", 256 * ( 256 * $$1 + $$2) + $$3); }')
ifdef SYSTEMD
CFLAGS += -DUSE_SYSTEMD=$(SYSTEMD)
#include "mpath_cmd.h"
#include "cli.h"
#include "debug.h"
+#include "strbuf.h"
static vector keys;
static vector handlers;
}
static int
-genhelp_sprint_aliases (char * reply, int maxlen, vector keys,
+genhelp_sprint_aliases (struct strbuf *reply, vector keys,
struct key * refkw)
{
- int i, len = 0;
+ int i;
struct key * kw;
+ size_t initial_len = get_strbuf_len(reply);
vector_foreach_slot (keys, kw, i) {
- if (kw->code == refkw->code && kw != refkw) {
- len += snprintf(reply + len, maxlen - len,
- "|%s", kw->str);
- if (len >= maxlen)
- return len;
- }
+ if (kw->code == refkw->code && kw != refkw &&
+ print_strbuf(reply, "|%s", kw->str) < 0)
+ return -1;
}
- return len;
+ return get_strbuf_len(reply) - initial_len;
}
static int
-do_genhelp(char *reply, int maxlen, const char *cmd, int error) {
- int len = 0;
+do_genhelp(struct strbuf *reply, const char *cmd, int error) {
int i, j;
uint64_t fp;
struct handler * h;
struct key * kw;
+ int rc = 0;
+ size_t initial_len = get_strbuf_len(reply);
switch(error) {
case ENOMEM:
- len += snprintf(reply + len, maxlen - len,
- "%s: Not enough memory\n", cmd);
+ rc = print_strbuf(reply, "%s: Not enough memory\n", cmd);
break;
case EAGAIN:
- len += snprintf(reply + len, maxlen - len,
- "%s: not found\n", cmd);
+ rc = print_strbuf(reply, "%s: not found\n", cmd);
break;
case EINVAL:
- len += snprintf(reply + len, maxlen - len,
- "%s: Missing argument\n", cmd);
+ rc = print_strbuf(reply, "%s: Missing argument\n", cmd);
break;
}
- if (len >= maxlen)
- goto out;
- len += snprintf(reply + len, maxlen - len, VERSION_STRING);
- if (len >= maxlen)
- goto out;
- len += snprintf(reply + len, maxlen - len, "CLI commands reference:\n");
- if (len >= maxlen)
- goto out;
+ if (rc < 0)
+ return -1;
+
+ if (print_strbuf(reply, VERSION_STRING) < 0 ||
+ append_strbuf_str(reply, "CLI commands reference:\n") < 0)
+ return -1;
vector_foreach_slot (handlers, h, i) {
fp = h->fingerprint;
vector_foreach_slot (keys, kw, j) {
if ((kw->code & fp)) {
fp -= kw->code;
- len += snprintf(reply + len , maxlen - len,
- " %s", kw->str);
- if (len >= maxlen)
- goto out;
- len += genhelp_sprint_aliases(reply + len,
- maxlen - len,
- keys, kw);
- if (len >= maxlen)
- goto out;
+ if (print_strbuf(reply, " %s", kw->str) < 0 ||
+ genhelp_sprint_aliases(reply, keys, kw) < 0)
+ return -1;
if (kw->has_param) {
- len += snprintf(reply + len,
- maxlen - len,
- " $%s", kw->str);
- if (len >= maxlen)
- goto out;
+ if (print_strbuf(reply, " $%s",
+ kw->str) < 0)
+ return -1;
}
}
}
- len += snprintf(reply + len, maxlen - len, "\n");
- if (len >= maxlen)
- goto out;
+ if (append_strbuf_str(reply, "\n") < 0)
+ return -1;
}
-out:
- return len;
+ return get_strbuf_len(reply) - initial_len;
}
static char *
genhelp_handler (const char *cmd, int error)
{
- char * reply;
- char * p = NULL;
- int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
-
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return NULL;
- p = reply;
- p += do_genhelp(reply, maxlen, cmd, error);
- again = ((p - reply) >= maxlen);
- REALLOC_REPLY(reply, again, maxlen);
- }
- return reply;
+ STRBUF_ON_STACK(reply);
+
+ if (do_genhelp(&reply, cmd, error) == -1)
+ condlog(0, "genhelp_handler: out of memory");
+ return steal_strbuf_str(&reply);
}
int
#include "cli.h"
#include "uevent.h"
#include "foreign.h"
+#include "strbuf.h"
#include "cli_handlers.h"
+#define SET_REPLY_AND_LEN(__rep, __len, string_literal) \
+ do { \
+ *(__rep) = strdup(string_literal); \
+ *(__len) = *(__rep) ? sizeof(string_literal) : 0; \
+ } while (0)
+
int
show_paths (char ** r, int * len, struct vectors * vecs, char * style,
int pretty)
{
+ STRBUF_ON_STACK(reply);
int i;
struct path * pp;
- char * c;
- char * reply, * header;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ int hdr_len = 0;
get_path_layout(vecs->pathvec, 1);
foreign_path_layout();
- reply = MALLOC(maxlen);
+ if (pretty && (hdr_len = snprint_path_header(&reply, style)) < 0)
+ return 1;
- while (again) {
- if (!reply)
+ vector_foreach_slot(vecs->pathvec, pp, i) {
+ if (snprint_path(&reply, style, pp, pretty) < 0)
return 1;
-
- c = reply;
-
- if (pretty)
- c += snprint_path_header(c, reply + maxlen - c,
- style);
- header = c;
-
- vector_foreach_slot(vecs->pathvec, pp, i)
- c += snprint_path(c, reply + maxlen - c,
- style, pp, pretty);
-
- c += snprint_foreign_paths(c, reply + maxlen - c,
- style, pretty);
-
- again = (c == reply + maxlen - 1);
-
- REALLOC_REPLY(reply, again, maxlen);
}
+ if (snprint_foreign_paths(&reply, style, pretty) < 0)
+ return 1;
- if (pretty && c == header) {
+ if (pretty && get_strbuf_len(&reply) == (size_t)hdr_len)
/* No output - clear header */
- *reply = '\0';
- c = reply;
- }
+ truncate_strbuf(&reply, 0);
- *r = reply;
- *len = (int)(c - reply + 1);
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
show_path (char ** r, int * len, struct vectors * vecs, struct path *pp,
char * style)
{
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ STRBUF_ON_STACK(reply);
get_path_layout(vecs->pathvec, 1);
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
-
- c = reply;
-
- c += snprint_path(c, reply + maxlen - c, style, pp, 0);
-
- again = (c == reply + maxlen - 1);
+ if (snprint_path(&reply, style, pp, 0) < 0)
+ return 1;
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
- REALLOC_REPLY(reply, again, maxlen);
- }
- *r = reply;
- *len = (int)(c - reply + 1);
return 0;
}
show_map_topology (char ** r, int * len, struct multipath * mpp,
struct vectors * vecs)
{
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ STRBUF_ON_STACK(reply);
if (update_multipath(vecs, mpp->alias, 0))
return 1;
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
- c = reply;
-
- c += snprint_multipath_topology(c, reply + maxlen - c, mpp, 2);
- again = (c == reply + maxlen - 1);
+ if (snprint_multipath_topology(&reply, mpp, 2) < 0)
+ return 1;
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
- REALLOC_REPLY(reply, again, maxlen);
- }
- *r = reply;
- *len = (int)(c - reply + 1);
return 0;
}
int
show_maps_topology (char ** r, int * len, struct vectors * vecs)
{
+ STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
get_path_layout(vecs->pathvec, 0);
foreign_path_layout();
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
-
- c = reply;
-
- vector_foreach_slot(vecs->mpvec, mpp, i) {
- if (update_multipath(vecs, mpp->alias, 0)) {
- i--;
- continue;
- }
- c += snprint_multipath_topology(c, reply + maxlen - c,
- mpp, 2);
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (update_multipath(vecs, mpp->alias, 0)) {
+ i--;
+ continue;
}
- c += snprint_foreign_topology(c, reply + maxlen - c, 2);
-
- again = (c == reply + maxlen - 1);
-
- REALLOC_REPLY(reply, again, maxlen);
+ if (snprint_multipath_topology(&reply, mpp, 2) < 0)
+ return 1;
}
+ if (snprint_foreign_topology(&reply, 2) < 0)
+ return 1;
- *r = reply;
- *len = (int)(c - reply + 1);
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
int
show_maps_json (char ** r, int * len, struct vectors * vecs)
{
+ STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
-
- if (VECTOR_SIZE(vecs->mpvec) > 0)
- maxlen *= PRINT_JSON_MULTIPLIER * VECTOR_SIZE(vecs->mpvec);
vector_foreach_slot(vecs->mpvec, mpp, i) {
if (update_multipath(vecs, mpp->alias, 0)) {
}
}
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
-
- c = reply;
-
- c += snprint_multipath_topology_json(c, maxlen, vecs);
- again = (c == reply + maxlen);
+ if (snprint_multipath_topology_json(&reply, vecs) < 0)
+ return 1;
- REALLOC_REPLY(reply, again, maxlen);
- }
- *r = reply;
- *len = (int)(c - reply);
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
show_map_json (char ** r, int * len, struct multipath * mpp,
struct vectors * vecs)
{
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ STRBUF_ON_STACK(reply);
if (update_multipath(vecs, mpp->alias, 0))
return 1;
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
- c = reply;
-
- c += snprint_multipath_map_json(c, maxlen, mpp);
- again = (c == reply + maxlen);
+ if (snprint_multipath_map_json(&reply, mpp) < 0)
+ return 1;
- REALLOC_REPLY(reply, again, maxlen);
- }
- *r = reply;
- *len = (int)(c - reply);
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
int
cli_list_wildcards (void * v, char ** reply, int * len, void * data)
{
- char * c;
-
- *reply = MALLOC(INITIAL_REPLY_LEN);
+ STRBUF_ON_STACK(buf);
- if (!*reply)
+ if (snprint_wildcards(&buf) < 0)
return 1;
- c = *reply;
- c += snprint_wildcards(c, INITIAL_REPLY_LEN);
-
- *len = INITIAL_REPLY_LEN;
+ *len = get_strbuf_len(&buf) + 1;
+ *reply = steal_strbuf_str(&buf);
return 0;
}
int
show_status (char ** r, int *len, struct vectors * vecs)
{
- char * c;
- char * reply;
-
- unsigned int maxlen = INITIAL_REPLY_LEN;
- reply = MALLOC(maxlen);
+ STRBUF_ON_STACK(reply);
- if (!reply)
+ if (snprint_status(&reply, vecs) < 0)
return 1;
- c = reply;
- c += snprint_status(c, reply + maxlen - c, vecs);
-
- *r = reply;
- *len = (int)(c - reply + 1);
+ *len = get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
int
show_daemon (char ** r, int *len)
{
- char * c;
- char * reply;
-
- unsigned int maxlen = INITIAL_REPLY_LEN;
- reply = MALLOC(maxlen);
+ STRBUF_ON_STACK(reply);
- if (!reply)
+ if (print_strbuf(&reply, "pid %d %s\n",
+ daemon_pid, daemon_status()) < 0)
return 1;
- c = reply;
- c += snprintf(c, INITIAL_REPLY_LEN, "pid %d %s\n",
- daemon_pid, daemon_status());
-
- *r = reply;
- *len = (int)(c - reply + 1);
+ *len = get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
show_map (char ** r, int *len, struct multipath * mpp, char * style,
int pretty)
{
- char * c;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
-
- reply = MALLOC(maxlen);
- while (again) {
- if (!reply)
- return 1;
+ STRBUF_ON_STACK(reply);
- c = reply;
- c += snprint_multipath(c, reply + maxlen - c, style,
- mpp, pretty);
-
- again = (c == reply + maxlen - 1);
+ if (snprint_multipath(&reply, style, mpp, pretty) < 0)
+ return 1;
- REALLOC_REPLY(reply, again, maxlen);
- }
- *r = reply;
- *len = (int)(c - reply + 1);
+ *len = get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
show_maps (char ** r, int *len, struct vectors * vecs, char * style,
int pretty)
{
+ STRBUF_ON_STACK(reply);
int i;
struct multipath * mpp;
- char * c, *header;
- char * reply;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ int hdr_len = 0;
get_multipath_layout(vecs->mpvec, 1);
foreign_multipath_layout();
- reply = MALLOC(maxlen);
-
- while (again) {
- if (!reply)
- return 1;
-
- c = reply;
- if (pretty)
- c += snprint_multipath_header(c, reply + maxlen - c,
- style);
- header = c;
-
- vector_foreach_slot(vecs->mpvec, mpp, i) {
- if (update_multipath(vecs, mpp->alias, 0)) {
- i--;
- continue;
- }
- c += snprint_multipath(c, reply + maxlen - c,
- style, mpp, pretty);
+ if (pretty && (hdr_len = snprint_multipath_header(&reply, style)) < 0)
+ return 1;
+ vector_foreach_slot(vecs->mpvec, mpp, i) {
+ if (update_multipath(vecs, mpp->alias, 0)) {
+ i--;
+ continue;
}
- c += snprint_foreign_multipaths(c, reply + maxlen - c,
- style, pretty);
- again = (c == reply + maxlen - 1);
-
- REALLOC_REPLY(reply, again, maxlen);
+ if (snprint_multipath(&reply, style, mpp, pretty) < 0)
+ return 1;
}
+ if (snprint_foreign_multipaths(&reply, style, pretty) < 0)
+ return 1;
- if (pretty && c == header) {
+ if (pretty && get_strbuf_len(&reply) == (size_t)hdr_len)
/* No output - clear header */
- *reply = '\0';
- c = reply;
- }
- *r = reply;
- *len = (int)(c - reply + 1);
+ truncate_strbuf(&reply, 0);
+
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
/* Have the checker reinstate this path asap */
pp->tick = 1;
return 0;
- } else if (!ev_remove_path(pp, vecs, true))
+ } else if (ev_remove_path(pp, vecs, true) &
+ REMOVE_PATH_SUCCESS)
/* Path removed in ev_remove_path() */
pp = NULL;
else {
}
return ev_add_path(pp, vecs, 1);
blacklisted:
- *reply = strdup("blacklisted\n");
- *len = strlen(*reply) + 1;
+ SET_REPLY_AND_LEN(reply, len, "blacklisted\n");
condlog(2, "%s: path blacklisted", param);
return 0;
}
struct vectors * vecs = (struct vectors *)data;
char * param = get_keyparam(v, PATH);
struct path *pp;
+ int ret;
param = convert_dev(param, 1);
condlog(2, "%s: remove path (operator)", param);
condlog(0, "%s: path already removed", param);
return 1;
}
- return ev_remove_path(pp, vecs, 1);
+ ret = ev_remove_path(pp, vecs, 1);
+ if (ret == REMOVE_PATH_DELAY)
+ SET_REPLY_AND_LEN(reply, len, "delayed\n");
+ else if (ret == REMOVE_PATH_MAP_ERROR)
+ SET_REPLY_AND_LEN(reply, len, "map reload error. removed\n");
+ return (ret == REMOVE_PATH_FAILURE);
}
int
invalid = 1;
pthread_cleanup_pop(1);
if (invalid) {
- *reply = strdup("blacklisted\n");
- *len = strlen(*reply) + 1;
+ SET_REPLY_AND_LEN(reply, len, "blacklisted\n");
condlog(2, "%s: map blacklisted", param);
return 1;
}
int resize_map(struct multipath *mpp, unsigned long long size,
struct vectors * vecs)
{
- char params[PARAMS_SIZE] = {0};
+ char *params __attribute__((cleanup(cleanup_charp))) = NULL;
unsigned long long orig_size = mpp->size;
mpp->size = size;
update_mpp_paths(mpp, vecs->pathvec);
- if (setup_map(mpp, params, PARAMS_SIZE, vecs) != 0) {
+ if (setup_map(mpp, ¶ms, vecs) != 0) {
condlog(0, "%s: failed to setup map for resize : %s",
mpp->alias, strerror(errno));
mpp->size = orig_size;
condlog(2, "reconfigure (operator)");
- rc = set_config_state(DAEMON_CONFIGURE);
+ rc = set_config_state(DAEMON_CONFIGURE);
if (rc == ETIMEDOUT) {
condlog(2, "timeout starting reconfiguration");
return 1;
int
show_blacklist (char ** r, int * len)
{
- char *c = NULL;
- char *reply = NULL;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ STRBUF_ON_STACK(reply);
struct config *conf;
- int fail = 0;
-
- reply = MALLOC(maxlen);
+ bool fail;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- while (again) {
- if (!reply) {
- fail = 1;
- break;
- }
-
- c = reply;
- c += snprint_blacklist_report(conf, c, maxlen);
- again = (c == reply + maxlen);
- REALLOC_REPLY(reply, again, maxlen);
- }
+ fail = snprint_blacklist_report(conf, &reply) < 0;
pthread_cleanup_pop(1);
if (fail)
return 1;
- *r = reply;
- *len = (int)(c - reply + 1);
+
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
int
show_devices (char ** r, int * len, struct vectors *vecs)
{
- char *c = NULL;
- char *reply = NULL;
- unsigned int maxlen = INITIAL_REPLY_LEN;
- int again = 1;
+ STRBUF_ON_STACK(reply);
struct config *conf;
- int fail = 0;
-
- reply = MALLOC(maxlen);
+ bool fail;
conf = get_multipath_config();
pthread_cleanup_push(put_multipath_config, conf);
- while (again) {
- if (!reply) {
- fail = 1;
- break;
- }
-
- c = reply;
- c += snprint_devices(conf, c, maxlen, vecs);
- again = (c == reply + maxlen);
- REALLOC_REPLY(reply, again, maxlen);
- }
+ fail = snprint_devices(conf, &reply, vecs) < 0;
pthread_cleanup_pop(1);
if (fail)
return 1;
- *r = reply;
- *len = (int)(c - reply + 1);
+
+ *len = (int)get_strbuf_len(&reply) + 1;
+ *r = steal_strbuf_str(&reply);
return 0;
}
struct multipath * mpp;
struct vectors * vecs = (struct vectors *)data;
char *mapname = get_keyparam(v, MAP);
- char *flagstr = "";
+ uint64_t key;
mapname = convert_dev(mapname, 0);
condlog(3, "%s: get persistent reservation key (operator)", mapname);
if (!*reply)
return 1;
- if (!get_be64(mpp->reservation_key)) {
+ key = get_be64(mpp->reservation_key);
+ if (!key) {
sprintf(*reply, "none\n");
- *len = strlen(*reply) + 1;
+ *len = sizeof("none\n");
return 0;
}
- if (mpp->sa_flags & MPATH_F_APTPL_MASK)
- flagstr = ":aptpl";
- snprintf(*reply, 26, "0x%" PRIx64 "%s\n",
- get_be64(mpp->reservation_key), flagstr);
- (*reply)[19] = '\0';
- *len = strlen(*reply) + 1;
+
+ /* This snprintf() can't overflow - PRIx64 needs max 16 chars */
+ *len = snprintf(*reply, 26, "0x%" PRIx64 "%s\n", key,
+ mpp->sa_flags & MPATH_F_APTPL_MASK ? ":aptpl" : "") + 1;
return 0;
}
pthread_testcancel();
r = 0;
if (curr_dev.action == EVENT_REMOVE)
- remove_map_by_alias(curr_dev.name, waiter->vecs, PURGE_VEC);
+ remove_map_by_alias(curr_dev.name, waiter->vecs);
else
r = update_multipath(waiter->vecs, curr_dev.name, 1);
pthread_cleanup_pop(1);
condlog(3, "%s: removing map from internal tables", mpp->alias);
if (!poll_dmevents)
stop_waiter_thread(mpp);
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
}
static void
update_map (struct multipath *mpp, struct vectors *vecs, int new_map)
{
int retries = 3;
- char params[PARAMS_SIZE] = {0};
+ char *params __attribute__((cleanup(cleanup_charp))) = NULL;
retry:
condlog(4, "%s: updating new map", mpp->alias);
verify_paths(mpp);
mpp->action = ACT_RELOAD;
- if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
+ if (setup_map(mpp, ¶ms, vecs)) {
condlog(0, "%s: failed to setup new map in update", mpp->alias);
retries = -1;
goto fail;
}
if (domap(mpp, params, 1) == DOMAP_FAIL && retries-- > 0) {
condlog(0, "%s: map_udate sleep", mpp->alias);
+ free(params);
+ params = NULL;
sleep(1);
goto retry;
}
fail:
if (new_map && (retries < 0 || wait_for_events(mpp, vecs))) {
condlog(0, "%s: failed to create new map", mpp->alias);
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
return 1;
}
return mpp;
out:
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
return NULL;
}
else
condlog(2, "%s: map flushed", mpp->alias);
- orphan_paths(vecs->pathvec, mpp, "map flushed");
remove_map_and_stop_waiter(mpp, vecs);
return 0;
return;
udd = udev_device_ref(pp->udev);
- if (ev_remove_path(pp, vecs, 1) != 0 && pp->mpp) {
+ if (!(ev_remove_path(pp, vecs, 1) & REMOVE_PATH_SUCCESS) && pp->mpp) {
pp->dmstate = PSTATE_FAILED;
dm_fail_path(pp->mpp->alias, pp->dev_t);
}
* Make another attempt to remove the path
*/
pp->mpp = prev_mpp;
- ret = ev_remove_path(pp, vecs, true);
- if (ret != 0) {
+ if (!(ev_remove_path(pp, vecs, true) &
+ REMOVE_PATH_SUCCESS)) {
/*
* Failure in ev_remove_path will keep
* path in pathvec in INIT_REMOVED state
dm_fail_path(pp->mpp->alias, pp->dev_t);
condlog(1, "%s: failed to re-add path still mapped in %s",
pp->dev, pp->mpp->alias);
+ ret = 1;
} else if (r == PATHINFO_OK)
/*
* Path successfully freed, move on to
ev_add_path (struct path * pp, struct vectors * vecs, int need_do_map)
{
struct multipath * mpp;
- char params[PARAMS_SIZE] = {0};
+ char *params __attribute((cleanup(cleanup_charp))) = NULL;
int retries = 3;
int start_waiter = 0;
int ret;
/*
* push the map to the device-mapper
*/
- if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
+ if (setup_map(mpp, ¶ms, vecs)) {
condlog(0, "%s: failed to setup map for addition of new "
"path %s", mpp->alias, pp->dev);
goto fail_map;
condlog(0, "%s: ev_add_path sleep", mpp->alias);
sleep(1);
update_mpp_paths(mpp, vecs->pathvec);
+ free(params);
+ params = NULL;
goto rescan;
}
else if (mpp->action == ACT_RELOAD)
goto fail;
fail_map:
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
fail:
orphan_path(pp, "failed to add path");
return 1;
uev_remove_path (struct uevent *uev, struct vectors * vecs, int need_do_map)
{
struct path *pp;
- int ret;
condlog(3, "%s: remove path (uevent)", uev->kernel);
delete_foreign(uev->udev);
pthread_testcancel();
pp = find_path_by_dev(vecs->pathvec, uev->kernel);
if (pp)
- ret = ev_remove_path(pp, vecs, need_do_map);
+ ev_remove_path(pp, vecs, need_do_map);
lock_cleanup_pop(vecs->lock);
- if (!pp) {
- /* Not an error; path might have been purged earlier */
+ if (!pp) /* Not an error; path might have been purged earlier */
condlog(0, "%s: path already removed", uev->kernel);
- return 0;
- }
- return ret;
+ return 0;
}
int
ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map)
{
struct multipath * mpp;
- int i, retval = 0;
- char params[PARAMS_SIZE] = {0};
+ int i, retval = REMOVE_PATH_SUCCESS;
+ char *params __attribute__((cleanup(cleanup_charp))) = NULL;
/*
* avoid referring to the map of an orphaned path
*/
if ((mpp = pp->mpp)) {
+ /*
+ * Mark the path as removed. In case of success, we
+ * will delete it for good. Otherwise, it will be deleted
+ * later, unless all attempts to reload this map fail.
+ */
+ set_path_removed(pp);
+
/*
* transform the mp->pg vector of vectors of paths
* into a mp->params string to feed the device-mapper
}
/*
- * Mark the path as removed. In case of success, we
- * will delete it for good. Otherwise, it will be deleted
- * later, unless all attempts to reload this map fail.
- * Note: we have to explicitly remove pp from mpp->paths,
+ * we have to explicitly remove pp from mpp->paths,
* update_mpp_paths() doesn't do that.
*/
- set_path_removed(pp);
i = find_slot(mpp->paths, pp);
if (i != -1)
vector_del_slot(mpp->paths, i);
condlog(2, "%s: removed map after"
" removing all paths",
alias);
- retval = 0;
/* flush_map() has freed the path */
goto out;
}
*/
}
- if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
+ if (setup_map(mpp, ¶ms, vecs)) {
condlog(0, "%s: failed to setup map for"
" removal of path %s", mpp->alias, pp->dev);
goto fail;
if (mpp->wait_for_udev) {
mpp->wait_for_udev = 2;
+ retval = REMOVE_PATH_DELAY;
goto out;
}
- if (!need_do_map)
+ if (!need_do_map) {
+ retval = REMOVE_PATH_DELAY;
goto out;
+ }
/*
* reload the map
*/
condlog(0, "%s: failed in domap for "
"removal of path %s",
mpp->alias, pp->dev);
- retval = 1;
+ retval = REMOVE_PATH_FAILURE;
} else {
/*
* update our state from kernel
char devt[BLK_DEV_SIZE];
strlcpy(devt, pp->dev_t, sizeof(devt));
+
+ /* setup_multipath will free the path
+ * regardless of whether it succeeds or
+ * fails */
if (setup_multipath(vecs, mpp))
- return 1;
- /*
- * Successful map reload without this path:
- * sync_map_state() will free it.
- */
+ return REMOVE_PATH_MAP_ERROR;
sync_map_state(mpp);
condlog(2, "%s: path removed from map %s",
return retval;
fail:
+ condlog(0, "%s: error removing path. removing map %s", pp->dev,
+ mpp->alias);
remove_map_and_stop_waiter(mpp, vecs);
- return 1;
+ return REMOVE_PATH_MAP_ERROR;
}
static int
condlog(0, "%s: path wwid changed from '%s' to '%s'",
uev->kernel, wwid, pp->wwid);
ev_remove_path(pp, vecs, 1);
- rescan_path(uev->udev);
needs_reinit = 1;
goto out;
} else {
vector_foreach_slot (vecs->mpvec, mpp, i)
if (update_multipath_table(mpp, vecs->pathvec, 0) != DMP_OK) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
i--;
}
static int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh,
int is_daemon)
{
- char params[PARAMS_SIZE] = {0};
+ char *params __attribute__((cleanup(cleanup_charp))) = NULL;
struct path *pp;
int i, r;
}
}
}
- if (setup_map(mpp, params, PARAMS_SIZE, vecs)) {
+ if (setup_map(mpp, ¶ms, vecs)) {
condlog(0, "%s: failed to setup map", mpp->alias);
return 1;
}
/* If path became failed again or continue failed, should reset
* path san_path_err_forget_rate and path dis_reinstate_time to
- * start a new stable check.
+ * start a new stable check.
*/
if ((pp->state != PATH_UP) && (pp->state != PATH_GHOST) &&
(pp->state != PATH_DELAYED)) {
*/
vector_foreach_slot(vecs->mpvec, mpp, i) {
if (wait_for_events(mpp, vecs)) {
- remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC);
+ remove_map(mpp, vecs->pathvec, vecs->mpvec);
i--;
continue;
}
pthread_attr_destroy(&waiter_attr);
}
+#ifndef URCU_VERSION
+# define URCU_VERSION 0
+#endif
+#if (URCU_VERSION >= 0x000800)
/*
* Use a non-default call_rcu_data for child().
*
* can't be joined with pthread_join(), leaving a memory leak.
*
* Therefore we create our own, which can be destroyed and joined.
+ * The cleanup handler needs to call rcu_barrier(), which is only
+ * available in user-space RCU v0.8 and newer. See
+ * https://lists.lttng.org/pipermail/lttng-dev/2021-May/029958.html
*/
static struct call_rcu_data *setup_rcu(void)
{
}
rcu_unregister_thread();
}
+#endif /* URCU_VERSION */
static void cleanup_child(void)
{
init_unwinder();
mlockall(MCL_CURRENT | MCL_FUTURE);
signal_init();
+#if (URCU_VERSION >= 0x000800)
mp_rcu_data = setup_rcu();
-
- if (atexit(cleanup_rcu) || atexit(cleanup_child))
+ if (atexit(cleanup_rcu))
+ fprintf(stderr, "failed to register RCU cleanup handler\n");
+#else
+ rcu_init();
+#endif
+ if (atexit(cleanup_child))
fprintf(stderr, "failed to register cleanup handlers\n");
setup_thread_attr(&misc_attr, 64 * 1024, 0);
DAEMON_STATUS_SIZE,
};
+enum remove_path_result {
+ REMOVE_PATH_FAILURE = 0x0, /* path could not be removed. It is still
+ * part of the kernel map, but its state
+ * is set to INIT_REMOVED, and it will be
+ * removed at the next possible occassion */
+ REMOVE_PATH_SUCCESS = 0x1, /* path was removed */
+ REMOVE_PATH_DELAY = 0x2, /* path is set to be removed later. it
+ * currently still exists and is part of the
+ * kernel map */
+ REMOVE_PATH_MAP_ERROR = 0x5, /* map was removed because of error. value
+ * includes REMOVE_PATH_SUCCESS bit
+ * because the path was also removed */
+};
+
struct prout_param_descriptor;
struct prin_resp;
Conflicts=shutdown.target
ConditionKernelCommandLine=!nompath
ConditionKernelCommandLine=!multipath=off
+ConditionVirtualization=!container
[Service]
Type=notify
LIBDEPS += -L. -L$(mpathcmddir) -lmultipath -lmpathcmd -lcmocka
TESTS := uevent parser util dmevents hwtable blacklist unaligned vpd pgpolicy \
- alias directio valid devt mpathvalid
+ alias directio valid devt mpathvalid strbuf
HELPERS := test-lib.o test-log.o
.SILENT: $(TESTS:%=%.o)
ifneq ($(DIO_TEST_DEV),)
directio-test_LIBDEPS := -laio
endif
+strbuf-test_OBJDEPS := ../libmultipath/strbuf.o
%.o: %.c
$(CC) $(CFLAGS) $($*-test_FLAGS) -c -o $@ $<
return ret;
}
+/* strbuf wrapper for the old format_devname() */
+static int __format_devname(char *name, int id, size_t len, const char *prefix)
+{
+ STRBUF_ON_STACK(buf);
+
+ if (append_strbuf_str(&buf, prefix) < 0 ||
+ format_devname(&buf, id) < 0 ||
+ len <= get_strbuf_len(&buf))
+ return -1;
+ strcpy(name, get_strbuf_str(&buf));
+ return get_strbuf_len(&buf);
+}
+
static void fd_mpatha(void **state)
{
char buf[32];
int rc;
- rc = format_devname(buf, 1, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 1, sizeof(buf), "FOO");
assert_int_equal(rc, 4);
assert_string_equal(buf, "FOOa");
}
char buf[5];
int rc;
- rc = format_devname(buf, 26, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26, sizeof(buf), "FOO");
assert_int_equal(rc, 4);
assert_string_equal(buf, "FOOz");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26 + 1, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26 + 1, sizeof(buf), "FOO");
assert_int_equal(rc, 5);
assert_string_equal(buf, "FOOaa");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26*26 + 26, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26*26 + 26, sizeof(buf), "FOO");
assert_int_equal(rc, 5);
assert_string_equal(buf, "FOOzz");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26*26 + 27, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26*26 + 27, sizeof(buf), "FOO");
assert_int_equal(rc, 6);
assert_string_equal(buf, "FOOaaa");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26*26*26 + 26*26 + 26, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26*26*26 + 26*26 + 26, sizeof(buf), "FOO");
assert_int_equal(rc, 6);
assert_string_equal(buf, "FOOzzz");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26*26*26 + 26*26 + 27, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 26*26*26 + 26*26 + 27, sizeof(buf), "FOO");
assert_int_equal(rc, 7);
assert_string_equal(buf, "FOOaaaa");
}
char buf[32];
int rc;
- rc = format_devname(buf, 26*26*26*26 + 26*26*26 + 26*26 + 26,
+ rc = __format_devname(buf, 26*26*26*26 + 26*26*26 + 26*26 + 26,
sizeof(buf), "FOO");
assert_int_equal(rc, 7);
assert_string_equal(buf, "FOOzzzz");
char buf[32];
int rc;
- rc = format_devname(buf, INT_MAX, sizeof(buf), "");
+ rc = __format_devname(buf, INT_MAX, sizeof(buf), "");
assert_int_equal(rc, strlen(MPATH_ID_INT_MAX));
assert_string_equal(buf, MPATH_ID_INT_MAX);
}
char buf[32];
int rc;
- rc = format_devname(buf, INT_MIN, sizeof(buf), "");
+ rc = __format_devname(buf, INT_MIN, sizeof(buf), "");
assert_int_equal(rc, -1);
}
char buf[4];
int rc;
- rc = format_devname(buf, 1, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 1, sizeof(buf), "FOO");
assert_int_equal(rc, -1);
}
char buf[5];
int rc;
- rc = format_devname(buf, 27, sizeof(buf), "FOO");
+ rc = __format_devname(buf, 27, sizeof(buf), "FOO");
assert_int_equal(rc, -1);
}
int rc, i;
for (i = 1; i < 5000; i++) {
- rc = format_devname(buf, i, sizeof(buf), "MPATH");
+ rc = __format_devname(buf, i, sizeof(buf), "MPATH");
assert_in_range(rc, 6, 8);
rc = scan_devname(buf, "MPATH");
assert_int_equal(rc, i);
srandom(1);
for (i = 1; i < 1000; i++) {
n = random() & 0xffff;
- rc = format_devname(buf, n, sizeof(buf), "MPATH");
+ rc = __format_devname(buf, n, sizeof(buf), "MPATH");
assert_in_range(rc, 6, 9);
rc = scan_devname(buf, "MPATH");
assert_int_equal(rc, n);
return mock_type(int);
}
-void __wrap_remove_map_by_alias(const char *alias, struct vectors * vecs,
- int purge_vec)
+void __wrap_remove_map_by_alias(const char *alias, struct vectors * vecs)
{
check_expected(alias);
assert_ptr_equal(vecs, waiter->vecs);
- assert_int_equal(purge_vec, 1);
}
/* pretend update the pretend dm devices. If fail is set, it
--- /dev/null
+/*
+ * Copyright (c) 2021 SUSE LLC
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <cmocka.h>
+#include <errno.h>
+#include "strbuf.h"
+#include "debug.h"
+#include "globals.c"
+
+void *__real_realloc(void *ptr, size_t size);
+
+static bool mock_realloc = false;
+void *__wrap_realloc(void *ptr, size_t size)
+{
+ void *p;
+ if (!mock_realloc)
+ return __real_realloc(ptr, size);
+
+ p = mock_ptr_type(void *);
+ condlog(4, "%s: %p, %zu -> %p", __func__, ptr, size, p);
+ return p;
+}
+
+static void test_strbuf_00(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ char *p;
+
+ assert_ptr_equal(buf.buf, NULL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+ p = steal_strbuf_str(&buf);
+ assert_ptr_equal(p, NULL);
+
+ assert_ptr_equal(buf.buf, NULL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ assert_int_equal(append_strbuf_str(&buf, "moin"), 4);
+ assert_int_equal(get_strbuf_len(&buf), 4);
+ assert_in_range(buf.size, 5, SIZE_MAX);
+ assert_string_equal(get_strbuf_str(&buf), "moin");
+ p = steal_strbuf_str(&buf);
+ assert_string_equal(p, "moin");
+ free(p);
+
+ assert_ptr_equal(buf.buf, NULL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ assert_int_equal(append_strbuf_str(&buf, NULL), -EINVAL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ assert_int_equal(append_strbuf_str(&buf, ""), 0);
+ /* appending a 0-length string allocates memory */
+ assert_in_range(buf.size, 1, SIZE_MAX);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+ p = steal_strbuf_str(&buf);
+ assert_string_equal(p, "");
+ free(p);
+
+ assert_int_equal(__append_strbuf_str(&buf, "x", 0), 0);
+ /* appending a 0-length string allocates memory */
+ assert_in_range(buf.size, 1, SIZE_MAX);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+}
+
+static void test_strbuf_alloc_err(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ size_t sz, ofs;
+ int rc;
+
+ mock_realloc = true;
+ will_return(__wrap_realloc, NULL);
+ assert_int_equal(append_strbuf_str(&buf, "moin"), -ENOMEM);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ mock_realloc = false;
+ assert_int_equal(append_strbuf_str(&buf, "moin"), 4);
+ sz = buf.size;
+ assert_in_range(sz, 5, SIZE_MAX);
+ assert_int_equal(buf.offs, 4);
+ assert_int_equal(get_strbuf_len(&buf), 4);
+ assert_string_equal(get_strbuf_str(&buf), "moin");
+
+ mock_realloc = true;
+ will_return(__wrap_realloc, NULL);
+ ofs = get_strbuf_len(&buf);
+ while ((rc = append_strbuf_str(&buf, " hello")) >= 0) {
+ condlog(3, "%s", get_strbuf_str(&buf));
+ assert_int_equal(rc, 6);
+ assert_int_equal(get_strbuf_len(&buf), ofs + 6);
+ assert_memory_equal(get_strbuf_str(&buf), "moin", 4);
+ assert_string_equal(get_strbuf_str(&buf) + ofs, " hello");
+ ofs = get_strbuf_len(&buf);
+ }
+ assert_int_equal(rc, -ENOMEM);
+ assert_int_equal(buf.size, sz);
+ assert_int_equal(get_strbuf_len(&buf), ofs);
+ assert_memory_equal(get_strbuf_str(&buf), "moin", 4);
+ assert_string_equal(get_strbuf_str(&buf) + ofs - 6, " hello");
+
+ reset_strbuf(&buf);
+ assert_ptr_equal(buf.buf, NULL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ mock_realloc = false;
+}
+
+static void test_strbuf_overflow(void **state)
+{
+ STRBUF_ON_STACK(buf);
+
+ assert_int_equal(append_strbuf_str(&buf, "x"), 1);
+ /* fake huge buffer */
+ buf.size = SIZE_MAX - 1;
+ buf.offs = buf.size - 1;
+ assert_int_equal(append_strbuf_str(&buf, "x"), -EOVERFLOW);
+}
+
+static void test_strbuf_big(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ const char big[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\n";
+ char *bbig;
+ int i;
+
+ /* Under valgrind, 30000 iterations need ca. 30s on my laptop */
+ for (i = 0; i < 30000; i++) {
+ if (i % 1000 == 0)
+ condlog(4, "%d", i);
+ assert_int_equal(append_strbuf_str(&buf, big), sizeof(big) - 1);
+ assert_int_equal(get_strbuf_len(&buf), (sizeof(big) - 1) * (i + 1));
+ assert_memory_equal(get_strbuf_str(&buf), big, sizeof(big) - 1);
+ assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf)
+ - (sizeof(big) - 1), big);
+ };
+ bbig = steal_strbuf_str(&buf);
+
+ assert_ptr_equal(buf.buf, NULL);
+ assert_int_equal(buf.size, 0);
+ assert_int_equal(buf.offs, 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ assert_int_equal(strlen(bbig), i * (sizeof(big) - 1));
+ assert_memory_equal(bbig, big, sizeof(big) - 1);
+ free(bbig);
+}
+
+static void test_strbuf_nul(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ char greet[] = "hello, sir!";
+
+ assert_int_equal(__append_strbuf_str(&buf, greet, 6), 6);
+ assert_string_equal(get_strbuf_str(&buf), "hello,");
+ assert_int_equal(__append_strbuf_str(&buf, greet, 6), 6);
+ assert_string_equal(get_strbuf_str(&buf), "hello,hello,");
+
+ /* overwrite comma with NUL; append_strbuf_str() stops at NUL byte */
+ greet[5] = '\0';
+ reset_strbuf(&buf);
+ assert_int_equal(append_strbuf_str(&buf, greet), 5);
+ assert_int_equal(get_strbuf_len(&buf), 5);
+ assert_string_equal(get_strbuf_str(&buf), "hello");
+ assert_int_equal(append_strbuf_str(&buf, greet), 5);
+ assert_int_equal(get_strbuf_len(&buf), 10);
+ assert_string_equal(get_strbuf_str(&buf), "hellohello");
+
+ /* __append_strbuf_str() appends full memory, including NUL bytes */
+ reset_strbuf(&buf);
+ assert_int_equal(__append_strbuf_str(&buf, greet, sizeof(greet) - 1),
+ sizeof(greet) - 1);
+ assert_int_equal(get_strbuf_len(&buf), sizeof(greet) - 1);
+ assert_string_equal(get_strbuf_str(&buf), "hello");
+ assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf) - 5, " sir!");
+ assert_int_equal(__append_strbuf_str(&buf, greet, sizeof(greet) - 1),
+ sizeof(greet) - 1);
+ assert_string_equal(get_strbuf_str(&buf), "hello");
+ assert_int_equal(get_strbuf_len(&buf), 2 * (sizeof(greet) - 1));
+ assert_string_equal(get_strbuf_str(&buf) + get_strbuf_len(&buf) - 5, " sir!");
+}
+
+static void test_strbuf_quoted(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ const char said[] = "She said ";
+ const char greet[] = "hi, man!";
+ char *p;
+ size_t n;
+
+ assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
+ assert_int_equal(append_strbuf_quoted(&buf, greet), sizeof(greet) + 1);
+ assert_string_equal(get_strbuf_str(&buf), "She said \"hi, man!\"");
+ n = get_strbuf_len(&buf);
+ p = steal_strbuf_str(&buf);
+ assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
+ assert_int_equal(append_strbuf_quoted(&buf, p), n + 4);
+ assert_string_equal(get_strbuf_str(&buf),
+ "She said \"She said \"\"hi, man!\"\"\"");
+ free(p);
+ n = get_strbuf_len(&buf);
+ p = steal_strbuf_str(&buf);
+ assert_int_equal(append_strbuf_str(&buf, said), sizeof(said) - 1);
+ assert_int_equal(append_strbuf_quoted(&buf, p), n + 8);
+ assert_string_equal(get_strbuf_str(&buf),
+ "She said \"She said \"\"She said \"\"\"\"hi, man!\"\"\"\"\"\"\"");
+ free(p);
+}
+
+static void test_strbuf_escaped(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ const char said[] = "She said \"hi, man\"";
+
+ assert_int_equal(append_strbuf_quoted(&buf, said), sizeof(said) + 3);
+ assert_string_equal(get_strbuf_str(&buf),
+ "\"She said \"\"hi, man\"\"\"");
+
+ reset_strbuf(&buf);
+ assert_int_equal(append_strbuf_quoted(&buf, "\""), 4);
+ assert_string_equal(get_strbuf_str(&buf), "\"\"\"\"");
+
+ reset_strbuf(&buf);
+ assert_int_equal(append_strbuf_quoted(&buf, "\"\""), 6);
+ assert_string_equal(get_strbuf_str(&buf), "\"\"\"\"\"\"");
+
+ reset_strbuf(&buf);
+ assert_int_equal(append_strbuf_quoted(&buf, "\"Hi\""), 8);
+ assert_string_equal(get_strbuf_str(&buf), "\"\"\"Hi\"\"\"");
+}
+
+#define SENTENCE "yields, preceded by itself, falsehood"
+static void test_print_strbuf(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ char sentence[] = SENTENCE;
+
+ assert_int_equal(print_strbuf(&buf, "\"%s\" %s.", sentence, sentence),
+ 2 * (sizeof(sentence) - 1) + 4);
+ assert_string_equal(get_strbuf_str(&buf),
+ "\"" SENTENCE "\" " SENTENCE ".");
+ condlog(3, "%s", get_strbuf_str(&buf));
+
+ reset_strbuf(&buf);
+ assert_int_equal(print_strbuf(&buf, "0x%08x", 0xdeadbeef), 10);
+ assert_string_equal(get_strbuf_str(&buf), "0xdeadbeef");
+
+ reset_strbuf(&buf);
+ assert_int_equal(print_strbuf(&buf, "%d%% of %d is %0.2f",
+ 5, 100, 0.05), 17);
+ assert_string_equal(get_strbuf_str(&buf), "5% of 100 is 0.05");
+}
+
+static void test_truncate_strbuf(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ const char str[] = "hello my dear!\n";
+ size_t sz, sz1;
+
+ assert_int_equal(truncate_strbuf(&buf, 1), -EFAULT);
+ assert_int_equal(truncate_strbuf(&buf, 0), -EFAULT);
+
+ assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
+ assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
+ assert_string_equal(get_strbuf_str(&buf), str);
+
+ assert_int_equal(truncate_strbuf(&buf, sizeof(str)), -ERANGE);
+ assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
+ assert_string_equal(get_strbuf_str(&buf), str);
+
+ assert_int_equal(truncate_strbuf(&buf, sizeof(str) - 1), 0);
+ assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 1);
+ assert_string_equal(get_strbuf_str(&buf), str);
+
+ assert_int_equal(truncate_strbuf(&buf, sizeof(str) - 2), 0);
+ assert_int_equal(get_strbuf_len(&buf), sizeof(str) - 2);
+ assert_string_not_equal(get_strbuf_str(&buf), str);
+ assert_memory_equal(get_strbuf_str(&buf), str, sizeof(str) - 2);
+
+ assert_int_equal(truncate_strbuf(&buf, 5), 0);
+ assert_int_equal(get_strbuf_len(&buf), 5);
+ assert_string_not_equal(get_strbuf_str(&buf), str);
+ assert_string_equal(get_strbuf_str(&buf), "hello");
+
+ reset_strbuf(&buf);
+ assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
+
+ sz = buf.size;
+ while (buf.size == sz)
+ assert_int_equal(append_strbuf_str(&buf, str), sizeof(str) - 1);
+
+ sz1 = buf.size;
+ assert_in_range(get_strbuf_len(&buf), sz + 1, SIZE_MAX);
+ assert_string_equal(get_strbuf_str(&buf) +
+ get_strbuf_len(&buf) - (sizeof(str) - 1), str);
+ assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf) + 1),
+ -ERANGE);
+ assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf)), 0);
+ assert_int_equal(truncate_strbuf(&buf, get_strbuf_len(&buf)
+ - (sizeof(str) - 1)), 0);
+ assert_in_range(get_strbuf_len(&buf), 1, sz);
+ assert_string_equal(get_strbuf_str(&buf) +
+ get_strbuf_len(&buf) - (sizeof(str) - 1), str);
+ assert_int_equal(buf.size, sz1);
+
+ assert_int_equal(truncate_strbuf(&buf, 5), 0);
+ assert_int_equal(get_strbuf_len(&buf), 5);
+ assert_string_equal(get_strbuf_str(&buf), "hello");
+ assert_int_equal(buf.size, sz1);
+
+ assert_int_equal(truncate_strbuf(&buf, 0), 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+ assert_int_equal(buf.size, sz1);
+}
+
+static void test_fill_strbuf(void **state)
+{
+ STRBUF_ON_STACK(buf);
+ int i;
+ char *p;
+
+ assert_int_equal(fill_strbuf(&buf, '+', -5), -EINVAL);
+
+ assert_int_equal(fill_strbuf(&buf, '+', 0), 0);
+ assert_int_equal(get_strbuf_len(&buf), 0);
+ assert_string_equal(get_strbuf_str(&buf), "");
+
+ assert_int_equal(fill_strbuf(&buf, '+', 1), 1);
+ assert_int_equal(get_strbuf_len(&buf), 1);
+ assert_string_equal(get_strbuf_str(&buf), "+");
+
+ assert_int_equal(fill_strbuf(&buf, '-', 3), 3);
+ assert_int_equal(get_strbuf_len(&buf), 4);
+ assert_string_equal(get_strbuf_str(&buf), "+---");
+
+ assert_int_equal(fill_strbuf(&buf, '\0', 3), 3);
+ assert_int_equal(get_strbuf_len(&buf), 7);
+ assert_string_equal(get_strbuf_str(&buf), "+---");
+
+ truncate_strbuf(&buf, 4);
+ assert_int_equal(fill_strbuf(&buf, '+', 4), 4);
+ assert_int_equal(get_strbuf_len(&buf), 8);
+ assert_string_equal(get_strbuf_str(&buf), "+---++++");
+
+ reset_strbuf(&buf);
+ assert_int_equal(fill_strbuf(&buf, 'x', 30000), 30000);
+ assert_int_equal(get_strbuf_len(&buf), 30000);
+ p = steal_strbuf_str(&buf);
+ assert_int_equal(strlen(p), 30000);
+ for (i = 0; i < 30000; i++)
+ assert_int_equal(p[i], 'x');
+ free(p);
+}
+
+static int test_strbuf(void)
+{
+ const struct CMUnitTest tests[] = {
+ cmocka_unit_test(test_strbuf_00),
+ cmocka_unit_test(test_strbuf_alloc_err),
+ cmocka_unit_test(test_strbuf_overflow),
+ cmocka_unit_test(test_strbuf_big),
+ cmocka_unit_test(test_strbuf_nul),
+ cmocka_unit_test(test_strbuf_quoted),
+ cmocka_unit_test(test_strbuf_escaped),
+ cmocka_unit_test(test_print_strbuf),
+ cmocka_unit_test(test_truncate_strbuf),
+ cmocka_unit_test(test_fill_strbuf),
+ };
+
+ return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
+int main(void)
+{
+ int ret = 0;
+
+ init_test_verbosity(-1);
+ ret += test_strbuf();
+ return ret;
+}