git: c8cc568961df - main - Provide an interface that allows GEOM modules to return multiple messages.

From: Kirk McKusick <mckusick_at_FreeBSD.org>
Date: Sun, 20 Feb 2022 05:33:11 UTC
The branch main has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=c8cc568961dfccf3d91821f06f7072437b04edf5

commit c8cc568961dfccf3d91821f06f7072437b04edf5
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2022-02-20 05:30:37 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2022-02-20 05:33:02 +0000

    Provide an interface that allows GEOM modules to return multiple messages.
    
    The gctl_error() function provides GEOM modules with the ability
    to report only a single message. When running with the verbose
    flag, commands that handle multiple devices may want to report a
    message for each of the devices on which it operates. This commit
    adds the gctl_msg() function that can be called multiple times
    to post messages. When finished issuing messages, the application
    must either call gctl_post_messages() or call gctl_error() to cause
    the messages to be reported to the calling process.
    
    Tested by:    Peter Holm
---
 sys/geom/geom.h     |  2 ++
 sys/geom/geom_ctl.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 57 insertions(+), 2 deletions(-)

diff --git a/sys/geom/geom.h b/sys/geom/geom.h
index d48deb0e0ae4..fbd9336b2e50 100644
--- a/sys/geom/geom.h
+++ b/sys/geom/geom.h
@@ -435,6 +435,8 @@ char const *gctl_get_asciiparam(struct gctl_req *req, const char *param);
 void *gctl_get_paraml(struct gctl_req *req, const char *param, int len);
 void *gctl_get_paraml_opt(struct gctl_req *req, const char *param, int len);
 int gctl_error(struct gctl_req *req, const char *fmt, ...) __printflike(2, 3);
+void gctl_msg(struct gctl_req *req, const char *fmt, ...) __printflike(2, 3);
+void gctl_post_messages(struct gctl_req *req);
 struct g_class *gctl_get_class(struct gctl_req *req, char const *arg);
 struct g_geom *gctl_get_geom(struct gctl_req *req, struct g_class *mp, char const *arg);
 struct g_provider *gctl_get_provider(struct gctl_req *req, char const *arg);
diff --git a/sys/geom/geom_ctl.c b/sys/geom/geom_ctl.c
index b0e2673bdc42..c387b9e5102c 100644
--- a/sys/geom/geom_ctl.c
+++ b/sys/geom/geom_ctl.c
@@ -91,18 +91,71 @@ gctl_error(struct gctl_req *req, const char *fmt, ...)
 	if (sbuf_done(req->serror)) {
 		if (!req->nerror)
 			req->nerror = EEXIST;
+#ifdef DIAGNOSTIC
+		printf("gctl_error: buffer closed, message discarded.\n");
+#endif
 		return (req->nerror);
 	}
 	if (!req->nerror)
 		req->nerror = EINVAL;
 
+	/* If this is the last of several messages, indent it on a new line */
+	if (sbuf_len(req->serror) > 0)
+		sbuf_cat(req->serror, "\n\t");
 	va_start(ap, fmt);
 	sbuf_vprintf(req->serror, fmt, ap);
 	va_end(ap);
+	gctl_post_messages(req);
+	return (req->nerror);
+}
+
+/*
+ * The gctl_error() function will only report a single message.
+ * Commands that handle multiple devices may want to report a
+ * message for each of the devices. The gctl_msg() function
+ * can be called multiple times to post messages. When done
+ * the application must either call gctl_post_messages() or
+ * call gctl_error() to cause the messages to be reported to
+ * the calling process.
+ */
+void
+gctl_msg(struct gctl_req *req, const char *fmt, ...)
+{
+	va_list ap;
+
+	if (req == NULL)
+		return;
+	if (sbuf_done(req->serror)) {
+#ifdef DIAGNOSTIC
+		printf("gctl_msg: buffer closed, message discarded.\n");
+#endif
+		return;
+	}
+	/* Put second and later messages indented on a new line */
+	if (sbuf_len(req->serror) > 0)
+		sbuf_cat(req->serror, "\n\t");
+	va_start(ap, fmt);
+	sbuf_vprintf(req->serror, fmt, ap);
+	va_end(ap);
+}
+
+/*
+ * Post the messages to the user.
+ */
+void
+gctl_post_messages(struct gctl_req *req)
+{
+
+	if (sbuf_done(req->serror)) {
+#ifdef DIAGNOSTIC
+		printf("gctl_post_messages: message buffer already closed.\n");
+#endif
+		return;
+	}
 	sbuf_finish(req->serror);
 	if (g_debugflags & G_F_CTLDUMP)
-		printf("gctl %p error \"%s\"\n", req, sbuf_data(req->serror));
-	return (req->nerror);
+		printf("gctl %p message(s) \"%s\"\n", req,
+		    sbuf_data(req->serror));
 }
 
 /*