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