/* $OpenBSD: optree.c,v 1.6 2009/01/14 21:05:53 fgsch Exp $ */ /* * Copyright (c) 2007 Federico G. Schwindt * * Permission to use, copy, modify, and distribute this software for * any purpose with or without fee is hereby granted, provided that * the above copyright notice and this permission notice appear in all * copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #include #include #include #include #include #include #include #include #include "defs.h" extern char *path_openprom; static void op_print(struct opiocdesc *opio, int depth) { char *p; int i, special; opio->op_name[opio->op_namelen] = '\0'; printf("%*s%s: ", depth * 4, " ", opio->op_name); if (opio->op_buflen > 0) { opio->op_buf[opio->op_buflen] = '\0'; special = 0; /* * XXX This allows multiple NUL characters within * string-valued properties, which may not be what we * want. But on macppc we have string-values * properties that end with multiple NUL characters, * and the serial number has them embedded within the * string. */ if (opio->op_buf[0] != '\0') { for (i = 0; i < opio->op_buflen; i++) { p = &opio->op_buf[i]; if (*p >= ' ' && *p <= '~') continue; if (*p == '\0') { if (i + 1 < opio->op_buflen) p++; if (*p >= ' ' && *p <= '~') continue; if (*p == '\0') continue; } special = 1; break; } } else { if (opio->op_buflen > 1) special = 1; } if (special) { for (i = 0; opio->op_buflen - i >= sizeof(int); i += sizeof(int)) { if (i) printf("."); printf("%08x", *(int *)(long)&opio->op_buf[i]); } if (i < opio->op_buflen) { if (i) printf("."); for (; i < opio->op_buflen; i++) { printf("%02x", *(u_char *)&opio->op_buf[i]); } } } else { for (i = 0; i < opio->op_buflen; i += strlen(&opio->op_buf[i]) + 1) { if (i && strlen(&opio->op_buf[i]) == 0) continue; if (i) printf(" + "); printf("'%s'", &opio->op_buf[i]); } } } else if(opio->op_buflen < 0) printf("too large"); printf("\n"); } void op_nodes(int fd, int node, int depth) { char op_buf[BUFSIZE * 8]; char op_name[BUFSIZE]; struct opiocdesc opio; opio.op_nodeid = node; opio.op_buf = op_buf; opio.op_name = op_name; if (!node) { if (ioctl(fd, OPIOCGETNEXT, &opio) < 0) err(1, "OPIOCGETNEXT"); node = opio.op_nodeid; } else printf("\n%*s", depth * 4, " "); printf("Node 0x%x\n", node); for (;;) { opio.op_buflen = sizeof(op_buf); opio.op_namelen = sizeof(op_name); /* Get the next property. */ if (ioctl(fd, OPIOCNEXTPROP, &opio) < 0) err(1, "OPIOCNEXTPROP"); op_buf[opio.op_buflen] = '\0'; (void)strlcpy(op_name, op_buf, sizeof(op_name)); opio.op_namelen = strlen(op_name); /* If it's the last, punt. */ if (opio.op_namelen == 0) break; bzero(op_buf, sizeof(op_buf)); opio.op_buflen = sizeof(op_buf); /* And its value. */ if (ioctl(fd, OPIOCGET, &opio) < 0) { if (errno != ENOMEM) err(1, "OPIOCGET"); opio.op_buflen = -1; /* for op_print */ } op_print(&opio, depth + 1); } /* Get next child. */ if (ioctl(fd, OPIOCGETCHILD, &opio) < 0) err(1, "OPIOCGETCHILD"); if (opio.op_nodeid) op_nodes(fd, opio.op_nodeid, depth + 1); /* Get next node/sibling. */ opio.op_nodeid = node; if (ioctl(fd, OPIOCGETNEXT, &opio) < 0) err(1, "OPIOCGETNEXT"); if (opio.op_nodeid) op_nodes(fd, opio.op_nodeid, depth); } void op_tree(void) { int fd; if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0) err(1, "open: %s", path_openprom); op_nodes(fd, 0, 0); (void)close(fd); }