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$");
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);
52129589Smariusstatic void	ofw_dump_properties(int, phandle_t, int, const char *, int,
53129589Smarius		    int);
54129589Smariusstatic void	ofw_dump(int, const char *, int, int, const char *, int, int);
55129589Smarius
56129589Smariusstatic void
57105401Stmmusage(void)
58105401Stmm{
59105401Stmm
60105401Stmm	fprintf(stderr,
61105401Stmm	    "usage: ofwdump -a [-p | -P property] [-R | -S]\n"
62105401Stmm	    "       ofwdump [-p | -P property] [-r] [-R | -S] [--] nodes\n");
63129589Smarius	exit(EX_USAGE);
64105401Stmm}
65105401Stmm
66105401Stmmint
67105401Stmmmain(int argc, char *argv[])
68105401Stmm{
69105401Stmm	int opt, i, fd;
70105401Stmm	int aflag, pflag, rflag, Rflag, Sflag;
71105401Stmm	char *Parg;
72105401Stmm
73105401Stmm	aflag = pflag = rflag = Rflag = Sflag = 0;
74105401Stmm	Parg = NULL;
75105401Stmm	while ((opt = getopt(argc, argv, "-aprP:RS")) != -1) {
76105401Stmm		if (opt == '-')
77105401Stmm			break;
78105401Stmm		switch (opt) {
79105401Stmm		case 'a':
80105401Stmm			aflag = 1;
81105401Stmm			rflag = 1;
82105401Stmm			break;
83105401Stmm		case 'p':
84105401Stmm			if (Parg != NULL)
85105401Stmm				usage();
86105401Stmm			pflag = 1;
87105401Stmm			break;
88105401Stmm		case 'r':
89105401Stmm			rflag = 1;
90105401Stmm			break;
91105401Stmm		case 'P':
92105401Stmm			if (pflag)
93105401Stmm				usage();
94105401Stmm			pflag = 1;
95105401Stmm			Parg = optarg;
96105401Stmm			break;
97105401Stmm		case 'R':
98105401Stmm			if (Sflag)
99105401Stmm				usage();
100105401Stmm			Rflag = 1;
101105401Stmm			break;
102105401Stmm		case 'S':
103105401Stmm			if (Rflag)
104105401Stmm				usage();
105105401Stmm			Sflag = 1;
106105401Stmm			break;
107129589Smarius		case '?':
108105401Stmm		default:
109105401Stmm			usage();
110129589Smarius			/* NOTREACHED */
111105401Stmm		}
112105401Stmm	}
113105401Stmm	argc -= optind;
114105401Stmm	argv += optind;
115105401Stmm
116129589Smarius	fd = ofw_open(O_RDONLY);
117105401Stmm	if (aflag) {
118105401Stmm		if (argc != 0)
119105401Stmm			usage();
120105401Stmm		ofw_dump(fd, NULL, rflag, pflag, Parg, Rflag, Sflag);
121105401Stmm	} else {
122129589Smarius		/*
123129589Smarius		 * For the sake of scripts, usage() is not called here if
124129589Smarius		 * argc == 0.
125129589Smarius		 */
126105401Stmm		for (i = 0; i < argc; i++)
127105401Stmm			ofw_dump(fd, argv[i], rflag, pflag, Parg, Rflag, Sflag);
128105401Stmm	}
129105401Stmm	ofw_close(fd);
130129589Smarius	return (EX_OK);
131105401Stmm}
132129589Smarius
133129589Smariusstatic void
134129589Smariusofw_indent(int level)
135129589Smarius{
136129589Smarius	int i;
137129589Smarius
138129589Smarius	for (i = 0; i < level; i++)
139129589Smarius		putchar(' ');
140129589Smarius}
141129589Smarius
142129589Smariusstatic void
143129589Smariusofw_dump_properties(int fd, phandle_t n, int level, const char *pmatch, int raw,
144129589Smarius    int str)
145129589Smarius{
146129589Smarius	static void *pbuf = NULL;
147129589Smarius	static char *visbuf = NULL;
148129589Smarius	static char printbuf[CHARSPERLINE + 1];
149129589Smarius	static int pblen = 0, vblen = 0;
150129589Smarius	char prop[32];
151129589Smarius	int nlen, len, i, j, max, vlen;
152129589Smarius
153129589Smarius	for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0;
154129589Smarius	     nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) {
155129589Smarius		if (pmatch != NULL && strcmp(pmatch, prop) != 0)
156129589Smarius			continue;
157129589Smarius		len = ofw_getprop_alloc(fd, n, prop, &pbuf, &pblen, 1);
158129589Smarius		if (len < 0)
159129589Smarius			continue;
160129589Smarius		if (raw)
161129589Smarius			write(STDOUT_FILENO, pbuf, len);
162129589Smarius		else if (str)
163129589Smarius			printf("%.*s\n", len, (char *)pbuf);
164129589Smarius		else {
165129589Smarius			ofw_indent(level * LVLINDENT + NAMEINDENT);
166129589Smarius			printf("%s:\n", prop);
167129589Smarius			/* Print in hex. */
168129589Smarius			for (i = 0; i < len; i += BYTESPERLINE) {
169129589Smarius				max = len - i;
170129589Smarius				max = max > BYTESPERLINE ? BYTESPERLINE : max;
171129589Smarius				ofw_indent(level * LVLINDENT + DUMPINDENT);
172129589Smarius				for (j = 0; j < max; j++)
173129589Smarius					printf("%02x ",
174129589Smarius					    ((unsigned char *)pbuf)[i + j]);
175129589Smarius				printf("\n");
176129589Smarius			}
177129589Smarius			/*
178129589Smarius			 * strvis() and print if it looks like it is
179129589Smarius			 * zero-terminated.
180129589Smarius			 */
181129589Smarius			if (((char *)pbuf)[len - 1] == '\0' &&
182129589Smarius			    strlen(pbuf) == (unsigned)len - 1) {
183129589Smarius				if (vblen < (len - 1) * 4 + 1) {
184129589Smarius					if (visbuf != NULL)
185129589Smarius						free(visbuf);
186129589Smarius					vblen = (OFIOCMAXVALUE + len) * 4 + 1;
187129589Smarius					if ((visbuf = malloc(vblen)) == NULL)
188129589Smarius						err(EX_OSERR,
189129589Smarius						    "malloc() failed");
190129589Smarius				}
191129589Smarius				vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL);
192129589Smarius				for (i = 0; i < vlen; i += CHARSPERLINE) {
193129589Smarius					ofw_indent(level * LVLINDENT +
194129589Smarius					    DUMPINDENT);
195129589Smarius					strlcpy(printbuf, &visbuf[i],
196129589Smarius					    sizeof(printbuf));
197129589Smarius					printf("'%s'\n", printbuf);
198129589Smarius				}
199129589Smarius			}
200129589Smarius		}
201129589Smarius	}
202129589Smarius}
203129589Smarius
204129589Smariusstatic void
205129589Smariusofw_dump_node(int fd, phandle_t n, int level, int rec, int prop,
206129589Smarius    const char *pmatch, int raw, int str)
207129589Smarius{
208129589Smarius	static void *nbuf = NULL;
209129589Smarius	static int nblen = 0;
210129589Smarius	int plen;
211129589Smarius	phandle_t c;
212129589Smarius
213129589Smarius	if (!(raw || str)) {
214129589Smarius		ofw_indent(level * LVLINDENT);
215129589Smarius		printf("Node %#lx", (unsigned long)n);
216129589Smarius		plen = ofw_getprop_alloc(fd, n, "name", &nbuf, &nblen, 1);
217129589Smarius		if (plen > 0)
218129589Smarius			printf(": %.*s\n", (int)plen, (char *)nbuf);
219129589Smarius		else
220129589Smarius			putchar('\n');
221129589Smarius	}
222129589Smarius	if (prop)
223129589Smarius		ofw_dump_properties(fd, n, level, pmatch, raw, str);
224129589Smarius	if (rec) {
225129589Smarius		for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) {
226129589Smarius			ofw_dump_node(fd, c, level + 1, rec, prop, pmatch,
227129589Smarius			    raw, str);
228129589Smarius		}
229129589Smarius	}
230129589Smarius}
231129589Smarius
232129589Smariusstatic void
233129589Smariusofw_dump(int fd, const char *start, int rec, int prop, const char *pmatch,
234129589Smarius    int raw, int str)
235129589Smarius{
236129589Smarius	phandle_t n;
237129589Smarius
238129589Smarius	n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start);
239129589Smarius	ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str);
240129589Smarius}
241