1 /*- 2 * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 18 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 22 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 23 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include <sys/cdefs.h> 27 __FBSDID("$FreeBSD$"); 28 29 #include <sys/types.h> 30 #include <sys/ioctl.h> 31 32 #include <dev/ofw/openfirmio.h> 33 34 #include <err.h> 35 #include <errno.h> 36 #include <fcntl.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <vis.h> 42 43 #include "pathnames.h" 44 #include "ofw_util.h" 45 46 /* Constants controlling the layout of the output. */ 47 #define LVLINDENT 2 48 #define NAMEINDENT 2 49 #define DUMPINDENT 4 50 #define CHARSPERLINE 60 51 #define BYTESPERLINE (CHARSPERLINE / 3) 52 53 /* Default space reserved for properties. */ 54 #define PROPBUFLEN 8192 55 56 #define OFW_IOCTL(fd, cmd, val) do { \ 57 if (ioctl(fd, cmd, val) == -1) \ 58 err(1, "ioctl(..., " #cmd ", ...) failed"); \ 59 } while (0) 60 61 int 62 ofw_open(void) 63 { 64 int fd; 65 66 if ((fd = open(PATH_DEV_OPENFIRM, O_RDONLY)) == -1) 67 err(1, "could not open " PATH_DEV_OPENFIRM); 68 return (fd); 69 } 70 71 void 72 ofw_close(int fd) 73 { 74 75 close(fd); 76 } 77 78 phandle_t 79 ofw_root(int fd) 80 { 81 82 return (ofw_peer(fd, 0)); 83 } 84 85 phandle_t 86 ofw_peer(int fd, phandle_t node) 87 { 88 phandle_t rv; 89 90 rv = node; 91 OFW_IOCTL(fd, OFIOCGETNEXT, &rv); 92 return (rv); 93 } 94 95 phandle_t 96 ofw_child(int fd, phandle_t node) 97 { 98 phandle_t rv; 99 100 rv = node; 101 OFW_IOCTL(fd, OFIOCGETCHILD, &rv); 102 return (rv); 103 } 104 105 phandle_t 106 ofw_finddevice(int fd, char *name) 107 { 108 struct ofiocdesc d; 109 110 d.of_nodeid = 0; 111 d.of_namelen = strlen(name); 112 d.of_name = name; 113 d.of_buflen = 0; 114 d.of_buf = NULL; 115 if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) { 116 if (errno == ENOENT) 117 err(2, "Node '%s' not found", name); 118 else 119 err(1, "ioctl(..., OFIOCFINDDEVICE, ...) failed"); 120 } 121 return (d.of_nodeid); 122 } 123 124 int 125 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen) 126 { 127 128 return (ofw_nextprop(fd, node, NULL, buf, buflen)); 129 } 130 131 int 132 ofw_nextprop(int fd, phandle_t node, char *prev, char *buf, int buflen) 133 { 134 struct ofiocdesc d; 135 136 d.of_nodeid = node; 137 d.of_namelen = prev != NULL ? strlen(prev) : 0; 138 d.of_name = prev; 139 d.of_buflen = buflen; 140 d.of_buf = buf; 141 if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) { 142 if (errno == ENOENT) 143 return (0); 144 else 145 err(1, "ioctl(..., OFIOCNEXTPROP, ...) failed"); 146 } 147 return (d.of_buflen); 148 } 149 150 static void * 151 ofw_malloc(int size) 152 { 153 void *p; 154 155 if ((p = malloc(size)) == NULL) 156 err(1, "malloc() failed"); 157 return (p); 158 } 159 160 int 161 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen) 162 { 163 struct ofiocdesc d; 164 165 d.of_nodeid = node; 166 d.of_namelen = strlen(name); 167 d.of_name = name; 168 d.of_buflen = buflen; 169 d.of_buf = buf; 170 OFW_IOCTL(fd, OFIOCGET, &d); 171 return (d.of_buflen); 172 } 173 174 int 175 ofw_getproplen(int fd, phandle_t node, const char *name) 176 { 177 struct ofiocdesc d; 178 179 d.of_nodeid = node; 180 d.of_namelen = strlen(name); 181 d.of_name = name; 182 OFW_IOCTL(fd, OFIOCGETPROPLEN, &d); 183 return (d.of_buflen); 184 } 185 186 int 187 ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf, 188 int *buflen, int reserve) 189 { 190 struct ofiocdesc d; 191 int len, rv; 192 193 do { 194 len = ofw_getproplen(fd, node, name); 195 if (len < 0) 196 return (len); 197 if (*buflen < len + reserve) { 198 if (*buf != NULL) 199 free(*buf); 200 *buflen = len + reserve + PROPBUFLEN; 201 *buf = ofw_malloc(*buflen); 202 } 203 d.of_nodeid = node; 204 d.of_namelen = strlen(name); 205 d.of_name = name; 206 d.of_buflen = *buflen - reserve; 207 d.of_buf = *buf; 208 rv = ioctl(fd, OFIOCGET, &d); 209 } while (rv == -1 && errno == ENOMEM); 210 if (rv == -1) 211 err(1, "ioctl(..., OFIOCGET, ...) failed"); 212 return (d.of_buflen); 213 } 214 215 static void 216 ofw_indent(int level) 217 { 218 int i; 219 220 for (i = 0; i < level; i++) 221 putchar(' '); 222 } 223 224 static void 225 ofw_dump_properties(int fd, phandle_t n, int level, char *pmatch, int raw, 226 int str) 227 { 228 static char *pbuf; 229 static char *visbuf; 230 static char printbuf[CHARSPERLINE + 1]; 231 static int pblen, vblen; 232 char prop[32]; 233 int nlen, len, i, j, max, vlen; 234 unsigned int b; 235 236 for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0; 237 nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) { 238 if (pmatch != NULL && strcmp(pmatch, prop) != 0) 239 continue; 240 len = ofw_getprop_alloc(fd, n, prop, (void **)&pbuf, &pblen, 1); 241 if (len < 0) 242 continue; 243 if (raw) 244 write(STDOUT_FILENO, pbuf, len); 245 else if (str) { 246 pbuf[len] = '\0'; 247 printf("%s\n", pbuf); 248 } else { 249 ofw_indent(level * LVLINDENT + NAMEINDENT); 250 printf("%s:\n", prop); 251 /* Print in hex. */ 252 for (i = 0; i < len; i += BYTESPERLINE) { 253 max = len - i; 254 max = max > BYTESPERLINE ? BYTESPERLINE : max; 255 ofw_indent(level * LVLINDENT + DUMPINDENT); 256 for (j = 0; j < max; j++) { 257 b = (unsigned char)pbuf[i + j]; 258 printf("%02x ", b); 259 } 260 printf("\n"); 261 } 262 /* 263 * strvis() and print if it looks like it is 264 * zero-terminated. 265 */ 266 if (pbuf[len - 1] == '\0' && 267 strlen(pbuf) == (unsigned)len - 1) { 268 if (vblen < (len - 1) * 4 + 1) { 269 if (visbuf != NULL) 270 free(visbuf); 271 vblen = (PROPBUFLEN + len) * 4 + 1; 272 visbuf = ofw_malloc(vblen); 273 } 274 vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL); 275 for (i = 0; i < vlen; i += CHARSPERLINE) { 276 ofw_indent(level * LVLINDENT + 277 DUMPINDENT); 278 strlcpy(printbuf, &visbuf[i], 279 sizeof(printbuf)); 280 printf("'%s'\n", printbuf); 281 } 282 } 283 } 284 } 285 } 286 287 static void 288 ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop, char *pmatch, 289 int raw, int str) 290 { 291 static char *nbuf; 292 static int nblen = 0; 293 int plen; 294 phandle_t c; 295 296 if (!(raw || str)) { 297 ofw_indent(level * LVLINDENT); 298 printf("Node %#lx", (unsigned long)n); 299 plen = ofw_getprop_alloc(fd, n, "name", (void **)&nbuf, 300 &nblen, 1); 301 if (plen > 0) { 302 nbuf[plen] = '\0'; 303 printf(": %s\n", nbuf); 304 } else 305 putchar('\n'); 306 } 307 if (prop) 308 ofw_dump_properties(fd, n, level, pmatch, raw, str); 309 if (rec) { 310 for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) { 311 ofw_dump_node(fd, c, level + 1, rec, prop, pmatch, 312 raw, str); 313 } 314 } 315 } 316 317 void 318 ofw_dump(int fd, char *start, int rec, int prop, char *pmatch, int raw, int str) 319 { 320 phandle_t n; 321 322 n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start); 323 ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str); 324 } 325 326