xref: /freebsd/usr.sbin/nvram/nvram.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1e5d34218SMaxim Sobolev /*
2e5d34218SMaxim Sobolev  * Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org>
3e5d34218SMaxim Sobolev  * All rights reserved.
4e5d34218SMaxim Sobolev  *
5e5d34218SMaxim Sobolev  * Redistribution and use in source and binary forms, with or without
6e5d34218SMaxim Sobolev  * modification, are permitted provided that the following conditions
7e5d34218SMaxim Sobolev  * are met:
8e5d34218SMaxim Sobolev  * 1. Redistributions of source code must retain the above copyright
9e5d34218SMaxim Sobolev  *    notice, this list of conditions and the following disclaimer.
10e5d34218SMaxim Sobolev  * 2. Redistributions in binary form must reproduce the above copyright
11e5d34218SMaxim Sobolev  *    notice, this list of conditions and the following disclaimer in the
12e5d34218SMaxim Sobolev  *    documentation and/or other materials provided with the distribution.
13e5d34218SMaxim Sobolev  *
14e5d34218SMaxim Sobolev  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e5d34218SMaxim Sobolev  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16e5d34218SMaxim Sobolev  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17e5d34218SMaxim Sobolev  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
18e5d34218SMaxim Sobolev  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19e5d34218SMaxim Sobolev  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20e5d34218SMaxim Sobolev  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21e5d34218SMaxim Sobolev  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22e5d34218SMaxim Sobolev  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
23e5d34218SMaxim Sobolev  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24e5d34218SMaxim Sobolev  * POSSIBILITY OF SUCH DAMAGE.
25e5d34218SMaxim Sobolev  */
26e5d34218SMaxim Sobolev 
27e5d34218SMaxim Sobolev #include <sys/types.h>
28e5d34218SMaxim Sobolev #include <sys/uio.h>
29e5d34218SMaxim Sobolev #include <err.h>
30e5d34218SMaxim Sobolev #include <errno.h>
31e5d34218SMaxim Sobolev #include <fcntl.h>
32e5d34218SMaxim Sobolev #include <paths.h>
33e5d34218SMaxim Sobolev #include <stdio.h>
34e5d34218SMaxim Sobolev #include <stdlib.h>
35e5d34218SMaxim Sobolev #include <string.h>
36e5d34218SMaxim Sobolev #include <unistd.h>
37e5d34218SMaxim Sobolev 
38e5d34218SMaxim Sobolev #include <dev/powermac_nvram/powermac_nvramvar.h>
39e5d34218SMaxim Sobolev 
40e5d34218SMaxim Sobolev #define	DEVICE_NAME	(_PATH_DEV "powermac_nvram")
41e5d34218SMaxim Sobolev 
42*a9cce232SAlfonso Gregory static void usage(void) __dead2;
43e5d34218SMaxim Sobolev static int remove_var(uint8_t *, int, const char *);
44e5d34218SMaxim Sobolev static int append_var(uint8_t *, int, const char *, const char *);
45e5d34218SMaxim Sobolev 
46e5d34218SMaxim Sobolev struct deletelist {
47e5d34218SMaxim Sobolev 	char *name;
48e5d34218SMaxim Sobolev 	struct deletelist *next;
49e5d34218SMaxim Sobolev 	struct deletelist *last;
50e5d34218SMaxim Sobolev };
51e5d34218SMaxim Sobolev 
52736aebfcSRoman Divacky static union {
53b1fcaf5fSRoman Divacky 	uint8_t buf[sizeof(struct chrp_header)];
54b1fcaf5fSRoman Divacky 	struct chrp_header header;
55b1fcaf5fSRoman Divacky } conv;
56b1fcaf5fSRoman Divacky 
57e5d34218SMaxim Sobolev int
main(int argc,char ** argv)58e5d34218SMaxim Sobolev main(int argc, char **argv)
59e5d34218SMaxim Sobolev {
60e5d34218SMaxim Sobolev 	int opt, dump, fd, res, i, size;
61e5d34218SMaxim Sobolev 	uint8_t buf[NVRAM_SIZE], *cp, *common;
62e5d34218SMaxim Sobolev 	struct deletelist *dl;
63e5d34218SMaxim Sobolev 
64e5d34218SMaxim Sobolev 	dump = 0;
65e5d34218SMaxim Sobolev 	dl = NULL;
66e5d34218SMaxim Sobolev 
67e5d34218SMaxim Sobolev 	while((opt = getopt(argc, argv, "d:p")) != -1) {
68e5d34218SMaxim Sobolev 		switch(opt) {
69e5d34218SMaxim Sobolev 		case 'p':
70e5d34218SMaxim Sobolev 			dump = 1;
71e5d34218SMaxim Sobolev 			break;
72e5d34218SMaxim Sobolev 
73e5d34218SMaxim Sobolev 		case 'd':
74e5d34218SMaxim Sobolev 			if (dl == NULL) {
75e5d34218SMaxim Sobolev 				dl = malloc(sizeof(*dl));
76e5d34218SMaxim Sobolev 				if (dl == NULL)
77e5d34218SMaxim Sobolev 					err(1, "malloc");
78e5d34218SMaxim Sobolev 				bzero(dl, sizeof(*dl));
79e5d34218SMaxim Sobolev 				dl->last = dl;
80e5d34218SMaxim Sobolev 			} else {
81e5d34218SMaxim Sobolev 				dl->last->next = malloc(sizeof(*dl));
82e5d34218SMaxim Sobolev 				if (dl->last->next == NULL)
83e5d34218SMaxim Sobolev 					err(1, "malloc");
84e5d34218SMaxim Sobolev 				dl->last = dl->last->next;
85e5d34218SMaxim Sobolev 				bzero(dl->last, sizeof(*dl));
86e5d34218SMaxim Sobolev 			}
87e5d34218SMaxim Sobolev 			dl->last->name = optarg;
88e5d34218SMaxim Sobolev 			break;
89e5d34218SMaxim Sobolev 
90e5d34218SMaxim Sobolev 		default:
91e5d34218SMaxim Sobolev 			usage();
92e5d34218SMaxim Sobolev 			/* Not reached */
93e5d34218SMaxim Sobolev 		}
94e5d34218SMaxim Sobolev 	}
95e5d34218SMaxim Sobolev 	argc -= optind;
96e5d34218SMaxim Sobolev 	argv += optind;
97e5d34218SMaxim Sobolev 
98e5d34218SMaxim Sobolev 	if (argc == 0 && dump == 0 && dl == NULL) {
99e5d34218SMaxim Sobolev 		usage();
100e5d34218SMaxim Sobolev 		/* Not reached */
101e5d34218SMaxim Sobolev 	}
102e5d34218SMaxim Sobolev 
103e5d34218SMaxim Sobolev 	fd = open(DEVICE_NAME, O_RDWR);
104e5d34218SMaxim Sobolev 	if (fd == -1)
105e5d34218SMaxim Sobolev 		err(1, DEVICE_NAME);
106e5d34218SMaxim Sobolev 	for (i = 0; i < (int)sizeof(buf);) {
107e5d34218SMaxim Sobolev 		res = read(fd, buf + i, sizeof(buf) - i);
108e5d34218SMaxim Sobolev 		if (res == -1 && errno != EINTR)
109e5d34218SMaxim Sobolev 			err(1, DEVICE_NAME);
110e5d34218SMaxim Sobolev 		if (res == 0)
111e5d34218SMaxim Sobolev 			break;
112e5d34218SMaxim Sobolev 		if (res > 0)
113e5d34218SMaxim Sobolev 			i += res;
114e5d34218SMaxim Sobolev 	}
115e5d34218SMaxim Sobolev 	if (i != sizeof(buf))
116e5d34218SMaxim Sobolev 		errx(1, "%s: short read", DEVICE_NAME);
117e5d34218SMaxim Sobolev 
118e5d34218SMaxim Sobolev 	/* Locate common block */
119e5d34218SMaxim Sobolev 	size = 0;
120e5d34218SMaxim Sobolev 	for (cp = buf; cp < buf + sizeof(buf); cp += size) {
121b1fcaf5fSRoman Divacky 		memcpy(conv.buf, cp, sizeof(struct chrp_header));
122b1fcaf5fSRoman Divacky 		size = conv.header.length * 0x10;
123b1fcaf5fSRoman Divacky 		if (strncmp(conv.header.name, "common", 7) == 0)
124e5d34218SMaxim Sobolev 			break;
125e5d34218SMaxim Sobolev 	}
126e5d34218SMaxim Sobolev 	if (cp >= buf + sizeof(buf) || size <= (int)sizeof(struct chrp_header))
127e5d34218SMaxim Sobolev 		errx(1, "%s: no common block", DEVICE_NAME);
128e5d34218SMaxim Sobolev 	common = cp + sizeof(struct chrp_header);
129e5d34218SMaxim Sobolev 	size -= sizeof(struct chrp_header);
130e5d34218SMaxim Sobolev 
131e5d34218SMaxim Sobolev 	if (dump != 0) {
132e5d34218SMaxim Sobolev 		while (size > 0) {
133e5d34218SMaxim Sobolev 			i = strlen(common) + 1;
134e5d34218SMaxim Sobolev 			if (i == 1)
135e5d34218SMaxim Sobolev 				break;
136e5d34218SMaxim Sobolev 			printf("%s\n", common);
137e5d34218SMaxim Sobolev 			size -= i;
138e5d34218SMaxim Sobolev 			common += i;
139e5d34218SMaxim Sobolev 		}
140e5d34218SMaxim Sobolev 		exit(0);
141e5d34218SMaxim Sobolev 	}
142e5d34218SMaxim Sobolev 
143e5d34218SMaxim Sobolev 	for (;dl != NULL; dl = dl->next) {
144e5d34218SMaxim Sobolev 		if (remove_var(common, size, dl->name) == 0)
145e5d34218SMaxim Sobolev 			warnx("%s: no such variable", dl->name);
146e5d34218SMaxim Sobolev 	}
147e5d34218SMaxim Sobolev 
148e5d34218SMaxim Sobolev 	for (; argc > 0; argc--, argv++) {
149e5d34218SMaxim Sobolev 		cp = strchr(*argv, '=');
150e5d34218SMaxim Sobolev 		if (cp == NULL)
151e5d34218SMaxim Sobolev 			errx(1, "%s: invalid argument", *argv);
152e5d34218SMaxim Sobolev 		cp[0] = '\0';
153e5d34218SMaxim Sobolev 		cp++;
154e5d34218SMaxim Sobolev 		remove_var(common, size, *argv);
155e5d34218SMaxim Sobolev 		if (append_var(common, size, *argv, cp) == -1)
156e5d34218SMaxim Sobolev 			errx(1, "%s: error setting variable", *argv);
157e5d34218SMaxim Sobolev 	}
158e5d34218SMaxim Sobolev 
159e5d34218SMaxim Sobolev 	for (i = 0; i < (int)sizeof(buf);) {
160e5d34218SMaxim Sobolev 		res = write(fd, buf + i, sizeof(buf) - i);
161e5d34218SMaxim Sobolev 		if (res == -1 && errno != EINTR)
162e5d34218SMaxim Sobolev 			err(1, DEVICE_NAME);
163e5d34218SMaxim Sobolev 		if (res == 0)
164e5d34218SMaxim Sobolev 			break;
165e5d34218SMaxim Sobolev 		if (res > 0)
166e5d34218SMaxim Sobolev 			i += res;
167e5d34218SMaxim Sobolev 	}
168e5d34218SMaxim Sobolev 	if (i != sizeof(buf))
169e5d34218SMaxim Sobolev 		errx(1, "%s: short write", DEVICE_NAME);
170e5d34218SMaxim Sobolev 	if (close(fd) == -1)
171e5d34218SMaxim Sobolev 		err(1, DEVICE_NAME);
172e5d34218SMaxim Sobolev 
173e5d34218SMaxim Sobolev 	exit(0);
174e5d34218SMaxim Sobolev }
175e5d34218SMaxim Sobolev 
176e5d34218SMaxim Sobolev static void
usage(void)177e5d34218SMaxim Sobolev usage(void)
178e5d34218SMaxim Sobolev {
179e5d34218SMaxim Sobolev 
180e5d34218SMaxim Sobolev 	fprintf(stderr, "usage: nvram [-p] | [-d name ...] [name=value ...]\n");
181e5d34218SMaxim Sobolev 	exit(1);
182e5d34218SMaxim Sobolev }
183e5d34218SMaxim Sobolev 
184e5d34218SMaxim Sobolev static int
remove_var(uint8_t * buf,int len,const char * var_name)185e5d34218SMaxim Sobolev remove_var(uint8_t *buf, int len, const char *var_name)
186e5d34218SMaxim Sobolev {
187e5d34218SMaxim Sobolev 	int nremoved, i, name_len;
188e5d34218SMaxim Sobolev 
189e5d34218SMaxim Sobolev 	nremoved = 0;
190e5d34218SMaxim Sobolev 	name_len = strlen(var_name);
191e5d34218SMaxim Sobolev 	while (len > 0) {
192e5d34218SMaxim Sobolev 		i = strlen(buf) + 1;
193e5d34218SMaxim Sobolev 		if (i == 1)
194e5d34218SMaxim Sobolev 			break;
195e5d34218SMaxim Sobolev 		if (strncmp(buf, var_name, name_len) == 0 && buf[name_len] == '=') {
196e5d34218SMaxim Sobolev 			memmove(buf, buf + i, len - i);
197e5d34218SMaxim Sobolev 			memset(buf + len - i, '\0', i);
198e5d34218SMaxim Sobolev 			nremoved += 1;
199e5d34218SMaxim Sobolev 			continue;
200e5d34218SMaxim Sobolev 		}
201e5d34218SMaxim Sobolev 		len -= i;
202e5d34218SMaxim Sobolev 		buf += i;
203e5d34218SMaxim Sobolev 	}
204e5d34218SMaxim Sobolev 	return nremoved;
205e5d34218SMaxim Sobolev }
206e5d34218SMaxim Sobolev 
207e5d34218SMaxim Sobolev static int
append_var(uint8_t * buf,int len,const char * var_name,const char * var_value)208e5d34218SMaxim Sobolev append_var(uint8_t *buf, int len, const char *var_name, const char *var_value)
209e5d34218SMaxim Sobolev {
210e5d34218SMaxim Sobolev 	int i, append_len;
211e5d34218SMaxim Sobolev 
212e5d34218SMaxim Sobolev 	while (len > 0) {
213e5d34218SMaxim Sobolev 		i = strlen(buf) + 1;
214e5d34218SMaxim Sobolev 		if (i == 1)
215e5d34218SMaxim Sobolev 			break;
216e5d34218SMaxim Sobolev 		len -= i;
217e5d34218SMaxim Sobolev 		buf += i;
218e5d34218SMaxim Sobolev 	}
219e5d34218SMaxim Sobolev 	append_len = strlen(var_name) + strlen(var_value) + 2;
220e5d34218SMaxim Sobolev 	if (len < append_len)
221e5d34218SMaxim Sobolev 		return -1;
222e5d34218SMaxim Sobolev 	sprintf(buf, "%s=%s", var_name, var_value);
223e5d34218SMaxim Sobolev 	return 0;
224e5d34218SMaxim Sobolev }
225