xref: /openbsd-src/usr.sbin/eeprom/optree.c (revision 850e275390052b330d93020bf619a739a3c277ac)
1 /*	$OpenBSD: optree.c,v 1.5 2008/03/23 12:05:43 miod Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Federico G. Schwindt <fgsch@openbsd.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
22  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
25  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/ioctl.h>
30 #include <err.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <unistd.h>
36 
37 #include <machine/openpromio.h>
38 
39 #include "defs.h"
40 
41 extern  char *path_openprom;
42 
43 static void
44 op_print(struct opiocdesc *opio, int depth)
45 {
46 	char *p;
47 	int i, special;
48 
49 	opio->op_name[opio->op_namelen] = '\0';
50 	printf("%*s%s: ", depth * 4, " ", opio->op_name);
51 	if (opio->op_buflen > 0) {
52 		opio->op_buf[opio->op_buflen] = '\0';
53 		special = 0;
54 
55 		/*
56 		 * XXX This allows multiple NUL characters within
57 		 * string-valued properties, which may not be what we
58 		 * want.  But on macppc we have string-values
59 		 * properties that end with multiple NUL characters,
60 		 * and the serial number has them embedded within the
61 		 * string.
62 		 */
63 		if (opio->op_buf[0] != '\0') {
64 			for (i = 0; i < opio->op_buflen; i++) {
65 				p = &opio->op_buf[i];
66 				if (*p >= ' ' && *p <= '~')
67 					continue;
68 				if (*p == '\0') {
69 					if (i + 1 < opio->op_buflen)
70 						p++;
71 					if (*p >= ' ' && *p <= '~')
72 						continue;
73 					if (*p == '\0')
74 						continue;
75 				}
76 
77 				special = 1;
78 				break;
79 			}
80 		} else {
81 			if (opio->op_buflen > 1)
82 				special = 1;
83 		}
84 
85 		if (special) {
86 			for (i = 0; opio->op_buflen - i >= sizeof(int);
87 			    i += sizeof(int)) {
88 				if (i)
89 					printf(".");
90 				printf("%08x", *(int *)(long)&opio->op_buf[i]);
91 			}
92 			if (i < opio->op_buflen) {
93 				if (i)
94 					printf(".");
95 				for (; i < opio->op_buflen; i++) {
96 					printf("%02x",
97 					    *(u_char *)&opio->op_buf[i]);
98 				}
99 			}
100 		} else {
101 			for (i = 0; i < opio->op_buflen;
102 			    i += strlen(&opio->op_buf[i]) + 1) {
103 				if (i && strlen(&opio->op_buf[i]) == 0)
104 					continue;
105 				if (i)
106 					printf(" + ");
107 				printf("'%s'", &opio->op_buf[i]);
108 			}
109 		}
110 	} else if(opio->op_buflen < 0)
111 		printf("too large");
112 	printf("\n");
113 }
114 
115 void
116 op_nodes(int fd, int node, int depth)
117 {
118 	char op_buf[BUFSIZE * 8];
119 	char op_name[BUFSIZE];
120 	struct opiocdesc opio;
121 
122 	opio.op_nodeid = node;
123 	opio.op_buf = op_buf;
124 	opio.op_name = op_name;
125 
126 	if (!node) {
127 		if (ioctl(fd, OPIOCGETNEXT, &opio) < 0)
128 			err(1, "OPIOCGETNEXT");
129 		node = opio.op_nodeid;
130 	} else
131 		printf("\n%*s", depth * 4, " ");
132 
133 	printf("Node 0x%x\n", node);
134 
135 	for (;;) {
136 		opio.op_buflen = sizeof(op_buf);
137 		opio.op_namelen = sizeof(op_name);
138 
139 		/* Get the next property. */
140 		if (ioctl(fd, OPIOCNEXTPROP, &opio) < 0)
141 			err(1, "OPIOCNEXTPROP");
142 
143 		op_buf[opio.op_buflen] = '\0';
144 		(void)strlcpy(op_name, op_buf, sizeof(op_name));
145 		opio.op_namelen = strlen(op_name);
146 
147 		/* If it's the last, punt. */
148 		if (opio.op_namelen == 0)
149 			break;
150 
151 		bzero(op_buf, sizeof(op_buf));
152 		opio.op_buflen = sizeof(op_buf);
153 
154 		/* And its value. */
155 		if (ioctl(fd, OPIOCGET, &opio) < 0) {
156 			if (errno != ENOMEM)
157 				err(1, "OPIOCGET");
158 
159 			opio.op_buflen = -1;	/* for op_print */
160 		}
161 
162 		op_print(&opio, depth + 1);
163 	}
164 
165 	/* Get next child. */
166 	if (ioctl(fd, OPIOCGETCHILD, &opio) < 0)
167 		err(1, "OPIOCGETCHILD");
168 	if (opio.op_nodeid)
169 		op_nodes(fd, opio.op_nodeid, depth + 1);
170 
171 	/* Get next node/sibling. */
172 	opio.op_nodeid = node;
173 	if (ioctl(fd, OPIOCGETNEXT, &opio) < 0)
174 		err(1, "OPIOCGETNEXT");
175 	if (opio.op_nodeid)
176 		op_nodes(fd, opio.op_nodeid, depth);
177 }
178 
179 void
180 op_tree(void)
181 {
182 	int fd;
183 
184 	if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0)
185 		err(1, "open: %s", path_openprom);
186 	op_nodes(fd, 0, 0);
187 	(void)close(fd);
188 }
189