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