From patchwork Thu Jul 15 10:52:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379845 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 05DF7C07E96 for ; Thu, 15 Jul 2021 10:54:53 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8FA706128C for ; Thu, 15 Jul 2021 10:54:52 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 8FA706128C Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-459-l3WYwTqANN6R3QKbCB01WQ-1; Thu, 15 Jul 2021 06:54:49 -0400 X-MC-Unique: l3WYwTqANN6R3QKbCB01WQ-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id EBC81101C8A8; Thu, 15 Jul 2021 10:54:44 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CBD2E60BF1; Thu, 15 Jul 2021 10:54:44 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 780851809C9A; Thu, 15 Jul 2021 10:54:44 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqiGu015568 for ; Thu, 15 Jul 2021 06:52:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9727910CD776; Thu, 15 Jul 2021 10:52:44 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast02.extmail.prod.ext.rdu2.redhat.com [10.11.55.18]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 921AC10CD899 for ; Thu, 15 Jul 2021 10:52:41 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id BD8B0800182 for ; Thu, 15 Jul 2021 10:52:41 +0000 (UTC) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-412-HEuunFzuMty_ZyvljR-WgQ-1; Thu, 15 Jul 2021 06:52:38 -0400 X-MC-Unique: HEuunFzuMty_ZyvljR-WgQ-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 88E392266F; Thu, 15 Jul 2021 10:52:37 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 4943813AB7; Thu, 15 Jul 2021 10:52:37 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id OEhHEHUT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:37 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:15 +0200 Message-Id: <20210715105223.30463-2-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqiGu015568 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 1/9] libmultipath: variable-size parameters in dm_get_map() X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck We've seen a crash of multipath in disassemble_map because of a params string exceeding PARAMS_SIZE. While the crash could have been fixed by a simple error check, I believe multipath should be able to work with arbitrary long parameter strings passed from the kernel. The parameter list of dm_get_map() has changed. Bumped ABI version and removed dm_get_map() and some functions from the ABI, which are only called from libmultipath itself. Signed-off-by: Martin Wilck --- libmultipath/devmapper.c | 44 ++++++++++++++++++++----------- libmultipath/devmapper.h | 4 +-- libmultipath/libmultipath.version | 6 +---- libmultipath/structs_vec.c | 11 +++++--- 4 files changed, 38 insertions(+), 27 deletions(-) diff --git a/libmultipath/devmapper.c b/libmultipath/devmapper.c index 945e625..a5194d8 100644 --- a/libmultipath/devmapper.c +++ b/libmultipath/devmapper.c @@ -648,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; @@ -682,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; @@ -761,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; @@ -799,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); @@ -1049,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 */ @@ -1065,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; @@ -1073,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; @@ -1431,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; @@ -1474,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 @@ -1486,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; } @@ -1620,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/libmultipath.version b/libmultipath/libmultipath.version index 0cff311..7567837 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_6.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; diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c index 7539019..24d6fd2 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c @@ -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); From patchwork Thu Jul 15 10:52:16 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379851 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-11.0 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,HELLOMYDEAR,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id B31DEC1B08C for ; Thu, 15 Jul 2021 10:54:58 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 44EDF61380 for ; Thu, 15 Jul 2021 10:54:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 44EDF61380 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-56-oVQo94yWMhCKrLS20MlDMw-1; Thu, 15 Jul 2021 06:54:55 -0400 X-MC-Unique: oVQo94yWMhCKrLS20MlDMw-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2B58E101C8CF; Thu, 15 Jul 2021 10:54:51 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0D03A175B9; Thu, 15 Jul 2021 10:54:51 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D65591809CB4; Thu, 15 Jul 2021 10:54:50 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqjvA015581 for ; Thu, 15 Jul 2021 06:52:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id DD4962087455; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast04.extmail.prod.ext.rdu2.redhat.com [10.11.55.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D4843208BDF1 for ; Thu, 15 Jul 2021 10:52:42 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id DB1EE1078464 for ; Thu, 15 Jul 2021 10:52:41 +0000 (UTC) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-510-S3S7S0k5OASlguxYXKe_BQ-1; Thu, 15 Jul 2021 06:52:39 -0400 X-MC-Unique: S3S7S0k5OASlguxYXKe_BQ-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id CB10F22919; Thu, 15 Jul 2021 10:52:37 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 9281E13AB7; Thu, 15 Jul 2021 10:52:37 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id AJspInUT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:37 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:16 +0200 Message-Id: <20210715105223.30463-3-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqjvA015581 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 2/9] libmultipath: strbuf: simple api for growing string buffers X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Add an API for string buffers that grow in size as text is added. This API will be useful in several places of the multipath-tools code base. Add unit tests for these helpers, too. Signed-off-by: Martin Wilck --- libmultipath/Makefile | 2 +- libmultipath/strbuf.c | 207 +++++++++++++++++++++ libmultipath/strbuf.h | 168 +++++++++++++++++ tests/Makefile | 3 +- tests/strbuf.c | 412 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 790 insertions(+), 2 deletions(-) create mode 100644 libmultipath/strbuf.c create mode 100644 libmultipath/strbuf.h create mode 100644 tests/strbuf.c 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/strbuf.c b/libmultipath/strbuf.c new file mode 100644 index 0000000..8422a50 --- /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 + 1 - (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; + + buf->offs = (char *)mempcpy(buf->buf + buf->offs, str, slen) + - buf->buf; + 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/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/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; +} From patchwork Thu Jul 15 10:52:17 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379855 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 23244C07E96 for ; Thu, 15 Jul 2021 10:55:42 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id AC3B561380 for ; Thu, 15 Jul 2021 10:55:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org AC3B561380 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-220-MN1SUPKROeCi_CbFmfptkw-1; Thu, 15 Jul 2021 06:55:39 -0400 X-MC-Unique: MN1SUPKROeCi_CbFmfptkw-1 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id DB30B188CA20; Thu, 15 Jul 2021 10:55:34 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id BA1FA100EBAD; Thu, 15 Jul 2021 10:55:34 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 5E18F4EA2A; Thu, 15 Jul 2021 10:55:34 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqihG015552 for ; Thu, 15 Jul 2021 06:52:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id 0CC382028759; Thu, 15 Jul 2021 10:52:44 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast05.extmail.prod.ext.rdu2.redhat.com [10.11.55.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 07C98202874F for ; Thu, 15 Jul 2021 10:52:41 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id CD84980015A for ; Thu, 15 Jul 2021 10:52:41 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-506-YuD4UJIIPuWiXRp1ZJWbPQ-1; Thu, 15 Jul 2021 06:52:39 -0400 X-MC-Unique: YuD4UJIIPuWiXRp1ZJWbPQ-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 1434D1FDED; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id D503E13AB7; Thu, 15 Jul 2021 10:52:37 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id YAByMnUT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:37 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:17 +0200 Message-Id: <20210715105223.30463-4-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqihG015552 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 3/9] libmultipath: variable-size parameters in assemble_map() X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Instead of using fixed PARAMS_SIZE-sized arrays for parameters, use dynamically allocated memory. The library version needs to be bumped, because setup_map() argument list has changed. Signed-off-by: Martin Wilck --- libmultipath/configure.c | 18 ++++++------ libmultipath/configure.h | 3 +- libmultipath/dmparser.c | 47 ++++++++++--------------------- libmultipath/dmparser.h | 2 +- libmultipath/libmultipath.version | 5 +++- libmultipath/structs.h | 1 - libmultipath/util.c | 5 ++++ libmultipath/util.h | 1 + multipathd/cli_handlers.c | 4 +-- multipathd/main.c | 20 +++++++------ 10 files changed, 50 insertions(+), 56 deletions(-) diff --git a/libmultipath/configure.c b/libmultipath/configure.c index a6ae335..1227864 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; @@ -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); @@ -1128,14 +1127,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; @@ -1247,8 +1246,7 @@ int coalesce_paths (struct vectors *vecs, vector mpvec, char *refwwid, } verify_paths(mpp); - params[0] = '\0'; - if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + if (setup_map(mpp, ¶ms, vecs)) { remove_map(mpp, vecs->pathvec, vecs->mpvec, KEEP_VEC); continue; } @@ -1260,6 +1258,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 " diff --git a/libmultipath/configure.h b/libmultipath/configure.h index 70cf77a..92a5aba 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); diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c index b306c46..fb09e0a 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"; + struct strbuf __attribute__((cleanup(reset_strbuf))) buff = STRBUF_INIT; 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/libmultipath.version b/libmultipath/libmultipath.version index 7567837..6dd52c2 100644 --- a/libmultipath/libmultipath.version +++ b/libmultipath/libmultipath.version @@ -31,7 +31,7 @@ * The new version inherits the previous ones. */ -LIBMULTIPATH_6.0.0 { +LIBMULTIPATH_7.0.0 { global: /* symbols referenced by multipath and multipathd */ add_foreign; @@ -267,6 +267,9 @@ global: /* added in 4.5.0 */ get_vpd_sgio; trigger_partitions_udev_change; + + /* added in 7.0.0 */ + cleanup_charp; local: *; }; diff --git a/libmultipath/structs.h b/libmultipath/structs.h index c52bcee..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 diff --git a/libmultipath/util.c b/libmultipath/util.c index 0e37f3f..e2fafe8 100644 --- a/libmultipath/util.c +++ b/libmultipath/util.c @@ -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/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index d70e1db..bce40b1 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -972,12 +972,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; diff --git a/multipathd/main.c b/multipathd/main.c index bdd629e..f760643 100644 --- a/multipathd/main.c +++ b/multipathd/main.c @@ -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; } @@ -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,9 @@ rescan: /* * push the map to the device-mapper */ - if (setup_map(mpp, params, PARAMS_SIZE, vecs)) { + free(params); + params = NULL; + 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; @@ -1189,7 +1193,7 @@ ev_remove_path (struct path *pp, struct vectors * vecs, int need_do_map) { struct multipath * mpp; int i, retval = REMOVE_PATH_SUCCESS; - char params[PARAMS_SIZE] = {0}; + char *params __attribute__((cleanup(cleanup_charp))) = NULL; /* * avoid referring to the map of an orphaned path @@ -1250,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; @@ -1940,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; @@ -1958,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; } From patchwork Thu Jul 15 10:52:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379849 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 38487C07E96 for ; Thu, 15 Jul 2021 10:54:58 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id B287261380 for ; Thu, 15 Jul 2021 10:54:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org B287261380 Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-321-NG6E6LDIMW-fquX42gt60Q-1; Thu, 15 Jul 2021 06:54:55 -0400 X-MC-Unique: NG6E6LDIMW-fquX42gt60Q-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 2E11F101C8AD; Thu, 15 Jul 2021 10:54:49 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0BF9F19C66; Thu, 15 Jul 2021 10:54:49 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id CF5A24EA38; Thu, 15 Jul 2021 10:54:48 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqjOM015578 for ; Thu, 15 Jul 2021 06:52:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id D163C103432; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast05.extmail.prod.ext.rdu2.redhat.com [10.11.55.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CBF57103CA2 for ; Thu, 15 Jul 2021 10:52:42 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8BC0180158D for ; Thu, 15 Jul 2021 10:52:42 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-355-8YmbFRysM_uvOzCDdNFMOw-1; Thu, 15 Jul 2021 06:52:39 -0400 X-MC-Unique: 8YmbFRysM_uvOzCDdNFMOw-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 5C4101FDFB; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 218E913AB7; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id SN+aBnYT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:38 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:18 +0200 Message-Id: <20210715105223.30463-5-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqjOM015578 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 4/9] libmultipath: use strbuf in dict.c X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Temporary solution for snprint_keyword(), as print.c hasn't been migrated yet. Signed-off-by: Martin Wilck --- libmultipath/dict.c | 313 ++++++++++++++++++----------------------- libmultipath/dict.h | 19 +-- libmultipath/parser.c | 47 ++++--- libmultipath/parser.h | 15 +- libmultipath/propsel.c | 147 +++++++++---------- 5 files changed, 253 insertions(+), 288 deletions(-) diff --git a/libmultipath/dict.c b/libmultipath/dict.c index dd08abf..e853050 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,18 @@ 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; 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; } - return p - buff; + return 0; } static int uid_attrs_handler(struct config *conf, vector strvec) @@ -526,18 +485,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 +600,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 +646,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 +664,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 +743,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 +806,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 +845,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 +885,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 +894,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 +965,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 +974,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 +1002,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 +1048,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 +1095,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 +1138,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 +1178,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 +1200,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 +1219,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 +1247,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 +1414,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 +1520,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 +1551,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 +1694,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/parser.c b/libmultipath/parser.c index c70243c..88c7b59 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; @@ -153,42 +154,44 @@ snprint_keyword(char *buff, int len, 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 snprintf(buff, len, "%s", get_strbuf_str(&sbuf)); } static const char quote_marker[] = { '\0', '"', '\0' }; diff --git a/libmultipath/parser.h b/libmultipath/parser.h index 06666cc..e8b6eb2 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) 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; } From patchwork Thu Jul 15 10:52:19 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379853 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0E0C9C47E48 for ; Thu, 15 Jul 2021 10:54:59 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 72A8E613BC for ; Thu, 15 Jul 2021 10:54:58 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 72A8E613BC Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-417-vcCSt2AfMH-NOQh9Z0LndA-1; Thu, 15 Jul 2021 06:54:54 -0400 X-MC-Unique: vcCSt2AfMH-NOQh9Z0LndA-1 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0AB98101C8BB; Thu, 15 Jul 2021 10:54:48 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D72205D6AB; Thu, 15 Jul 2021 10:54:47 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id A448A1809CB4; Thu, 15 Jul 2021 10:54:47 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqnOZ015644 for ; Thu, 15 Jul 2021 06:52:49 -0400 Received: by smtp.corp.redhat.com (Postfix) id 863D3103CB4; Thu, 15 Jul 2021 10:52:49 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast03.extmail.prod.ext.rdu2.redhat.com [10.11.55.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 7E5F6103CC8 for ; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 647278037A4 for ; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-219-3x1GpDgOP5aOmTqYvky3dg-1; Thu, 15 Jul 2021 06:52:40 -0400 X-MC-Unique: 3x1GpDgOP5aOmTqYvky3dg-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id BCF0F22997; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 7092A13AB7; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id GNCUGXYT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:38 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:19 +0200 Message-Id: <20210715105223.30463-6-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqnOZ015644 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 5/9] libmultipath: use strbuf in print.c X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Use the strbuf API in print.c, wherever growing string buffers are appropriate. This requires a large amount of changes in print.c itself, and in other files that use functions from print.c. It makes no sense to separate this into smaller patches though, as the various snprint_xyz() functions depend on each other, and need to use similar prototypes. libmultipath version must be bumped, as all the printing functions have changed prototypes. Also, add the required strbuf functions to the libmultipath API. Change the libmultipath calls in prioritizers, foreign libs, and in multipathd according to the strbuf-related API changes. While working on print.c, I made a couple of other other minor changes: - all snprint_xyz() functions return a negative error in case of failure (most likely is -ENOMEM). In case of success, the number of printed characters is returned. - snprint_progress(): use fill_strbuf() rather than repeated iterations - _snprint_multipath(), _snprint_path(), snprint_multipath_header(), snprint_path_header(), _snprint_pathgroup(): use fill_strbuf() instead of the PAD/NOPAD logic. - _snprint_multipath_topology(): simplified the ASCII art generation for the topology tree somewhat. - snprint_json_xyz(): use fill_strbuf() rather than printing the indent repeatedly. - snprint_blacklist_group(), snprint_blacklist_devgroup(): combined two print statements into one. In cli_handlers.c, fixed the returned values for the "len" parameter in some functions (it's supposed to be the strlen of the reply + 1). Signed-off-by: Martin Wilck --- libmultipath/blacklist.c | 13 +- libmultipath/discovery.c | 13 +- libmultipath/foreign.c | 78 +- libmultipath/foreign.h | 13 +- libmultipath/foreign/nvme.c | 100 +- libmultipath/generic.c | 26 +- libmultipath/generic.h | 17 +- libmultipath/libmultipath.version | 14 +- libmultipath/parser.c | 5 +- libmultipath/parser.h | 2 +- libmultipath/print.c | 1696 +++++++++------------- libmultipath/print.h | 67 +- libmultipath/prioritizers/weightedpath.c | 71 +- multipathd/cli_handlers.c | 345 ++--- 14 files changed, 1000 insertions(+), 1460 deletions(-) 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/discovery.c b/libmultipath/discovery.c index e9f5703..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" }, @@ -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; } @@ -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/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/libmultipath.version b/libmultipath/libmultipath.version index 6dd52c2..1d84d97 100644 --- a/libmultipath/libmultipath.version +++ b/libmultipath/libmultipath.version @@ -31,7 +31,7 @@ * The new version inherits the previous ones. */ -LIBMULTIPATH_7.0.0 { +LIBMULTIPATH_8.0.0 { global: /* symbols referenced by multipath and multipathd */ add_foreign; @@ -273,3 +273,15 @@ global: local: *; }; + +LIBMULTIPATH_8.1.0 { +global: + reset_strbuf; + append_strbuf_str; + get_strbuf_len; + get_strbuf_str; + steal_strbuf_str; + fill_strbuf; + print_strbuf; + truncate_strbuf; +} LIBMULTIPATH_8.0.0; diff --git a/libmultipath/parser.c b/libmultipath/parser.c index 88c7b59..8ca91bf 100644 --- a/libmultipath/parser.c +++ b/libmultipath/parser.c @@ -150,7 +150,7 @@ 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; @@ -191,7 +191,8 @@ snprint_keyword(char *buff, int len, char *fmt, struct keyword *kw, } } while (*fmt++); out: - return snprintf(buff, len, "%s", get_strbuf_str(&sbuf)); + 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 e8b6eb2..b43d46f 100644 --- a/libmultipath/parser.h +++ b/libmultipath/parser.h @@ -82,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 29ce499..4bf2f7c 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -1,4 +1,4 @@ - /* +/* * Copyright (c) 2005 Christophe Varoqui */ #include @@ -31,59 +31,33 @@ #include "discovery.h" #include "util.h" #include "foreign.h" +#include "strbuf.h" #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 +68,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 +247,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 +265,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 +281,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 +297,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 +340,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:%" PRIu64, + return print_strbuf(buff, "%i:%i:%i:%" PRIu64, pp->sg_id.host_no, pp->sg_id.channel, pp->sg_id.scsi_id, @@ -400,159 +367,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 +526,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,28 +536,28 @@ 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[42]; @@ -599,7 +565,7 @@ snprint_tgt_wwpn (char * buff, size_t len, const struct path * pp) 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 +577,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 +748,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 +807,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 +818,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 +848,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 +859,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 +880,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 +903,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 +926,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; + 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 = 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] = {}; + 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 = 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; - - do { - if (TAIL <= 0) - break; + int initial_len = get_strbuf_len(line); + const char *f; + struct path_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 = 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,268 +1095,203 @@ 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"); @@ -1445,57 +1303,53 @@ snprint_hwentry (const struct config *conf, if (!rootkw) return 0; - fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) + return rc; + 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; - fwd += snprintf(buff + fwd, len - fwd, "devices {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "devices {\n")) < 0) + return rc; + 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; @@ -1504,49 +1358,44 @@ snprint_mpentry (const struct config *conf, char * buff, int len, if (!rootkw) return 0; - fwd += snprintf(buff + fwd, len - fwd, "\tmultipath {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "\tmultipath {\n")) < 0) + return rc; + 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; - fwd += snprintf(buff + fwd, len - fwd, "multipaths {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "multipaths {\n")) < 0) + return rc; + 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 +1404,397 @@ 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; - 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; - 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; + size_t initial_len = get_strbuf_len(buff); rootkw = find_keyword(conf->keywords, NULL, "blacklist"); if (!rootkw) return 0; - 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; + 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; + 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; + 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; + 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; vector_foreach_slot (conf->blist_device, bled, i) { - fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) + return rc; + 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; + if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, bled)) < 0) + return rc; 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, + "\t\t%k %v\n\t}\n", kw, 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; + size_t initial_len = get_strbuf_len(buff); rootkw = find_keyword(conf->keywords, NULL, "blacklist_exceptions"); if (!rootkw) return 0; - 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; + 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; + 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; + 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; + 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; vector_foreach_slot (conf->elist_device, eled, i) { - fwd += snprintf(buff + fwd, len - fwd, "\tdevice {\n"); - if (fwd >= len) - return len; + if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) + return rc; + 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; + if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, eled)) < 0) + return rc; 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, "\t\t%k %v\n\t}\n", + kw, 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; + if (len) + *len = get_strbuf_len(&buff); + reply = steal_strbuf_str(&buff); - 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 (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 +1816,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 +1838,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 +1867,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..b922812 100644 --- a/libmultipath/print.h +++ b/libmultipath/print.h @@ -2,6 +2,8 @@ #define _PRINT_H #include "dm-generic.h" +struct strbuf; + #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" @@ -25,7 +27,7 @@ #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_INDENT_N 3 #define PRINT_JSON_MAP "{\n" \ " \"name\" : \"%n\",\n" \ " \"uuid\" : \"%w\",\n" \ @@ -79,21 +81,21 @@ 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 +108,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 +144,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 650088b..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:%" PRIu64, 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/multipathd/cli_handlers.c b/multipathd/cli_handlers.c index bce40b1..6d3a0ae 100644 --- a/multipathd/cli_handlers.c +++ b/multipathd/cli_handlers.c @@ -30,6 +30,7 @@ #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) \ @@ -42,49 +43,30 @@ 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; } @@ -92,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; } @@ -121,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)) { @@ -206,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; } @@ -228,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; } @@ -420,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; } @@ -479,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; } @@ -506,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; } @@ -1366,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; } @@ -1408,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; } From patchwork Thu Jul 15 10:52:20 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379847 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5DA5FC1B08C for ; Thu, 15 Jul 2021 10:54:54 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id EE0AD6120A for ; Thu, 15 Jul 2021 10:54:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org EE0AD6120A Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-536-FeUSwv7bNMuBYibkpVS-jQ-1; Thu, 15 Jul 2021 06:54:51 -0400 X-MC-Unique: FeUSwv7bNMuBYibkpVS-jQ-1 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 1C7B4804164; Thu, 15 Jul 2021 10:54:47 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F2B005DEFA; Thu, 15 Jul 2021 10:54:46 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id C56F11809CB3; Thu, 15 Jul 2021 10:54:46 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqjcp015573 for ; Thu, 15 Jul 2021 06:52:45 -0400 Received: by smtp.corp.redhat.com (Postfix) id E811B202874F; Thu, 15 Jul 2021 10:52:44 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast04.extmail.prod.ext.rdu2.redhat.com [10.11.55.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id E3BBB21602AF for ; Thu, 15 Jul 2021 10:52:44 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C837D1078462 for ; Thu, 15 Jul 2021 10:52:44 +0000 (UTC) Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-58-tql8q9LaO3-Wq4zQNcgijA-1; Thu, 15 Jul 2021 06:52:40 -0400 X-MC-Unique: tql8q9LaO3-Wq4zQNcgijA-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 0AC39229A9; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id C37F013D86; Thu, 15 Jul 2021 10:52:38 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id SIPjLXYT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:38 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:20 +0200 Message-Id: <20210715105223.30463-7-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqjcp015573 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 6/9] libmultipath: print.c: fail hard if keywords are not found X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck A failure in find_keyword() means an internal error. Fail hard rather than returning an empty string. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski --- libmultipath/print.c | 101 +++++++++++++++---------------------------- 1 file changed, 35 insertions(+), 66 deletions(-) diff --git a/libmultipath/print.c b/libmultipath/print.c index 4bf2f7c..5b86483 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include "checkers.h" @@ -1294,14 +1295,9 @@ snprint_hwentry (const struct config *conf, 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"); - - if (!rootkw) - return 0; + assert(rootkw); if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) return rc; @@ -1324,8 +1320,7 @@ static int snprint_hwtable(const struct config *conf, struct strbuf *buff, 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; @@ -1355,8 +1350,7 @@ snprint_mpentry (const struct config *conf, struct strbuf *buff, 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; @@ -1387,8 +1381,7 @@ static int snprint_mptable(const struct config *conf, struct strbuf *buff, 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; @@ -1435,8 +1428,7 @@ static int snprint_overrides(const struct config *conf, struct strbuf *buff, size_t initial_len = get_strbuf_len(buff); rootkw = find_keyword(conf->keywords, NULL, "overrides"); - if (!rootkw) - return 0; + assert(rootkw); if ((rc = append_strbuf_str(buff, "overrides {\n")) < 0) return rc; @@ -1461,8 +1453,7 @@ static int snprint_defaults(const struct config *conf, struct strbuf *buff) size_t initial_len = get_strbuf_len(buff); rootkw = find_keyword(conf->keywords, NULL, "defaults"); - if (!rootkw) - return 0; + assert(rootkw); if ((rc = append_strbuf_str(buff, "defaults {\n")) < 0) return rc; @@ -1584,63 +1575,52 @@ static int snprint_blacklist(const struct config *conf, struct strbuf *buff) struct blentry * ble; struct blentry_device * bled; 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); 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; + 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; + 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; + 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; + 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) { - if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) - return rc; - - kw = find_keyword(conf->keywords, rootkw->sub, "vendor"); - if (!kw) - return 0; - if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, bled)) < 0) + if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n", + kw, bled)) < 0) return rc; - kw = find_keyword(conf->keywords, rootkw->sub, "product"); - if (!kw) - return 0; - if ((rc = snprint_keyword(buff, - "\t\t%k %v\n\t}\n", kw, bled)) < 0) + if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n", + pkw, bled)) < 0) return rc; } @@ -1656,63 +1636,52 @@ static int snprint_blacklist_except(const struct config *conf, struct blentry * ele; struct blentry_device * eled; 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); 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; + 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; + 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; + 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; + 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) { - if ((rc = append_strbuf_str(buff, "\tdevice {\n")) < 0) - return rc; - - kw = find_keyword(conf->keywords, rootkw->sub, "vendor"); - if (!kw) - return 0; - if ((rc = snprint_keyword(buff, "\t\t%k %v\n", kw, eled)) < 0) + if ((rc = snprint_keyword(buff, "\tdevice {\n\t\t%k %v\n", + kw, eled)) < 0) return rc; - kw = find_keyword(conf->keywords, rootkw->sub, "product"); - if (!kw) - return 0; if ((rc = snprint_keyword(buff, "\t\t%k %v\n\t}\n", - kw, eled)) < 0) + pkw, eled)) < 0) return rc; } From patchwork Thu Jul 15 10:52:21 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379857 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 870AFC07E96 for ; Thu, 15 Jul 2021 10:56:02 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 052136120A for ; Thu, 15 Jul 2021 10:56:01 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 052136120A Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-1-rD0bSVKdMZi-Zyp13il57w-1; Thu, 15 Jul 2021 06:54:50 -0400 X-MC-Unique: rD0bSVKdMZi-Zyp13il57w-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id B325250750; Thu, 15 Jul 2021 10:54:45 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 994F02C175; Thu, 15 Jul 2021 10:54:45 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 67A611809CAC; Thu, 15 Jul 2021 10:54:45 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqjGo015580 for ; Thu, 15 Jul 2021 06:52:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id DE44D208BDE5; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast03.extmail.prod.ext.rdu2.redhat.com [10.11.55.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D6423208BDF2 for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [207.211.31.120]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 217C980D099 for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-425-3nlOGNJDPwygESHvXelNTw-1; Thu, 15 Jul 2021 06:52:40 -0400 X-MC-Unique: 3nlOGNJDPwygESHvXelNTw-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 419B41FE00; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 0FED313AB7; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id 8Do3AncT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:39 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:21 +0200 Message-Id: <20210715105223.30463-8-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqjGo015580 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 7/9] libmultipath: print.h: move macros to print.c X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Move all macros to print.c that aren't used in other source files. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski --- libmultipath/print.c | 66 +++++++++++++++++++++++++++++++++++++++++ libmultipath/print.h | 70 +------------------------------------------- 2 files changed, 67 insertions(+), 69 deletions(-) diff --git a/libmultipath/print.c b/libmultipath/print.c index 5b86483..6a5c465 100644 --- a/libmultipath/print.c +++ b/libmultipath/print.c @@ -34,6 +34,72 @@ #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)) /* diff --git a/libmultipath/print.h b/libmultipath/print.h index b922812..c6674a5 100644 --- a/libmultipath/print.h +++ b/libmultipath/print.h @@ -2,80 +2,12 @@ #define _PRINT_H #include "dm-generic.h" -struct strbuf; - -#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_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 MAX_LINE_LEN 80 -#define MAX_LINES 64 -#define MAX_FIELD_LEN 128 -#define PROGRESS_LEN 10 +struct strbuf; struct path_data { char wildcard; From patchwork Thu Jul 15 10:52:22 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379839 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1DF1AC07E96 for ; Thu, 15 Jul 2021 10:54:35 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 977B66128C for ; Thu, 15 Jul 2021 10:54:34 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 977B66128C Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-436-wNnNtkJyO8y2WcZDwW6zGg-1; Thu, 15 Jul 2021 06:54:31 -0400 X-MC-Unique: wNnNtkJyO8y2WcZDwW6zGg-1 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 93813100C609; Thu, 15 Jul 2021 10:54:26 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EB34719C66; Thu, 15 Jul 2021 10:54:24 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 29BEE1809C99; Thu, 15 Jul 2021 10:54:21 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqi2w015550 for ; Thu, 15 Jul 2021 06:52:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id F19992028693; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast04.extmail.prod.ext.rdu2.redhat.com [10.11.55.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id EC7BC21602AF for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 142281078466 for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-364-0FNO9UeWNnu8CUvY7w17qQ-1; Thu, 15 Jul 2021 06:52:40 -0400 X-MC-Unique: 0FNO9UeWNnu8CUvY7w17qQ-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id 804D01FE0C; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 4B40213AB7; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id YGvEEHcT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:39 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:22 +0200 Message-Id: <20210715105223.30463-9-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqi2w015550 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 8/9] libmultipath: use strbuf in alias.c. X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck We can avoid some buffer length checks here, too. Also, simplify the implementation of format_devname(). Created a wrapper for the format_devname() test case, to avoid chaning the test cases themselves. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski --- libmultipath/alias.c | 84 +++++++++++++++++++------------------------- tests/alias.c | 41 +++++++++++++-------- 2 files changed, 63 insertions(+), 62 deletions(-) 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/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); From patchwork Thu Jul 15 10:52:23 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Martin Wilck X-Patchwork-Id: 12379841 X-Patchwork-Delegate: christophe.varoqui@free.fr Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-13.8 required=3.0 tests=BAYES_00, HEADER_FROM_DIFFERENT_DOMAINS,INCLUDES_CR_TRAILER,INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 105ADC07E96 for ; Thu, 15 Jul 2021 10:54:49 +0000 (UTC) Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [216.205.24.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 92E676136E for ; Thu, 15 Jul 2021 10:54:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 92E676136E Authentication-Results: mail.kernel.org; dmarc=fail (p=quarantine dis=none) header.from=suse.com Authentication-Results: mail.kernel.org; spf=tempfail smtp.mailfrom=dm-devel-bounces@redhat.com Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-499-DPrymbZ1Ph-qAseQSEBuzw-1; Thu, 15 Jul 2021 06:54:45 -0400 X-MC-Unique: DPrymbZ1Ph-qAseQSEBuzw-1 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 31A5F101C8B4; Thu, 15 Jul 2021 10:54:41 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 13F0B179E6; Thu, 15 Jul 2021 10:54:41 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id EBF7A4EA2F; Thu, 15 Jul 2021 10:54:39 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 16FAqjxb015579 for ; Thu, 15 Jul 2021 06:52:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id DA7A8208BDE9; Thu, 15 Jul 2021 10:52:45 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D433A208BDE6 for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id 8C37B18A01A9 for ; Thu, 15 Jul 2021 10:52:43 +0000 (UTC) Received: from smtp-out2.suse.de (smtp-out2.suse.de [195.135.220.29]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-317-oSNPfADFP1uEPT-u7xnU2g-1; Thu, 15 Jul 2021 06:52:41 -0400 X-MC-Unique: oSNPfADFP1uEPT-u7xnU2g-1 Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out2.suse.de (Postfix) with ESMTPS id B50F41FE0E; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from imap1.suse-dmz.suse.de (imap1.suse-dmz.suse.de [192.168.254.73]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap1.suse-dmz.suse.de (Postfix) with ESMTPS id 8799613D86; Thu, 15 Jul 2021 10:52:39 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap1.suse-dmz.suse.de with ESMTPSA id +NOMH3cT8GDQIAAAGKfGzw (envelope-from ); Thu, 15 Jul 2021 10:52:39 +0000 From: mwilck@suse.com To: Christophe Varoqui , Benjamin Marzinski Date: Thu, 15 Jul 2021 12:52:23 +0200 Message-Id: <20210715105223.30463-10-mwilck@suse.com> In-Reply-To: <20210715105223.30463-1-mwilck@suse.com> References: <20210715105223.30463-1-mwilck@suse.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 16FAqjxb015579 X-loop: dm-devel@redhat.com Cc: dm-devel@redhat.com, Martin Wilck Subject: [dm-devel] [PATCH 9/9] multipathd: use strbuf in cli.c X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=dm-devel-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com From: Martin Wilck Here, too, strbuf can be used to simplify code. Signed-off-by: Martin Wilck Reviewed-by: Benjamin Marzinski --- multipathd/cli.c | 94 ++++++++++++++++++------------------------------ 1 file changed, 34 insertions(+), 60 deletions(-) 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