1 /* $OpenBSD: optree.c,v 1.5 2008/03/23 12:05:43 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Federico G. Schwindt <fgsch@openbsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 17 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 22 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 24 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/ioctl.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <unistd.h> 36 37 #include <machine/openpromio.h> 38 39 #include "defs.h" 40 41 extern char *path_openprom; 42 43 static void 44 op_print(struct opiocdesc *opio, int depth) 45 { 46 char *p; 47 int i, special; 48 49 opio->op_name[opio->op_namelen] = '\0'; 50 printf("%*s%s: ", depth * 4, " ", opio->op_name); 51 if (opio->op_buflen > 0) { 52 opio->op_buf[opio->op_buflen] = '\0'; 53 special = 0; 54 55 /* 56 * XXX This allows multiple NUL characters within 57 * string-valued properties, which may not be what we 58 * want. But on macppc we have string-values 59 * properties that end with multiple NUL characters, 60 * and the serial number has them embedded within the 61 * string. 62 */ 63 if (opio->op_buf[0] != '\0') { 64 for (i = 0; i < opio->op_buflen; i++) { 65 p = &opio->op_buf[i]; 66 if (*p >= ' ' && *p <= '~') 67 continue; 68 if (*p == '\0') { 69 if (i + 1 < opio->op_buflen) 70 p++; 71 if (*p >= ' ' && *p <= '~') 72 continue; 73 if (*p == '\0') 74 continue; 75 } 76 77 special = 1; 78 break; 79 } 80 } else { 81 if (opio->op_buflen > 1) 82 special = 1; 83 } 84 85 if (special) { 86 for (i = 0; opio->op_buflen - i >= sizeof(int); 87 i += sizeof(int)) { 88 if (i) 89 printf("."); 90 printf("%08x", *(int *)(long)&opio->op_buf[i]); 91 } 92 if (i < opio->op_buflen) { 93 if (i) 94 printf("."); 95 for (; i < opio->op_buflen; i++) { 96 printf("%02x", 97 *(u_char *)&opio->op_buf[i]); 98 } 99 } 100 } else { 101 for (i = 0; i < opio->op_buflen; 102 i += strlen(&opio->op_buf[i]) + 1) { 103 if (i && strlen(&opio->op_buf[i]) == 0) 104 continue; 105 if (i) 106 printf(" + "); 107 printf("'%s'", &opio->op_buf[i]); 108 } 109 } 110 } else if(opio->op_buflen < 0) 111 printf("too large"); 112 printf("\n"); 113 } 114 115 void 116 op_nodes(int fd, int node, int depth) 117 { 118 char op_buf[BUFSIZE * 8]; 119 char op_name[BUFSIZE]; 120 struct opiocdesc opio; 121 122 opio.op_nodeid = node; 123 opio.op_buf = op_buf; 124 opio.op_name = op_name; 125 126 if (!node) { 127 if (ioctl(fd, OPIOCGETNEXT, &opio) < 0) 128 err(1, "OPIOCGETNEXT"); 129 node = opio.op_nodeid; 130 } else 131 printf("\n%*s", depth * 4, " "); 132 133 printf("Node 0x%x\n", node); 134 135 for (;;) { 136 opio.op_buflen = sizeof(op_buf); 137 opio.op_namelen = sizeof(op_name); 138 139 /* Get the next property. */ 140 if (ioctl(fd, OPIOCNEXTPROP, &opio) < 0) 141 err(1, "OPIOCNEXTPROP"); 142 143 op_buf[opio.op_buflen] = '\0'; 144 (void)strlcpy(op_name, op_buf, sizeof(op_name)); 145 opio.op_namelen = strlen(op_name); 146 147 /* If it's the last, punt. */ 148 if (opio.op_namelen == 0) 149 break; 150 151 bzero(op_buf, sizeof(op_buf)); 152 opio.op_buflen = sizeof(op_buf); 153 154 /* And its value. */ 155 if (ioctl(fd, OPIOCGET, &opio) < 0) { 156 if (errno != ENOMEM) 157 err(1, "OPIOCGET"); 158 159 opio.op_buflen = -1; /* for op_print */ 160 } 161 162 op_print(&opio, depth + 1); 163 } 164 165 /* Get next child. */ 166 if (ioctl(fd, OPIOCGETCHILD, &opio) < 0) 167 err(1, "OPIOCGETCHILD"); 168 if (opio.op_nodeid) 169 op_nodes(fd, opio.op_nodeid, depth + 1); 170 171 /* Get next node/sibling. */ 172 opio.op_nodeid = node; 173 if (ioctl(fd, OPIOCGETNEXT, &opio) < 0) 174 err(1, "OPIOCGETNEXT"); 175 if (opio.op_nodeid) 176 op_nodes(fd, opio.op_nodeid, depth); 177 } 178 179 void 180 op_tree(void) 181 { 182 int fd; 183 184 if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0) 185 err(1, "open: %s", path_openprom); 186 op_nodes(fd, 0, 0); 187 (void)close(fd); 188 } 189