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