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/types.h>
35#include <err.h>
36#include <errno.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41#include "devinfo.h"
42
43static int	rflag;
44static int	vflag;
45
46static void	print_resource(struct devinfo_res *);
47static int	print_device_matching_resource(struct devinfo_res *, void *);
48static int	print_device_rman_resources(struct devinfo_rman *, void *);
49static int	print_device(struct devinfo_dev *, void *);
50static int	print_rman_resource(struct devinfo_res *, void *);
51static int	print_rman(struct devinfo_rman *, void *);
52
53struct indent_arg
54{
55	int	indent;
56	void	*arg;
57};
58
59/*
60 * Print a resource.
61 */
62void
63print_resource(struct devinfo_res *res)
64{
65	struct devinfo_rman	*rman;
66	int			hexmode;
67
68	rman = devinfo_handle_to_rman(res->dr_rman);
69	hexmode =  (rman->dm_size > 1000) || (rman->dm_size == 0);
70	printf(hexmode ? "0x%jx" : "%ju", res->dr_start);
71	if (res->dr_size > 1)
72		printf(hexmode ? "-0x%jx" : "-%ju",
73		    res->dr_start + res->dr_size - 1);
74}
75
76/*
77 * Print resource information if this resource matches the
78 * given device.
79 *
80 * If the given indent is 0, return an indicator that a matching
81 * resource exists.
82 */
83int
84print_device_matching_resource(struct devinfo_res *res, void *arg)
85{
86	struct indent_arg	*ia = (struct indent_arg *)arg;
87	struct devinfo_dev	*dev = (struct devinfo_dev *)ia->arg;
88	int			i;
89
90	if (devinfo_handle_to_device(res->dr_device) == dev) {
91		/* in 'detect' mode, found a match */
92		if (ia->indent == 0)
93			return(1);
94		for (i = 0; i < ia->indent; i++)
95			printf(" ");
96		print_resource(res);
97		printf("\n");
98	}
99	return(0);
100}
101
102/*
103 * Print resource information for this device and resource manager.
104 */
105int
106print_device_rman_resources(struct devinfo_rman *rman, void *arg)
107{
108	struct indent_arg	*ia = (struct indent_arg *)arg;
109	int			indent, i;
110
111	indent = ia->indent;
112
113	/* check whether there are any resources matching this device */
114	ia->indent = 0;
115	if (devinfo_foreach_rman_resource(rman,
116	    print_device_matching_resource, ia) != 0) {
117
118		/* there are, print header */
119		for (i = 0; i < indent; i++)
120			printf(" ");
121		printf("%s:\n", rman->dm_desc);
122
123		/* print resources */
124		ia->indent = indent + 4;
125		devinfo_foreach_rman_resource(rman,
126		    print_device_matching_resource, ia);
127	}
128	ia->indent = indent;
129	return(0);
130}
131
132static void
133print_dev(struct devinfo_dev *dev)
134{
135
136	printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown");
137	if (vflag && *dev->dd_pnpinfo)
138		printf(" pnpinfo %s", dev->dd_pnpinfo);
139	if (vflag && *dev->dd_location)
140		printf(" at %s", dev->dd_location);
141	if (!(dev->dd_flags & DF_ENABLED))
142		printf(" (disabled)");
143	else if (dev->dd_flags & DF_SUSPENDED)
144		printf(" (suspended)");
145}
146
147
148/*
149 * Print information about a device.
150 */
151int
152print_device(struct devinfo_dev *dev, void *arg)
153{
154	struct indent_arg	ia;
155	int			i, indent;
156
157	if (vflag || (dev->dd_name[0] != 0 && dev->dd_state >= DS_ATTACHED)) {
158		indent = (int)(intptr_t)arg;
159		for (i = 0; i < indent; i++)
160			printf(" ");
161		print_dev(dev);
162		printf("\n");
163		if (rflag) {
164			ia.indent = indent + 4;
165			ia.arg = dev;
166			devinfo_foreach_rman(print_device_rman_resources,
167			    (void *)&ia);
168		}
169	}
170
171	return(devinfo_foreach_device_child(dev, print_device,
172	    (void *)((char *)arg + 2)));
173}
174
175/*
176 * Print information about a resource under a resource manager.
177 */
178int
179print_rman_resource(struct devinfo_res *res, void *arg __unused)
180{
181	struct devinfo_dev	*dev;
182
183	printf("    ");
184	print_resource(res);
185	dev = devinfo_handle_to_device(res->dr_device);
186	if ((dev != NULL) && (dev->dd_name[0] != 0)) {
187		printf(" (%s)", dev->dd_name);
188	} else {
189		printf(" ----");
190	}
191	printf("\n");
192	return(0);
193}
194
195/*
196 * Print information about a resource manager.
197 */
198int
199print_rman(struct devinfo_rman *rman, void *arg __unused)
200{
201	printf("%s:\n", rman->dm_desc);
202	devinfo_foreach_rman_resource(rman, print_rman_resource, 0);
203	return(0);
204}
205
206static int
207print_path(struct devinfo_dev *dev, void *xname)
208{
209	const char *name = xname;
210	int rv;
211
212	if (strcmp(dev->dd_name, name) == 0) {
213		print_dev(dev);
214		if (vflag)
215			printf("\n");
216		return (1);
217	}
218
219	rv = devinfo_foreach_device_child(dev, print_path, xname);
220	if (rv == 1) {
221		printf(" ");
222		print_dev(dev);
223		if (vflag)
224			printf("\n");
225	}
226	return (rv);
227}
228
229static void __dead2
230usage(void)
231{
232	fprintf(stderr, "%s\n%s\n%s\n",
233	    "usage: devinfo [-rv]",
234	    "       devinfo -u",
235	    "       devinfo -p dev [-v]");
236	exit(1);
237}
238
239int
240main(int argc, char *argv[])
241{
242	struct devinfo_dev	*root;
243	int			c, uflag, rv;
244	char			*path = NULL;
245
246	uflag = 0;
247	while ((c = getopt(argc, argv, "p:ruv")) != -1) {
248		switch(c) {
249		case 'p':
250			path = optarg;
251			break;
252		case 'r':
253			rflag++;
254			break;
255		case 'u':
256			uflag++;
257			break;
258		case 'v':
259			vflag++;
260			break;
261		default:
262			usage();
263		}
264	}
265
266	if (path && (rflag || uflag))
267		usage();
268
269	if ((rv = devinfo_init()) != 0) {
270		errno = rv;
271		err(1, "devinfo_init");
272	}
273
274	if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL)
275		errx(1, "can't find root device");
276
277	if (path) {
278		if (devinfo_foreach_device_child(root, print_path, (void *)path) == 0)
279			errx(1, "%s: Not found", path);
280		if (!vflag)
281			printf("\n");
282	} else if (uflag) {
283		/* print resource usage? */
284		devinfo_foreach_rman(print_rman, NULL);
285	} else {
286		/* print device hierarchy */
287		devinfo_foreach_device_child(root, print_device, (void *)0);
288	}
289	return(0);
290}
291