xref: /freebsd/usr.sbin/ofwdump/ofw_util.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 char *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 	unsigned int b;
235 
236 	for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
237 	     nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) {
238 		if (pmatch != NULL && strcmp(pmatch, prop) != 0)
239 			continue;
240 		len = ofw_getprop_alloc(fd, n, prop, (void **)&pbuf, &pblen, 1);
241 		if (len < 0)
242 			continue;
243 		if (raw)
244 			write(STDOUT_FILENO, pbuf, len);
245 		else if (str) {
246 			pbuf[len] = '\0';
247 			printf("%s\n", pbuf);
248 		} else {
249 			ofw_indent(level * LVLINDENT + NAMEINDENT);
250 			printf("%s:\n", prop);
251 			/* Print in hex. */
252 			for (i = 0; i < len; i += BYTESPERLINE) {
253 				max = len - i;
254 				max = max > BYTESPERLINE ? BYTESPERLINE : max;
255 				ofw_indent(level * LVLINDENT + DUMPINDENT);
256 				for (j = 0; j < max; j++) {
257 					b = (unsigned char)pbuf[i + j];
258 					printf("%02x ", b);
259 				}
260 				printf("\n");
261 			}
262 			/*
263 			 * strvis() and print if it looks like it is
264 			 * zero-terminated.
265 			 */
266 			if (pbuf[len - 1] == '\0' &&
267 			    strlen(pbuf) == (unsigned)len - 1) {
268 				if (vblen < (len - 1) * 4 + 1) {
269 					if (visbuf != NULL)
270 						free(visbuf);
271 					vblen = (PROPBUFLEN + len) * 4 + 1;
272 					visbuf = ofw_malloc(vblen);
273 				}
274 				vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
275 				for (i = 0; i < vlen; i += CHARSPERLINE) {
276 					ofw_indent(level * LVLINDENT +
277 					    DUMPINDENT);
278 					strlcpy(printbuf, &visbuf[i],
279 					    sizeof(printbuf));
280 					printf("'%s'\n", printbuf);
281 				}
282 			}
283 		}
284 	}
285 }
286 
287 static void
288 ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop, char *pmatch,
289     int raw, int str)
290 {
291 	static char *nbuf;
292 	static int nblen = 0;
293 	int plen;
294 	phandle_t c;
295 
296 	if (!(raw || str)) {
297 		ofw_indent(level * LVLINDENT);
298 		printf("Node %#lx", (unsigned long)n);
299 		plen = ofw_getprop_alloc(fd, n, "name", (void **)&nbuf,
300 		    &nblen, 1);
301 		if (plen > 0) {
302 			nbuf[plen] = '\0';
303 			printf(": %s\n", nbuf);
304 		} else
305 			putchar('\n');
306 	}
307 	if (prop)
308 		ofw_dump_properties(fd, n, level, pmatch, raw, str);
309 	if (rec) {
310 		for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
311 			ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
312 			    raw, str);
313 		}
314 	}
315 }
316 
317 void
318 ofw_dump(int fd, char *start, int rec, int prop, char *pmatch, int raw, int str)
319 {
320 	phandle_t n;
321 
322 	n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
323 	ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
324 }
325 
326