1105401Stmm/*-
2105401Stmm * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
3105401Stmm * All rights reserved.
4105401Stmm *
5105401Stmm * Redistribution and use in source and binary forms, with or without
6105401Stmm * modification, are permitted provided that the following conditions
7105401Stmm * are met:
8105401Stmm * 1. Redistributions of source code must retain the above copyright
9105401Stmm *    notice, this list of conditions and the following disclaimer.
10105401Stmm * 2. Redistributions in binary form must reproduce the above copyright
11105401Stmm *    notice, this list of conditions and the following disclaimer in the
12105401Stmm *    documentation and/or other materials provided with the distribution.
13105401Stmm *
14105401Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15105401Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16105401Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17105401Stmm * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18105401Stmm * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19105401Stmm * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20105401Stmm * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21105401Stmm * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22105401Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23105401Stmm * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24105401Stmm */
25105401Stmm
26105401Stmm#include <sys/cdefs.h>
27105401Stmm__FBSDID("$FreeBSD: releng/11.0/usr.sbin/ofwdump/ofwdump.c 277256 2015-01-16 18:42:49Z nwhitehorn $");
28105401Stmm
29129589Smarius#include <dev/ofw/openfirm.h>
30129589Smarius#include <dev/ofw/openfirmio.h>
31129589Smarius
32129589Smarius#include <err.h>
33129589Smarius#include <fcntl.h>
34105401Stmm#include <stdio.h>
35105401Stmm#include <stdlib.h>
36129589Smarius#include <string.h>
37129589Smarius#include <sysexits.h>
38105401Stmm#include <unistd.h>
39129589Smarius#include <vis.h>
40105401Stmm
41105401Stmm#include "ofw_util.h"
42105401Stmm
43129589Smarius/* Constants controlling the layout of the output. */
44129589Smarius#define	LVLINDENT	2
45129589Smarius#define	NAMEINDENT	2
46129589Smarius#define	DUMPINDENT	4
47129589Smarius#define	CHARSPERLINE	60
48129589Smarius#define	BYTESPERLINE	(CHARSPERLINE / 3)
49105401Stmm
50129589Smariusstatic void	usage(void);
51129589Smariusstatic void	ofw_indent(int);
52277256Snwhitehornstatic void	ofw_dump_properties(int, phandle_t, int, int, int);
53277256Snwhitehornstatic void	ofw_dump_property(int fd, phandle_t n, int level,
54277256Snwhitehorn		    const char *prop, int raw, int str);
55129589Smariusstatic void	ofw_dump(int, const char *, int, int, const char *, int, int);
56129589Smarius
57129589Smariusstatic void
58105401Stmmusage(void)
59105401Stmm{
60105401Stmm
61105401Stmm	fprintf(stderr,
62105401Stmm	    "usage: ofwdump -a [-p | -P property] [-R | -S]\n"
63105401Stmm	    "       ofwdump [-p | -P property] [-r] [-R | -S] [--] nodes\n");
64129589Smarius	exit(EX_USAGE);
65105401Stmm}
66105401Stmm
67105401Stmmint
68105401Stmmmain(int argc, char *argv[])
69105401Stmm{
70105401Stmm	int opt, i, fd;
71105401Stmm	int aflag, pflag, rflag, Rflag, Sflag;
72105401Stmm	char *Parg;
73105401Stmm
74105401Stmm	aflag = pflag = rflag = Rflag = Sflag = 0;
75105401Stmm	Parg = NULL;
76105401Stmm	while ((opt = getopt(argc, argv, "-aprP:RS")) != -1) {
77105401Stmm		if (opt == '-')
78105401Stmm			break;
79105401Stmm		switch (opt) {
80105401Stmm		case 'a':
81105401Stmm			aflag = 1;
82105401Stmm			rflag = 1;
83105401Stmm			break;
84105401Stmm		case 'p':
85105401Stmm			if (Parg != NULL)
86105401Stmm				usage();
87105401Stmm			pflag = 1;
88105401Stmm			break;
89105401Stmm		case 'r':
90105401Stmm			rflag = 1;
91105401Stmm			break;
92105401Stmm		case 'P':
93105401Stmm			if (pflag)
94105401Stmm				usage();
95105401Stmm			pflag = 1;
96105401Stmm			Parg = optarg;
97105401Stmm			break;
98105401Stmm		case 'R':
99105401Stmm			if (Sflag)
100105401Stmm				usage();
101105401Stmm			Rflag = 1;
102105401Stmm			break;
103105401Stmm		case 'S':
104105401Stmm			if (Rflag)
105105401Stmm				usage();
106105401Stmm			Sflag = 1;
107105401Stmm			break;
108129589Smarius		case '?':
109105401Stmm		default:
110105401Stmm			usage();
111129589Smarius			/* NOTREACHED */
112105401Stmm		}
113105401Stmm	}
114105401Stmm	argc -= optind;
115105401Stmm	argv += optind;
116105401Stmm
117129589Smarius	fd = ofw_open(O_RDONLY);
118105401Stmm	if (aflag) {
119105401Stmm		if (argc != 0)
120105401Stmm			usage();
121105401Stmm		ofw_dump(fd, NULL, rflag, pflag, Parg, Rflag, Sflag);
122105401Stmm	} else {
123129589Smarius		/*
124129589Smarius		 * For the sake of scripts, usage() is not called here if
125129589Smarius		 * argc == 0.
126129589Smarius		 */
127105401Stmm		for (i = 0; i < argc; i++)
128105401Stmm			ofw_dump(fd, argv[i], rflag, pflag, Parg, Rflag, Sflag);
129105401Stmm	}
130105401Stmm	ofw_close(fd);
131129589Smarius	return (EX_OK);
132105401Stmm}
133129589Smarius
134129589Smariusstatic void
135129589Smariusofw_indent(int level)
136129589Smarius{
137129589Smarius	int i;
138129589Smarius
139129589Smarius	for (i = 0; i < level; i++)
140129589Smarius		putchar(' ');
141129589Smarius}
142129589Smarius
143129589Smariusstatic void
144277256Snwhitehornofw_dump_properties(int fd, phandle_t n, int level, int raw, int str)
145277256Snwhitehorn{
146277256Snwhitehorn	int nlen;
147277256Snwhitehorn	char prop[32];
148277256Snwhitehorn
149277256Snwhitehorn	for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
150277256Snwhitehorn	     nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop)))
151277256Snwhitehorn		ofw_dump_property(fd, n, level, prop, raw, str);
152277256Snwhitehorn}
153277256Snwhitehorn
154277256Snwhitehornstatic void
155277256Snwhitehornofw_dump_property(int fd, phandle_t n, int level, const char *prop, int raw,
156129589Smarius    int str)
157129589Smarius{
158129589Smarius	static void *pbuf = NULL;
159129589Smarius	static char *visbuf = NULL;
160129589Smarius	static char printbuf[CHARSPERLINE + 1];
161129589Smarius	static int pblen = 0, vblen = 0;
162277256Snwhitehorn	int len, i, j, max, vlen;
163129589Smarius
164277256Snwhitehorn	len = ofw_getprop_alloc(fd, n, prop, &pbuf, &pblen, 1);
165277256Snwhitehorn	if (len < 0)
166277256Snwhitehorn		return;
167277256Snwhitehorn	if (raw)
168277256Snwhitehorn		write(STDOUT_FILENO, pbuf, len);
169277256Snwhitehorn	else if (str)
170277256Snwhitehorn		printf("%.*s\n", len, (char *)pbuf);
171277256Snwhitehorn	else {
172277256Snwhitehorn		ofw_indent(level * LVLINDENT + NAMEINDENT);
173277256Snwhitehorn		printf("%s:\n", prop);
174277256Snwhitehorn		/* Print in hex. */
175277256Snwhitehorn		for (i = 0; i < len; i += BYTESPERLINE) {
176277256Snwhitehorn			max = len - i;
177277256Snwhitehorn			max = max > BYTESPERLINE ? BYTESPERLINE : max;
178277256Snwhitehorn			ofw_indent(level * LVLINDENT + DUMPINDENT);
179277256Snwhitehorn			for (j = 0; j < max; j++)
180277256Snwhitehorn				printf("%02x ",
181277256Snwhitehorn				    ((unsigned char *)pbuf)[i + j]);
182277256Snwhitehorn			printf("\n");
183277256Snwhitehorn		}
184277256Snwhitehorn		/*
185277256Snwhitehorn		 * strvis() and print if it looks like it is
186277256Snwhitehorn		 * zero-terminated.
187277256Snwhitehorn		 */
188277256Snwhitehorn		if (((char *)pbuf)[len - 1] == '\0' &&
189277256Snwhitehorn		    strlen(pbuf) == (unsigned)len - 1) {
190277256Snwhitehorn			if (vblen < (len - 1) * 4 + 1) {
191277256Snwhitehorn				if (visbuf != NULL)
192277256Snwhitehorn					free(visbuf);
193277256Snwhitehorn				vblen = (OFIOCMAXVALUE + len) * 4 + 1;
194129589Smarius					if ((visbuf = malloc(vblen)) == NULL)
195129589Smarius						err(EX_OSERR,
196129589Smarius						    "malloc() failed");
197129589Smarius			}
198277256Snwhitehorn			vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
199277256Snwhitehorn			for (i = 0; i < vlen; i += CHARSPERLINE) {
200277256Snwhitehorn				ofw_indent(level * LVLINDENT +
201277256Snwhitehorn				    DUMPINDENT);
202277256Snwhitehorn				strlcpy(printbuf, &visbuf[i],
203277256Snwhitehorn				    sizeof(printbuf));
204277256Snwhitehorn				printf("'%s'\n", printbuf);
205277256Snwhitehorn			}
206129589Smarius		}
207129589Smarius	}
208129589Smarius}
209129589Smarius
210129589Smariusstatic void
211129589Smariusofw_dump_node(int fd, phandle_t n, int level, int rec, int prop,
212129589Smarius    const char *pmatch, int raw, int str)
213129589Smarius{
214129589Smarius	static void *nbuf = NULL;
215129589Smarius	static int nblen = 0;
216129589Smarius	int plen;
217129589Smarius	phandle_t c;
218129589Smarius
219129589Smarius	if (!(raw || str)) {
220129589Smarius		ofw_indent(level * LVLINDENT);
221129589Smarius		printf("Node %#lx", (unsigned long)n);
222129589Smarius		plen = ofw_getprop_alloc(fd, n, "name", &nbuf, &nblen, 1);
223129589Smarius		if (plen > 0)
224129589Smarius			printf(": %.*s\n", (int)plen, (char *)nbuf);
225129589Smarius		else
226129589Smarius			putchar('\n');
227129589Smarius	}
228277256Snwhitehorn	if (prop) {
229277256Snwhitehorn		if (pmatch)
230277256Snwhitehorn			ofw_dump_property(fd, n, level, pmatch, raw, str);
231277256Snwhitehorn		else
232277256Snwhitehorn			ofw_dump_properties(fd, n, level, raw, str);
233277256Snwhitehorn	}
234129589Smarius	if (rec) {
235129589Smarius		for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
236129589Smarius			ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
237129589Smarius			    raw, str);
238129589Smarius		}
239129589Smarius	}
240129589Smarius}
241129589Smarius
242129589Smariusstatic void
243129589Smariusofw_dump(int fd, const char *start, int rec, int prop, const char *pmatch,
244129589Smarius    int raw, int str)
245129589Smarius{
246129589Smarius	phandle_t n;
247129589Smarius
248129589Smarius	n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
249129589Smarius	ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
250129589Smarius}
251