git: c759aca606ce - main - devinfo: Add support for libxo
- Reply: Phil Shafer : "Re: git: c759aca606ce - main - devinfo: Add support for libxo"
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Tue, 06 May 2025 22:02:24 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=c759aca606cee8352c1d739bf7a762c8a2ed2012
commit c759aca606cee8352c1d739bf7a762c8a2ed2012
Author: ktullavik <ktullavik@gmail.com>
AuthorDate: 2024-10-17 21:24:27 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2025-05-06 22:01:47 +0000
devinfo: Add support for libxo
Reviewed by: imp
Pull-Request: https://github.com/freebsd/freebsd-src/pull/1480
Closes: https://github.com/freebsd/freebsd-src/pull/1480
---
usr.sbin/devinfo/Makefile | 2 +-
usr.sbin/devinfo/devinfo.c | 217 +++++++++++++++++++++++++++++++++++++--------
2 files changed, 181 insertions(+), 38 deletions(-)
diff --git a/usr.sbin/devinfo/Makefile b/usr.sbin/devinfo/Makefile
index f6506c176c9c..55b234f18363 100644
--- a/usr.sbin/devinfo/Makefile
+++ b/usr.sbin/devinfo/Makefile
@@ -2,6 +2,6 @@ PACKAGE= devmatch
PROG= devinfo
MAN= devinfo.8
-LIBADD= devinfo
+LIBADD= xo devinfo
.include <bsd.prog.mk>
diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c
index 43d88481d903..629a04ba6687 100644
--- a/usr.sbin/devinfo/devinfo.c
+++ b/usr.sbin/devinfo/devinfo.c
@@ -4,6 +4,7 @@
* Copyright (c) 2000, 2001 Michael Smith
* Copyright (c) 2000 BSDi
* All rights reserved.
+ * Copyright (c) 2024 KT Ullavik
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -40,12 +41,18 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+
+#include <libxo/xo.h>
#include "devinfo.h"
static bool rflag;
static bool vflag;
+static int open_tag_count;
+static char *last_res;
static void print_indent(int);
+static void print_kvlist(char *);
+static char* xml_safe_string(char *);
static void print_resource(struct devinfo_res *);
static int print_device_matching_resource(struct devinfo_res *, void *);
static int print_device_rman_resources(struct devinfo_rman *, void *);
@@ -74,7 +81,46 @@ print_indent(int n)
n = MIN((size_t)n, sizeof(buffer) - 1);
memset(buffer, ' ', n);
buffer[n] = '\0';
- printf("%s", buffer);
+ xo_emit("{Pa:%s}", buffer);
+}
+
+/*
+ * Takes a list of key-value pairs in the form
+ * "key1=val1 key2=val2 ..." and prints them according
+ * to xo formatting.
+ */
+static void
+print_kvlist(char *s)
+{
+ char *kv;
+ char *copy;
+
+ if ((copy = strdup(s)) == NULL)
+ xo_err(1, "No memory!");
+
+ while ((kv = strsep(©, " ")) != NULL) {
+ char* k = strsep(&kv, "=");
+ xo_emit("{ea:%s/%s} {d:%s}={d:%s}", k, kv, k, kv);
+ }
+ free(copy);
+}
+
+static char
+*xml_safe_string(char *desc)
+{
+ int i;
+ char *s;
+
+ if ((s = strdup(desc)) == NULL) {
+ xo_err(1, "No memory!");
+ }
+
+ for (i=0; s[i] != '\0'; i++) {
+ if (s[i] == ' ' || s[i] == '/') {
+ s[i] = '-';
+ }
+ }
+ return s;
}
/*
@@ -86,20 +132,28 @@ print_resource(struct devinfo_res *res)
struct devinfo_rman *rman;
bool hexmode;
rman_res_t end;
+ char *safe_desc;
rman = devinfo_handle_to_rman(res->dr_rman);
hexmode = (rman->dm_size > 1000) || (rman->dm_size == 0);
end = res->dr_start + res->dr_size - 1;
+ safe_desc = xml_safe_string(rman->dm_desc);
+ xo_open_instance(safe_desc);
+
if (hexmode) {
- printf("0x%jx", res->dr_start);
+ xo_emit("{:start/0x%jx}", res->dr_start);
if (res->dr_size > 1)
- printf("-0x%jx", end);
+ xo_emit("{D:-}{d:end/0x%jx}", end);
+ xo_emit("{e:end/0x%jx}", end);
} else {
- printf("%ju", res->dr_start);
+ xo_emit("{:start/%ju}", res->dr_start);
if (res->dr_size > 1)
- printf("-%ju", end);
+ xo_emit("{D:-}{d:end/%ju}", end);
+ xo_emit("{e:end/%ju}", end);
}
+ xo_close_instance(safe_desc);
+ free(safe_desc);
}
/*
@@ -121,7 +175,7 @@ print_device_matching_resource(struct devinfo_res *res, void *arg)
return(1);
print_indent(ia->indent);
print_resource(res);
- printf("\n");
+ xo_emit("\n");
}
return(0);
}
@@ -134,6 +188,7 @@ print_device_rman_resources(struct devinfo_rman *rman, void *arg)
{
struct indent_arg *ia = (struct indent_arg *)arg;
int indent;
+ char *safe_desc;
indent = ia->indent;
@@ -143,13 +198,18 @@ print_device_rman_resources(struct devinfo_rman *rman, void *arg)
print_device_matching_resource, ia) != 0) {
/* there are, print header */
+ safe_desc = xml_safe_string(rman->dm_desc);
print_indent(indent);
- printf("%s:\n", rman->dm_desc);
+ xo_emit("{d:%s}:\n", rman->dm_desc);
+ xo_open_list(safe_desc);
/* print resources */
ia->indent = indent + 4;
devinfo_foreach_rman_resource(rman,
print_device_matching_resource, ia);
+
+ xo_close_list(safe_desc);
+ free(safe_desc);
}
ia->indent = indent;
return(0);
@@ -160,20 +220,40 @@ print_device_props(struct devinfo_dev *dev)
{
if (vflag) {
if (*dev->dd_desc) {
- printf(" <%s>", dev->dd_desc);
+ xo_emit(" <{d:%s}>", dev->dd_desc);
+ xo_emit("{e:description/%s}", dev->dd_desc);
}
if (*dev->dd_pnpinfo) {
- printf(" pnpinfo %s", dev->dd_pnpinfo);
+ xo_open_container("pnpinfo");
+ xo_emit("{D: pnpinfo}");
+
+ if ((strcmp(dev->dd_pnpinfo, "unknown") == 0))
+ xo_emit("{D: unknown}");
+ else
+ print_kvlist(dev->dd_pnpinfo);
+
+ xo_close_container("pnpinfo");
}
if (*dev->dd_location) {
- printf(" at %s", dev->dd_location);
+ xo_open_container("location");
+ xo_emit("{D: at}");
+ print_kvlist(dev->dd_location);
+ xo_close_container("location");
}
+
+ // If verbose, then always print state for json/xml.
+ if (!(dev->dd_flags & DF_ENABLED))
+ xo_emit("{e:state/disabled}");
+ else if (dev->dd_flags & DF_SUSPENDED)
+ xo_emit("{e:state/suspended}");
+ else
+ xo_emit("{e:state/enabled}");
}
if (!(dev->dd_flags & DF_ENABLED))
- printf(" (disabled)");
+ xo_emit("{D: (disabled)}");
else if (dev->dd_flags & DF_SUSPENDED)
- printf(" (suspended)");
+ xo_emit("{D: (suspended)}");
}
/*
@@ -183,16 +263,20 @@ static int
print_device(struct devinfo_dev *dev, void *arg)
{
struct indent_arg ia;
- int indent;
+ int indent, ret;
+ const char* devname = dev->dd_name[0] ? dev->dd_name : "unknown";
bool printit = vflag || (dev->dd_name[0] != 0 &&
dev->dd_state >= DS_ATTACHED);
if (printit) {
indent = (int)(intptr_t)arg;
print_indent(indent);
- printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown");
+
+ xo_open_container(devname);
+ xo_emit("{d:%s}", devname);
+
print_device_props(dev);
- printf("\n");
+ xo_emit("\n");
if (rflag) {
ia.indent = indent + 4;
ia.arg = dev;
@@ -201,8 +285,13 @@ print_device(struct devinfo_dev *dev, void *arg)
}
}
- return(devinfo_foreach_device_child(dev, print_device,
+ ret = (devinfo_foreach_device_child(dev, print_device,
(void *)((char *)arg + 2)));
+
+ if (printit) {
+ xo_close_container(devname);
+ }
+ return(ret);
}
/*
@@ -214,6 +303,7 @@ print_rman_resource(struct devinfo_res *res, void *arg __unused)
struct devinfo_dev *dev;
struct devinfo_rman *rman;
rman_res_t end;
+ char *res_str, *entry = NULL;
bool hexmode;
dev = devinfo_handle_to_device(res->dr_device);
@@ -221,24 +311,38 @@ print_rman_resource(struct devinfo_res *res, void *arg __unused)
hexmode = (rman->dm_size > 1000) || (rman->dm_size == 0);
end = res->dr_start + res->dr_size - 1;
- printf(" ");
-
if (hexmode) {
if (res->dr_size > 1)
- printf("0x%jx-0x%jx", res->dr_start, end);
+ asprintf(&res_str, "0x%jx-0x%jx", res->dr_start, end);
else
- printf("0x%jx", res->dr_start);
+ asprintf(&res_str, "0x%jx", res->dr_start);
} else {
if (res->dr_size > 1)
- printf("%ju-%ju", res->dr_start, end);
+ asprintf(&res_str, "%ju-%ju", res->dr_start, end);
else
- printf("%ju", res->dr_start);
+ asprintf(&res_str, "%ju", res->dr_start);
+ }
+
+ xo_emit("{P: }");
+
+ if (last_res == NULL) {
+ // First resource
+ xo_open_list(res_str);
+ } else if (strcmp(res_str, last_res) != 0) {
+ // We can't repeat json keys. So we keep an
+ // open list from the last iteration and only
+ // create a new list when see a new resource.
+ xo_close_list(last_res);
+ xo_open_list(res_str);
}
dev = devinfo_handle_to_device(res->dr_device);
if (dev != NULL) {
if (dev->dd_name[0] != 0) {
printf(" (%s)", dev->dd_name);
+ asprintf(&entry, "{el:%s}{D:%s} {D:(%s)}\n",
+ res_str, res_str, dev->dd_name);
+ xo_emit(entry, dev->dd_name);
} else {
printf(" (unknown)");
if (vflag && *dev->dd_pnpinfo)
@@ -247,9 +351,11 @@ print_rman_resource(struct devinfo_res *res, void *arg __unused)
printf(" at %s", dev->dd_location);
}
} else {
- printf(" ----");
+ asprintf(&entry, "{el:%s}{D:%s} {D:----}\n", res_str, res_str);
+ xo_emit(entry, "----");
}
- printf("\n");
+ free(entry);
+ last_res = res_str;
return(0);
}
@@ -259,8 +365,16 @@ print_rman_resource(struct devinfo_res *res, void *arg __unused)
int
print_rman(struct devinfo_rman *rman, void *arg __unused)
{
- printf("%s:\n", rman->dm_desc);
+ char* safe_desc = xml_safe_string(rman->dm_desc);
+
+ xo_emit("{d:%s}:\n", rman->dm_desc);
+ xo_open_container(safe_desc);
+
devinfo_foreach_rman_resource(rman, print_rman_resource, 0);
+
+ xo_close_list(last_res);
+ xo_close_container(safe_desc);
+ free(safe_desc);
return(0);
}
@@ -269,12 +383,17 @@ print_device_path_entry(struct devinfo_dev *dev)
{
const char *devname = dev->dd_name[0] ? dev->dd_name : "unknown";
- printf("%s", devname);
+ xo_open_container(devname);
+ open_tag_count++;
+ xo_emit("{d:%s }", devname);
print_device_props(dev);
if (vflag)
- printf("\n");
+ xo_emit("\n");
}
+/*
+ * Recurse until we find the right dev. On the way up we print path.
+ */
static int
print_device_path(struct devinfo_dev *dev, void *xname)
{
@@ -288,7 +407,7 @@ print_device_path(struct devinfo_dev *dev, void *xname)
rv = devinfo_foreach_device_child(dev, print_device_path, xname);
if (rv == 1) {
- printf(" ");
+ xo_emit("{P: }");
print_device_path_entry(dev);
}
return (rv);
@@ -297,19 +416,26 @@ print_device_path(struct devinfo_dev *dev, void *xname)
static void
print_path(struct devinfo_dev *root, char *path)
{
- if (devinfo_foreach_device_child(root, print_device_path, (void *)path) == 0)
- errx(1, "%s: Not found", path);
+ open_tag_count = 0;
+ if (devinfo_foreach_device_child(root, print_device_path,
+ (void *)path) == 0)
+ xo_errx(1, "%s: Not found", path);
if (!vflag)
- printf("\n");
+ xo_emit("\n");
+
+ while (open_tag_count > 0) {
+ xo_close_container_d();
+ open_tag_count--;
+ }
}
static void __dead2
usage(void)
{
- fprintf(stderr, "%s\n%s\n%s\n",
- "usage: devinfo [-rv]",
- " devinfo -u [-v]",
- " devinfo -p dev [-v]");
+ xo_error(
+ "usage: devinfo [-rv]\n",
+ " devinfo -u [-v]\n",
+ " devinfo -p dev [-v]\n");
exit(1);
}
@@ -321,6 +447,11 @@ main(int argc, char *argv[])
bool uflag;
char *path = NULL;
+ argc = xo_parse_args(argc, argv);
+ if (argc < 0) {
+ exit(1);
+ }
+
uflag = false;
while ((c = getopt(argc, argv, "p:ruv")) != -1) {
switch(c) {
@@ -346,20 +477,32 @@ main(int argc, char *argv[])
if ((rv = devinfo_init()) != 0) {
errno = rv;
- err(1, "devinfo_init");
+ xo_err(1, "devinfo_init");
}
if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL)
- errx(1, "can't find root device");
+ xo_errx(1, "can't find root device");
if (path) {
+ xo_set_flags(NULL, XOF_DTRT);
+ xo_open_container("device-path");
print_path(root, path);
+ xo_close_container("device-path");
} else if (uflag) {
/* print resource usage? */
+ xo_set_flags(NULL, XOF_DTRT);
+ xo_open_container("device-resources");
devinfo_foreach_rman(print_rman, NULL);
+ xo_close_container("device-resources");
} else {
/* print device hierarchy */
+ xo_open_container("device-information");
devinfo_foreach_device_child(root, print_device, (void *)0);
+ xo_close_container("device-information");
+ }
+
+ if (xo_finish() < 0) {
+ exit(1);
}
return(0);
}