Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 6 May 2025 22:02:24 GMT
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: c759aca606ce - main - devinfo: Add support for libxo
Message-ID:  <202505062202.546M2O1b042545@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
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(&copy, " ")) != 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);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202505062202.546M2O1b042545>