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 <string.h> 39 #include <unistd.h> 40 #include <vis.h> 41 42 #include "pathnames.h" 43 #include "ofw_util.h" 44 45 /* Constants controlling the layout of the output. */ 46 #define LVLINDENT 2 47 #define NAMEINDENT 2 48 #define DUMPINDENT 4 49 #define CHARSPERLINE 60 50 #define BYTESPERLINE (CHARSPERLINE / 3) 51 52 /* Maximum supported property size. */ 53 #define PROPBUFLEN 1024 54 55 #define OFW_IOCTL(fd, cmd, val) do { \ 56 if (ioctl(fd, cmd, val) == -1) \ 57 err(1, "ioctl(..., " #cmd ", ...) failed"); \ 58 } while (0) 59 60 int 61 ofw_open(void) 62 { 63 int fd; 64 65 if ((fd = open(PATH_DEV_OPENFIRM, O_RDONLY)) == -1) 66 err(1, "could not open " PATH_DEV_OPENFIRM); 67 return (fd); 68 } 69 70 void 71 ofw_close(int fd) 72 { 73 74 close(fd); 75 } 76 77 phandle_t 78 ofw_root(int fd) 79 { 80 81 return (ofw_peer(fd, 0)); 82 } 83 84 phandle_t 85 ofw_peer(int fd, phandle_t node) 86 { 87 phandle_t rv; 88 89 rv = node; 90 OFW_IOCTL(fd, OFIOCGETNEXT, &rv); 91 return (rv); 92 } 93 94 phandle_t 95 ofw_child(int fd, phandle_t node) 96 { 97 phandle_t rv; 98 99 rv = node; 100 OFW_IOCTL(fd, OFIOCGETCHILD, &rv); 101 return (rv); 102 } 103 104 phandle_t 105 ofw_finddevice(int fd, char *name) 106 { 107 struct ofiocdesc d; 108 109 d.of_nodeid = 0; 110 d.of_namelen = strlen(name); 111 d.of_name = name; 112 d.of_buflen = 0; 113 d.of_buf = NULL; 114 if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) { 115 if (errno == ENOENT) 116 err(2, "Node '%s' not found", name); 117 else 118 err(1, "ioctl(..., OFIOCFINDDEVICE, ...) failed"); 119 } 120 return (d.of_nodeid); 121 } 122 123 int 124 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen) 125 { 126 127 return (ofw_nextprop(fd, node, NULL, buf, buflen)); 128 } 129 130 int 131 ofw_nextprop(int fd, phandle_t node, char *prev, char *buf, int buflen) 132 { 133 struct ofiocdesc d; 134 135 d.of_nodeid = node; 136 d.of_namelen = prev != NULL ? strlen(prev) : 0; 137 d.of_name = prev; 138 d.of_buflen = buflen; 139 d.of_buf = buf; 140 if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) { 141 if (errno == ENOENT) 142 return (0); 143 else 144 err(1, "ioctl(..., OFIOCNEXTPROP, ...) failed"); 145 } 146 return (d.of_buflen); 147 } 148 149 int 150 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen) 151 { 152 struct ofiocdesc d; 153 154 d.of_nodeid = node; 155 d.of_namelen = strlen(name); 156 d.of_name = name; 157 d.of_buflen = buflen; 158 d.of_buf = buf; 159 OFW_IOCTL(fd, OFIOCGET, &d); 160 return (d.of_buflen); 161 } 162 163 static void 164 ofw_indent(int level) 165 { 166 int i; 167 168 for (i = 0; i < level; i++) 169 putchar(' '); 170 } 171 172 static void 173 ofw_dump_properties(int fd, phandle_t n, int level, char *pmatch, int raw, 174 int str) 175 { 176 static char pbuf[PROPBUFLEN]; 177 static char visbuf[PROPBUFLEN * 4 + 1]; 178 static char printbuf[CHARSPERLINE + 1]; 179 char prop[32]; 180 int nlen, len, i, j, max, vlen; 181 unsigned int b; 182 183 for (nlen = ofw_firstprop(fd, n, prop, sizeof(prop)); nlen != 0; 184 nlen = ofw_nextprop(fd, n, prop, prop, sizeof(prop))) { 185 if (pmatch != NULL && strcmp(pmatch, prop) != 0) 186 continue; 187 len = ofw_getprop(fd, n, prop, pbuf, sizeof(pbuf) - 1); 188 if (raw) 189 write(STDOUT_FILENO, pbuf, len); 190 else if (str) { 191 pbuf[len] = '\0'; 192 printf("%s\n", pbuf); 193 } else { 194 ofw_indent(level * LVLINDENT + NAMEINDENT); 195 printf("%s:\n", prop); 196 /* Print in hex. */ 197 for (i = 0; i < len; i += BYTESPERLINE) { 198 max = len - i; 199 max = max > BYTESPERLINE ? BYTESPERLINE : max; 200 ofw_indent(level * LVLINDENT + DUMPINDENT); 201 for (j = 0; j < max; j++) { 202 b = (unsigned char)pbuf[i + j]; 203 printf("%02x ", b); 204 } 205 printf("\n"); 206 } 207 /* 208 * strvis() and print if it looks like it is 209 * zero-terminated. 210 */ 211 if (pbuf[len - 1] == '\0' && 212 strlen(pbuf) == (unsigned)len - 1) { 213 vlen = strvis(visbuf, pbuf, VIS_TAB | VIS_NL); 214 for (i = 0; i < vlen; i += CHARSPERLINE) { 215 ofw_indent(level * LVLINDENT + 216 DUMPINDENT); 217 strlcpy(printbuf, &visbuf[i], 218 sizeof(printbuf)); 219 printf("'%s'\n", printbuf); 220 } 221 } 222 } 223 } 224 } 225 226 static void 227 ofw_dump_node(int fd, phandle_t n, int level, int rec, int prop, char *pmatch, 228 int raw, int str) 229 { 230 static char nbuf[PROPBUFLEN]; 231 phandle_t c; 232 233 if (!(raw || str)) { 234 ofw_indent(level * LVLINDENT); 235 printf("Node %#lx", (unsigned long)n); 236 if (ofw_getprop(fd, n, "name", nbuf, sizeof(nbuf) - 1) > 0) 237 printf(": %s\n", nbuf); 238 else 239 putchar('\n'); 240 } 241 if (prop) 242 ofw_dump_properties(fd, n, level, pmatch, raw, str); 243 if (rec) { 244 for (c = ofw_child(fd, n); c != 0; c = ofw_peer(fd, c)) { 245 ofw_dump_node(fd, c, level + 1, rec, prop, pmatch, 246 raw, str); 247 } 248 } 249 } 250 251 void 252 ofw_dump(int fd, char *start, int rec, int prop, char *pmatch, int raw, int str) 253 { 254 phandle_t n; 255 256 n = start == NULL ? ofw_root(fd) : ofw_finddevice(fd, start); 257 ofw_dump_node(fd, n, 0, rec, prop, pmatch, raw, str); 258 } 259 260