xref: /openbsd-src/usr.sbin/eeprom/optree.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: optree.c,v 1.6 2009/01/14 21:05:53 fgsch Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Federico G. Schwindt <fgsch@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for
7  * any purpose with or without fee is hereby granted, provided that
8  * the above copyright notice and this permission notice appear in all
9  * copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
12  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
13  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
14  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA
16  * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
17  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18  * PERFORMANCE OF THIS SOFTWARE.
19  */
20 
21 #include <sys/ioctl.h>
22 #include <err.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include <machine/openpromio.h>
30 
31 #include "defs.h"
32 
33 extern  char *path_openprom;
34 
35 static void
36 op_print(struct opiocdesc *opio, int depth)
37 {
38 	char *p;
39 	int i, special;
40 
41 	opio->op_name[opio->op_namelen] = '\0';
42 	printf("%*s%s: ", depth * 4, " ", opio->op_name);
43 	if (opio->op_buflen > 0) {
44 		opio->op_buf[opio->op_buflen] = '\0';
45 		special = 0;
46 
47 		/*
48 		 * XXX This allows multiple NUL characters within
49 		 * string-valued properties, which may not be what we
50 		 * want.  But on macppc we have string-values
51 		 * properties that end with multiple NUL characters,
52 		 * and the serial number has them embedded within the
53 		 * string.
54 		 */
55 		if (opio->op_buf[0] != '\0') {
56 			for (i = 0; i < opio->op_buflen; i++) {
57 				p = &opio->op_buf[i];
58 				if (*p >= ' ' && *p <= '~')
59 					continue;
60 				if (*p == '\0') {
61 					if (i + 1 < opio->op_buflen)
62 						p++;
63 					if (*p >= ' ' && *p <= '~')
64 						continue;
65 					if (*p == '\0')
66 						continue;
67 				}
68 
69 				special = 1;
70 				break;
71 			}
72 		} else {
73 			if (opio->op_buflen > 1)
74 				special = 1;
75 		}
76 
77 		if (special) {
78 			for (i = 0; opio->op_buflen - i >= sizeof(int);
79 			    i += sizeof(int)) {
80 				if (i)
81 					printf(".");
82 				printf("%08x", *(int *)(long)&opio->op_buf[i]);
83 			}
84 			if (i < opio->op_buflen) {
85 				if (i)
86 					printf(".");
87 				for (; i < opio->op_buflen; i++) {
88 					printf("%02x",
89 					    *(u_char *)&opio->op_buf[i]);
90 				}
91 			}
92 		} else {
93 			for (i = 0; i < opio->op_buflen;
94 			    i += strlen(&opio->op_buf[i]) + 1) {
95 				if (i && strlen(&opio->op_buf[i]) == 0)
96 					continue;
97 				if (i)
98 					printf(" + ");
99 				printf("'%s'", &opio->op_buf[i]);
100 			}
101 		}
102 	} else if(opio->op_buflen < 0)
103 		printf("too large");
104 	printf("\n");
105 }
106 
107 void
108 op_nodes(int fd, int node, int depth)
109 {
110 	char op_buf[BUFSIZE * 8];
111 	char op_name[BUFSIZE];
112 	struct opiocdesc opio;
113 
114 	opio.op_nodeid = node;
115 	opio.op_buf = op_buf;
116 	opio.op_name = op_name;
117 
118 	if (!node) {
119 		if (ioctl(fd, OPIOCGETNEXT, &opio) < 0)
120 			err(1, "OPIOCGETNEXT");
121 		node = opio.op_nodeid;
122 	} else
123 		printf("\n%*s", depth * 4, " ");
124 
125 	printf("Node 0x%x\n", node);
126 
127 	for (;;) {
128 		opio.op_buflen = sizeof(op_buf);
129 		opio.op_namelen = sizeof(op_name);
130 
131 		/* Get the next property. */
132 		if (ioctl(fd, OPIOCNEXTPROP, &opio) < 0)
133 			err(1, "OPIOCNEXTPROP");
134 
135 		op_buf[opio.op_buflen] = '\0';
136 		(void)strlcpy(op_name, op_buf, sizeof(op_name));
137 		opio.op_namelen = strlen(op_name);
138 
139 		/* If it's the last, punt. */
140 		if (opio.op_namelen == 0)
141 			break;
142 
143 		bzero(op_buf, sizeof(op_buf));
144 		opio.op_buflen = sizeof(op_buf);
145 
146 		/* And its value. */
147 		if (ioctl(fd, OPIOCGET, &opio) < 0) {
148 			if (errno != ENOMEM)
149 				err(1, "OPIOCGET");
150 
151 			opio.op_buflen = -1;	/* for op_print */
152 		}
153 
154 		op_print(&opio, depth + 1);
155 	}
156 
157 	/* Get next child. */
158 	if (ioctl(fd, OPIOCGETCHILD, &opio) < 0)
159 		err(1, "OPIOCGETCHILD");
160 	if (opio.op_nodeid)
161 		op_nodes(fd, opio.op_nodeid, depth + 1);
162 
163 	/* Get next node/sibling. */
164 	opio.op_nodeid = node;
165 	if (ioctl(fd, OPIOCGETNEXT, &opio) < 0)
166 		err(1, "OPIOCGETNEXT");
167 	if (opio.op_nodeid)
168 		op_nodes(fd, opio.op_nodeid, depth);
169 }
170 
171 void
172 op_tree(void)
173 {
174 	int fd;
175 
176 	if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0)
177 		err(1, "open: %s", path_openprom);
178 	op_nodes(fd, 0, 0);
179 	(void)close(fd);
180 }
181