1/*	$NetBSD: ophandlers.c,v 1.10 2008/04/28 20:24:15 martin Exp $	*/
2
3/*-
4 * Copyright (c) 1996 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/types.h>
33#include <sys/ioctl.h>
34#include <err.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <stdio.h>
38#include <string.h>
39#include <unistd.h>
40
41#include <machine/eeprom.h>
42#include <machine/openpromio.h>
43
44#include "defs.h"
45
46extern	char *path_openprom;
47extern	int eval;
48extern	int verbose;
49
50static	char err_str[BUFSIZE];
51
52static	void op_notsupp (struct extabent *, struct opiocdesc *, char *);
53
54/*
55 * There are several known fields that I either don't know how to
56 * deal with or require special treatment.
57 */
58static	struct extabent opextab[] = {
59	{ "security-password",		op_notsupp },
60	{ "security-mode",		op_notsupp },
61	{ "oem-logo",			op_notsupp },
62	{ NULL,				op_notsupp },
63};
64
65#define BARF(str1, str2) {						\
66	snprintf(err_str, sizeof err_str, "%s: %s", (str1), (str2));	\
67	++eval;								\
68	return (err_str);						\
69};
70
71void
72op_action(keyword, arg)
73	char *keyword, *arg;
74{
75	char	*cp;
76
77	if ((cp = op_handler(keyword, arg)) != NULL)
78		warnx("%s", cp);
79	return;
80}
81
82#if defined(__sparc__) && !defined(__arch64__)
83int
84check_for_openprom()
85{
86	int fd, rv, optnode;
87
88	/* if we can't open it, obviously we can't use it. */
89	if ((fd = open(path_openprom, O_RDONLY)) < 0)
90		return (0);
91
92	/* check for the presence of OpenFirmware with OPIOCGETOPTNODE */
93	rv = ioctl(fd, OPIOCGETOPTNODE, (char *)&optnode);
94	close (fd);
95
96	return (rv == 0);
97}
98#endif
99
100char *
101op_handler(keyword, arg)
102	char *keyword, *arg;
103{
104	struct opiocdesc opio;
105	struct extabent *ex;
106	char opio_buf[BUFSIZE];
107	int fd, optnode;
108
109	if ((fd = open(path_openprom, arg ? O_RDWR : O_RDONLY, 0640)) < 0)
110		BARF(path_openprom, strerror(errno));
111
112	/* Check to see if it's a special-case keyword. */
113	for (ex = opextab; ex->ex_keyword != NULL; ++ex)
114		if (strcmp(ex->ex_keyword, keyword) == 0)
115			break;
116
117	if (ioctl(fd, OPIOCGETOPTNODE, (char *)&optnode) < 0) {
118		(void)close(fd);
119		BARF("OPIOCGETOPTNODE", strerror(errno));
120	}
121
122	memset(&opio_buf[0], 0, sizeof(opio_buf));
123	memset(&opio, 0, sizeof(opio));
124	opio.op_nodeid = optnode;
125	opio.op_name = keyword;
126	opio.op_namelen = strlen(opio.op_name);
127
128	if (arg) {
129		if (verbose) {
130			printf("old: ");
131
132			opio.op_buf = &opio_buf[0];
133			opio.op_buflen = sizeof(opio_buf);
134			if (ioctl(fd, OPIOCGET, (char *)&opio) < 0) {
135				(void)close(fd);
136				BARF("OPIOCGET", strerror(errno));
137			}
138
139			if (opio.op_buflen <= 0) {
140				printf("nothing available for %s\n", keyword);
141				goto out;
142			}
143
144			if (ex->ex_keyword != NULL)
145				(*ex->ex_handler)(ex, &opio, NULL);
146			else
147				printf("%s\n", opio.op_buf);
148		}
149 out:
150		if (ex->ex_keyword != NULL)
151			(*ex->ex_handler)(ex, &opio, arg);
152		else {
153			opio.op_buf = arg;
154			opio.op_buflen = strlen(arg);
155		}
156
157		if (ioctl(fd, OPIOCSET, (char *)&opio) < 0) {
158			(void)close(fd);
159			BARF("invalid keyword", keyword);
160		}
161
162		if (verbose) {
163			printf("new: ");
164			if (ex->ex_keyword != NULL)
165				(*ex->ex_handler)(ex, &opio, NULL);
166			else
167				printf("%s\n", opio.op_buf);
168		}
169	} else {
170		opio.op_buf = &opio_buf[0];
171		opio.op_buflen = sizeof(opio_buf);
172		if (ioctl(fd, OPIOCGET, (char *)&opio) < 0) {
173			(void)close(fd);
174			BARF("OPIOCGET", strerror(errno));
175		}
176
177		if (opio.op_buflen <= 0) {
178			(void)snprintf(err_str, sizeof err_str,
179			    "nothing available for %s", keyword);
180			return (err_str);
181		}
182
183		if (ex->ex_keyword != NULL)
184			(*ex->ex_handler)(ex, &opio, NULL);
185		else
186			printf("%s=%s\n", keyword, opio.op_buf);
187	}
188
189	(void)close(fd);
190	return (NULL);
191}
192
193/* ARGSUSED */
194static void
195op_notsupp(exent, opiop, arg)
196	struct extabent *exent;
197	struct opiocdesc *opiop;
198	char *arg;
199{
200
201	warnx("property `%s' not yet supported", exent->ex_keyword);
202}
203
204/*
205 * XXX: This code is quite ugly.  You have been warned.
206 * (Really!  This is the only way I could get it to work!)
207 */
208void
209op_dump()
210{
211	struct opiocdesc opio1, opio2;
212	struct extabent *ex;
213	char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], buf4[BUFSIZE];
214	int fd, optnode;
215
216	if ((fd = open(path_openprom, O_RDONLY, 0640)) < 0)
217		err(1, "open: %s", path_openprom);
218
219	if (ioctl(fd, OPIOCGETOPTNODE, (char *)&optnode) < 0)
220		err(1, "OPIOCGETOPTNODE");
221
222	memset(&opio1, 0, sizeof(opio1));
223
224	/* This will grab the first property name from OPIOCNEXTPROP. */
225	memset(buf1, 0, sizeof(buf1));
226	memset(buf2, 0, sizeof(buf2));
227
228	opio1.op_nodeid = opio2.op_nodeid = optnode;
229
230	opio1.op_name = buf1;
231	opio1.op_buf = buf2;
232
233	opio2.op_name = buf3;
234	opio2.op_buf = buf4;
235
236	/*
237	 * For reference: opio1 is for obtaining the name.  Pass the
238	 * name of the last property read in op_name, and the next one
239	 * will be returned in op_buf.  To get the first name, pass
240	 * an empty string.  There are no more properties when an
241	 * empty string is returned.
242	 *
243	 * opio2 is for obtaining the value associated with that name.
244	 * For some crazy reason, it seems as if we need to do all
245	 * of that gratuitious zapping and copying.  *sigh*
246	 */
247	for (;;) {
248		opio1.op_namelen = strlen(opio1.op_name);
249		opio1.op_buflen = sizeof(buf2);
250
251		if (ioctl(fd, OPIOCNEXTPROP, (char *)&opio1) < 0)
252			err(1, "ioctl: OPIOCNEXTPROP");
253
254		/*
255		 * The name of the property we wish to get the
256		 * value for has been stored in the value field
257		 * of opio1.  If the length of the name is 0, there
258		 * are no more properties left.
259		 */
260		strcpy(opio2.op_name, opio1.op_buf);	/* XXX strcpy is safe */
261		opio2.op_namelen = strlen(opio2.op_name);
262
263		if (opio2.op_namelen == 0) {
264			(void)close(fd);
265			return;
266		}
267
268		memset(opio2.op_buf, 0, sizeof(buf4));
269		opio2.op_buflen = sizeof(buf4);
270
271		if (ioctl(fd, OPIOCGET, (char *)&opio2) < 0)
272			err(1, "ioctl: OPIOCGET");
273
274		for (ex = opextab; ex->ex_keyword != NULL; ++ex)
275			if (strcmp(ex->ex_keyword, opio2.op_name) == 0)
276				break;
277
278		if (ex->ex_keyword != NULL)
279			(*ex->ex_handler)(ex, &opio2, NULL);
280		else
281			printf("%s=%s\n", opio2.op_name, opio2.op_buf);
282
283		/*
284		 * Place the name of the last read value back into
285		 * opio1 so that we may obtain the next name.
286		 */
287		memset(opio1.op_name, 0, sizeof(buf1));
288		memset(opio1.op_buf, 0, sizeof(buf2));
289		strcpy(opio1.op_name, opio2.op_name);	/* XXX strcpy is safe */
290	}
291	/* NOTREACHED */
292}
293