xref: /freebsd/usr.sbin/ofwdump/ofw_util.c (revision 2357939bc239bd5334a169b62313806178dd8f30)
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 <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <vis.h>
42 
43 #include "pathnames.h"
44 #include "ofw_util.h"
45 
46 /* Constants controlling the layout of the output. */
47 #define	LVLINDENT	2
48 #define	NAMEINDENT	2
49 #define	DUMPINDENT	4
50 #define	CHARSPERLINE	60
51 #define	BYTESPERLINE	(CHARSPERLINE / 3)
52 
53 /* Default space reserved for properties. */
54 #define	PROPBUFLEN	8192
55 
56 #define	OFW_IOCTL(fd, cmd, val)	do {					\
57 	if (ioctl(fd, cmd, val) == -1)					\
58 		err(1, "ioctl(..., " #cmd ", ...) failed");		\
59 } while (0)
60 
61 int
62 ofw_open(void)
63 {
64 	int fd;
65 
66 	if ((fd = open(PATH_DEV_OPENFIRM, O_RDONLY)) == -1)
67 		err(1, "could not open " PATH_DEV_OPENFIRM);
68 	return (fd);
69 }
70 
71 void
72 ofw_close(int fd)
73 {
74 
75 	close(fd);
76 }
77 
78 phandle_t
79 ofw_root(int fd)
80 {
81 
82 	return (ofw_peer(fd, 0));
83 }
84 
85 phandle_t
86 ofw_peer(int fd, phandle_t node)
87 {
88 	phandle_t rv;
89 
90 	rv = node;
91 	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
92 	return (rv);
93 }
94 
95 phandle_t
96 ofw_child(int fd, phandle_t node)
97 {
98 	phandle_t rv;
99 
100 	rv = node;
101 	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
102 	return (rv);
103 }
104 
105 phandle_t
106 ofw_finddevice(int fd, char *name)
107 {
108 	struct ofiocdesc d;
109 
110 	d.of_nodeid = 0;
111 	d.of_namelen = strlen(name);
112 	d.of_name = name;
113 	d.of_buflen = 0;
114 	d.of_buf = NULL;
115 	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
116 		if (errno == ENOENT)
117 			err(2, "Node '%s' not found", name);
118 		else
119 			err(1, "ioctl(..., OFIOCFINDDEVICE, ...) failed");
120 	}
121 	return (d.of_nodeid);
122 }
123 
124 int
125 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
126 {
127 
128 	return (ofw_nextprop(fd, node, NULL, buf, buflen));
129 }
130 
131 int
132 ofw_nextprop(int fd, phandle_t node, char *prev, char *buf, int buflen)
133 {
134 	struct ofiocdesc d;
135 
136 	d.of_nodeid = node;
137 	d.of_namelen = prev != NULL ? strlen(prev) : 0;
138 	d.of_name = prev;
139 	d.of_buflen = buflen;
140 	d.of_buf = buf;
141 	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
142 		if (errno == ENOENT)
143 			return (0);
144 		else
145 			err(1, "ioctl(..., OFIOCNEXTPROP, ...) failed");
146 	}
147 	return (d.of_buflen);
148 }
149 
150 static void *
151 ofw_malloc(int size)
152 {
153 	void *p;
154 
155 	if ((p = malloc(size)) == NULL)
156 		err(1, "malloc() failed");
157 	return (p);
158 }
159 
160 int
161 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
162 {
163 	struct ofiocdesc d;
164 
165 	d.of_nodeid = node;
166 	d.of_namelen = strlen(name);
167 	d.of_name = name;
168 	d.of_buflen = buflen;
169 	d.of_buf = buf;
170 	OFW_IOCTL(fd, OFIOCGET, &d);
171 	return (d.of_buflen);
172 }
173 
174 int
175 ofw_getproplen(int fd, phandle_t node, const char *name)
176 {
177 	struct ofiocdesc d;
178 
179 	d.of_nodeid = node;
180 	d.of_namelen = strlen(name);
181 	d.of_name = name;
182 	OFW_IOCTL(fd, OFIOCGETPROPLEN, &d);
183 	return (d.of_buflen);
184 }
185 
186 int
187 ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf,
188     int *buflen, int reserve)
189 {
190 	struct ofiocdesc d;
191 	int len, rv;
192 
193 	do {
194 		len = ofw_getproplen(fd, node, name);
195 		if (len < 0)
196 			return (len);
197 		if (*buflen < len + reserve) {
198 			if (*buf != NULL)
199 				free(*buf);
200 			*buflen = len + reserve + PROPBUFLEN;
201 			*buf = ofw_malloc(*buflen);
202 		}
203 		d.of_nodeid = node;
204 		d.of_namelen = strlen(name);
205 		d.of_name = name;
206 		d.of_buflen = *buflen - reserve;
207 		d.of_buf = *buf;
208 		rv = ioctl(fd, OFIOCGET, &d);
209 	} while (rv == -1 && errno == ENOMEM);
210 	if (rv == -1)
211 		err(1, "ioctl(..., OFIOCGET, ...) failed");
212 	return (d.of_buflen);
213 }
214 
215 static void
216 ofw_indent(int level)
217 {
218 	int i;
219 
220 	for (i = 0; i < level; i++)
221 		putchar(' ');
222 }
223 
224 static void
225 ofw_dump_properties(int fd, phandle_t n, int level, char *pmatch, int raw,
226     int str)
227 {
228 	static void *pbuf;
229 	static char *visbuf;
230 	static char printbuf[CHARSPERLINE + 1];
231 	static int pblen, vblen;
232 	char prop[32];
233 	int nlen, len, i, j, max, vlen;
234 
235 	for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
236 	     nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) {
237 		if (pmatch != NULL && strcmp(pmatch, prop) != 0)
238 			continue;
239 		len = ofw_getprop_alloc(fd, n, prop, &pbuf, &pblen, 1);
240 		if (len < 0)
241 			continue;
242 		if (raw)
243 			write(STDOUT_FILENO, pbuf, len);
244 		else if (str) {
245 			printf("%.*s\n", (int)len, (char *)pbuf);
246 		} else {
247 			ofw_indent(level * LVLINDENT + NAMEINDENT);
248 			printf("%s:\n", prop);
249 			/* Print in hex. */
250 			for (i = 0; i < len; i += BYTESPERLINE) {
251 				max = len - i;
252 				max = max > BYTESPERLINE ? BYTESPERLINE : max;
253 				ofw_indent(level * LVLINDENT + DUMPINDENT);
254 				for (j = 0; j < max; j++)
255 					printf("%02x ",
256 					    ((unsigned char *)pbuf)[i + j]);
257 				printf("\n");
258 			}
259 			/*
260 			 * strvis() and print if it looks like it is
261 			 * zero-terminated.
262 			 */
263 			if (((char *)pbuf)[len - 1] == '\0' &&
264 			    strlen(pbuf) == (unsigned)len - 1) {
265 				if (vblen < (len - 1) * 4 + 1) {
266 					if (visbuf != NULL)
267 						free(visbuf);
268 					vblen = (PROPBUFLEN + len) * 4 + 1;
269 					visbuf = ofw_malloc(vblen);
270 				}
271 				vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
272 				for (i = 0; i < vlen; i += CHARSPERLINE) {
273 					ofw_indent(level * LVLINDENT +
274 					    DUMPINDENT);
275 					strlcpy(printbuf, &visbuf[i],
276 					    sizeof(printbuf));
277 					printf("'%s'\n", printbuf);
278 				}
279 			}
280 		}
281 	}
282 }
283 
284 static void
285 ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop, char *pmatch,
286     int raw, int str)
287 {
288 	static void *nbuf;
289 	static int nblen = 0;
290 	int plen;
291 	phandle_t c;
292 
293 	if (!(raw || str)) {
294 		ofw_indent(level * LVLINDENT);
295 		printf("Node %#lx", (unsigned long)n);
296 		plen = ofw_getprop_alloc(fd, n, "name", &nbuf, &nblen, 1);
297 		if (plen > 0)
298 			printf(": %.*s\n", (int)plen, (char *)nbuf);
299 		else
300 			putchar('\n');
301 	}
302 	if (prop)
303 		ofw_dump_properties(fd, n, level, pmatch, raw, str);
304 	if (rec) {
305 		for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
306 			ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
307 			    raw, str);
308 		}
309 	}
310 }
311 
312 void
313 ofw_dump(int fd, char *start, int rec, int prop, char *pmatch, int raw, int str)
314 {
315 	phandle_t n;
316 
317 	n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
318 	ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
319 }
320 
321