nvram.c revision 160892
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 160892 2006-08-01 22:19:01Z sobomax $ 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 54160892Ssobomaxint 55160892Ssobomaxmain(int argc, char **argv) 56160892Ssobomax{ 57160892Ssobomax int opt, dump, fd, res, i, size; 58160892Ssobomax uint8_t buf[NVRAM_SIZE], *cp, *common; 59160892Ssobomax struct chrp_header *header; 60160892Ssobomax struct deletelist *dl; 61160892Ssobomax 62160892Ssobomax dump = 0; 63160892Ssobomax dl = NULL; 64160892Ssobomax 65160892Ssobomax while((opt = getopt(argc, argv, "d:p")) != -1) { 66160892Ssobomax switch(opt) { 67160892Ssobomax case 'p': 68160892Ssobomax dump = 1; 69160892Ssobomax break; 70160892Ssobomax 71160892Ssobomax case 'd': 72160892Ssobomax if (dl == NULL) { 73160892Ssobomax dl = malloc(sizeof(*dl)); 74160892Ssobomax if (dl == NULL) 75160892Ssobomax err(1, "malloc"); 76160892Ssobomax bzero(dl, sizeof(*dl)); 77160892Ssobomax dl->last = dl; 78160892Ssobomax } else { 79160892Ssobomax dl->last->next = malloc(sizeof(*dl)); 80160892Ssobomax if (dl->last->next == NULL) 81160892Ssobomax err(1, "malloc"); 82160892Ssobomax dl->last = dl->last->next; 83160892Ssobomax bzero(dl->last, sizeof(*dl)); 84160892Ssobomax } 85160892Ssobomax dl->last->name = optarg; 86160892Ssobomax break; 87160892Ssobomax 88160892Ssobomax default: 89160892Ssobomax usage(); 90160892Ssobomax /* Not reached */ 91160892Ssobomax } 92160892Ssobomax } 93160892Ssobomax argc -= optind; 94160892Ssobomax argv += optind; 95160892Ssobomax 96160892Ssobomax if (argc == 0 && dump == 0 && dl == NULL) { 97160892Ssobomax usage(); 98160892Ssobomax /* Not reached */ 99160892Ssobomax } 100160892Ssobomax 101160892Ssobomax fd = open(DEVICE_NAME, O_RDWR); 102160892Ssobomax if (fd == -1) 103160892Ssobomax err(1, DEVICE_NAME); 104160892Ssobomax for (i = 0; i < (int)sizeof(buf);) { 105160892Ssobomax res = read(fd, buf + i, sizeof(buf) - i); 106160892Ssobomax if (res == -1 && errno != EINTR) 107160892Ssobomax err(1, DEVICE_NAME); 108160892Ssobomax if (res == 0) 109160892Ssobomax break; 110160892Ssobomax if (res > 0) 111160892Ssobomax i += res; 112160892Ssobomax } 113160892Ssobomax if (i != sizeof(buf)) 114160892Ssobomax errx(1, "%s: short read", DEVICE_NAME); 115160892Ssobomax 116160892Ssobomax /* Locate common block */ 117160892Ssobomax size = 0; 118160892Ssobomax for (cp = buf; cp < buf + sizeof(buf); cp += size) { 119160892Ssobomax header = (struct chrp_header *)cp; 120160892Ssobomax size = header->length * 0x10; 121160892Ssobomax if (strncmp(header->name, "common", 7) == 0) 122160892Ssobomax break; 123160892Ssobomax } 124160892Ssobomax if (cp >= buf + sizeof(buf) || size <= (int)sizeof(struct chrp_header)) 125160892Ssobomax errx(1, "%s: no common block", DEVICE_NAME); 126160892Ssobomax common = cp + sizeof(struct chrp_header); 127160892Ssobomax size -= sizeof(struct chrp_header); 128160892Ssobomax 129160892Ssobomax if (dump != 0) { 130160892Ssobomax while (size > 0) { 131160892Ssobomax i = strlen(common) + 1; 132160892Ssobomax if (i == 1) 133160892Ssobomax break; 134160892Ssobomax printf("%s\n", common); 135160892Ssobomax size -= i; 136160892Ssobomax common += i; 137160892Ssobomax } 138160892Ssobomax exit(0); 139160892Ssobomax } 140160892Ssobomax 141160892Ssobomax for (;dl != NULL; dl = dl->next) { 142160892Ssobomax if (remove_var(common, size, dl->name) == 0) 143160892Ssobomax warnx("%s: no such variable", dl->name); 144160892Ssobomax } 145160892Ssobomax 146160892Ssobomax for (; argc > 0; argc--, argv++) { 147160892Ssobomax cp = strchr(*argv, '='); 148160892Ssobomax if (cp == NULL) 149160892Ssobomax errx(1, "%s: invalid argument", *argv); 150160892Ssobomax cp[0] = '\0'; 151160892Ssobomax cp++; 152160892Ssobomax remove_var(common, size, *argv); 153160892Ssobomax if (append_var(common, size, *argv, cp) == -1) 154160892Ssobomax errx(1, "%s: error setting variable", *argv); 155160892Ssobomax } 156160892Ssobomax 157160892Ssobomax for (i = 0; i < (int)sizeof(buf);) { 158160892Ssobomax res = write(fd, buf + i, sizeof(buf) - i); 159160892Ssobomax if (res == -1 && errno != EINTR) 160160892Ssobomax err(1, DEVICE_NAME); 161160892Ssobomax if (res == 0) 162160892Ssobomax break; 163160892Ssobomax if (res > 0) 164160892Ssobomax i += res; 165160892Ssobomax } 166160892Ssobomax if (i != sizeof(buf)) 167160892Ssobomax errx(1, "%s: short write", DEVICE_NAME); 168160892Ssobomax if (close(fd) == -1) 169160892Ssobomax err(1, DEVICE_NAME); 170160892Ssobomax 171160892Ssobomax exit(0); 172160892Ssobomax} 173160892Ssobomax 174160892Ssobomaxstatic void 175160892Ssobomaxusage(void) 176160892Ssobomax{ 177160892Ssobomax 178160892Ssobomax fprintf(stderr, "usage: nvram [-p] | [-d name ...] [name=value ...]\n"); 179160892Ssobomax exit(1); 180160892Ssobomax} 181160892Ssobomax 182160892Ssobomaxstatic int 183160892Ssobomaxremove_var(uint8_t *buf, int len, const char *var_name) 184160892Ssobomax{ 185160892Ssobomax int nremoved, i, name_len; 186160892Ssobomax 187160892Ssobomax nremoved = 0; 188160892Ssobomax name_len = strlen(var_name); 189160892Ssobomax while (len > 0) { 190160892Ssobomax i = strlen(buf) + 1; 191160892Ssobomax if (i == 1) 192160892Ssobomax break; 193160892Ssobomax if (strncmp(buf, var_name, name_len) == 0 && buf[name_len] == '=') { 194160892Ssobomax memmove(buf, buf + i, len - i); 195160892Ssobomax memset(buf + len - i, '\0', i); 196160892Ssobomax nremoved += 1; 197160892Ssobomax continue; 198160892Ssobomax } 199160892Ssobomax len -= i; 200160892Ssobomax buf += i; 201160892Ssobomax } 202160892Ssobomax return nremoved; 203160892Ssobomax} 204160892Ssobomax 205160892Ssobomaxstatic int 206160892Ssobomaxappend_var(uint8_t *buf, int len, const char *var_name, const char *var_value) 207160892Ssobomax{ 208160892Ssobomax int i, append_len; 209160892Ssobomax 210160892Ssobomax while (len > 0) { 211160892Ssobomax i = strlen(buf) + 1; 212160892Ssobomax if (i == 1) 213160892Ssobomax break; 214160892Ssobomax len -= i; 215160892Ssobomax buf += i; 216160892Ssobomax } 217160892Ssobomax append_len = strlen(var_name) + strlen(var_value) + 2; 218160892Ssobomax if (len < append_len) 219160892Ssobomax return -1; 220160892Ssobomax sprintf(buf, "%s=%s", var_name, var_value); 221160892Ssobomax return 0; 222160892Ssobomax} 223