xref: /openbsd/usr.sbin/eeprom/optree.c (revision e5dd7070)
1 /*	$OpenBSD: optree.c,v 1.10 2019/06/28 13:32:47 deraadt 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, multi, special;
40 	uint32_t cell;
41 
42 	opio->op_name[opio->op_namelen] = '\0';
43 	printf("%*s%s: ", depth * 4, " ", opio->op_name);
44 	if (opio->op_buflen > 0) {
45 		opio->op_buf[opio->op_buflen] = '\0';
46 		multi = special = 0;
47 
48 		/*
49 		 * On macppc we have string-values properties that end
50 		 * with multiple NUL characters, and the serial number
51 		 * has them embedded within the string.
52 		 */
53 		if (opio->op_buf[0] != '\0') {
54 			for (i = 0; i < opio->op_buflen; i++) {
55 				p = &opio->op_buf[i];
56 				if (*p >= ' ' && *p <= '~')
57 					continue;
58 				if (*p == '\0') {
59 					if (i + 1 < opio->op_buflen)
60 						p++;
61 					if (*p >= ' ' && *p <= '~') {
62 						special = multi;
63 						continue;
64 					}
65 					if (*p == '\0') {
66 						multi = 1;
67 						continue;
68 					}
69 				}
70 
71 				special = 1;
72 				break;
73 			}
74 		} else {
75 			if (opio->op_buflen > 1)
76 				special = 1;
77 		}
78 
79 		if (special && strcmp(opio->op_name, "serial-number") != 0) {
80 			for (i = 0; opio->op_buflen - i >= sizeof(int);
81 			    i += sizeof(int)) {
82 				if (i)
83 					printf(".");
84 				cell = *(uint32_t *)&opio->op_buf[i];
85 				printf("%08x", betoh32(cell));
86 			}
87 			if (i < opio->op_buflen) {
88 				if (i)
89 					printf(".");
90 				for (; i < opio->op_buflen; i++) {
91 					printf("%02x",
92 					    *(u_char *)&opio->op_buf[i]);
93 				}
94 			}
95 		} else {
96 			for (i = 0; i < opio->op_buflen;
97 			    i += strlen(&opio->op_buf[i]) + 1) {
98 				if (i && strlen(&opio->op_buf[i]) == 0)
99 					continue;
100 				if (i)
101 					printf(" + ");
102 				printf("'%s'", &opio->op_buf[i]);
103 			}
104 		}
105 	} else if(opio->op_buflen < 0)
106 		printf("too large");
107 	printf("\n");
108 }
109 
110 void
111 op_nodes(int fd, int node, int depth)
112 {
113 	char op_buf[BUFSIZE * 8];
114 	char op_name[BUFSIZE];
115 	struct opiocdesc opio;
116 
117 	memset(op_name, 0, sizeof(op_name));
118 	opio.op_nodeid = node;
119 	opio.op_buf = op_buf;
120 	opio.op_name = op_name;
121 
122 	if (!node) {
123 		if (ioctl(fd, OPIOCGETNEXT, &opio) == -1)
124 			err(1, "OPIOCGETNEXT");
125 		node = opio.op_nodeid;
126 	} else
127 		printf("\n%*s", depth * 4, " ");
128 
129 	printf("Node 0x%x\n", node);
130 
131 	for (;;) {
132 		opio.op_buflen = sizeof(op_buf);
133 		opio.op_namelen = sizeof(op_name);
134 
135 		/* Get the next property. */
136 		if (ioctl(fd, OPIOCNEXTPROP, &opio) == -1)
137 			err(1, "OPIOCNEXTPROP");
138 
139 		op_buf[opio.op_buflen] = '\0';
140 		(void)strlcpy(op_name, op_buf, sizeof(op_name));
141 		opio.op_namelen = strlen(op_name);
142 
143 		/* If it's the last, punt. */
144 		if (opio.op_namelen == 0)
145 			break;
146 
147 		bzero(op_buf, sizeof(op_buf));
148 		opio.op_buflen = sizeof(op_buf);
149 
150 		/* And its value. */
151 		if (ioctl(fd, OPIOCGET, &opio) == -1) {
152 			if (errno != ENOMEM)
153 				err(1, "OPIOCGET");
154 
155 			opio.op_buflen = -1;	/* for op_print */
156 		}
157 
158 		op_print(&opio, depth + 1);
159 	}
160 
161 	/* Get next child. */
162 	if (ioctl(fd, OPIOCGETCHILD, &opio) == -1)
163 		err(1, "OPIOCGETCHILD");
164 	if (opio.op_nodeid)
165 		op_nodes(fd, opio.op_nodeid, depth + 1);
166 
167 	/* Get next node/sibling. */
168 	opio.op_nodeid = node;
169 	if (ioctl(fd, OPIOCGETNEXT, &opio) == -1)
170 		err(1, "OPIOCGETNEXT");
171 	if (opio.op_nodeid)
172 		op_nodes(fd, opio.op_nodeid, depth);
173 }
174 
175 void
176 op_tree(void)
177 {
178 	int fd;
179 
180 	if ((fd = open(path_openprom, O_RDONLY, 0640)) == -1)
181 		err(1, "open: %s", path_openprom);
182 	op_nodes(fd, 0, 0);
183 	(void)close(fd);
184 }
185