1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2000, 2001 Michael Smith 5 * Copyright (c) 2000 BSDi 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 /* 31 * Print information about system device configuration. 32 */ 33 34 #include <sys/cdefs.h> 35 #include <sys/types.h> 36 #include <err.h> 37 #include <errno.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <string.h> 41 #include <unistd.h> 42 #include "devinfo.h" 43 44 static int rflag; 45 static int vflag; 46 47 static void print_resource(struct devinfo_res *); 48 static int print_device_matching_resource(struct devinfo_res *, void *); 49 static int print_device_rman_resources(struct devinfo_rman *, void *); 50 static int print_device(struct devinfo_dev *, void *); 51 static int print_rman_resource(struct devinfo_res *, void *); 52 static int print_rman(struct devinfo_rman *, void *); 53 54 struct indent_arg 55 { 56 int indent; 57 void *arg; 58 }; 59 60 /* 61 * Print a resource. 62 */ 63 void 64 print_resource(struct devinfo_res *res) 65 { 66 struct devinfo_rman *rman; 67 int hexmode; 68 69 rman = devinfo_handle_to_rman(res->dr_rman); 70 hexmode = (rman->dm_size > 1000) || (rman->dm_size == 0); 71 printf(hexmode ? "0x%jx" : "%ju", res->dr_start); 72 if (res->dr_size > 1) 73 printf(hexmode ? "-0x%jx" : "-%ju", 74 res->dr_start + res->dr_size - 1); 75 } 76 77 /* 78 * Print resource information if this resource matches the 79 * given device. 80 * 81 * If the given indent is 0, return an indicator that a matching 82 * resource exists. 83 */ 84 int 85 print_device_matching_resource(struct devinfo_res *res, void *arg) 86 { 87 struct indent_arg *ia = (struct indent_arg *)arg; 88 struct devinfo_dev *dev = (struct devinfo_dev *)ia->arg; 89 int i; 90 91 if (devinfo_handle_to_device(res->dr_device) == dev) { 92 /* in 'detect' mode, found a match */ 93 if (ia->indent == 0) 94 return(1); 95 for (i = 0; i < ia->indent; i++) 96 printf(" "); 97 print_resource(res); 98 printf("\n"); 99 } 100 return(0); 101 } 102 103 /* 104 * Print resource information for this device and resource manager. 105 */ 106 int 107 print_device_rman_resources(struct devinfo_rman *rman, void *arg) 108 { 109 struct indent_arg *ia = (struct indent_arg *)arg; 110 int indent, i; 111 112 indent = ia->indent; 113 114 /* check whether there are any resources matching this device */ 115 ia->indent = 0; 116 if (devinfo_foreach_rman_resource(rman, 117 print_device_matching_resource, ia) != 0) { 118 119 /* there are, print header */ 120 for (i = 0; i < indent; i++) 121 printf(" "); 122 printf("%s:\n", rman->dm_desc); 123 124 /* print resources */ 125 ia->indent = indent + 4; 126 devinfo_foreach_rman_resource(rman, 127 print_device_matching_resource, ia); 128 } 129 ia->indent = indent; 130 return(0); 131 } 132 133 static void 134 print_dev(struct devinfo_dev *dev) 135 { 136 137 printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown"); 138 if (vflag && *dev->dd_pnpinfo) 139 printf(" pnpinfo %s", dev->dd_pnpinfo); 140 if (vflag && *dev->dd_location) 141 printf(" at %s", dev->dd_location); 142 if (!(dev->dd_flags & DF_ENABLED)) 143 printf(" (disabled)"); 144 else if (dev->dd_flags & DF_SUSPENDED) 145 printf(" (suspended)"); 146 } 147 148 149 /* 150 * Print information about a device. 151 */ 152 int 153 print_device(struct devinfo_dev *dev, void *arg) 154 { 155 struct indent_arg ia; 156 int i, indent; 157 158 if (vflag || (dev->dd_name[0] != 0 && dev->dd_state >= DS_ATTACHED)) { 159 indent = (int)(intptr_t)arg; 160 for (i = 0; i < indent; i++) 161 printf(" "); 162 print_dev(dev); 163 printf("\n"); 164 if (rflag) { 165 ia.indent = indent + 4; 166 ia.arg = dev; 167 devinfo_foreach_rman(print_device_rman_resources, 168 (void *)&ia); 169 } 170 } 171 172 return(devinfo_foreach_device_child(dev, print_device, 173 (void *)((char *)arg + 2))); 174 } 175 176 /* 177 * Print information about a resource under a resource manager. 178 */ 179 int 180 print_rman_resource(struct devinfo_res *res, void *arg __unused) 181 { 182 struct devinfo_dev *dev; 183 184 printf(" "); 185 print_resource(res); 186 dev = devinfo_handle_to_device(res->dr_device); 187 if ((dev != NULL) && (dev->dd_name[0] != 0)) { 188 printf(" (%s)", dev->dd_name); 189 } else { 190 printf(" ----"); 191 } 192 printf("\n"); 193 return(0); 194 } 195 196 /* 197 * Print information about a resource manager. 198 */ 199 int 200 print_rman(struct devinfo_rman *rman, void *arg __unused) 201 { 202 printf("%s:\n", rman->dm_desc); 203 devinfo_foreach_rman_resource(rman, print_rman_resource, 0); 204 return(0); 205 } 206 207 static int 208 print_path(struct devinfo_dev *dev, void *xname) 209 { 210 const char *name = xname; 211 int rv; 212 213 if (strcmp(dev->dd_name, name) == 0) { 214 print_dev(dev); 215 if (vflag) 216 printf("\n"); 217 return (1); 218 } 219 220 rv = devinfo_foreach_device_child(dev, print_path, xname); 221 if (rv == 1) { 222 printf(" "); 223 print_dev(dev); 224 if (vflag) 225 printf("\n"); 226 } 227 return (rv); 228 } 229 230 static void __dead2 231 usage(void) 232 { 233 fprintf(stderr, "%s\n%s\n%s\n", 234 "usage: devinfo [-rv]", 235 " devinfo -u", 236 " devinfo -p dev [-v]"); 237 exit(1); 238 } 239 240 int 241 main(int argc, char *argv[]) 242 { 243 struct devinfo_dev *root; 244 int c, uflag, rv; 245 char *path = NULL; 246 247 uflag = 0; 248 while ((c = getopt(argc, argv, "p:ruv")) != -1) { 249 switch(c) { 250 case 'p': 251 path = optarg; 252 break; 253 case 'r': 254 rflag++; 255 break; 256 case 'u': 257 uflag++; 258 break; 259 case 'v': 260 vflag++; 261 break; 262 default: 263 usage(); 264 } 265 } 266 267 if (path && (rflag || uflag)) 268 usage(); 269 270 if ((rv = devinfo_init()) != 0) { 271 errno = rv; 272 err(1, "devinfo_init"); 273 } 274 275 if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL) 276 errx(1, "can't find root device"); 277 278 if (path) { 279 if (devinfo_foreach_device_child(root, print_path, (void *)path) == 0) 280 errx(1, "%s: Not found", path); 281 if (!vflag) 282 printf("\n"); 283 } else if (uflag) { 284 /* print resource usage? */ 285 devinfo_foreach_rman(print_rman, NULL); 286 } else { 287 /* print device hierarchy */ 288 devinfo_foreach_device_child(root, print_device, (void *)0); 289 } 290 return(0); 291 } 292