xref: /freebsd/usr.sbin/ofwdump/ofw_util.c (revision 1d386b48)
1 /*-
2  * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
18  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
23  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include <sys/cdefs.h>
27 #include <sys/types.h>
28 #include <sys/ioctl.h>
29 
30 #include <dev/ofw/openfirmio.h>
31 
32 #include <err.h>
33 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sysexits.h>
39 #include <unistd.h>
40 
41 #include "pathnames.h"
42 #include "ofw_util.h"
43 
44 #define	OFW_IOCTL(fd, cmd, val)	do {					\
45 	if (ioctl(fd, cmd, val) == -1)					\
46 		err(EX_IOERR, "ioctl(..., " #cmd ", ...) failed");	\
47 } while (0)
48 
49 int
50 ofw_open(int mode)
51 {
52 	int fd;
53 
54 	if ((fd = open(PATH_DEV_OPENFIRM, mode)) == -1)
55 		err(EX_UNAVAILABLE, "could not open " PATH_DEV_OPENFIRM);
56 	return (fd);
57 }
58 
59 void
60 ofw_close(int fd)
61 {
62 
63 	close(fd);
64 }
65 
66 phandle_t
67 ofw_root(int fd)
68 {
69 
70 	return (ofw_peer(fd, 0));
71 }
72 
73 phandle_t
74 ofw_optnode(int fd)
75 {
76 	phandle_t rv;
77 
78 	OFW_IOCTL(fd, OFIOCGETOPTNODE, &rv);
79 	return (rv);
80 }
81 
82 phandle_t
83 ofw_peer(int fd, phandle_t node)
84 {
85 	phandle_t rv;
86 
87 	rv = node;
88 	OFW_IOCTL(fd, OFIOCGETNEXT, &rv);
89 	return (rv);
90 }
91 
92 phandle_t
93 ofw_child(int fd, phandle_t node)
94 {
95 	phandle_t rv;
96 
97 	rv = node;
98 	OFW_IOCTL(fd, OFIOCGETCHILD, &rv);
99 	return (rv);
100 }
101 
102 phandle_t
103 ofw_finddevice(int fd, const char *name)
104 {
105 	struct ofiocdesc d;
106 
107 	d.of_nodeid = 0;
108 	d.of_namelen = strlen(name);
109 	d.of_name = name;
110 	d.of_buflen = 0;
111 	d.of_buf = NULL;
112 	if (ioctl(fd, OFIOCFINDDEVICE, &d) == -1) {
113 		if (errno == ENOENT)
114 			err(EX_UNAVAILABLE, "Node '%s' not found", name);
115 		else
116 			err(EX_IOERR,
117 			    "ioctl(..., OFIOCFINDDEVICE, ...) failed");
118 	}
119 	return (d.of_nodeid);
120 }
121 
122 int
123 ofw_firstprop(int fd, phandle_t node, char *buf, int buflen)
124 {
125 
126 	return (ofw_nextprop(fd, node, NULL, buf, buflen));
127 }
128 
129 int
130 ofw_nextprop(int fd, phandle_t node, const char *prev, char *buf, int buflen)
131 {
132 	struct ofiocdesc d;
133 
134 	d.of_nodeid = node;
135 	d.of_namelen = prev != NULL ? strlen(prev) : 0;
136 	d.of_name = prev;
137 	d.of_buflen = buflen;
138 	d.of_buf = buf;
139 	if (ioctl(fd, OFIOCNEXTPROP, &d) == -1) {
140 		if (errno == ENOENT)
141 			return (0);
142 		else
143 			err(EX_IOERR, "ioctl(..., OFIOCNEXTPROP, ...) failed");
144 	}
145 	return (d.of_buflen);
146 }
147 
148 static void *
149 ofw_malloc(int size)
150 {
151 	void *p;
152 
153 	if ((p = malloc(size)) == NULL)
154 		err(EX_OSERR, "malloc() failed");
155 	return (p);
156 }
157 
158 int
159 ofw_getprop(int fd, phandle_t node, const char *name, void *buf, int buflen)
160 {
161 	struct ofiocdesc d;
162 
163 	d.of_nodeid = node;
164 	d.of_namelen = strlen(name);
165 	d.of_name = name;
166 	d.of_buflen = buflen;
167 	d.of_buf = buf;
168 	OFW_IOCTL(fd, OFIOCGET, &d);
169 	return (d.of_buflen);
170 }
171 
172 int
173 ofw_setprop(int fd, phandle_t node, const char *name, const void *buf,
174     int buflen)
175 {
176 	struct ofiocdesc d;
177 
178 	d.of_nodeid = node;
179 	d.of_namelen = strlen(name);
180 	d.of_name = name;
181 	d.of_buflen = buflen;
182 	d.of_buf = ofw_malloc(buflen);
183 	memcpy(d.of_buf, buf, buflen);
184 	OFW_IOCTL(fd, OFIOCSET, &d);
185 	free(d.of_buf);
186 	return (d.of_buflen);
187 }
188 
189 int
190 ofw_getproplen(int fd, phandle_t node, const char *name)
191 {
192 	struct ofiocdesc d;
193 
194 	d.of_nodeid = node;
195 	d.of_namelen = strlen(name);
196 	d.of_name = name;
197 	OFW_IOCTL(fd, OFIOCGETPROPLEN, &d);
198 	return (d.of_buflen);
199 }
200 
201 int
202 ofw_getprop_alloc(int fd, phandle_t node, const char *name, void **buf,
203     int *buflen, int reserve)
204 {
205 	struct ofiocdesc d;
206 	int len, rv;
207 
208 	do {
209 		len = ofw_getproplen(fd, node, name);
210 		if (len < 0)
211 			return (len);
212 		if (*buflen < len + reserve) {
213 			if (*buf != NULL)
214 				free(*buf);
215 			*buflen = len + reserve + OFIOCMAXVALUE;
216 			*buf = ofw_malloc(*buflen);
217 		}
218 		d.of_nodeid = node;
219 		d.of_namelen = strlen(name);
220 		d.of_name = name;
221 		d.of_buflen = *buflen - reserve;
222 		d.of_buf = *buf;
223 		rv = ioctl(fd, OFIOCGET, &d);
224 	} while (rv == -1 && errno == ENOMEM);
225 	if (rv == -1)
226 		err(EX_IOERR, "ioctl(..., OFIOCGET, ...) failed");
227 	return (d.of_buflen);
228 }
229