xref: /freebsd/usr.sbin/ofwdump/ofw_util.c (revision 71fe318b852b8dfb3e799cb12ef184750f7f8eac)
1 /*-
2  * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 __FBSDID("$FreeBSD$");
28 
29 #include <sys/types.h>
30 #include <sys/ioctl.h>
31 
32 #include <dev/ofw/openfirmio.h>
33 
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <unistd.h>
40 #include <vis.h>
41 
42 #include "pathnames.h"
43 #include "ofw_util.h"
44 
45 /* Constants controlling the layout of the output. */
46 #define	LVLINDENT	2
47 #define	NAMEINDENT	2
48 #define	DUMPINDENT	4
49 #define	CHARSPERLINE	60
50 #define	BYTESPERLINE	(CHARSPERLINE / 3)
51 
52 /* Maximum supported property size. */
53 #define	PROPBUFLEN	1024
54 
55 #define	OFW_IOCTL(fd, cmd, val)	do {					\
56 	if (ioctl(fd, cmd, val) == -1)					\
57 		err(1, "ioctl(..., " #cmd ", ...) failed");		\
58 } while (0)
59 
60 int
61 ofw_open(void)
62 {
63 	int fd;
64 
65 	if ((fd = open(PATH_DEV_OPENFIRM, O_RDONLY)) == -1)
66 		err(1, "could not open " PATH_DEV_OPENFIRM);
67 	return (fd);
68 }
69 
70 void
71 ofw_close(int fd)
72 {
73 
74 	close(fd);
75 }
76 
77 phandle_t
78 ofw_root(int fd)
79 {
80 
81 	return (ofw_peer(fd, 0));
82 }
83 
84 phandle_t
85 ofw_peer(int fd, phandle_t node)
86 {
87 	phandle_t rv;
88 
89 	rv = node;
90 	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
91 	return (rv);
92 }
93 
94 phandle_t
95 ofw_child(int fd, phandle_t node)
96 {
97 	phandle_t rv;
98 
99 	rv = node;
100 	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
101 	return (rv);
102 }
103 
104 phandle_t
105 ofw_finddevice(int fd, char *name)
106 {
107 	struct ofiocdesc d;
108 
109 	d.of_nodeid = 0;
110 	d.of_namelen = strlen(name);
111 	d.of_name = name;
112 	d.of_buflen = 0;
113 	d.of_buf = NULL;
114 	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
115 		if (errno == ENOENT)
116 			err(2, "Node '%s' not found", name);
117 		else
118 			err(1, "ioctl(..., OFIOCFINDDEVICE, ...) failed");
119 	}
120 	return (d.of_nodeid);
121 }
122 
123 int
124 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
125 {
126 
127 	return (ofw_nextprop(fd, node, NULL, buf, buflen));
128 }
129 
130 int
131 ofw_nextprop(int fd, phandle_t node, char *prev, char *buf, int buflen)
132 {
133 	struct ofiocdesc d;
134 
135 	d.of_nodeid = node;
136 	d.of_namelen = prev != NULL ? strlen(prev) : 0;
137 	d.of_name = prev;
138 	d.of_buflen = buflen;
139 	d.of_buf = buf;
140 	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
141 		if (errno == ENOENT)
142 			return (0);
143 		else
144 			err(1, "ioctl(..., OFIOCNEXTPROP, ...) failed");
145 	}
146 	return (d.of_buflen);
147 }
148 
149 int
150 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
151 {
152 	struct ofiocdesc d;
153 
154 	d.of_nodeid = node;
155 	d.of_namelen = strlen(name);
156 	d.of_name = name;
157 	d.of_buflen = buflen;
158 	d.of_buf = buf;
159 	OFW_IOCTL(fd, OFIOCGET, &d);
160 	return (d.of_buflen);
161 }
162 
163 static void
164 ofw_indent(int level)
165 {
166 	int i;
167 
168 	for (i = 0; i < level; i++)
169 		putchar(' ');
170 }
171 
172 static void
173 ofw_dump_properties(int fd, phandle_t n, int level, char *pmatch, int raw,
174     int str)
175 {
176 	static char pbuf[PROPBUFLEN];
177 	static char visbuf[PROPBUFLEN * 4 + 1];
178 	static char printbuf[CHARSPERLINE + 1];
179 	char prop[32];
180 	int nlen, len, i, j, max, vlen;
181 	unsigned int b;
182 
183 	for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
184 	     nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) {
185 		if (pmatch != NULL && strcmp(pmatch, prop) != 0)
186 			continue;
187 		len = ofw_getprop(fd, n, prop, pbuf, sizeof(pbuf) - 1);
188 		if (raw)
189 			write(STDOUT_FILENO, pbuf, len);
190 		else if (str) {
191 			pbuf[len] = '\0';
192 			printf("%s\n", pbuf);
193 		} else {
194 			ofw_indent(level * LVLINDENT + NAMEINDENT);
195 			printf("%s:\n", prop);
196 			/* Print in hex. */
197 			for (i = 0; i < len; i += BYTESPERLINE) {
198 				max = len - i;
199 				max = max > BYTESPERLINE ? BYTESPERLINE : max;
200 				ofw_indent(level * LVLINDENT + DUMPINDENT);
201 				for (j = 0; j < max; j++) {
202 					b = (unsigned char)pbuf[i + j];
203 					printf("%02x ", b);
204 				}
205 				printf("\n");
206 			}
207 			/*
208 			 * strvis() and print if it looks like it is
209 			 * zero-terminated.
210 			 */
211 			if (pbuf[len - 1] == '\0' &&
212 			    strlen(pbuf) == (unsigned)len - 1) {
213 				vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
214 				for (i = 0; i < vlen; i += CHARSPERLINE) {
215 					ofw_indent(level * LVLINDENT +
216 					    DUMPINDENT);
217 					strlcpy(printbuf, &visbuf[i],
218 					    sizeof(printbuf));
219 					printf("'%s'\n", printbuf);
220 				}
221 			}
222 		}
223 	}
224 }
225 
226 static void
227 ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop, char *pmatch,
228     int raw, int str)
229 {
230 	static char nbuf[PROPBUFLEN];
231 	phandle_t c;
232 
233 	if (!(raw || str)) {
234 		ofw_indent(level * LVLINDENT);
235 		printf("Node %#lx", (unsigned long)n);
236 		if (ofw_getprop(fd, n, "name", nbuf, sizeof(nbuf) - 1) > 0)
237 			printf(": %s\n", nbuf);
238 		else
239 			putchar('\n');
240 	}
241 	if (prop)
242 		ofw_dump_properties(fd, n, level, pmatch, raw, str);
243 	if (rec) {
244 		for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
245 			ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
246 			    raw, str);
247 		}
248 	}
249 }
250 
251 void
252 ofw_dump(int fd, char *start, int rec, int prop, char *pmatch, int raw, int str)
253 {
254 	phandle_t n;
255 
256 	n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
257 	ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
258 }
259 
260