From nobody Mon Nov 17 20:25:40 2025 X-Original-To: dev-commits-src-branches@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4d9K4h3X28z6GvFp; Mon, 17 Nov 2025 20:25:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R12" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4d9K4h2tfVz3H91; Mon, 17 Nov 2025 20:25:40 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1763411140; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=CiMu78+MlZSxZXiKfPsdNuzZ7VqQJakw3JuZP5sObv0=; b=PeOqQqNdJcv4kzNPWaJQB4+HVNZbeoBt9ghZFpYFBUdvLcm41hyEKc6v7H27bhurXR5muh DZnxyUxFJnYnM1KqLb9WzlVVs7Hki2zeUc5Eggchh/YyDmIXUrjMH/QFkTV0fYOy4bM03I 8fE6CyL2XufDlawtnvtvxuJJw0g2fdejPNHz82vCYHHbMUX3TIck+r1nV07Q7fhS36KavY NyHSZFzoaVrhHWNk8wYOVruL29kFFjyju3F+Vm3FrhEdkxttJZG77OmJ+4LxPMzHS81ry7 2+49pNAhJCZj/GcgehKb1uc9JbMtCfvBcYv18L3yXZLY+9V2BwpFsJZNtfme1g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1763411140; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=CiMu78+MlZSxZXiKfPsdNuzZ7VqQJakw3JuZP5sObv0=; b=FnoHC6p5XqG+0/ILT+589RxVVMsIYZVdrGmZdkQXejqBxjnesoHCBlf7ldANHvvNIbG1g/ A/cpddBT+G1DsJU8tT7ORl+p2BbP9fISbeip/L4L9i3q90/qs+6jQoeXUepvkv9lKg2KXD xq4CjN81aAkOomgsHjyRedjXjAK3IlrGXJ399C+XmxH1zwqo8BLryZ603FA/2hor9mMlHP kjkwaOV9Sex2EhR3kGSqTGZOyD3kUgqtR/I2XqZNYzvMLKt9zPOgDHS+DuoC8sKlDm2+Ce GAYbAa+pt5bzVVysxermye7XU5Umic2oHvqmkAcixei7GUJhBauMOezIY6LX1g== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1763411140; a=rsa-sha256; cv=none; b=YrkXSsWRpUkJzOZRLR6o3ruPrY65ksk3BqVvVX1H3P0BlNC5PI9RyE4aznLFtOSA8//tjf iKmvJ7MFB0LJWPdQxsV0Fn+6d42XsxhyVcZztJPoYO4KSfLzaVhRgU3z+/DK5KECxTKprb 5X/PuIokofRsvCZcExkSez1dKLYnqRpXRLx8jWWXvpTNBjE0ymOsX54dgPt4+cOIB/MrPZ G+IveT+nkF4kn2zthPGCoiYYphpkF2KZ51A0T2nZRD3ggovSAiol2yjI8poByRbDyDBh1G 7ewmfjalLiQAjYgCNy6WU1UH41ARLohckSijNY1gOcl1pgrxgtFXBIV226EGDg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 4d9K4h2THpz7xs; Mon, 17 Nov 2025 20:25:40 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.18.1/8.18.1) with ESMTP id 5AHKPeA2040634; Mon, 17 Nov 2025 20:25:40 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.18.1/8.18.1/Submit) id 5AHKPeek040631; Mon, 17 Nov 2025 20:25:40 GMT (envelope-from git) Date: Mon, 17 Nov 2025 20:25:40 GMT Message-Id: <202511172025.5AHKPeek040631@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Kirk McKusick Subject: git: 259264460d8d - stable/15 - Add --libxo support for geom status and list sub commands. List-Id: Commits to the stable branches of the FreeBSD src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-branches List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-branches@freebsd.org Sender: owner-dev-commits-src-branches@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: mckusick X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 259264460d8dca4b7c51a73bad101ea78b3209e3 Auto-Submitted: auto-generated The branch stable/15 has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=259264460d8dca4b7c51a73bad101ea78b3209e3 commit 259264460d8dca4b7c51a73bad101ea78b3209e3 Author: Kirk McKusick AuthorDate: 2025-10-13 21:15:05 +0000 Commit: Kirk McKusick 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 #include #include +#include #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); }