nvram.c revision 253162
1160892Ssobomax/* 2160892Ssobomax * Copyright (c) 2006 Maxim Sobolev <sobomax@FreeBSD.org> 3160892Ssobomax * All rights reserved. 4160892Ssobomax * 5160892Ssobomax * Redistribution and use in source and binary forms, with or without 6160892Ssobomax * modification, are permitted provided that the following conditions 7160892Ssobomax * are met: 8160892Ssobomax * 1. Redistributions of source code must retain the above copyright 9160892Ssobomax * notice, this list of conditions and the following disclaimer. 10160892Ssobomax * 2. Redistributions in binary form must reproduce the above copyright 11160892Ssobomax * notice, this list of conditions and the following disclaimer in the 12160892Ssobomax * documentation and/or other materials provided with the distribution. 13160892Ssobomax * 14160892Ssobomax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15160892Ssobomax * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16160892Ssobomax * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17160892Ssobomax * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 18160892Ssobomax * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19160892Ssobomax * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 20160892Ssobomax * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21160892Ssobomax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 22160892Ssobomax * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 23160892Ssobomax * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24160892Ssobomax * POSSIBILITY OF SUCH DAMAGE. 25160892Ssobomax * 26160892Ssobomax * $FreeBSD: head/usr.sbin/nvram/nvram.c 253162 2013-07-10 18:07:01Z rdivacky $ 27160892Ssobomax */ 28160892Ssobomax 29160892Ssobomax#include <sys/types.h> 30160892Ssobomax#include <sys/uio.h> 31160892Ssobomax#include <err.h> 32160892Ssobomax#include <errno.h> 33160892Ssobomax#include <fcntl.h> 34160892Ssobomax#include <paths.h> 35160892Ssobomax#include <stdio.h> 36160892Ssobomax#include <stdlib.h> 37160892Ssobomax#include <string.h> 38160892Ssobomax#include <unistd.h> 39160892Ssobomax 40160892Ssobomax#include <dev/powermac_nvram/powermac_nvramvar.h> 41160892Ssobomax 42160892Ssobomax#define DEVICE_NAME (_PATH_DEV "powermac_nvram") 43160892Ssobomax 44160892Ssobomaxstatic void usage(void); 45160892Ssobomaxstatic int remove_var(uint8_t *, int, const char *); 46160892Ssobomaxstatic int append_var(uint8_t *, int, const char *, const char *); 47160892Ssobomax 48160892Ssobomaxstruct deletelist { 49160892Ssobomax char *name; 50160892Ssobomax struct deletelist *next; 51160892Ssobomax struct deletelist *last; 52160892Ssobomax}; 53160892Ssobomax 54253162Srdivackystatic union { 55239733Srdivacky uint8_t buf[sizeof(struct chrp_header)]; 56239733Srdivacky struct chrp_header header; 57239733Srdivacky} conv; 58239733Srdivacky 59160892Ssobomaxint 60160892Ssobomaxmain(int argc, char **argv) 61160892Ssobomax{ 62160892Ssobomax int opt, dump, fd, res, i, size; 63160892Ssobomax uint8_t buf[NVRAM_SIZE], *cp, *common; 64160892Ssobomax struct deletelist *dl; 65160892Ssobomax 66160892Ssobomax dump = 0; 67160892Ssobomax dl = NULL; 68160892Ssobomax 69160892Ssobomax while((opt = getopt(argc, argv, "d:p")) != -1) { 70160892Ssobomax switch(opt) { 71160892Ssobomax case 'p': 72160892Ssobomax dump = 1; 73160892Ssobomax break; 74160892Ssobomax 75160892Ssobomax case 'd': 76160892Ssobomax if (dl == NULL) { 77160892Ssobomax dl = malloc(sizeof(*dl)); 78160892Ssobomax if (dl == NULL) 79160892Ssobomax err(1, "malloc"); 80160892Ssobomax bzero(dl, sizeof(*dl)); 81160892Ssobomax dl->last = dl; 82160892Ssobomax } else { 83160892Ssobomax dl->last->next = malloc(sizeof(*dl)); 84160892Ssobomax if (dl->last->next == NULL) 85160892Ssobomax err(1, "malloc"); 86160892Ssobomax dl->last = dl->last->next; 87160892Ssobomax bzero(dl->last, sizeof(*dl)); 88160892Ssobomax } 89160892Ssobomax dl->last->name = optarg; 90160892Ssobomax break; 91160892Ssobomax 92160892Ssobomax default: 93160892Ssobomax usage(); 94160892Ssobomax /* Not reached */ 95160892Ssobomax } 96160892Ssobomax } 97160892Ssobomax argc -= optind; 98160892Ssobomax argv += optind; 99160892Ssobomax 100160892Ssobomax if (argc == 0 && dump == 0 && dl == NULL) { 101160892Ssobomax usage(); 102160892Ssobomax /* Not reached */ 103160892Ssobomax } 104160892Ssobomax 105160892Ssobomax fd = open(DEVICE_NAME, O_RDWR); 106160892Ssobomax if (fd == -1) 107160892Ssobomax err(1, DEVICE_NAME); 108160892Ssobomax for (i = 0; i < (int)sizeof(buf);) { 109160892Ssobomax res = read(fd, buf + i, sizeof(buf) - i); 110160892Ssobomax if (res == -1 && errno != EINTR) 111160892Ssobomax err(1, DEVICE_NAME); 112160892Ssobomax if (res == 0) 113160892Ssobomax break; 114160892Ssobomax if (res > 0) 115160892Ssobomax i += res; 116160892Ssobomax } 117160892Ssobomax if (i != sizeof(buf)) 118160892Ssobomax errx(1, "%s: short read", DEVICE_NAME); 119160892Ssobomax 120160892Ssobomax /* Locate common block */ 121160892Ssobomax size = 0; 122160892Ssobomax for (cp = buf; cp < buf + sizeof(buf); cp += size) { 123239733Srdivacky memcpy(conv.buf, cp, sizeof(struct chrp_header)); 124239733Srdivacky size = conv.header.length * 0x10; 125239733Srdivacky if (strncmp(conv.header.name, "common", 7) == 0) 126160892Ssobomax break; 127160892Ssobomax } 128160892Ssobomax if (cp >= buf + sizeof(buf) || size <= (int)sizeof(struct chrp_header)) 129160892Ssobomax errx(1, "%s: no common block", DEVICE_NAME); 130160892Ssobomax common = cp + sizeof(struct chrp_header); 131160892Ssobomax size -= sizeof(struct chrp_header); 132160892Ssobomax 133160892Ssobomax if (dump != 0) { 134160892Ssobomax while (size > 0) { 135160892Ssobomax i = strlen(common) + 1; 136160892Ssobomax if (i == 1) 137160892Ssobomax break; 138160892Ssobomax printf("%s\n", common); 139160892Ssobomax size -= i; 140160892Ssobomax common += i; 141160892Ssobomax } 142160892Ssobomax exit(0); 143160892Ssobomax } 144160892Ssobomax 145160892Ssobomax for (;dl != NULL; dl = dl->next) { 146160892Ssobomax if (remove_var(common, size, dl->name) == 0) 147160892Ssobomax warnx("%s: no such variable", dl->name); 148160892Ssobomax } 149160892Ssobomax 150160892Ssobomax for (; argc > 0; argc--, argv++) { 151160892Ssobomax cp = strchr(*argv, '='); 152160892Ssobomax if (cp == NULL) 153160892Ssobomax errx(1, "%s: invalid argument", *argv); 154160892Ssobomax cp[0] = '\0'; 155160892Ssobomax cp++; 156160892Ssobomax remove_var(common, size, *argv); 157160892Ssobomax if (append_var(common, size, *argv, cp) == -1) 158160892Ssobomax errx(1, "%s: error setting variable", *argv); 159160892Ssobomax } 160160892Ssobomax 161160892Ssobomax for (i = 0; i < (int)sizeof(buf);) { 162160892Ssobomax res = write(fd, buf + i, sizeof(buf) - i); 163160892Ssobomax if (res == -1 && errno != EINTR) 164160892Ssobomax err(1, DEVICE_NAME); 165160892Ssobomax if (res == 0) 166160892Ssobomax break; 167160892Ssobomax if (res > 0) 168160892Ssobomax i += res; 169160892Ssobomax } 170160892Ssobomax if (i != sizeof(buf)) 171160892Ssobomax errx(1, "%s: short write", DEVICE_NAME); 172160892Ssobomax if (close(fd) == -1) 173160892Ssobomax err(1, DEVICE_NAME); 174160892Ssobomax 175160892Ssobomax exit(0); 176160892Ssobomax} 177160892Ssobomax 178160892Ssobomaxstatic void 179160892Ssobomaxusage(void) 180160892Ssobomax{ 181160892Ssobomax 182160892Ssobomax fprintf(stderr, "usage: nvram [-p] | [-d name ...] [name=value ...]\n"); 183160892Ssobomax exit(1); 184160892Ssobomax} 185160892Ssobomax 186160892Ssobomaxstatic int 187160892Ssobomaxremove_var(uint8_t *buf, int len, const char *var_name) 188160892Ssobomax{ 189160892Ssobomax int nremoved, i, name_len; 190160892Ssobomax 191160892Ssobomax nremoved = 0; 192160892Ssobomax name_len = strlen(var_name); 193160892Ssobomax while (len > 0) { 194160892Ssobomax i = strlen(buf) + 1; 195160892Ssobomax if (i == 1) 196160892Ssobomax break; 197160892Ssobomax if (strncmp(buf, var_name, name_len) == 0 && buf[name_len] == '=') { 198160892Ssobomax memmove(buf, buf + i, len - i); 199160892Ssobomax memset(buf + len - i, '\0', i); 200160892Ssobomax nremoved += 1; 201160892Ssobomax continue; 202160892Ssobomax } 203160892Ssobomax len -= i; 204160892Ssobomax buf += i; 205160892Ssobomax } 206160892Ssobomax return nremoved; 207160892Ssobomax} 208160892Ssobomax 209160892Ssobomaxstatic int 210160892Ssobomaxappend_var(uint8_t *buf, int len, const char *var_name, const char *var_value) 211160892Ssobomax{ 212160892Ssobomax int i, append_len; 213160892Ssobomax 214160892Ssobomax while (len > 0) { 215160892Ssobomax i = strlen(buf) + 1; 216160892Ssobomax if (i == 1) 217160892Ssobomax break; 218160892Ssobomax len -= i; 219160892Ssobomax buf += i; 220160892Ssobomax } 221160892Ssobomax append_len = strlen(var_name) + strlen(var_value) + 2; 222160892Ssobomax if (len < append_len) 223160892Ssobomax return -1; 224160892Ssobomax sprintf(buf, "%s=%s", var_name, var_value); 225160892Ssobomax return 0; 226160892Ssobomax} 227