1 /* $OpenBSD: optree.c,v 1.11 2021/10/24 21:24:18 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
op_print(struct opiocdesc * opio,int depth)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
op_nodes(int fd,int node,int depth)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
op_tree(void)176 op_tree(void)
177 {
178 int fd;
179
180 if ((fd = open(path_openprom, O_RDONLY)) == -1)
181 err(1, "open: %s", path_openprom);
182 op_nodes(fd, 0, 0);
183 (void)close(fd);
184 }
185