devinfo.c revision 330449
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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__FBSDID("$FreeBSD: stable/11/usr.sbin/devinfo/devinfo.c 330449 2018-03-05 07:26:05Z eadler $");
36
37#include <sys/types.h>
38#include <err.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <unistd.h>
42#include "devinfo.h"
43
44static int	rflag;
45static int	vflag;
46
47static void	print_resource(struct devinfo_res *);
48static int	print_device_matching_resource(struct devinfo_res *, void *);
49static int	print_device_rman_resources(struct devinfo_rman *, void *);
50static int	print_device(struct devinfo_dev *, void *);
51static int	print_rman_resource(struct devinfo_res *, void *);
52static int	print_rman(struct devinfo_rman *, void *);
53
54struct indent_arg
55{
56	int	indent;
57	void	*arg;
58};
59
60/*
61 * Print a resource.
62 */
63void
64print_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 */
84int
85print_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 */
106int
107print_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/*
134 * Print information about a device.
135 */
136int
137print_device(struct devinfo_dev *dev, void *arg)
138{
139	struct indent_arg	ia;
140	int			i, indent;
141
142	if (vflag || (dev->dd_name[0] != 0 && dev->dd_state >= DS_ATTACHED)) {
143		indent = (int)(intptr_t)arg;
144		for (i = 0; i < indent; i++)
145			printf(" ");
146		printf("%s", dev->dd_name[0] ? dev->dd_name : "unknown");
147		if (vflag && *dev->dd_pnpinfo)
148			printf(" pnpinfo %s", dev->dd_pnpinfo);
149		if (vflag && *dev->dd_location)
150			printf(" at %s", dev->dd_location);
151		if (!(dev->dd_flags & DF_ENABLED))
152			printf(" (disabled)");
153		else if (dev->dd_flags & DF_SUSPENDED)
154			printf(" (suspended)");
155		printf("\n");
156		if (rflag) {
157			ia.indent = indent + 4;
158			ia.arg = dev;
159			devinfo_foreach_rman(print_device_rman_resources,
160			    (void *)&ia);
161		}
162	}
163
164	return(devinfo_foreach_device_child(dev, print_device,
165	    (void *)((char *)arg + 2)));
166}
167
168/*
169 * Print information about a resource under a resource manager.
170 */
171int
172print_rman_resource(struct devinfo_res *res, void *arg __unused)
173{
174	struct devinfo_dev	*dev;
175
176	printf("    ");
177	print_resource(res);
178	dev = devinfo_handle_to_device(res->dr_device);
179	if ((dev != NULL) && (dev->dd_name[0] != 0)) {
180		printf(" (%s)", dev->dd_name);
181	} else {
182		printf(" ----");
183	}
184	printf("\n");
185	return(0);
186}
187
188/*
189 * Print information about a resource manager.
190 */
191int
192print_rman(struct devinfo_rman *rman, void *arg __unused)
193{
194	printf("%s:\n", rman->dm_desc);
195	devinfo_foreach_rman_resource(rman, print_rman_resource, 0);
196	return(0);
197}
198
199int
200main(int argc, char *argv[])
201{
202	struct devinfo_dev	*root;
203	int			c, uflag;
204
205	uflag = 0;
206	while ((c = getopt(argc, argv, "ruv")) != -1) {
207		switch(c) {
208		case 'r':
209			rflag++;
210			break;
211		case 'u':
212			uflag++;
213			break;
214		case 'v':
215			vflag++;
216			break;
217		default:
218			fprintf(stderr, "%s\n%s\n",
219			    "usage: devinfo [-rv]",
220			    "       devinfo -u");
221			exit(1);
222		}
223	}
224
225	if (devinfo_init())
226		err(1, "devinfo_init");
227
228	if ((root = devinfo_handle_to_device(DEVINFO_ROOT_DEVICE)) == NULL)
229		errx(1, "can't find root device");
230
231	/* print resource usage? */
232	if (uflag) {
233		devinfo_foreach_rman(print_rman, NULL);
234	} else {
235		/* print device hierarchy */
236		devinfo_foreach_device_child(root, print_device, (void *)0);
237	}
238	return(0);
239}
240