1/* 2 * NVRAM variable manipulation (Linux user mode half) 3 * 4 * Copyright 2005, Broadcom Corporation 5 * All Rights Reserved. 6 * 7 * THIS SOFTWARE IS OFFERED "AS IS", AND BROADCOM GRANTS NO WARRANTIES OF ANY 8 * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. BROADCOM 9 * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS 10 * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. 11 * 12 * $Id: nvram_linux.c,v 1.18 2005/05/16 12:35:03 honor Exp $ 13 */ 14 15#include <stdio.h> 16#include <stdlib.h> 17#include <unistd.h> 18#include <errno.h> 19#include <error.h> 20#include <string.h> 21#include <sys/ioctl.h> 22#include <sys/types.h> 23#include <sys/stat.h> 24#include <fcntl.h> 25#include <sys/mman.h> 26 27#include <shared.h> 28#include <typedefs.h> 29#include <bcmnvram.h> 30#include <nvram_convert.h> 31#include <shutils.h> 32#include <utils.h> 33 34#define PATH_DEV_NVRAM "/dev/nvram" 35 36/* Globals */ 37static int nvram_fd = -1; 38static char *nvram_buf = NULL; 39 40int 41nvram_init(void *unused) 42{ 43 if (nvram_fd >= 0) 44 return 0; 45 46 if ((nvram_fd = open(PATH_DEV_NVRAM, O_RDWR)) < 0) 47 goto err; 48 49 /* Map kernel string buffer into user space */ 50 nvram_buf = mmap(NULL, MAX_NVRAM_SPACE, PROT_READ, MAP_SHARED, nvram_fd, 0); 51 if (nvram_buf == MAP_FAILED) { 52 close(nvram_fd); 53 nvram_fd = -1; 54 goto err; 55 } 56 57 fcntl(nvram_fd, F_SETFD, FD_CLOEXEC); 58 59 return 0; 60 61err: 62 perror(PATH_DEV_NVRAM); 63 return errno; 64} 65 66char *nvram_get(const char *name) 67{ 68 char tmp[100]; 69 char *value; 70 size_t count = strlen(name) + 1; 71 unsigned long *off = (unsigned long *)tmp; 72 73 if (nvram_fd < 0) { 74 if (nvram_init(NULL) != 0) return NULL; 75 } 76 77 if (count > sizeof(tmp)) { 78 if ((off = malloc(count)) == NULL) return NULL; 79 } 80 81 /* Get offset into mmap() space */ 82 strcpy((char *) off, name); 83 count = read(nvram_fd, off, count); 84 85 if (count == sizeof(*off)) { 86 value = &nvram_buf[*off]; 87 } 88 else { 89 value = NULL; 90 if (count < 0) perror(PATH_DEV_NVRAM); 91 } 92 93 if (off != (unsigned long *)tmp) free(off); 94 return value; 95} 96 97int nvram_getall(char *buf, int count) 98{ 99 int r; 100 101 if (count <= 0) return 0; 102 103 *buf = 0; 104 if (nvram_fd < 0) { 105 if ((r = nvram_init(NULL)) != 0) return r; 106 } 107 r = read(nvram_fd, buf, count); 108 if (r < 0) perror(PATH_DEV_NVRAM); 109 return (r == count) ? 0 : r; 110} 111 112static char *nvram_xfr_buf = NULL; 113 114char * 115nvram_xfr(const char *buf) 116{ 117 size_t count = strlen(buf)*2+1; // ham 1120 118 int ret; 119 char tmpbuf[1024]; 120 121 if(nvram_fd < 0) 122 if ((ret = nvram_init(NULL))) 123 return NULL; 124 125 if(count > sizeof(tmpbuf)) 126 return NULL; 127 128 strcpy(tmpbuf, buf); 129 130 if(!nvram_xfr_buf) 131 nvram_xfr_buf = (char *)malloc(1024+1); 132 133 if(!nvram_xfr_buf) return NULL; 134 135 ret = ioctl(nvram_fd, NVRAM_MAGIC, tmpbuf); 136 137 if(ret<0) { 138 return NULL; 139 } 140 else { 141 strcpy(nvram_xfr_buf, tmpbuf); 142 return nvram_xfr_buf; 143 } 144} 145 146 147static int _nvram_set(const char *name, const char *value) 148{ 149 size_t count = strlen(name) + 1; 150 char tmp[100]; 151 char *buf = tmp; 152 int ret; 153 154 if (nvram_fd < 0) { 155 if ((ret = nvram_init(NULL)) != 0) return ret; 156 } 157 158 /* Unset if value is NULL */ 159 if (value) count += strlen(value) + 1; 160 161 if (count > sizeof(tmp)) { 162 if ((buf = malloc(count)) == NULL) return -ENOMEM; 163 } 164 165 if (value) { 166 sprintf(buf, "%s=%s", name, value); 167 } 168 else { 169 strcpy(buf, name); 170 } 171 172 ret = write(nvram_fd, buf, count); 173 174 if (ret < 0) perror(PATH_DEV_NVRAM); 175 176 if (buf != tmp) free(buf); 177 178 return (ret == count) ? 0 : ret; 179} 180 181int nvram_set(const char *name, const char *value) 182{ 183 return _nvram_set(name, value); 184} 185 186int nvram_unset(const char *name) 187{ 188 return _nvram_set(name, NULL); 189} 190 191int nvram_commit(void) 192{ 193 int r = 0; 194 FILE *fp; 195 196 if (nvram_get(ASUS_STOP_COMMIT) != NULL) 197 { 198 cprintf("# skip nvram commit #\n"); 199 return r; 200 } 201 202 fp = fopen("/var/log/commit_ret", "w"); 203 204 if (wait_action_idle(10)) { 205 if (nvram_fd < 0) { 206 if ((r = nvram_init(NULL)) != 0) goto finish; 207 } 208 set_action(ACT_NVRAM_COMMIT); 209// nvram_unset("dirty"); 210 r = ioctl(nvram_fd, NVRAM_MAGIC, NULL); 211 set_action(ACT_IDLE); 212 213 if (r < 0) { 214 perror(PATH_DEV_NVRAM); 215 cprintf("commit: error\n"); 216 if(fp!=NULL) 217 fprintf(fp,"commit: error\n"); 218 } 219 else { 220 if(fp!=NULL) 221 fprintf(fp,"commit: OK\n"); 222 } 223 } 224 else { 225 cprintf("commit: system busy\n"); 226 if(fp!=NULL) 227 fprintf(fp,"commit: system busy\n"); 228 } 229 230finish: 231 if(fp!=NULL) fclose(fp); 232 233 return r; 234} 235 236/* 237 * Write a file to an NVRAM variable. 238 * @param name name of variable to get 239 * @param filenname name of file to write 240 * @return return code 241 * 242 * Preserve mode (permissions) of the file. 243 * Create the output directory. 244 */ 245#define MAX_FS 4096 246#define MAGICNUM 0x12161770 /* Ludwig van Beethoven's birthdate. */ 247int nvram_file2nvram(const char *varname, const char *filename) 248{ 249 FILE *fp; 250 int c,count; 251 int i=0,j=0; 252 struct stat stbuf; 253 unsigned char mem[MAX_FS], buf[3 * MAX_FS]; 254 255 if ( !(fp=fopen(filename,"rb") )) { 256 perror(""); 257 return 1; 258 } 259 260 stat(filename, &stbuf); 261 *((mode_t *)mem) = stbuf.st_mode; 262 *((mode_t *)mem+1) = MAGICNUM; 263 264 count=fread(mem + 2*sizeof(mode_t), 1, sizeof(mem) - 2*sizeof(mode_t), fp); 265 if (!feof(fp)) { 266 fclose(fp); 267 fprintf(stderr, "File too big.\n"); 268 return(1); 269 } 270 fclose(fp); 271 count += 2*sizeof(mode_t); 272 for (j = 0; j < count; j++) { 273 if (i > sizeof(buf)-3 ) 274 break; 275 c=mem[j]; 276 if (c >= 32 && c <= 126 && c != '\\' && c != '~') { 277 buf[i++]=(unsigned char) c; 278 } else if (c==0) { 279 buf[i++]='~'; 280 } else { 281 buf[i++]='\\'; 282 sprintf(buf+i,"%02X",c); 283 i+=2; 284 } 285 } 286 buf[i]=0; 287 nvram_set(varname,buf); 288 return 0; 289} 290 291/* 292 * Get the value of an NVRAM variable and write it to a file. 293 * It must have been written with nvram_file2nvram. 294 * Directory path(s) are created, and permissions are preserved. 295 * @param name name of variable to get 296 * @param filenname name of file to write 297 * @return return code 298 */ 299int nvram_nvram2file(const char *varname, const char *filename) 300{ 301 int fnum; 302 int c,tmp; 303 int i=0,j=0; 304 unsigned char *cp; 305 unsigned char mem[MAX_FS], buf[3 * MAX_FS]; 306 307 cp = nvram_get(varname); 308 if (cp == NULL) { 309 printf("Key does not exist: %s\n", varname); 310 return(1); 311 } 312 strcpy(buf, cp); 313 while (buf[i] && j < sizeof(mem)-3 ) { 314 if (buf[i] == '\\') { 315 i++; 316 tmp=buf[i+2]; 317 buf[i+2]=0; 318 sscanf(buf+i,"%02X",&c); 319 buf[i+2]=tmp; 320 i+=2; 321 mem[j]=c;j++; 322 } else if (buf[i] == '~') { 323 mem[j++]=0; 324 i++; 325 } else { 326 mem[j++]=buf[i++]; 327 } 328 } 329 330 if (j<=0) 331 return j; 332 if (*((mode_t *)mem+1) != MAGICNUM) { 333 printf("Error: '%s' not created by nvram setfile.\n", varname); 334 return(-1); 335 } 336 337 /* Create the directories to the path, as necessary. */ 338 strcpy(buf, filename); 339 cp = strrchr(buf, '/'); 340 if (cp && cp > buf) { 341 *cp = 0; 342 eval("mkdir", "-m", "0777", "-p", buf); 343 } 344 345 if ( (fnum=open(filename, O_WRONLY | O_CREAT | O_TRUNC, *((mode_t *)mem))) < 0) { 346 printf("failed. errno: %d\n", errno); 347 perror(filename); 348 return (-1); 349 } 350 i = write(fnum, mem + 2*sizeof(mode_t), j- 2* sizeof(mode_t)); 351 if (i != j- 2* sizeof(mode_t)) 352 perror(filename); 353 close(fnum); 354 return (i != (j- 2* sizeof(mode_t))); 355} 356