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