From: DongHun Kwak Date: Fri, 14 Jan 2022 04:50:20 +0000 (+0900) Subject: Imported Upstream version 0.8.7 X-Git-Tag: upstream/0.8.7^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6a3706f97f14db2b51507e9cb0af751ade98abd5;p=platform%2Fupstream%2Fmultipath-tools.git Imported Upstream version 0.8.7 --- diff --git a/.gitignore b/.gitignore index 9926756..087dffc 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,9 @@ *.a *.gz *.d +\#* +cscope.files +cscope.out kpartx/kpartx multipath/multipath multipathd/multipathd @@ -21,5 +24,6 @@ libdmmp/test/libdmmp_test libdmmp/test/libdmmp_speed_test tests/*-test tests/*.out +tests/*.vgr libmultipath/nvme-ioctl.c libmultipath/nvme-ioctl.h diff --git a/Makefile.inc b/Makefile.inc index f1e2313..d0ec9b4 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -95,12 +95,13 @@ TEST_CC_OPTION = $(shell \ 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 diff --git a/README.alua b/README.alua index b15eb48..5d2b1c6 100644 --- a/README.alua +++ b/README.alua @@ -6,7 +6,7 @@ To enable ALUA, the following options should be changed: - 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: diff --git a/kpartx/kpartx.c b/kpartx/kpartx.c index 8ff116b..7bc6454 100644 --- a/kpartx/kpartx.c +++ b/kpartx/kpartx.c @@ -766,6 +766,8 @@ getblock (int fd, unsigned int blknr) { 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; } diff --git a/libdmmp/Makefile b/libdmmp/Makefile index 764a0bc..79b92fb 100644 --- a/libdmmp/Makefile +++ b/libdmmp/Makefile @@ -76,6 +76,8 @@ docs/man/%.3.gz: docs/man/%.3 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 diff --git a/libdmmp/docs/man/dmmp_context_free.3 b/libdmmp/docs/man/dmmp_context_free.3 index 0d26f42..7c109e1 100644 --- a/libdmmp/docs/man/dmmp_context_free.3 +++ b/libdmmp/docs/man/dmmp_context_free.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_log_func_set.3 b/libdmmp/docs/man/dmmp_context_log_func_set.3 index 986793d..be311ec 100644 --- a/libdmmp/docs/man/dmmp_context_log_func_set.3 +++ b/libdmmp/docs/man/dmmp_context_log_func_set.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_log_priority_get.3 b/libdmmp/docs/man/dmmp_context_log_priority_get.3 index 9a273a2..be38301 100644 --- a/libdmmp/docs/man/dmmp_context_log_priority_get.3 +++ b/libdmmp/docs/man/dmmp_context_log_priority_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_log_priority_set.3 b/libdmmp/docs/man/dmmp_context_log_priority_set.3 index 469c5a4..79e4d2e 100644 --- a/libdmmp/docs/man/dmmp_context_log_priority_set.3 +++ b/libdmmp/docs/man/dmmp_context_log_priority_set.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_new.3 b/libdmmp/docs/man/dmmp_context_new.3 index 0eaeb00..12505f9 100644 --- a/libdmmp/docs/man/dmmp_context_new.3 +++ b/libdmmp/docs/man/dmmp_context_new.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_timeout_get.3 b/libdmmp/docs/man/dmmp_context_timeout_get.3 index 1df2793..2ed825d 100644 --- a/libdmmp/docs/man/dmmp_context_timeout_get.3 +++ b/libdmmp/docs/man/dmmp_context_timeout_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_timeout_set.3 b/libdmmp/docs/man/dmmp_context_timeout_set.3 index f3d7709..16bc9d9 100644 --- a/libdmmp/docs/man/dmmp_context_timeout_set.3 +++ b/libdmmp/docs/man/dmmp_context_timeout_set.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_userdata_get.3 b/libdmmp/docs/man/dmmp_context_userdata_get.3 index fb713d5..eff446c 100644 --- a/libdmmp/docs/man/dmmp_context_userdata_get.3 +++ b/libdmmp/docs/man/dmmp_context_userdata_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_context_userdata_set.3 b/libdmmp/docs/man/dmmp_context_userdata_set.3 index c5bf63f..d7be869 100644 --- a/libdmmp/docs/man/dmmp_context_userdata_set.3 +++ b/libdmmp/docs/man/dmmp_context_userdata_set.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_flush_mpath.3 b/libdmmp/docs/man/dmmp_flush_mpath.3 index cdfd526..359607e 100644 --- a/libdmmp/docs/man/dmmp_flush_mpath.3 +++ b/libdmmp/docs/man/dmmp_flush_mpath.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_last_error_msg.3 b/libdmmp/docs/man/dmmp_last_error_msg.3 index 20acbc6..378c55a 100644 --- a/libdmmp/docs/man/dmmp_last_error_msg.3 +++ b/libdmmp/docs/man/dmmp_last_error_msg.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_log_priority_str.3 b/libdmmp/docs/man/dmmp_log_priority_str.3 index 3b5f828..b276160 100644 --- a/libdmmp/docs/man/dmmp_log_priority_str.3 +++ b/libdmmp/docs/man/dmmp_log_priority_str.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_mpath_array_free.3 b/libdmmp/docs/man/dmmp_mpath_array_free.3 index 8c294e0..0514a66 100644 --- a/libdmmp/docs/man/dmmp_mpath_array_free.3 +++ b/libdmmp/docs/man/dmmp_mpath_array_free.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_mpath_array_get.3 b/libdmmp/docs/man/dmmp_mpath_array_get.3 index e211db4..8b0e5b5 100644 --- a/libdmmp/docs/man/dmmp_mpath_array_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_array_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 b/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 index e802fe6..ddead55 100644 --- a/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_kdev_name_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_mpath_name_get.3 b/libdmmp/docs/man/dmmp_mpath_name_get.3 index d70579e..2b0027e 100644 --- a/libdmmp/docs/man/dmmp_mpath_name_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_name_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_mpath_wwid_get.3 b/libdmmp/docs/man/dmmp_mpath_wwid_get.3 index 3d060e9..b8e9e7d 100644 --- a/libdmmp/docs/man/dmmp_mpath_wwid_get.3 +++ b/libdmmp/docs/man/dmmp_mpath_wwid_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_array_get.3 b/libdmmp/docs/man/dmmp_path_array_get.3 index 53340b3..21f486b 100644 --- a/libdmmp/docs/man/dmmp_path_array_get.3 +++ b/libdmmp/docs/man/dmmp_path_array_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_blk_name_get.3 b/libdmmp/docs/man/dmmp_path_blk_name_get.3 index da5f9f0..5938f0e 100644 --- a/libdmmp/docs/man/dmmp_path_blk_name_get.3 +++ b/libdmmp/docs/man/dmmp_path_blk_name_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_array_get.3 b/libdmmp/docs/man/dmmp_path_group_array_get.3 index 6eee4a2..ca3187c 100644 --- a/libdmmp/docs/man/dmmp_path_group_array_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_array_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_id_get.3 b/libdmmp/docs/man/dmmp_path_group_id_get.3 index 4f07b53..a84f31f 100644 --- a/libdmmp/docs/man/dmmp_path_group_id_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_id_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_priority_get.3 b/libdmmp/docs/man/dmmp_path_group_priority_get.3 index a48b270..1cda8af 100644 --- a/libdmmp/docs/man/dmmp_path_group_priority_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_priority_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_selector_get.3 b/libdmmp/docs/man/dmmp_path_group_selector_get.3 index 407b3f4..f55477b 100644 --- a/libdmmp/docs/man/dmmp_path_group_selector_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_selector_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_status_get.3 b/libdmmp/docs/man/dmmp_path_group_status_get.3 index a81aeb3..53e68b8 100644 --- a/libdmmp/docs/man/dmmp_path_group_status_get.3 +++ b/libdmmp/docs/man/dmmp_path_group_status_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_group_status_str.3 b/libdmmp/docs/man/dmmp_path_group_status_str.3 index e4a9f74..98f877a 100644 --- a/libdmmp/docs/man/dmmp_path_group_status_str.3 +++ b/libdmmp/docs/man/dmmp_path_group_status_str.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_status_get.3 b/libdmmp/docs/man/dmmp_path_status_get.3 index 025cfee..baa4437 100644 --- a/libdmmp/docs/man/dmmp_path_status_get.3 +++ b/libdmmp/docs/man/dmmp_path_status_get.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_path_status_str.3 b/libdmmp/docs/man/dmmp_path_status_str.3 index 3944d39..425e472 100644 --- a/libdmmp/docs/man/dmmp_path_status_str.3 +++ b/libdmmp/docs/man/dmmp_path_status_str.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_reconfig.3 b/libdmmp/docs/man/dmmp_reconfig.3 index a743e30..36bd504 100644 --- a/libdmmp/docs/man/dmmp_reconfig.3 +++ b/libdmmp/docs/man/dmmp_reconfig.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libdmmp/docs/man/dmmp_strerror.3 b/libdmmp/docs/man/dmmp_strerror.3 index 4d753d3..3acd9c9 100644 --- a/libdmmp/docs/man/dmmp_strerror.3 +++ b/libdmmp/docs/man/dmmp_strerror.3 @@ -1,4 +1,4 @@ -.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 diff --git a/libmpathpersist/mpath_persist.c b/libmpathpersist/mpath_persist.c index 190e970..803a2a2 100644 --- a/libmpathpersist/mpath_persist.c +++ b/libmpathpersist/mpath_persist.c @@ -410,7 +410,7 @@ get_mpvec (vector curmp, vector pathvec, char * refwwid) 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); @@ -604,7 +604,8 @@ int mpath_prout_common(struct multipath *mpp,int rq_servact, int rq_scope, 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, @@ -663,6 +664,11 @@ int mpath_prout_rel(struct multipath *mpp,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++){ diff --git a/libmultipath/Makefile b/libmultipath/Makefile index e7254f3..7f3921c 100644 --- a/libmultipath/Makefile +++ b/libmultipath/Makefile @@ -53,7 +53,7 @@ OBJS = memory.o parser.o vector.o devmapper.o callout.o \ 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) diff --git a/libmultipath/alias.c b/libmultipath/alias.c index 02bc9d6..ad7e512 100644 --- a/libmultipath/alias.c +++ b/libmultipath/alias.c @@ -22,7 +22,7 @@ #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 @@ -61,31 +61,23 @@ valid_alias(const char *alias) 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 @@ -123,11 +115,14 @@ scan_devname(const char *alias, const char *prefix) 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]; @@ -285,10 +280,10 @@ rlookup_binding(FILE *f, char *buff, const char *map_alias) 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", @@ -296,16 +291,12 @@ allocate_binding(int fd, const char *wwid, int id, const char *prefix) 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){ @@ -313,24 +304,25 @@ allocate_binding(int fd, const char *wwid, int id, const char *prefix) 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; } @@ -560,7 +552,7 @@ static int add_binding(Bindings *bindings, const char *alias, const char *wwid) 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) @@ -570,16 +562,12 @@ static int write_bindings_file(const Bindings *bindings, int fd) 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; } diff --git a/libmultipath/blacklist.c b/libmultipath/blacklist.c index 6c6a597..4e315c9 100644 --- a/libmultipath/blacklist.c +++ b/libmultipath/blacklist.c @@ -14,6 +14,7 @@ #include "blacklist.h" #include "structs_vec.h" #include "print.h" +#include "strbuf.h" char *check_invert(char *str, bool *invert) { @@ -341,19 +342,21 @@ int 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; } diff --git a/libmultipath/checkers.c b/libmultipath/checkers.c index 2dd9915..8039c2b 100644 --- a/libmultipath/checkers.c +++ b/libmultipath/checkers.c @@ -368,7 +368,7 @@ static void checker_cleanup_thread(void *arg) { struct checker_class *cls = arg; - (void)checker_class_unref(cls); + free_checker_class(cls); rcu_unregister_thread(); } diff --git a/libmultipath/configure.c b/libmultipath/configure.c index 6ca1f4b..7edb355 100644 --- a/libmultipath/configure.c +++ b/libmultipath/configure.c @@ -292,8 +292,7 @@ static int wait_for_pending_paths(struct multipath *mpp, 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; @@ -397,7 +396,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, 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 */ @@ -462,7 +461,7 @@ int setup_map(struct multipath *mpp, char *params, int params_size, * 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; } @@ -811,7 +810,7 @@ void select_action (struct multipath *mpp, const struct _vector *curmp, 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); @@ -1061,29 +1060,8 @@ int domap(struct multipath *mpp, char *params, int is_daemon) 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; @@ -1128,14 +1106,14 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, 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; @@ -1220,7 +1198,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, 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; } @@ -1247,9 +1225,8 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, } 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; } @@ -1260,6 +1237,8 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, 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 " @@ -1269,7 +1248,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, 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; @@ -1278,7 +1257,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, } 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); @@ -1303,38 +1282,13 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, 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: diff --git a/libmultipath/configure.h b/libmultipath/configure.h index 70cf77a..efe18b7 100644 --- a/libmultipath/configure.h +++ b/libmultipath/configure.h @@ -47,8 +47,7 @@ enum { 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); @@ -60,3 +59,4 @@ struct udev_device *get_udev_device(const char *dev, enum devtypes dev_type); 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); diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index 095cbc0..c05dc20 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -49,6 +49,9 @@ static int dm_conf_verbosity; #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, @@ -384,7 +387,8 @@ libmp_dm_task_create(int task) #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 || @@ -598,8 +602,8 @@ int dm_addmap_reload(struct multipath *mpp, char *params, int flush) 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); @@ -644,7 +648,7 @@ int dm_map_present(const char * str) 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; @@ -678,12 +682,13 @@ int dm_get_map(const char *name, unsigned long long *size, char *outparams) 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; @@ -757,7 +762,7 @@ is_mpath_part(const char *part_name, const char *map_name) 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; @@ -795,8 +800,12 @@ int dm_get_status(const char *name, char *outstatus) 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); @@ -1045,7 +1054,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove, 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 */ @@ -1061,7 +1070,7 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove, 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; @@ -1069,6 +1078,8 @@ int _dm_flush_map (const char * mapname, int need_sync, int deferred_remove, /* 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; @@ -1122,7 +1133,8 @@ dm_flush_map_nopaths(const char * mapname, int deferred_remove) #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); } @@ -1426,7 +1438,7 @@ do_foreach_partmaps (const char * mapname, 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; @@ -1469,7 +1481,7 @@ do_foreach_partmaps (const char * mapname, /* * 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 @@ -1481,12 +1493,15 @@ do_foreach_partmaps (const char * mapname, 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; } @@ -1573,7 +1588,7 @@ dm_cancel_deferred_remove (struct multipath *mpp) #else int -dm_cancel_deferred_remove (struct multipath *mpp) +dm_cancel_deferred_remove (struct multipath *mpp __attribute__((unused))) { return 0; } @@ -1615,17 +1630,19 @@ struct rename_data { 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; } diff --git a/libmultipath/devmapper.h b/libmultipath/devmapper.h index e29b4d4..45a676d 100644 --- a/libmultipath/devmapper.h +++ b/libmultipath/devmapper.h @@ -44,8 +44,8 @@ int dm_addmap_create (struct multipath *mpp, char *params); 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); diff --git a/libmultipath/dict.c b/libmultipath/dict.c index dd08abf..7a72738 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -26,6 +26,7 @@ #include #include "mpath_cmd.h" #include "dict.h" +#include "strbuf.h" static int set_int(vector strvec, void *ptr) @@ -143,84 +144,45 @@ set_yes_no_undef(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) \ @@ -232,32 +194,32 @@ def_ ## option ## _handler (struct config *conf, vector strvec) \ #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) \ @@ -272,11 +234,11 @@ hw_ ## option ## _handler (struct config *conf, vector strvec) \ #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) \ @@ -290,10 +252,10 @@ ovr_ ## option ## _handler (struct config *conf, vector strvec) \ #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) \ @@ -308,11 +270,11 @@ mp_ ## option ## _handler (struct config *conf, vector strvec) \ #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) @@ -354,13 +316,13 @@ static int def_partition_delim_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[] = { @@ -403,10 +365,10 @@ def_find_multipaths_handler(struct config *conf, vector strvec) } 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]); } @@ -419,21 +381,19 @@ declare_ovr_snprint(selector, print_str) 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) @@ -526,18 +486,23 @@ declare_mp_snprint(minio_rq, print_nonzero) 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) @@ -636,10 +601,11 @@ static int def_disable_changed_wwids_handler(struct config *conf, vector strvec) { 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) @@ -681,11 +647,10 @@ def_ ## option ## _handler (struct config *conf, vector strvec) \ #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) \ @@ -700,12 +665,11 @@ mp_ ## option ## _handler (struct config *conf, vector strvec) \ #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 @@ -780,30 +744,30 @@ set_gid(vector strvec, void *ptr, int *flags) } 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) @@ -843,16 +807,15 @@ set_undef_off_zero(vector strvec, void *ptr) 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) @@ -883,13 +846,13 @@ set_dev_loss(vector strvec, void *ptr) } 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) @@ -923,7 +886,7 @@ set_pgpolicy(vector strvec, void *ptr) } int -print_pgpolicy(char * buff, int len, long pgpolicy) +print_pgpolicy(struct strbuf *buff, long pgpolicy) { char str[POLICY_NAME_SIZE]; @@ -932,7 +895,7 @@ print_pgpolicy(char * buff, int len, long pgpolicy) 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) @@ -1003,7 +966,7 @@ max_fds_handler(struct config *conf, vector strvec) } 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; @@ -1012,9 +975,9 @@ snprint_max_fds (struct config *conf, char * buff, int len, const void * data) 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 @@ -1040,14 +1003,14 @@ set_rr_weight(vector strvec, void *ptr) } 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; } @@ -1086,19 +1049,19 @@ set_pgfailback(vector strvec, void *ptr) } 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); } } @@ -1133,17 +1096,17 @@ no_path_retry_helper(vector strvec, void *ptr) } 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); } } @@ -1176,12 +1139,12 @@ def_log_checker_err_handler(struct config *conf, vector strvec) } 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 @@ -1216,18 +1179,17 @@ set_reservation_key(vector strvec, struct be64 *be64_ptr, uint8_t *flags_ptr, } 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 @@ -1239,12 +1201,11 @@ def_reservation_key_handler(struct config *conf, vector strvec) } 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 @@ -1259,13 +1220,12 @@ mp_reservation_key_handler(struct config *conf, vector strvec) } 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 @@ -1288,15 +1248,15 @@ set_off_int_undef(vector strvec, void *ptr) } 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); } } @@ -1455,13 +1415,13 @@ out: } 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; } @@ -1561,19 +1521,18 @@ declare_ble_handler(blist_protocol) 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 @@ -1593,24 +1552,22 @@ declare_ble_device_handler(vendor, elist_device, buff, NULL) 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); } /* @@ -1738,8 +1695,7 @@ deprecated_handler(struct config *conf, vector strvec) } 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; } diff --git a/libmultipath/dict.h b/libmultipath/dict.h index a917e1c..d80f990 100644 --- a/libmultipath/dict.h +++ b/libmultipath/dict.h @@ -6,16 +6,17 @@ #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 */ diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index ec99a7a..f25fe9e 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -35,6 +35,7 @@ #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" }, @@ -635,7 +636,7 @@ sysfs_set_rport_tmo(struct multipath *mpp, struct path *pp) { struct udev_device *rport_dev = NULL; char value[16], *eptr; - char rport_id[32]; + char rport_id[42]; unsigned int tmo; int ret; @@ -895,11 +896,11 @@ sysfs_set_scsi_tmo (struct multipath *mpp, unsigned int checkint) } 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; } @@ -1427,7 +1428,7 @@ scsi_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable) 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, @@ -1462,7 +1463,7 @@ scsi_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable) /* * 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, @@ -1577,7 +1578,7 @@ ccw_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable) &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, @@ -1636,7 +1637,7 @@ cciss_sysfs_pathinfo (struct path *pp, const struct _vector *hwtable) */ 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, @@ -1815,7 +1816,7 @@ scsi_ioctl_pathinfo (struct path * pp, int mask) 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, @@ -2380,11 +2381,11 @@ int pathinfo(struct path *pp, struct config *conf, int mask) * 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; diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c index b306c46..4ba7f33 100644 --- a/libmultipath/dmparser.c +++ b/libmultipath/dmparser.c @@ -15,6 +15,7 @@ #include "util.h" #include "debug.h" #include "dmparser.h" +#include "strbuf.h" #define WORD_SIZE 64 @@ -41,40 +42,21 @@ merge_words(char **dst, const char *word) 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); @@ -87,14 +69,15 @@ assemble_map (struct multipath * mp, char * params, int len) 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; @@ -106,19 +89,19 @@ assemble_map (struct multipath * mp, char * params, int len) 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. diff --git a/libmultipath/dmparser.h b/libmultipath/dmparser.h index 212fee5..666ae74 100644 --- a/libmultipath/dmparser.h +++ b/libmultipath/dmparser.h @@ -1,3 +1,3 @@ -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 *); diff --git a/libmultipath/foreign.c b/libmultipath/foreign.c index fce1934..e091a1d 100644 --- a/libmultipath/foreign.c +++ b/libmultipath/foreign.c @@ -34,6 +34,7 @@ #include "structs.h" #include "structs_vec.h" #include "print.h" +#include "strbuf.h" static vector foreigns; @@ -497,11 +498,11 @@ void foreign_multipath_layout(void) 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) { @@ -521,58 +522,32 @@ int snprint_foreign_topology(char *buf, int len, int verbosity) 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) { @@ -584,7 +559,7 @@ int snprint_foreign_paths(char *buf, int len, const char *style, int pretty) 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); @@ -592,28 +567,27 @@ int snprint_foreign_paths(char *buf, int len, const char *style, int pretty) 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) { @@ -625,7 +599,7 @@ int snprint_foreign_multipaths(char *buf, int len, 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); @@ -633,18 +607,18 @@ int snprint_foreign_multipaths(char *buf, int len, 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; } diff --git a/libmultipath/foreign.h b/libmultipath/foreign.h index acd3360..77fc485 100644 --- a/libmultipath/foreign.h +++ b/libmultipath/foreign.h @@ -18,9 +18,9 @@ #define _FOREIGN_H #include #include +#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" */ @@ -267,35 +267,32 @@ void foreign_multipath_layout(void); * 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); /** diff --git a/libmultipath/foreign/nvme.c b/libmultipath/foreign/nvme.c index b726be2..d40c086 100644 --- a/libmultipath/foreign/nvme.c +++ b/libmultipath/foreign/nvme.c @@ -37,6 +37,7 @@ #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"; @@ -138,7 +139,7 @@ static void rstrip(char *str) } 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]; @@ -146,26 +147,26 @@ static int snprint_nvme_map(const struct gen_multipath *gmp, 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", @@ -173,30 +174,30 @@ static int snprint_nvme_map(const struct gen_multipath *gmp, "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* @@ -214,7 +215,7 @@ nvme_pg_rel_paths(__attribute__((unused)) const struct gen_pathgroup *gpg, /* 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; @@ -223,14 +224,13 @@ static int snprint_hcil(const struct nvme_path *np, char *buf, int len) 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; @@ -239,37 +239,37 @@ static int snprint_nvme_path(const struct gen_path *gp, 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': @@ -277,46 +277,45 @@ static int snprint_nvme_path(const struct gen_path *gp, 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); @@ -324,22 +323,19 @@ static int snprint_nvme_pg(const struct gen_pathgroup *gmp, 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 = { diff --git a/libmultipath/generic.c b/libmultipath/generic.c index 5f03b9e..e7cf297 100644 --- a/libmultipath/generic.c +++ b/libmultipath/generic.c @@ -15,23 +15,23 @@ along with this program. If not, see . */ - -#include #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) " : ""); } diff --git a/libmultipath/generic.h b/libmultipath/generic.h index 6346ffe..57c123c 100644 --- a/libmultipath/generic.h +++ b/libmultipath/generic.h @@ -18,6 +18,7 @@ #define _GENERIC_H #include "vector.h" +struct strbuf; struct gen_multipath; struct gen_pathgroup; struct gen_path; @@ -50,26 +51,24 @@ struct gen_multipath_ops { * 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); }; /** @@ -95,7 +94,7 @@ struct gen_pathgroup_ops { * 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 { @@ -104,7 +103,7 @@ 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 { @@ -129,6 +128,6 @@ struct gen_path { * foreign libraries. */ int generic_style(const struct gen_multipath*, - char *buf, int len, int verbosity); + struct strbuf *buf, int verbosity); #endif /* _GENERIC_H */ diff --git a/libmultipath/hwtable.c b/libmultipath/hwtable.c index 58fa738..0caac0d 100644 --- a/libmultipath/hwtable.c +++ b/libmultipath/hwtable.c @@ -107,7 +107,7 @@ static struct hwentry default_hw[] = { * HPE */ { - /* 3PAR / Primera */ + /* 3PAR / Primera / Alletra 9000 */ .vendor = "3PARdata", .product = "VV", .pgpolicy = GROUP_BY_PRIO, @@ -225,7 +225,7 @@ static struct hwentry default_hw[] = { .prio_name = PRIO_ALUA, }, { - /* Nimble Storage */ + /* Nimble Storage / HPE Alletra 6000 */ .vendor = "Nimble", .product = "Server", .hwhandler = "1 alua", @@ -659,7 +659,8 @@ static struct hwentry default_hw[] = { .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, @@ -1078,11 +1079,14 @@ static struct hwentry default_hw[] = { * 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 diff --git a/libmultipath/libmultipath.version b/libmultipath/libmultipath.version index 0cff311..eb5b5b5 100644 --- a/libmultipath/libmultipath.version +++ b/libmultipath/libmultipath.version @@ -31,7 +31,7 @@ * The new version inherits the previous ones. */ -LIBMULTIPATH_5.0.0 { +LIBMULTIPATH_9.0.0 { global: /* symbols referenced by multipath and multipathd */ add_foreign; @@ -58,8 +58,6 @@ global: count_active_paths; delete_all_foreign; delete_foreign; - disassemble_map; - disassemble_status; dlog; dm_cancel_deferred_remove; dm_enablegroup; @@ -70,10 +68,8 @@ global: 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; @@ -271,6 +267,23 @@ global: /* 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: *; }; diff --git a/libmultipath/parser.c b/libmultipath/parser.c index c70243c..8ca91bf 100644 --- a/libmultipath/parser.c +++ b/libmultipath/parser.c @@ -25,6 +25,7 @@ #include "parser.h" #include "memory.h" #include "debug.h" +#include "strbuf.h" /* local vars */ static int sublevel = 0; @@ -33,7 +34,7 @@ static int line_nr; 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; @@ -72,7 +73,7 @@ install_sublevel_end(void) 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; @@ -149,46 +150,49 @@ find_keyword(vector keywords, vector v, char * name) } 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' }; diff --git a/libmultipath/parser.h b/libmultipath/parser.h index 06666cc..b43d46f 100644 --- a/libmultipath/parser.h +++ b/libmultipath/parser.h @@ -34,16 +34,20 @@ /* 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; }; @@ -60,16 +64,15 @@ struct keyword { /* 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) @@ -79,7 +82,7 @@ extern vector alloc_strvec(char *string); 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); diff --git a/libmultipath/print.c b/libmultipath/print.c index 8151e11..2fb9f4e 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "checkers.h" @@ -31,59 +32,99 @@ #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'}; @@ -94,184 +135,177 @@ snprint_size (char * buff, size_t len, unsigned long long size) 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; @@ -280,16 +314,16 @@ snprint_multipath_vpr (char * buff, size_t len, const struct multipath * mpp) 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; @@ -298,14 +332,14 @@ snprint_multipath_vend (char * buff, size_t len, const struct multipath * mpp) 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; @@ -314,14 +348,14 @@ snprint_multipath_prod (char * buff, size_t len, const struct multipath * mpp) 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; @@ -330,40 +364,40 @@ snprint_multipath_rev (char * buff, size_t len, const struct multipath * mpp) 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; @@ -373,26 +407,26 @@ snprint_multipath_vpd_data(char * buff, size_t len, 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, @@ -400,159 +434,158 @@ snprint_hcil (char * buff, size_t len, const struct path * pp) } 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]; @@ -560,7 +593,7 @@ snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr) 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); @@ -570,36 +603,36 @@ snprint_host_attr (char * buff, size_t len, const struct path * pp, char *attr) } 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, @@ -611,111 +644,111 @@ snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp) } 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[] = { @@ -782,24 +815,33 @@ struct pathgroup_data pgd[] = { {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 @@ -832,10 +874,10 @@ 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); @@ -843,9 +885,9 @@ _get_path_layout (const struct _vector *gpvec, enum layout_reset reset) 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); } } } @@ -873,10 +915,10 @@ _get_multipath_layout (const struct _vector *gmvec, 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); @@ -884,9 +926,9 @@ _get_multipath_layout (const struct _vector *gmvec, 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); } @@ -905,14 +947,14 @@ mpd_lookup(char wildcard) } 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 * @@ -928,14 +970,14 @@ pd_lookup(char wildcard) } 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 * @@ -951,220 +993,168 @@ pgd_lookup(char wildcard) } 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 && @@ -1172,381 +1162,299 @@ snprint_multipath_style(const struct gen_multipath *gmp, char *style, int len, 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; @@ -1555,496 +1463,373 @@ static int snprint_mptable(const struct config *conf, 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, " \n"); + if ((rc = append_strbuf_str(buff, " \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, " \n"); + if ((rc = append_strbuf_str(buff, " \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; ipathvec, 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; @@ -2066,10 +1851,6 @@ int snprint_devices(struct config *conf, char *buff, size_t len, 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; @@ -2092,41 +1873,27 @@ int snprint_devices(struct config *conf, char *buff, size_t len, } 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) @@ -2135,12 +1902,18 @@ void print_all_paths_custo(vector pathvec, int banner, char *fmt) } 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); } diff --git a/libmultipath/print.h b/libmultipath/print.h index 0042cef..c6674a5 100644 --- a/libmultipath/print.h +++ b/libmultipath/print.h @@ -2,98 +2,32 @@ #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 { @@ -106,37 +40,35 @@ void _get_path_layout (const struct _vector *gpvec, 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); @@ -144,14 +76,13 @@ void _print_multipath_topology (const struct gen_multipath * gmp, _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 */ diff --git a/libmultipath/prioritizers/weightedpath.c b/libmultipath/prioritizers/weightedpath.c index 916970d..ea03fc3 100644 --- a/libmultipath/prioritizers/weightedpath.c +++ b/libmultipath/prioritizers/weightedpath.c @@ -35,52 +35,37 @@ #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; @@ -101,24 +86,22 @@ int prio_path_weight(struct path *pp, char *prio_args) } 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; } @@ -131,7 +114,8 @@ int prio_path_weight(struct path *pp, char *prio_args) 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); } @@ -139,7 +123,6 @@ int prio_path_weight(struct path *pp, char *prio_args) } } - FREE(arg); return priority; } diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index b7b3379..b287667 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -24,6 +24,7 @@ #include "prioritizers/alua_rtpg.h" #include "prkey.h" #include "propsel.h" +#include "strbuf.h" #include #include @@ -191,7 +192,7 @@ out: 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); @@ -199,15 +200,16 @@ int select_rr_weight(struct config *conf, struct multipath * mp) 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); @@ -215,8 +217,9 @@ int select_pgfailback(struct config *conf, struct multipath * mp) 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; } @@ -339,7 +342,7 @@ void reconcile_features_with_options(const char *id, char **features, int* no_pa { 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; @@ -360,17 +363,15 @@ void reconcile_features_with_options(const char *id, char **features, int* no_pa 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); } @@ -704,7 +705,7 @@ out: 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); @@ -716,10 +717,10 @@ int select_no_path_retry(struct config *conf, struct multipath *mp) 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); @@ -770,22 +771,23 @@ int select_minio(struct config *conf, struct multipath *mp) 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); @@ -793,15 +795,16 @@ int select_dev_loss(struct config *conf, struct multipath *mp) 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); @@ -810,8 +813,9 @@ int select_eh_deadline(struct config *conf, struct multipath *mp) /* 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; } @@ -833,7 +837,7 @@ out: 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; @@ -851,10 +855,10 @@ out: 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; } @@ -951,16 +955,16 @@ use_delay_watch_checks(struct config *conf, struct multipath *mp) { 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; } @@ -969,23 +973,23 @@ use_delay_wait_checks(struct config *conf, struct multipath *mp) { 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); @@ -1001,16 +1005,17 @@ int select_delay_checks(struct config *conf, struct multipath *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; } @@ -1029,7 +1034,7 @@ static int san_path_deprecated_warned; 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; @@ -1042,9 +1047,9 @@ int select_san_path_err_threshold(struct config *conf, struct multipath *mp) 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; } @@ -1052,7 +1057,7 @@ out: 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; @@ -1065,9 +1070,9 @@ int select_san_path_err_forget_rate(struct config *conf, struct multipath *mp) 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; @@ -1076,7 +1081,7 @@ out: 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; @@ -1089,9 +1094,9 @@ int select_san_path_err_recovery_time(struct config *conf, struct multipath *mp) 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; @@ -1100,7 +1105,7 @@ out: 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); @@ -1114,17 +1119,16 @@ out: 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); @@ -1132,17 +1136,16 @@ int select_marginal_path_err_rate_threshold(struct config *conf, struct multipat 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); @@ -1150,17 +1153,17 @@ int select_marginal_path_err_recheck_gap_time(struct config *conf, struct multip 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); @@ -1168,10 +1171,9 @@ int select_marginal_path_double_failed_time(struct config *conf, struct multipat 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; } @@ -1215,7 +1217,7 @@ out: 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); @@ -1223,8 +1225,9 @@ int select_ghost_delay (struct config *conf, struct multipath * mp) 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; } diff --git a/libmultipath/strbuf.c b/libmultipath/strbuf.c new file mode 100644 index 0000000..a24a57d --- /dev/null +++ b/libmultipath/strbuf.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 2021 SUSE LLC + * SPDX-License-Identifier: GPL-2.0-only + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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; +} diff --git a/libmultipath/strbuf.h b/libmultipath/strbuf.h new file mode 100644 index 0000000..5903572 --- /dev/null +++ b/libmultipath/strbuf.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2021 SUSE LLC + * SPDX-License-Identifier: GPL-2.0-only + */ +#ifndef _STRBUF_H +#define _STRBUF_H +#include +#include + +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 diff --git a/libmultipath/structs.c b/libmultipath/structs.c index 8751fc2..6e5a103 100644 --- a/libmultipath/structs.c +++ b/libmultipath/structs.c @@ -96,7 +96,7 @@ alloc_path (void) 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; diff --git a/libmultipath/structs.h b/libmultipath/structs.h index c8447e5..399540e 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -13,7 +13,6 @@ #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 @@ -178,6 +177,8 @@ enum scsi_protocol { SCSI_PROTOCOL_UNSPEC = 0xf, /* No specific protocol */ }; +#define SCSI_INVALID_LUN ~0ULL + enum no_undef_states { NU_NO = -1, NU_UNDEF = 0, @@ -258,7 +259,7 @@ struct sg_id { 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; diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c index d242c06..85d97ac 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c @@ -45,8 +45,8 @@ int update_mpp_paths(struct multipath *mpp, vector pathvec) /* * 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 && @@ -334,7 +334,7 @@ void set_path_removed(struct path *pp) } void -remove_map(struct multipath *mpp, vector pathvec, vector mpvec, int purge_vec) +remove_map(struct multipath *mpp, vector pathvec, vector mpvec) { int i; @@ -343,7 +343,7 @@ remove_map(struct multipath *mpp, vector pathvec, vector mpvec, int purge_vec) */ orphan_paths(pathvec, mpp, "map removed internally"); - if (purge_vec && + if (mpvec && (i = find_slot(mpvec, (void *)mpp)) != -1) vector_del_slot(mpvec, i); @@ -354,12 +354,12 @@ 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) +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); } } @@ -373,7 +373,7 @@ remove_maps(struct vectors * vecs) 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--; } @@ -416,12 +416,12 @@ int 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; @@ -429,14 +429,17 @@ update_multipath_table (struct multipath *mpp, vector pathvec, int flags) 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); @@ -701,7 +704,7 @@ struct multipath *add_map_with_path(struct vectors *vecs, struct path *pp, return mpp; out: - remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC); + remove_map(mpp, vecs->pathvec, vecs->mpvec); return NULL; } diff --git a/libmultipath/structs_vec.h b/libmultipath/structs_vec.h index ee2b723..29ede45 100644 --- a/libmultipath/structs_vec.h +++ b/libmultipath/structs_vec.h @@ -27,15 +27,8 @@ int update_mpp_paths(struct multipath * mpp, vector pathvec); 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 *); diff --git a/libmultipath/sysfs.c b/libmultipath/sysfs.c index 7a2af1e..9ff145f 100644 --- a/libmultipath/sysfs.c +++ b/libmultipath/sysfs.c @@ -358,7 +358,7 @@ bool sysfs_is_multipathed(struct path *pp, bool set_wwid) strchop(pp->wwid); } } - } else if (nr < 0) + } else if (nr < 0) condlog(1, "%s: error reading from %s: %m", __func__, pathbuf); diff --git a/libmultipath/uevent.c b/libmultipath/uevent.c index d3061bf..4265904 100644 --- a/libmultipath/uevent.c +++ b/libmultipath/uevent.c @@ -569,7 +569,7 @@ int uevent_listen(struct udev *udev) } 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); diff --git a/libmultipath/util.c b/libmultipath/util.c index 0e37f3f..ea85840 100644 --- a/libmultipath/util.c +++ b/libmultipath/util.c @@ -223,8 +223,8 @@ setup_thread_attr(pthread_attr_t *attr, size_t stacksize, int detached) 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) { @@ -455,3 +455,8 @@ int should_exit(void) { return 0; } + +void cleanup_charp(char **p) +{ + free(*p); +} diff --git a/libmultipath/util.h b/libmultipath/util.h index e9b48f9..89027f8 100644 --- a/libmultipath/util.h +++ b/libmultipath/util.h @@ -123,4 +123,5 @@ static inline void clear_bit_in_bitfield(unsigned int bit, struct bitfield *bf) ___p; \ }) +void cleanup_charp(char **p); #endif /* _UTIL_H */ diff --git a/libmultipath/version.h b/libmultipath/version.h index 6e68199..34e1d90 100644 --- a/libmultipath/version.h +++ b/libmultipath/version.h @@ -20,8 +20,8 @@ #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" diff --git a/multipath/main.c b/multipath/main.c index ef89c7c..65ece83 100644 --- a/multipath/main.c +++ b/multipath/main.c @@ -191,14 +191,14 @@ get_dm_mpvec (enum mpath_cmds cmd, vector curmp, vector pathvec, char * refwwid) 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; } @@ -456,6 +456,7 @@ configure (struct config *conf, enum mpath_cmds cmd, { vector curmp = NULL; vector pathvec = NULL; + vector newmp = NULL; int r = RTVL_FAIL, rc; int di_flag = 0; char * refwwid = NULL; @@ -466,9 +467,9 @@ configure (struct config *conf, enum mpath_cmds cmd, */ 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; } @@ -570,14 +571,27 @@ configure (struct config *conf, enum mpath_cmds cmd, /* * 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; } @@ -823,6 +837,7 @@ main (int argc, char *argv[]) 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); diff --git a/multipath/multipath.8 b/multipath/multipath.8 index 5b29a5d..17df59f 100644 --- a/multipath/multipath.8 +++ b/multipath/multipath.8 @@ -225,7 +225,7 @@ Dry run, do not create or update devmaps. .TP .B \-e Enable all foreign libraries. This overrides the -.I enable_foreign +.I enable_foreign option from \fBmultipath.conf(5)\fR. . .TP diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 index 064e482..d6b8c7f 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 @@ -1251,7 +1251,7 @@ The default is: in \fB/sys/block//queue/max_sectors_kb\fR 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 diff --git a/multipathd/Makefile b/multipathd/Makefile index d053c1e..393b6cb 100644 --- a/multipathd/Makefile +++ b/multipathd/Makefile @@ -16,6 +16,8 @@ LDFLAGS += $(BIN_LDFLAGS) 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) diff --git a/multipathd/cli.c b/multipathd/cli.c index bdc9fb1..4d6c37c 100644 --- a/multipathd/cli.c +++ b/multipathd/cli.c @@ -16,6 +16,7 @@ #include "mpath_cmd.h" #include "cli.h" #include "debug.h" +#include "strbuf.h" static vector keys; static vector handlers; @@ -354,107 +355,80 @@ alloc_handlers (void) } 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 diff --git a/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index 1de6ad8..6d3a0ae 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -30,55 +30,43 @@ #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; } @@ -86,28 +74,14 @@ int 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; } @@ -115,84 +89,51 @@ int 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)) { @@ -200,21 +141,11 @@ show_maps_json (char ** r, int * len, struct vectors * vecs) } } - 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; } @@ -222,28 +153,16 @@ int 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; } @@ -414,58 +333,40 @@ cli_list_maps_json (void * v, char ** reply, int * len, void * data) 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; } @@ -473,26 +374,13 @@ int 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; } @@ -500,51 +388,34 @@ int 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; } @@ -752,7 +623,8 @@ cli_add_path (void * v, char ** reply, int * len, void * data) /* 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 { @@ -801,8 +673,7 @@ cli_add_path (void * v, char ** reply, int * len, void * data) } 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; } @@ -813,6 +684,7 @@ cli_del_path (void * v, char ** reply, int * len, void * data) 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); @@ -821,7 +693,12 @@ cli_del_path (void * v, char ** reply, int * len, void * data) 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 @@ -845,8 +722,7 @@ cli_add_map (void * v, char ** reply, int * len, void * data) 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; } @@ -961,12 +837,12 @@ cli_reload(void *v, char **reply, int *len, void *data) 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; @@ -1204,7 +1080,7 @@ cli_reconfigure(void * v, char ** reply, int * len, void * data) 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; @@ -1355,34 +1231,20 @@ cli_fail(void * v, char ** reply, int * len, void * data) 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; } @@ -1397,34 +1259,20 @@ cli_list_blacklist (void * v, char ** reply, int * len, void * data) 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; } @@ -1529,7 +1377,7 @@ cli_getprkey(void * v, char ** reply, int * len, void * data) 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); @@ -1542,17 +1390,16 @@ cli_getprkey(void * v, char ** reply, int * len, void * data) 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; } diff --git a/multipathd/dmevents.c b/multipathd/dmevents.c index f52f597..f035ee7 100644 --- a/multipathd/dmevents.c +++ b/multipathd/dmevents.c @@ -359,7 +359,7 @@ static int dmevent_loop (void) 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); diff --git a/multipathd/main.c b/multipathd/main.c index 102946b..3aff241 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -385,7 +385,7 @@ remove_map_and_stop_waiter(struct multipath *mpp, struct vectors *vecs) 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 @@ -489,7 +489,7 @@ static int 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); @@ -502,13 +502,15 @@ retry: 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; } @@ -516,7 +518,7 @@ 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; } @@ -570,7 +572,7 @@ add_map_without_path (struct vectors *vecs, const char *alias) return mpp; out: - remove_map(mpp, vecs->pathvec, vecs->mpvec, PURGE_VEC); + remove_map(mpp, vecs->pathvec, vecs->mpvec); return NULL; } @@ -660,7 +662,6 @@ flush_map(struct multipath * mpp, struct vectors * vecs, int nopaths) else condlog(2, "%s: map flushed", mpp->alias); - orphan_paths(vecs->pathvec, mpp, "map flushed"); remove_map_and_stop_waiter(mpp, vecs); return 0; @@ -839,7 +840,7 @@ handle_path_wwid_change(struct path *pp, struct vectors *vecs) 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); } @@ -949,8 +950,8 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) * 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 @@ -961,6 +962,7 @@ uev_add_path (struct uevent *uev, struct vectors * vecs, int need_do_map) 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 @@ -1028,7 +1030,7 @@ int 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; @@ -1104,7 +1106,7 @@ rescan: /* * 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; @@ -1129,6 +1131,8 @@ rescan: 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) @@ -1158,7 +1162,7 @@ rescan: 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; @@ -1168,7 +1172,6 @@ static int 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); @@ -1178,27 +1181,31 @@ uev_remove_path (struct uevent *uev, struct vectors * vecs, int need_do_map) 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 @@ -1210,13 +1217,9 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) } /* - * 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); @@ -1243,7 +1246,6 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) condlog(2, "%s: removed map after" " removing all paths", alias); - retval = 0; /* flush_map() has freed the path */ goto out; } @@ -1252,7 +1254,7 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) */ } - 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; @@ -1260,11 +1262,14 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) 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 */ @@ -1273,7 +1278,7 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_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 @@ -1281,12 +1286,12 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) 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", @@ -1302,8 +1307,10 @@ out: 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 @@ -1356,7 +1363,6 @@ uev_update_path (struct uevent *uev, struct vectors * vecs) 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 { @@ -1463,7 +1469,7 @@ map_discovery (struct vectors * vecs) 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--; } @@ -1938,7 +1944,7 @@ int update_prio(struct path *pp, int refresh_all) 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; @@ -1956,7 +1962,7 @@ static int reload_map(struct vectors *vecs, struct multipath *mpp, int refresh, } } } - 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; } @@ -2012,7 +2018,7 @@ static int check_path_reinstate_state(struct path * pp) { /* 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)) { @@ -2700,7 +2706,7 @@ configure (struct vectors * vecs) */ 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; } @@ -3031,6 +3037,10 @@ static void cleanup_threads(void) 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(). * @@ -3040,6 +3050,9 @@ static void cleanup_threads(void) * 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) { @@ -3072,6 +3085,7 @@ static void cleanup_rcu(void) } rcu_unregister_thread(); } +#endif /* URCU_VERSION */ static void cleanup_child(void) { @@ -3116,9 +3130,14 @@ child (__attribute__((unused)) void *param) 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); diff --git a/multipathd/main.h b/multipathd/main.h index ddd953f..bc1f938 100644 --- a/multipathd/main.h +++ b/multipathd/main.h @@ -13,6 +13,20 @@ enum daemon_status { 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; diff --git a/multipathd/multipathd.service b/multipathd/multipathd.service index 7d547fa..0b2ac81 100644 --- a/multipathd/multipathd.service +++ b/multipathd/multipathd.service @@ -8,6 +8,7 @@ DefaultDependencies=no Conflicts=shutdown.target ConditionKernelCommandLine=!nompath ConditionKernelCommandLine=!multipath=off +ConditionVirtualization=!container [Service] Type=notify diff --git a/tests/Makefile b/tests/Makefile index e70c8ed..8cbc4b7 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -13,7 +13,7 @@ CFLAGS += $(BIN_CFLAGS) -I$(multipathdir) -I$(mpathcmddir) \ 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) @@ -63,6 +63,7 @@ mpathvalid-test_OBJDEPS := ../libmpathvalid/mpath_valid.o ifneq ($(DIO_TEST_DEV),) directio-test_LIBDEPS := -laio endif +strbuf-test_OBJDEPS := ../libmultipath/strbuf.o %.o: %.c $(CC) $(CFLAGS) $($*-test_FLAGS) -c -o $@ $< diff --git a/tests/alias.c b/tests/alias.c index 7e7c187..3ca6c28 100644 --- a/tests/alias.c +++ b/tests/alias.c @@ -81,12 +81,25 @@ int __wrap_dm_get_uuid(const char *name, char *uuid, int uuid_len) 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"); } @@ -97,7 +110,7 @@ static void fd_mpathz(void **state) 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"); } @@ -107,7 +120,7 @@ static void fd_mpathaa(void **state) 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"); } @@ -117,7 +130,7 @@ static void fd_mpathzz(void **state) 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"); } @@ -127,7 +140,7 @@ static void fd_mpathaaa(void **state) 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"); } @@ -137,7 +150,7 @@ static void fd_mpathzzz(void **state) 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"); } @@ -147,7 +160,7 @@ static void fd_mpathaaaa(void **state) 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"); } @@ -157,7 +170,7 @@ static void fd_mpathzzzz(void **state) 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"); @@ -169,7 +182,7 @@ static void fd_mpath_max(void **state) 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); } @@ -180,7 +193,7 @@ static void fd_mpath_max1(void **state) 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); } @@ -189,7 +202,7 @@ static void fd_mpath_short(void **state) 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); } @@ -198,7 +211,7 @@ static void fd_mpath_short1(void **state) 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); } @@ -323,7 +336,7 @@ static void sd_fd_many(void **state) 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); @@ -338,7 +351,7 @@ static void sd_fd_random(void **state) 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); diff --git a/tests/dmevents.c b/tests/dmevents.c index 204cf1d..68c4ad4 100644 --- a/tests/dmevents.c +++ b/tests/dmevents.c @@ -323,12 +323,10 @@ int __wrap_poll(struct pollfd *fds, nfds_t nfds, int timeout) 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 diff --git a/tests/strbuf.c b/tests/strbuf.c new file mode 100644 index 0000000..43a477d --- /dev/null +++ b/tests/strbuf.c @@ -0,0 +1,412 @@ +/* + * Copyright (c) 2021 SUSE LLC + * SPDX-License-Identifier: GPL-2.0-only + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#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; +}