diff --git a/usr.sbin/devinfo/Makefile b/usr.sbin/devinfo/Makefile index 55b234f18363..f6506c176c9c 100644 --- a/usr.sbin/devinfo/Makefile +++ b/usr.sbin/devinfo/Makefile @@ -1,7 +1,7 @@ PACKAGE= devmatch PROG= devinfo MAN= devinfo.8 -LIBADD= xo devinfo +LIBADD= devinfo .include diff --git a/usr.sbin/devinfo/devinfo.8 b/usr.sbin/devinfo/devinfo.8 index c34713d367ff..15a6059c166f 100644 --- a/usr.sbin/devinfo/devinfo.8 +++ b/usr.sbin/devinfo/devinfo.8 @@ -1,100 +1,88 @@ .\" .\" SPDX-License-Identifer: BSD-2-Clause .\" .\" Copyright (c) 2002 Hiten Pandya .\" Copyright (c) 2002 Robert N. M. Watson .\" .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR .\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES .\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, .\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT .\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, .\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .Dd August 28, 2025 .Dt DEVINFO 8 .Os .Sh NAME .Nm devinfo .Nd print information about system device configuration .Sh SYNOPSIS .Nm -.Op Fl -libxo .Op Fl rv .Nm -.Op Fl -libxo .Fl p Ar dev Op Fl v .Nm -.Op Fl -libxo .Fl u Op Fl v .Sh DESCRIPTION The .Nm utility, without any arguments, shows the hierarchy of devices available in the system, starting from the .Dq nexus device. .Pp The following options are accepted: -.Bl -tag -width "--libxo" -.It Fl -libxo -Generate output via -.Xr libxo 3 -in a selection of different human and machine readable formats. -See -.Xr xo_options 7 -for details on command line arguments. +.Bl -tag -width indent .It Fl p Ar dev Display the path of .Ar dev back to the root of the device tree. .It Fl r Causes hardware resource information .Pq such as IRQ, I/O ports, I/O memory addresses to be also listed, under each device that has reserved those resources. .It Fl u Displays the same information as with .Fl r but sorts by resource type rather than by device, allowing to review the set of system resources by usage and available resources. I.e., it lists all the IRQ consumers together. .It Fl v Display all devices in the driver tree, not just those that are attached or busy. Without this flag, only those devices that have attached are reported. This flag also displays verbose information about each device. .El .Sh SEE ALSO .Xr systat 1 , .Xr devinfo 3 , -.Xr libxo 3 , -.Xr xo_options 7 , .Xr devctl 8 , .Xr iostat 8 , .Xr pciconf 8 , .Xr vmstat 8 , .Xr devclass 9 , .Xr device 9 .Sh HISTORY The .Nm utility appeared in .Fx 5.0 . .Sh AUTHORS .An Mike Smith Aq Mt msmith@FreeBSD.org diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c index 4163151ec840..43d88481d903 100644 --- a/usr.sbin/devinfo/devinfo.c +++ b/usr.sbin/devinfo/devinfo.c @@ -1,507 +1,365 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * 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 * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Print information about system device configuration. */ #include #include #include #include #include #include #include #include - -#include #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 *); static void print_device_props(struct devinfo_dev *); static int print_device(struct devinfo_dev *, void *); static int print_rman_resource(struct devinfo_res *, void *); static int print_rman(struct devinfo_rman *, void *); static int print_device_path(struct devinfo_dev *, void *); static void print_path(struct devinfo_dev *, char *); static void usage(void); struct indent_arg { int indent; void *arg; }; static void print_indent(int n) { static char buffer[1024]; if (n < 1) return; n = MIN((size_t)n, sizeof(buffer) - 1); memset(buffer, ' ', n); buffer[n] = '\0'; - 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:key/%s}={d:value/%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; + printf("%s", buffer); } /* * Print a resource. */ void 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) { - xo_emit("{:start/0x%jx}", res->dr_start); + printf("0x%jx", res->dr_start); if (res->dr_size > 1) - xo_emit("{D:-}{d:end/0x%jx}", end); - xo_emit("{e:end/0x%jx}", end); + printf("-0x%jx", end); } else { - xo_emit("{:start/%ju}", res->dr_start); + printf("%ju", res->dr_start); if (res->dr_size > 1) - xo_emit("{D:-}{d:end/%ju}", end); - xo_emit("{e:end/%ju}", end); + printf("-%ju", end); } - xo_close_instance(safe_desc); - free(safe_desc); } /* * Print resource information if this resource matches the * given device. * * If the given indent is 0, return an indicator that a matching * resource exists. */ int print_device_matching_resource(struct devinfo_res *res, void *arg) { struct indent_arg *ia = (struct indent_arg *)arg; struct devinfo_dev *dev = (struct devinfo_dev *)ia->arg; if (devinfo_handle_to_device(res->dr_device) == dev) { /* in 'detect' mode, found a match */ if (ia->indent == 0) return(1); print_indent(ia->indent); print_resource(res); - xo_emit("\n"); + printf("\n"); } return(0); } /* * Print resource information for this device and resource manager. */ int 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; /* check whether there are any resources matching this device */ ia->indent = 0; if (devinfo_foreach_rman_resource(rman, print_device_matching_resource, ia) != 0) { /* there are, print header */ - safe_desc = xml_safe_string(rman->dm_desc); print_indent(indent); - xo_emit("<{:description/%s}>\n", rman->dm_desc); - xo_open_list(safe_desc); + printf("%s:\n", rman->dm_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); } static void print_device_props(struct devinfo_dev *dev) { if (vflag) { if (*dev->dd_desc) { - xo_emit("<{:description/%s}>", dev->dd_desc); + printf(" <%s>", dev->dd_desc); } if (*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"); + printf(" pnpinfo %s", dev->dd_pnpinfo); } if (*dev->dd_location) { - xo_open_container("location"); - xo_emit("{D: at}"); - print_kvlist(dev->dd_location); - xo_close_container("location"); + printf(" at %s", dev->dd_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)) - xo_emit("{D: (disabled)}"); + printf(" (disabled)"); else if (dev->dd_flags & DF_SUSPENDED) - xo_emit("{D: (suspended)}"); + printf(" (suspended)"); } /* * Print information about a device. */ static int print_device(struct devinfo_dev *dev, void *arg) { struct indent_arg ia; - int indent, ret; - const char* devname = dev->dd_name[0] ? dev->dd_name : "unknown"; + int indent; bool printit = vflag || (dev->dd_name[0] != 0 && dev->dd_state >= DS_ATTACHED); if (printit) { indent = (int)(intptr_t)arg; print_indent(indent); - - xo_open_container(devname); - xo_emit("{d:devicename/%s}", devname); - + printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown"); print_device_props(dev); - xo_emit("\n"); + printf("\n"); if (rflag) { ia.indent = indent + 4; ia.arg = dev; devinfo_foreach_rman(print_device_rman_resources, (void *)&ia); } } - ret = (devinfo_foreach_device_child(dev, print_device, + return(devinfo_foreach_device_child(dev, print_device, (void *)((char *)arg + 2))); - - if (printit) { - xo_close_container(devname); - } - return(ret); } /* * Print information about a resource under a resource manager. */ int 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); 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; + printf(" "); + if (hexmode) { if (res->dr_size > 1) - asprintf(&res_str, "0x%jx-0x%jx", res->dr_start, end); + printf("0x%jx-0x%jx", res->dr_start, end); else - asprintf(&res_str, "0x%jx", res->dr_start); + printf("0x%jx", res->dr_start); } else { if (res->dr_size > 1) - asprintf(&res_str, "%ju-%ju", res->dr_start, end); + printf("%ju-%ju", res->dr_start, end); else - 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); + printf("%ju", res->dr_start); } 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) printf(" pnpinfo %s", dev->dd_pnpinfo); if (vflag && *dev->dd_location) printf(" at %s", dev->dd_location); } } else { - asprintf(&entry, "{el:%s}{D:%s} {D:----}\n", res_str, res_str); - xo_emit(entry, "----"); + printf(" ----"); } - free(entry); - last_res = res_str; + printf("\n"); return(0); } /* * Print information about a resource manager. */ int print_rman(struct devinfo_rman *rman, void *arg __unused) { - char* safe_desc = xml_safe_string(rman->dm_desc); - - xo_emit("<{:description/%s}\n>", rman->dm_desc); - xo_open_container(safe_desc); - + printf("%s:\n", rman->dm_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); } static void print_device_path_entry(struct devinfo_dev *dev) { const char *devname = dev->dd_name[0] ? dev->dd_name : "unknown"; - xo_open_container(devname); - open_tag_count++; - xo_emit("{:devicename/%s} ", devname); + printf("%s", devname); print_device_props(dev); if (vflag) - xo_emit("\n"); + printf("\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) { const char *name = xname; int rv; if (strcmp(dev->dd_name, name) == 0) { print_device_path_entry(dev); return (1); } rv = devinfo_foreach_device_child(dev, print_device_path, xname); if (rv == 1) { - xo_emit("{P: }"); + printf(" "); print_device_path_entry(dev); } return (rv); } static void print_path(struct devinfo_dev *root, char *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 (devinfo_foreach_device_child(root, print_device_path, (void *)path) == 0) + errx(1, "%s: Not found", path); if (!vflag) - xo_emit("\n"); - - while (open_tag_count > 0) { - xo_close_container_d(); - open_tag_count--; - } + printf("\n"); } static void __dead2 usage(void) { - xo_error( - "usage: devinfo [-rv]\n", - " devinfo -u [-v]\n", - " devinfo -p dev [-v]\n"); + fprintf(stderr, "%s\n%s\n%s\n", + "usage: devinfo [-rv]", + " devinfo -u [-v]", + " devinfo -p dev [-v]"); exit(1); } int main(int argc, char *argv[]) { struct devinfo_dev *root; int c, rv; 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) { case 'p': path = optarg; break; case 'r': rflag = true; break; case 'u': uflag = true; break; case 'v': vflag = true; break; default: usage(); } } if (path && (rflag || uflag)) usage(); if ((rv = devinfo_init()) != 0) { errno = rv; - xo_err(1, "devinfo_init"); + err(1, "devinfo_init"); } if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL) - xo_errx(1, "can't find root device"); + 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); }