1/*	$NetBSD: prephandlers.c,v 1.2 2008/04/28 20:24:15 martin Exp $	*/
2
3/*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Tim Rightnour.
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 <string.h>
38#include <stdio.h>
39#include <string.h>
40#include <unistd.h>
41
42#include <machine/nvram.h>
43
44#include "defs.h"
45
46extern char *path_prepnvram;
47extern int eval;
48extern int verbose;
49
50static char err_str[BUFSIZE];
51
52static void prep_notsupp(struct extabent *, struct pnviocdesc *, char *);
53
54/*
55 * XXX
56 * This file needs a recalc checksum routine, and a routine to call a
57 * write back to nvram.  The prep NVRAM is stored in RAM after boot, to
58 * prevent horrific bitbanging on the NVRAM chip, we read and write into RAM
59 * until a save operation is called.  At that time we write the ram-based
60 * NVRAM back to the physical NVRAM.  This is a fairly expensive operation.
61 */
62
63
64/*
65 * There are several known fields that I either don't know how to
66 * deal with or require special treatment.
67 */
68static struct extabent prepextab[] = {
69	{NULL, prep_notsupp},
70};
71#define BARF(str1, str2) {						\
72	snprintf(err_str, sizeof err_str, "%s: %s", (str1), (str2));	\
73	++eval;								\
74	return (err_str);						\
75};
76
77void
78prep_action(char *keyword, char *arg)
79{
80	char *cp;
81
82	if ((cp = prep_handler(keyword, arg)) != NULL)
83		warnx("%s", cp);
84	return;
85}
86
87char *
88prep_handler(char *keyword, char *arg)
89{
90	struct pnviocdesc nvio;
91	struct extabent *ex;
92	char nvio_buf[BUFSIZE];
93	int fd;
94
95	if ((fd = open(path_prepnvram, arg ? O_RDWR : O_RDONLY, 0640)) < 0)
96		BARF(path_prepnvram, strerror(errno));
97
98	/* Check to see if it's a special-case keyword. */
99	for (ex = prepextab; ex->ex_keyword != NULL; ++ex)
100		if (strcmp(ex->ex_keyword, keyword) == 0)
101			break;
102
103	memset(&nvio_buf[0], 0, sizeof(nvio_buf));
104	memset(&nvio, 0, sizeof(nvio));
105	nvio.pnv_name = keyword;
106	nvio.pnv_namelen = strlen(nvio.pnv_name);
107
108	if (arg) {
109		if (verbose) {
110			printf("old: ");
111
112			nvio.pnv_buf = &nvio_buf[0];
113			nvio.pnv_buflen = sizeof(nvio_buf);
114			if (ioctl(fd, PNVIOCGET, (char *) &nvio) < 0) {
115				(void)close(fd);
116				BARF("PNVIOCGET", strerror(errno));
117			}
118
119			if (nvio.pnv_buflen <= 0) {
120				printf("nothing available for %s\n", keyword);
121				goto out;
122			}
123			if (ex->ex_keyword != NULL)
124				(*ex->ex_handler) (ex, &nvio, NULL);
125			else
126				printf("%s\n", nvio.pnv_buf);
127		}
128out:
129		if (ex->ex_keyword != NULL)
130			(*ex->ex_handler) (ex, &nvio, arg);
131		else {
132			nvio.pnv_buf = arg;
133			nvio.pnv_buflen = strlen(arg);
134		}
135
136		if (ioctl(fd, PNVIOCSET, (char *) &nvio) < 0) {
137			(void)close(fd);
138			BARF("invalid keyword", keyword);
139		}
140
141		if (verbose) {
142			printf("new: ");
143			if (ex->ex_keyword != NULL)
144				(*ex->ex_handler) (ex, &nvio, NULL);
145			else
146				printf("%s\n", nvio.pnv_buf);
147		}
148	} else {
149		nvio.pnv_buf = &nvio_buf[0];
150		nvio.pnv_buflen = sizeof(nvio_buf);
151		if (ioctl(fd, PNVIOCGET, (char *) &nvio) < 0) {
152			(void)close(fd);
153			BARF("PNVIOCGET", strerror(errno));
154		}
155
156		if (nvio.pnv_buflen <= 0) {
157			(void) snprintf(err_str, sizeof err_str,
158			    "nothing available for %s", keyword);
159			return (err_str);
160		}
161		if (ex->ex_keyword != NULL)
162			(*ex->ex_handler) (ex, &nvio, NULL);
163		else
164			printf("%s=%s\n", keyword, nvio.pnv_buf);
165	}
166
167	(void) close(fd);
168	return (NULL);
169}
170/* ARGSUSED */
171static void
172prep_notsupp(struct extabent * exent, struct pnviocdesc * nviop, char *arg)
173{
174
175	warnx("property `%s' not yet supported", exent->ex_keyword);
176}
177/*
178 * Derrived from op_dump().  This should dump the contents of the PReP
179 * NVRAM chip.
180 */
181
182void
183prep_dump()
184{
185	struct pnviocdesc nvio1, nvio2;
186	char buf1[BUFSIZE], buf2[BUFSIZE], buf3[BUFSIZE], buf4[BUFSIZE];
187	int fd, optnode, nrofvars;
188
189	if ((fd = open(path_prepnvram, O_RDONLY, 0640)) < 0)
190		err(1, "open: %s", path_prepnvram);
191
192	memset(&nvio1, 0, sizeof(nvio1));
193
194	if (ioctl(fd, PNVIOCGETNUMGE, (char *) &nvio1) < 0)
195		err(1, "PNVIOCGETNUMGE");
196
197	nrofvars = nvio1.pnv_num;
198	if (nrofvars < 1)
199		err(1, "PNVIOCGETNUMGE");
200
201	memset(&nvio1, 0, sizeof(nvio1));
202	memset(buf1, 0, sizeof(buf1));
203	memset(buf2, 0, sizeof(buf2));
204	memset(buf3, 0, sizeof(buf3));
205	memset(buf4, 0, sizeof(buf4));
206	nvio1.pnv_name = NULL;
207	nvio1.pnv_buf = buf2;
208	nvio2.pnv_name = buf3;
209	nvio2.pnv_buf = buf4;
210	for (optnode = 0; optnode < nrofvars; optnode++) {
211		nvio1.pnv_buflen = sizeof(buf2);
212
213		if (ioctl(fd, PNVIOCGETNEXTNAME, (char *) &nvio1) < 0)
214			err(1, "PNVIOCGETNEXTNAME");
215
216		if (optnode == 0)
217			nvio1.pnv_name = buf1;
218
219		/* the property name is now stored in nvio1.pnv_buf */
220		strcpy(nvio2.pnv_name, nvio1.pnv_buf);	/* safe */
221		nvio2.pnv_namelen = strlen(nvio2.pnv_name);
222
223		if (nvio2.pnv_namelen == 0) {
224			(void) close(fd);
225			return;
226		}
227		memset(nvio2.pnv_buf, 0, sizeof(buf4));
228		nvio2.pnv_buflen = sizeof(buf4);
229
230		if (ioctl(fd, PNVIOCGET, (char *) &nvio2) < 0)
231			err(1, "PNVIOCGET");
232
233		printf("%s=%s\n", nvio1.pnv_buf, nvio2.pnv_buf);
234
235		/* now clean out the buffers for the next loop */
236
237		memset(nvio1.pnv_name, 0, sizeof(buf1));
238		memset(nvio1.pnv_buf, 0, sizeof(buf2));
239		strcpy(nvio1.pnv_name, nvio2.pnv_name);	/* safe */
240		nvio1.pnv_namelen = strlen(nvio1.pnv_name);
241	}
242	close(fd);
243}
244