The branch stable/15 has been updated by mckusick:

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

commit 259264460d8dca4b7c51a73bad101ea78b3209e3
Author:     Kirk McKusick <[email protected]>
AuthorDate: 2025-10-13 21:15:05 +0000
Commit:     Kirk McKusick <[email protected]>
CommitDate: 2025-11-17 20:25:21 +0000

    Add --libxo support for geom status and list sub commands.
    
    Submitted-by: Johan Söllvander
    Differential Revision: https://reviews.freebsd.org/D37615
    Differential Revision: https://reviews.freebsd.org/D53110
    Differential Revision: https://reviews.freebsd.org/D53180
    Differential Revision: https://reviews.freebsd.org/D53313
    
    (cherry picked from commit 0d4642a67e59f8da5e00a05001c342bdad2a806f)
    (cherry-picked from commit 2168e15ee89b4206d8e65a4ea04e4721f60f4060)
    (cherry picked from commit 2f461ddd784b4abdb7f88701d20fc45f658c42f5)
    (cherry picked from commit c174f518c9c8cf3a567c5f60414508ac951a2ae4)
---
 sbin/geom/Makefile    |   2 +-
 sbin/geom/core/geom.c | 254 +++++++++++++++++++++++++++++++++++---------------
 2 files changed, 179 insertions(+), 77 deletions(-)

diff --git a/sbin/geom/Makefile b/sbin/geom/Makefile
index 078503d3ae67..61561ef1ff1b 100644
--- a/sbin/geom/Makefile
+++ b/sbin/geom/Makefile
@@ -9,7 +9,7 @@ MAN=            geom.8
 CFLAGS+=       -I${.CURDIR} -I${.CURDIR}/core
 CFLAGS+=       -DGEOM_CLASS_DIR=\"${GEOM_CLASS_DIR}\"
 
-LIBADD=                geom util
+LIBADD=                geom util xo
 
 .if defined(RESCUE)
 .PATH: ${SRCTOP}/lib/geom/part \
diff --git a/sbin/geom/core/geom.c b/sbin/geom/core/geom.c
index b78021194ddd..51ea52a3e858 100644
--- a/sbin/geom/core/geom.c
+++ b/sbin/geom/core/geom.c
@@ -49,9 +49,12 @@
 #include <assert.h>
 #include <libgeom.h>
 #include <geom.h>
+#include <libxo/xo.h>
 
 #include "misc/subr.h"
 
+#define GEOM_XO_VERSION "1"
+
 #ifdef STATIC_GEOM_CLASSES
 extern uint32_t gpart_version;
 extern struct g_command gpart_class_commands[];
@@ -513,6 +516,7 @@ run_command(int argc, char *argv[])
        gctl_free(req);
        if (verbose)
                printf("Done.\n");
+       xo_finish();
        exit(EXIT_SUCCESS);
 }
 
@@ -810,6 +814,10 @@ main(int argc, char *argv[])
        provider_name = NULL;
        tflag = false;
 
+       argc = xo_parse_args(argc, argv);
+       if (argc < 0)
+               return (argc);
+
        if (strcmp(getprogname(), "geom") == 0) {
                while ((ch = getopt(argc, argv, "hp:t")) != -1) {
                        switch (ch) {
@@ -831,6 +839,7 @@ main(int argc, char *argv[])
                 * Don't adjust argc and argv, it would break get_class().
                 */
        }
+       xo_set_version(GEOM_XO_VERSION);
 
        if (tflag && provider_name != NULL) {
                errx(EXIT_FAILURE,
@@ -839,6 +848,7 @@ main(int argc, char *argv[])
 
        if (provider_name != NULL) {
                list_one_geom_by_provider(provider_name);
+               xo_finish();
                return (0);
        }
 
@@ -882,29 +892,33 @@ find_geom(struct gclass *classp, const char *name)
 }
 
 static void
-list_one_provider(struct gprovider *pp, const char *prefix)
+list_one_provider(struct gprovider *pp, const char *padding)
 {
        struct gconfig *conf;
        char buf[5];
 
-       printf("Name: %s\n", pp->lg_name);
+       xo_emit("{Lcw:Name}{:name}\n", pp->lg_name);
        humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
            HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
-       printf("%sMediasize: %jd (%s)\n", prefix, (intmax_t)pp->lg_mediasize,
-           buf);
-       printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
+       xo_emit("{P:/%s}{Lcw:Mediasize}{:mediasize/%jd} ({N:/%s})\n",
+           padding, (intmax_t)pp->lg_mediasize, buf);
+       xo_emit("{P:/%s}{Lcw:Sectorsize}{:sectorsize/%u}\n",
+           padding, pp->lg_sectorsize);
        if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
-               printf("%sStripesize: %ju\n", prefix, pp->lg_stripesize);
-               printf("%sStripeoffset: %ju\n", prefix, pp->lg_stripeoffset);
+               xo_emit("{P:/%s}{Lcw:Stripesize}{:stripesize/%ju}\n",
+                   padding, pp->lg_stripesize);
+               xo_emit("{P:/%s}{Lcw:Stripeoffset}{:stripeoffset/%ju}\n",
+                   padding, pp->lg_stripeoffset);
        }
-       printf("%sMode: %s\n", prefix, pp->lg_mode);
+       xo_emit("{P:/%s}{Lcw:Mode}{:mode}\n", padding, pp->lg_mode);
        LIST_FOREACH(conf, &pp->lg_config, lg_config) {
-               printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
+               xo_emit("{P:/%s}{Lcwa:}{a:}\n", padding, conf->lg_name,
+                   conf->lg_name, conf->lg_val ? conf->lg_val : "");
        }
 }
 
 static void
-list_one_consumer(struct gconsumer *cp, const char *prefix)
+list_one_consumer(struct gconsumer *cp, const char *padding)
 {
        struct gprovider *pp;
        struct gconfig *conf;
@@ -915,20 +929,24 @@ list_one_consumer(struct gconsumer *cp, const char 
*prefix)
        else {
                char buf[5];
 
-               printf("Name: %s\n", pp->lg_name);
+               xo_emit("{Lcw:Name}{:name}\n", pp->lg_name);
                humanize_number(buf, sizeof(buf), (int64_t)pp->lg_mediasize, "",
                    HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
-               printf("%sMediasize: %jd (%s)\n", prefix,
-                   (intmax_t)pp->lg_mediasize, buf);
-               printf("%sSectorsize: %u\n", prefix, pp->lg_sectorsize);
+               xo_emit("{P:/%s}{Lcw:Mediasize}{:mediasize/%jd} ({N:/%s})\n",
+                   padding, (intmax_t)pp->lg_mediasize, buf);
+               xo_emit("{P:/%s}{Lcw:Sectorsize}{:sectorsize/%u}\n",
+                   padding, pp->lg_sectorsize);
                if (pp->lg_stripesize > 0 || pp->lg_stripeoffset > 0) {
-                       printf("%sStripesize: %ju\n", prefix, 
pp->lg_stripesize);
-                       printf("%sStripeoffset: %ju\n", prefix, 
pp->lg_stripeoffset);
+                       xo_emit("{P:/%s}{Lcw:Stripesize}{:stripesize/%ju}\n",
+                           padding, pp->lg_stripesize);
+                       
xo_emit("{P:/%s}{Lcw:Stripeoffset}{:stripeoffset/%ju}\n",
+                           padding, pp->lg_stripeoffset);
                }
-               printf("%sMode: %s\n", prefix, cp->lg_mode);
+               xo_emit("{P:/%s}{Lcw:Mode}{:mode}\n", padding, pp->lg_mode);
        }
        LIST_FOREACH(conf, &cp->lg_config, lg_config) {
-               printf("%s%s: %s\n", prefix, conf->lg_name, conf->lg_val);
+               xo_emit("{P:/%s}{Lcwa:}{a:}\n", padding, conf->lg_name,
+                   conf->lg_name, conf->lg_val ? conf->lg_val : "");
        }
 }
 
@@ -940,27 +958,36 @@ list_one_geom(struct ggeom *gp)
        struct gconfig *conf;
        unsigned n;
 
-       printf("Geom name: %s\n", gp->lg_name);
+       xo_emit("{Lcw:Geom name}{:name}\n", gp->lg_name);
        LIST_FOREACH(conf, &gp->lg_config, lg_config) {
-               printf("%s: %s\n", conf->lg_name, conf->lg_val);
+               xo_emit("{Lcwa:}{a:}\n", conf->lg_name, conf->lg_name,
+                   conf->lg_val ? conf->lg_val : "");
        }
        if (!LIST_EMPTY(&gp->lg_provider)) {
-               printf("Providers:\n");
+               xo_open_list("providers");
+               xo_emit("{Tc:Providers}\n");
                n = 1;
                LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
-                       printf("%u. ", n++);
+                       xo_emit("{T:/%u}. ", n++);
+                       xo_open_instance("provider");
                        list_one_provider(pp, "   ");
+                       xo_close_instance("provider");
                }
+               xo_close_list("providers");
        }
        if (!LIST_EMPTY(&gp->lg_consumer)) {
-               printf("Consumers:\n");
+               xo_open_list("consumers");
+               xo_emit("{Tc:Consumers}\n");
                n = 1;
                LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
-                       printf("%u. ", n++);
+                       xo_emit("{T:/%u}. ", n++);
+                       xo_open_instance("consumer");
                        list_one_consumer(cp, "   ");
+                       xo_close_instance("consumer");
                }
+               xo_close_list("consumers");
        }
-       printf("\n");
+       xo_emit("\n");
 }
 
 static void
@@ -978,8 +1005,10 @@ list_one_geom_by_provider(const char *provider_name)
        if (gp == NULL)
                errx(EXIT_FAILURE, "Cannot find provider '%s'.", provider_name);
 
-       printf("Geom class: %s\n", gp->lg_class->lg_name);
+       xo_open_container(provider_name);
+       xo_emit("{Lwc:Geom class}{:class}\n", gp->lg_class->lg_name);
        list_one_geom(gp);
+       xo_close_container(provider_name);
 }
 
 static void
@@ -1038,14 +1067,20 @@ std_list(struct gctl_req *req, unsigned flags __unused)
                                    "an instance named '%s'.",
                                    gclass_name, name);
                        }
+                       xo_open_container(gclass_name);
                        list_one_geom(gp);
+                       xo_close_container(gclass_name);
                }
        } else {
+               xo_open_list(gclass_name);
                LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
                        if (LIST_EMPTY(&gp->lg_provider) && !all)
                                continue;
+                       xo_open_instance("geom");
                        list_one_geom(gp);
+                       xo_close_instance("geom");
                }
+               xo_close_list(gclass_name);
        }
        geom_deletetree(&mesh);
 }
@@ -1115,34 +1150,24 @@ status_update_len_prs(struct ggeom *gp, int *name_len, 
int *status_len)
 }
 
 static char *
-status_one_consumer(struct gconsumer *cp)
+status_one_consumer(struct gconsumer *cp, const char *value)
 {
-       static char buf[256];
        struct gprovider *pp;
        struct gconfig *conf;
-       const char *state, *syncr;
+       char *ret;
 
        pp = cp->lg_provider;
        if (pp == NULL)
                return (NULL);
-       state = NULL;
-       syncr = NULL;
+       ret = NULL;
        LIST_FOREACH(conf, &cp->lg_config, lg_config) {
-               if (strcasecmp(conf->lg_name, "state") == 0)
-                       state = conf->lg_val;
-               if (strcasecmp(conf->lg_name, "synchronized") == 0)
-                       syncr = conf->lg_val;
-       }
-       if (state == NULL && syncr == NULL)
-               snprintf(buf, sizeof(buf), "%s", pp->lg_name);
-       else if (state != NULL && syncr != NULL) {
-               snprintf(buf, sizeof(buf), "%s (%s, %s)", pp->lg_name,
-                   state, syncr);
-       } else {
-               snprintf(buf, sizeof(buf), "%s (%s)", pp->lg_name,
-                   state ? state : syncr);
+               if (strcasecmp(conf->lg_name, value) == 0)
+                       ret = conf->lg_val;
        }
-       return (buf);
+
+       if (ret == NULL)
+               return (NULL);
+       return (ret);
 }
 
 static void
@@ -1150,8 +1175,9 @@ status_one_geom(struct ggeom *gp, int script, int 
name_len, int status_len)
 {
        struct gconsumer *cp;
        struct gconfig *conf;
-       const char *name, *status, *component;
-       int gotone;
+       char fmt[64];
+       const char *name, *status, *cstate, *csyncr;
+       int gotone, len;
 
        name = gp->lg_name;
        status = "N/A";
@@ -1161,21 +1187,59 @@ status_one_geom(struct ggeom *gp, int script, int 
name_len, int status_len)
                        break;
                }
        }
-       gotone = 0;
+       gotone = len = 0;
+       xo_open_instance("status");
        LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
-               component = status_one_consumer(cp);
-               if (component == NULL)
+               if (cp->lg_provider == NULL)
                        continue;
+
+               cstate = status_one_consumer(cp, "state");
+               csyncr = status_one_consumer(cp, "synchronized");
+               if (!gotone || script) {
+                       if (!gotone) {
+                               xo_emit("{t:name/%*s}  {t:status/%*s}  ",
+                                   name_len, name, status_len, status);
+                               xo_open_list("components");
+                       } else {
+                               /*
+                                * XXX: running the same xo_emit() as above or
+                                * variations of it will cause the XML/JSON to
+                                * produce extra "components" lists in script
+                                * mode
+                                */
+
+                               snprintf(fmt, sizeof(fmt), "%*s  %*s  ",
+                                   name_len, name, status_len, status);
+                               xo_emit(fmt);
+                       }
+               }
+
+               xo_open_instance("components");
+               if (cstate != NULL && csyncr != NULL) {
+                       xo_emit("{P:/%*s}{:component} ({:state}, 
{:synchronized})\n",
+                           len, "", cp->lg_provider->lg_name, cstate, csyncr);
+               } else if (cstate != NULL) {
+                       xo_emit("{P:/%*s}{:component} ({:state})\n",
+                           len, "", cp->lg_provider->lg_name, cstate);
+               } else if (csyncr != NULL) {
+                       xo_emit("{P:/%*s}{:component} ({:synchronized})\n",
+                           len, "", cp->lg_provider->lg_name, csyncr);
+               } else {
+                       xo_emit("{P:/%*s}{:component}\n",
+                           len, "", cp->lg_provider->lg_name);
+               }
+               xo_close_instance("components");
                gotone = 1;
-               printf("%*s  %*s  %s\n", name_len, name, status_len, status,
-                   component);
-               if (!script)
-                       name = status = "";
+               if (!len && !script)
+                       len = name_len + status_len + 4;
        }
        if (!gotone) {
-               printf("%*s  %*s  %s\n", name_len, name, status_len, status,
-                   "N/A");
+               xo_emit("{t:name/%*s}  {t:status/%*s}  N/A\n",
+                   name_len, name, status_len, status);
+       } else {
+               xo_close_list("components");
        }
+       xo_close_instance("status");
 }
 
 static void
@@ -1184,9 +1248,11 @@ status_one_geom_prs(struct ggeom *gp, int script, int 
name_len, int status_len)
        struct gprovider *pp;
        struct gconsumer *cp;
        struct gconfig *conf;
-       const char *name, *status, *component;
-       int gotone;
+       const char *name, *status, *cstate, *csyncr;
+       char fmt[64];
+       int gotone, len;
 
+       xo_open_instance("status");
        LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
                name = pp->lg_name;
                status = "N/A";
@@ -1202,22 +1268,60 @@ status_one_geom_prs(struct ggeom *gp, int script, int 
name_len, int status_len)
                                break;
                        }
                }
-               gotone = 0;
+               gotone = len = 0;
                LIST_FOREACH(cp, &gp->lg_consumer, lg_consumer) {
-                       component = status_one_consumer(cp);
-                       if (component == NULL)
+                       if (cp->lg_provider == NULL)
                                continue;
+
+                       cstate = status_one_consumer(cp, "state");
+                       csyncr = status_one_consumer(cp, "synchronized");
+                       if (!gotone || script) {
+                               if (!gotone) {
+                                       xo_emit("{t:name/%*s}  {t:status/%*s}  
",
+                                           name_len, name, status_len, status);
+                                       xo_open_list("components");
+                               } else {
+                                       /*
+                                        * XXX: running the same xo_emit() as
+                                        * above or variations of it will
+                                        * cause the XML/JSON to produce
+                                        * extra "components" lists in
+                                        * script mode
+                                        */
+
+                                       snprintf(fmt, sizeof(fmt), "%*s  %*s  ",
+                                           name_len, name, status_len, status);
+                                       xo_emit(fmt);
+                               }
+                       }
+
+                       xo_open_instance("component");
+                       if (cstate != NULL && csyncr != NULL) {
+                               xo_emit("{P:/%*s}{:component} ({:state}, 
{:synchronized})\n",
+                                   len, "", cp->lg_provider->lg_name, cstate, 
csyncr);
+                       } else if (cstate != NULL) {
+                               xo_emit("{P:/%*s}{:component} ({:state})\n",
+                                   len, "", cp->lg_provider->lg_name, cstate);
+                       } else if (csyncr != NULL) {
+                               xo_emit("{P:/%*s}{:component} 
({:synchronized})\n",
+                                   len, "", cp->lg_provider->lg_name, csyncr);
+                       } else {
+                               xo_emit("{P:/%*s}{:component}\n",
+                                   len, "", cp->lg_provider->lg_name);
+                       }
+                       xo_close_instance("component");
                        gotone = 1;
-                       printf("%*s  %*s  %s\n", name_len, name,
-                           status_len, status, component);
-                       if (!script)
-                               name = status = "";
+                       if (!len && !script)
+                               len = name_len + status_len + 4;
                }
                if (!gotone) {
-                       printf("%*s  %*s  %s\n", name_len, name,
-                           status_len, status, "N/A");
+                       xo_emit("{t:name/%*s}  {t:status/%*s}  N/A\n",
+                           name_len, name, status_len, status);
+               } else {
+                       xo_close_list("components");
                }
        }
+       xo_close_instance("status");
 }
 
 static void
@@ -1240,13 +1344,9 @@ std_status(struct gctl_req *req, unsigned flags __unused)
        all = gctl_get_int(req, "all");
        geoms = gctl_get_int(req, "geoms");
        script = gctl_get_int(req, "script");
-       if (script) {
-               name_len = 0;
-               status_len = 0;
-       } else {
-               name_len = strlen("Name");
-               status_len = strlen("Status");
-       }
+       name_len = strlen("Name");
+       status_len = strlen("Status");
+
        if (nargs > 0) {
                for (i = 0, n = 0; i < nargs; i++) {
                        name = gctl_get_ascii(req, "arg%d", i);
@@ -1282,9 +1382,10 @@ std_status(struct gctl_req *req, unsigned flags __unused)
                        goto end;
        }
        if (!script) {
-               printf("%*s  %*s  %s\n", name_len, "Name", status_len, "Status",
-                   "Components");
+               xo_emit("{T:/%*s}  {T:/%*s}  {T:Components}\n",
+                   name_len, "Name", status_len, "Status");
        }
+       xo_open_list(gclass_name);
        if (nargs > 0) {
                for (i = 0; i < nargs; i++) {
                        name = gctl_get_ascii(req, "arg%d", i);
@@ -1312,6 +1413,7 @@ std_status(struct gctl_req *req, unsigned flags __unused)
                        }
                }
        }
+       xo_close_list(gclass_name);
 end:
        geom_deletetree(&mesh);
 }

Reply via email to