1ae115bc7Smrj /* 2ae115bc7Smrj * CDDL HEADER START 3ae115bc7Smrj * 4ae115bc7Smrj * The contents of this file are subject to the terms of the 5ae115bc7Smrj * Common Development and Distribution License (the "License"). 6ae115bc7Smrj * You may not use this file except in compliance with the License. 7ae115bc7Smrj * 8ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10ae115bc7Smrj * See the License for the specific language governing permissions 11ae115bc7Smrj * and limitations under the License. 12ae115bc7Smrj * 13ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18ae115bc7Smrj * 19ae115bc7Smrj * CDDL HEADER END 20ae115bc7Smrj */ 2123a1cceaSRoger A. Faulkner 22ae115bc7Smrj /* 23*f64ca102SToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com> 247d59361aSGangadhar Mylapuram * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. 25ae115bc7Smrj */ 26ae115bc7Smrj 27ae115bc7Smrj #include "benv.h" 28ae115bc7Smrj #include <ctype.h> 29ae115bc7Smrj #include <stdarg.h> 30ae115bc7Smrj #include <sys/mman.h> 31ae115bc7Smrj #include <unistd.h> 32ae115bc7Smrj #include <signal.h> 33ae115bc7Smrj #include <sys/wait.h> 34ae115bc7Smrj 35ae115bc7Smrj /* 36ae115bc7Smrj * Usage: % eeprom [-v] [-f prom_dev] [-] 37ae115bc7Smrj * % eeprom [-v] [-f prom_dev] field[=value] ... 38ae115bc7Smrj */ 39ae115bc7Smrj 40ae115bc7Smrj extern void get_kbenv(void); 41ae115bc7Smrj extern void close_kbenv(void); 42ae115bc7Smrj extern caddr_t get_propval(char *name, char *node); 4323a1cceaSRoger A. Faulkner extern void setpname(char *prog); 443b133becSGangadhar Mylapuram extern char *getbootcmd(void); 45ae115bc7Smrj 46ae115bc7Smrj char *boottree; 47ae115bc7Smrj struct utsname uts_buf; 48ae115bc7Smrj 49ae115bc7Smrj static int test; 50ae115bc7Smrj int verbose; 51ae115bc7Smrj 52ae115bc7Smrj /* 53ae115bc7Smrj * Concatenate a NULL terminated list of strings into 54ae115bc7Smrj * a single string. 55ae115bc7Smrj */ 56ae115bc7Smrj char * 57ae115bc7Smrj strcats(char *s, ...) 58ae115bc7Smrj { 59ae115bc7Smrj char *cp, *ret; 60ae115bc7Smrj size_t len; 61ae115bc7Smrj va_list ap; 62ae115bc7Smrj 63ae115bc7Smrj va_start(ap, s); 64ae115bc7Smrj for (ret = NULL, cp = s; cp; cp = va_arg(ap, char *)) { 65ae115bc7Smrj if (ret == NULL) { 66ae115bc7Smrj ret = strdup(s); 67ae115bc7Smrj len = strlen(ret) + 1; 68ae115bc7Smrj } else { 69ae115bc7Smrj len += strlen(cp); 70ae115bc7Smrj ret = realloc(ret, len); 71ae115bc7Smrj (void) strcat(ret, cp); 72ae115bc7Smrj } 73ae115bc7Smrj } 74ae115bc7Smrj va_end(ap); 75ae115bc7Smrj 76ae115bc7Smrj return (ret); 77ae115bc7Smrj } 78ae115bc7Smrj 79ae115bc7Smrj eplist_t * 80ae115bc7Smrj new_list(void) 81ae115bc7Smrj { 82ae115bc7Smrj eplist_t *list; 83ae115bc7Smrj 84ae115bc7Smrj list = (eplist_t *)malloc(sizeof (eplist_t)); 85ae115bc7Smrj (void) memset(list, 0, sizeof (eplist_t)); 86ae115bc7Smrj 87ae115bc7Smrj list->next = list; 88ae115bc7Smrj list->prev = list; 89ae115bc7Smrj list->item = NULL; 90ae115bc7Smrj 91ae115bc7Smrj return (list); 92ae115bc7Smrj } 93ae115bc7Smrj 94ae115bc7Smrj void 95ae115bc7Smrj add_item(void *item, eplist_t *list) 96ae115bc7Smrj { 97ae115bc7Smrj eplist_t *entry; 98ae115bc7Smrj 99ae115bc7Smrj entry = (eplist_t *)malloc(sizeof (eplist_t)); 100ae115bc7Smrj (void) memset(entry, 0, sizeof (eplist_t)); 101ae115bc7Smrj entry->item = item; 102ae115bc7Smrj 103ae115bc7Smrj entry->next = list; 104ae115bc7Smrj entry->prev = list->prev; 105ae115bc7Smrj list->prev->next = entry; 106ae115bc7Smrj list->prev = entry; 107ae115bc7Smrj } 108ae115bc7Smrj 109ae115bc7Smrj typedef struct benv_ent { 110ae115bc7Smrj char *cmd; 111ae115bc7Smrj char *name; 112ae115bc7Smrj char *val; 113ae115bc7Smrj } benv_ent_t; 114ae115bc7Smrj 115ae115bc7Smrj typedef struct benv_des { 116ae115bc7Smrj char *name; 117ae115bc7Smrj int fd; 118ae115bc7Smrj caddr_t adr; 119ae115bc7Smrj size_t len; 120ae115bc7Smrj eplist_t *elist; 121ae115bc7Smrj } benv_des_t; 122ae115bc7Smrj 123ae115bc7Smrj static benv_des_t * 124ae115bc7Smrj new_bd(void) 125ae115bc7Smrj { 126ae115bc7Smrj 127ae115bc7Smrj benv_des_t *bd; 128ae115bc7Smrj 129ae115bc7Smrj bd = (benv_des_t *)malloc(sizeof (benv_des_t)); 130ae115bc7Smrj (void) memset(bd, 0, sizeof (benv_des_t)); 131ae115bc7Smrj 132ae115bc7Smrj bd->elist = new_list(); 133ae115bc7Smrj 134ae115bc7Smrj return (bd); 135ae115bc7Smrj } 136ae115bc7Smrj 137ae115bc7Smrj /* 138ae115bc7Smrj * Create a new entry. Comment entries have NULL names. 139ae115bc7Smrj */ 140ae115bc7Smrj static benv_ent_t * 141ae115bc7Smrj new_bent(char *comm, char *cmd, char *name, char *val) 142ae115bc7Smrj { 143ae115bc7Smrj benv_ent_t *bent; 144ae115bc7Smrj 145ae115bc7Smrj bent = (benv_ent_t *)malloc(sizeof (benv_ent_t)); 146ae115bc7Smrj (void) memset(bent, 0, sizeof (benv_ent_t)); 147ae115bc7Smrj 148ae115bc7Smrj if (comm) { 149ae115bc7Smrj bent->cmd = strdup(comm); 150ae115bc7Smrj comm = NULL; 151ae115bc7Smrj } else { 152ae115bc7Smrj bent->cmd = strdup(cmd); 153ae115bc7Smrj bent->name = strdup(name); 154ae115bc7Smrj if (val) 155ae115bc7Smrj bent->val = strdup(val); 156ae115bc7Smrj } 157ae115bc7Smrj 158ae115bc7Smrj return (bent); 159ae115bc7Smrj } 160ae115bc7Smrj 161ae115bc7Smrj /* 162ae115bc7Smrj * Add a new entry to the benv entry list. Entries can be 163ae115bc7Smrj * comments or commands. 164ae115bc7Smrj */ 165ae115bc7Smrj static void 166ae115bc7Smrj add_bent(eplist_t *list, char *comm, char *cmd, char *name, char *val) 167ae115bc7Smrj { 168ae115bc7Smrj benv_ent_t *bent; 169ae115bc7Smrj 170ae115bc7Smrj bent = new_bent(comm, cmd, name, val); 171ae115bc7Smrj add_item((void *)bent, list); 172ae115bc7Smrj } 173ae115bc7Smrj 174ae115bc7Smrj static benv_ent_t * 175ae115bc7Smrj get_var(char *name, eplist_t *list) 176ae115bc7Smrj { 177ae115bc7Smrj eplist_t *e; 178ae115bc7Smrj benv_ent_t *p; 179ae115bc7Smrj 180ae115bc7Smrj for (e = list->next; e != list; e = e->next) { 181ae115bc7Smrj p = (benv_ent_t *)e->item; 182ae115bc7Smrj if (p->name != NULL && strcmp(p->name, name) == 0) 183ae115bc7Smrj return (p); 184ae115bc7Smrj } 185ae115bc7Smrj 186ae115bc7Smrj return (NULL); 187ae115bc7Smrj } 188ae115bc7Smrj 189ae115bc7Smrj static void 190ae115bc7Smrj print_var(char *name, eplist_t *list) 191ae115bc7Smrj { 192ae115bc7Smrj benv_ent_t *p; 1937d59361aSGangadhar Mylapuram char *bootcmd; 194ae115bc7Smrj 195*f64ca102SToomas Soome if (strcmp(name, "bootcmd") == 0) { 1967d59361aSGangadhar Mylapuram bootcmd = getbootcmd(); 1977d59361aSGangadhar Mylapuram (void) printf("%s=%s\n", name, bootcmd ? bootcmd : ""); 1987d59361aSGangadhar Mylapuram } else if ((p = get_var(name, list)) == NULL) { 199ae115bc7Smrj (void) printf("%s: data not available.\n", name); 2007d59361aSGangadhar Mylapuram } else { 201ae115bc7Smrj (void) printf("%s=%s\n", name, p->val ? p->val : ""); 202ae115bc7Smrj } 2037d59361aSGangadhar Mylapuram } 204ae115bc7Smrj 205ae115bc7Smrj static void 206ae115bc7Smrj print_vars(eplist_t *list) 207ae115bc7Smrj { 208ae115bc7Smrj eplist_t *e; 209ae115bc7Smrj benv_ent_t *p; 210ae115bc7Smrj 211ae115bc7Smrj for (e = list->next; e != list; e = e->next) { 212ae115bc7Smrj p = (benv_ent_t *)e->item; 213ae115bc7Smrj if (p->name != NULL) { 214ae115bc7Smrj (void) printf("%s=%s\n", p->name, p->val ? p->val : ""); 215ae115bc7Smrj } 216ae115bc7Smrj } 217ae115bc7Smrj } 218ae115bc7Smrj 219ae115bc7Smrj /* 220ae115bc7Smrj * Write a string to a file, quoted appropriately. We use single 221ae115bc7Smrj * quotes to prevent any variable expansion. Of course, we backslash-quote 222ae115bc7Smrj * any single quotes or backslashes. 223ae115bc7Smrj */ 224ae115bc7Smrj static void 225ae115bc7Smrj put_quoted(FILE *fp, char *val) 226ae115bc7Smrj { 227ae115bc7Smrj (void) putc('\'', fp); 228ae115bc7Smrj while (*val) { 229ae115bc7Smrj switch (*val) { 230ae115bc7Smrj case '\'': 231ae115bc7Smrj case '\\': 232ae115bc7Smrj (void) putc('\\', fp); 233ae115bc7Smrj /* FALLTHROUGH */ 234ae115bc7Smrj default: 235ae115bc7Smrj (void) putc(*val, fp); 236ae115bc7Smrj break; 237ae115bc7Smrj } 238ae115bc7Smrj val++; 239ae115bc7Smrj } 240ae115bc7Smrj (void) putc('\'', fp); 241ae115bc7Smrj } 242ae115bc7Smrj 243455710d3Srscott /* 244455710d3Srscott * Returns 1 if bootenv.rc was modified, 0 otherwise. 245455710d3Srscott */ 246455710d3Srscott static int 247ae115bc7Smrj set_var(char *name, char *val, eplist_t *list) 248ae115bc7Smrj { 249ae115bc7Smrj benv_ent_t *p; 250ae115bc7Smrj 2517d59361aSGangadhar Mylapuram if (strcmp(name, "bootcmd") == 0) 2527d59361aSGangadhar Mylapuram return (0); 2537d59361aSGangadhar Mylapuram 254ae115bc7Smrj if (verbose) { 255ae115bc7Smrj (void) printf("old:"); 256ae115bc7Smrj print_var(name, list); 257ae115bc7Smrj } 258ae115bc7Smrj 259ae115bc7Smrj if ((p = get_var(name, list)) != NULL) { 260ae115bc7Smrj free(p->val); 261ae115bc7Smrj p->val = strdup(val); 262ae115bc7Smrj } else 263ae115bc7Smrj add_bent(list, NULL, "setprop", name, val); 264ae115bc7Smrj 265ae115bc7Smrj if (verbose) { 266ae115bc7Smrj (void) printf("new:"); 267ae115bc7Smrj print_var(name, list); 268ae115bc7Smrj } 269455710d3Srscott return (1); 270ae115bc7Smrj } 271ae115bc7Smrj 272ae115bc7Smrj /* 273455710d3Srscott * Returns 1 if bootenv.rc is modified or 0 if no modification was 274455710d3Srscott * necessary. This allows us to implement non super-user look-up of 275455710d3Srscott * variables by name without the user being yelled at for trying to 276455710d3Srscott * modify the bootenv.rc file. 277ae115bc7Smrj */ 278ae115bc7Smrj static int 279ae115bc7Smrj proc_var(char *name, eplist_t *list) 280ae115bc7Smrj { 281ae115bc7Smrj register char *val; 282ae115bc7Smrj 283ae115bc7Smrj if ((val = strchr(name, '=')) == NULL) { 284ae115bc7Smrj print_var(name, list); 285ae115bc7Smrj return (0); 286ae115bc7Smrj } else { 287ae115bc7Smrj *val++ = '\0'; 288455710d3Srscott return (set_var(name, val, list)); 289ae115bc7Smrj } 290ae115bc7Smrj } 291ae115bc7Smrj 292ae115bc7Smrj static void 293ae115bc7Smrj init_benv(benv_des_t *bd, char *file) 294ae115bc7Smrj { 295ae115bc7Smrj get_kbenv(); 296ae115bc7Smrj 297ae115bc7Smrj if (test) 298ae115bc7Smrj boottree = "/tmp"; 299ae115bc7Smrj else if ((boottree = (char *)get_propval("boottree", "chosen")) == NULL) 300ae115bc7Smrj boottree = strcats("/boot", NULL); 301ae115bc7Smrj 302ae115bc7Smrj if (file != NULL) 303ae115bc7Smrj bd->name = file; 304ae115bc7Smrj else 305ae115bc7Smrj bd->name = strcats(boottree, "/solaris/bootenv.rc", NULL); 306ae115bc7Smrj } 307ae115bc7Smrj 308ae115bc7Smrj static void 309ae115bc7Smrj map_benv(benv_des_t *bd) 310ae115bc7Smrj { 311ae115bc7Smrj if ((bd->fd = open(bd->name, O_RDONLY)) == -1) 312ae115bc7Smrj if (errno == ENOENT) 313ae115bc7Smrj return; 314ae115bc7Smrj else 315ae115bc7Smrj exit(_error(PERROR, "cannot open %s", bd->name)); 316ae115bc7Smrj 317ae115bc7Smrj if ((bd->len = (size_t)lseek(bd->fd, 0, SEEK_END)) == 0) { 318ae115bc7Smrj if (close(bd->fd) == -1) 319ae115bc7Smrj exit(_error(PERROR, "close error on %s", bd->name)); 320ae115bc7Smrj return; 321ae115bc7Smrj } 322ae115bc7Smrj 323ae115bc7Smrj (void) lseek(bd->fd, 0, SEEK_SET); 324ae115bc7Smrj 325ae115bc7Smrj if ((bd->adr = mmap((caddr_t)0, bd->len, (PROT_READ | PROT_WRITE), 326ae115bc7Smrj MAP_PRIVATE, bd->fd, 0)) == MAP_FAILED) 327ae115bc7Smrj exit(_error(PERROR, "cannot map %s", bd->name)); 328ae115bc7Smrj } 329ae115bc7Smrj 330ae115bc7Smrj static void 331ae115bc7Smrj unmap_benv(benv_des_t *bd) 332ae115bc7Smrj { 333ae115bc7Smrj if (munmap(bd->adr, bd->len) == -1) 334ae115bc7Smrj exit(_error(PERROR, "unmap error on %s", bd->name)); 335ae115bc7Smrj 336ae115bc7Smrj if (close(bd->fd) == -1) 337ae115bc7Smrj exit(_error(PERROR, "close error on %s", bd->name)); 338ae115bc7Smrj } 339ae115bc7Smrj 340ae115bc7Smrj #define NL '\n' 341ae115bc7Smrj #define COMM '#' 342ae115bc7Smrj 343ae115bc7Smrj /* 344ae115bc7Smrj * Add a comment block to the benv list. 345ae115bc7Smrj */ 346ae115bc7Smrj static void 347ae115bc7Smrj add_comm(benv_des_t *bd, char *base, char *last, char **next, int *line) 348ae115bc7Smrj { 349ae115bc7Smrj int nl, lines; 350ae115bc7Smrj char *p; 351ae115bc7Smrj 352ae115bc7Smrj nl = 0; 353ae115bc7Smrj for (p = base, lines = 0; p < last; p++) { 354ae115bc7Smrj if (*p == NL) { 355ae115bc7Smrj nl++; 356ae115bc7Smrj lines++; 357ae115bc7Smrj } else if (nl) { 358ae115bc7Smrj if (*p != COMM) 359ae115bc7Smrj break; 360ae115bc7Smrj nl = 0; 361ae115bc7Smrj } 362ae115bc7Smrj } 363ae115bc7Smrj *(p - 1) = NULL; 364ae115bc7Smrj add_bent(bd->elist, base, NULL, NULL, NULL); 365ae115bc7Smrj *next = p; 366ae115bc7Smrj *line += lines; 367ae115bc7Smrj } 368ae115bc7Smrj 369ae115bc7Smrj /* 370ae115bc7Smrj * Parse out an operator (setprop) from the boot environment 371ae115bc7Smrj */ 372ae115bc7Smrj static char * 373ae115bc7Smrj parse_cmd(benv_des_t *bd, char **next, int *line) 374ae115bc7Smrj { 375ae115bc7Smrj char *strbegin; 376ae115bc7Smrj char *badeof = "unexpected EOF in %s line %d"; 377ae115bc7Smrj char *syntax = "syntax error in %s line %d"; 378ae115bc7Smrj char *c = *next; 379ae115bc7Smrj 380ae115bc7Smrj /* 381ae115bc7Smrj * Skip spaces or tabs. New lines increase the line count. 382ae115bc7Smrj */ 383ae115bc7Smrj while (isspace(*c)) { 384ae115bc7Smrj if (*c++ == '\n') 385ae115bc7Smrj (*line)++; 386ae115bc7Smrj } 387ae115bc7Smrj 388ae115bc7Smrj /* 389ae115bc7Smrj * Check for a the setprop command. Currently that's all we 390ae115bc7Smrj * seem to support. 391ae115bc7Smrj * 392ae115bc7Smrj * XXX need support for setbinprop? 393ae115bc7Smrj */ 394ae115bc7Smrj 395ae115bc7Smrj /* 396ae115bc7Smrj * Check first for end of file. Finding one now would be okay. 397ae115bc7Smrj * We should also bail if we are at the start of a comment. 398ae115bc7Smrj */ 399ae115bc7Smrj if (*c == '\0' || *c == COMM) { 400ae115bc7Smrj *next = c; 401ae115bc7Smrj return (NULL); 402ae115bc7Smrj } 403ae115bc7Smrj 404ae115bc7Smrj strbegin = c; 405ae115bc7Smrj while (*c && !isspace(*c)) 406ae115bc7Smrj c++; 407ae115bc7Smrj 408ae115bc7Smrj /* 409ae115bc7Smrj * Check again for end of file. Finding one now would NOT be okay. 410ae115bc7Smrj */ 411ae115bc7Smrj if (*c == '\0') { 412ae115bc7Smrj exit(_error(NO_PERROR, badeof, bd->name, *line)); 413ae115bc7Smrj } 414ae115bc7Smrj 415ae115bc7Smrj *c++ = '\0'; 416ae115bc7Smrj *next = c; 417ae115bc7Smrj 418ae115bc7Smrj /* 419ae115bc7Smrj * Last check is to make sure the command is a setprop! 420ae115bc7Smrj */ 421ae115bc7Smrj if (strcmp(strbegin, "setprop") != 0) { 422ae115bc7Smrj exit(_error(NO_PERROR, syntax, bd->name, *line)); 423ae115bc7Smrj /* NOTREACHED */ 424ae115bc7Smrj } 425ae115bc7Smrj return (strbegin); 426ae115bc7Smrj } 427ae115bc7Smrj 428ae115bc7Smrj /* 429ae115bc7Smrj * Parse out the name (LHS) of a setprop from the boot environment 430ae115bc7Smrj */ 431ae115bc7Smrj static char * 432ae115bc7Smrj parse_name(benv_des_t *bd, char **next, int *line) 433ae115bc7Smrj { 434ae115bc7Smrj char *strbegin; 435ae115bc7Smrj char *badeof = "unexpected EOF in %s line %d"; 436ae115bc7Smrj char *syntax = "syntax error in %s line %d"; 437ae115bc7Smrj char *c = *next; 438ae115bc7Smrj 439ae115bc7Smrj /* 440ae115bc7Smrj * Skip spaces or tabs. No tolerance for new lines now. 441ae115bc7Smrj */ 442ae115bc7Smrj while (isspace(*c)) { 443ae115bc7Smrj if (*c++ == '\n') 444ae115bc7Smrj exit(_error(NO_PERROR, syntax, bd->name, *line)); 445ae115bc7Smrj } 446ae115bc7Smrj 447ae115bc7Smrj /* 448ae115bc7Smrj * Grab a name for the property to set. 449ae115bc7Smrj */ 450ae115bc7Smrj 451ae115bc7Smrj /* 452ae115bc7Smrj * Check first for end of file. Finding one now would NOT be okay. 453ae115bc7Smrj */ 454ae115bc7Smrj if (*c == '\0') { 455ae115bc7Smrj exit(_error(NO_PERROR, badeof, bd->name, *line)); 456ae115bc7Smrj } 457ae115bc7Smrj 458ae115bc7Smrj strbegin = c; 459ae115bc7Smrj while (*c && !isspace(*c)) 460ae115bc7Smrj c++; 461ae115bc7Smrj 462ae115bc7Smrj /* 463ae115bc7Smrj * At this point in parsing we have 'setprop name'. What follows 464ae115bc7Smrj * is a newline, other whitespace, or EOF. Most of the time we 465ae115bc7Smrj * want to replace a white space character with a NULL to terminate 466ae115bc7Smrj * the name, and then continue on processing. A newline here provides 467ae115bc7Smrj * the most grief. If we just replace it with a null we'll 468ae115bc7Smrj * potentially get the setprop on the next line as the value of this 469ae115bc7Smrj * setprop! So, if the last thing we see is a newline we'll have to 470ae115bc7Smrj * dup the string. 471ae115bc7Smrj */ 472ae115bc7Smrj if (isspace(*c)) { 473ae115bc7Smrj if (*c == '\n') { 474ae115bc7Smrj *c = '\0'; 475ae115bc7Smrj strbegin = strdup(strbegin); 476ae115bc7Smrj *c = '\n'; 477ae115bc7Smrj } else { 478ae115bc7Smrj *c++ = '\0'; 479ae115bc7Smrj } 480ae115bc7Smrj } 481ae115bc7Smrj 482ae115bc7Smrj *next = c; 483ae115bc7Smrj return (strbegin); 484ae115bc7Smrj } 485ae115bc7Smrj 486ae115bc7Smrj /* 487ae115bc7Smrj * Parse out the value (RHS) of a setprop line from the boot environment 488ae115bc7Smrj */ 489ae115bc7Smrj static char * 490ae115bc7Smrj parse_value(benv_des_t *bd, char **next, int *line) 491ae115bc7Smrj { 492ae115bc7Smrj char *strbegin; 493ae115bc7Smrj char *badeof = "unexpected EOF in %s line %d"; 494ae115bc7Smrj char *result; 495ae115bc7Smrj char *c = *next; 496ae115bc7Smrj char quote; 497ae115bc7Smrj 498ae115bc7Smrj /* 499ae115bc7Smrj * Skip spaces or tabs. A newline here would indicate a 500ae115bc7Smrj * NULL property value. 501ae115bc7Smrj */ 502ae115bc7Smrj while (isspace(*c)) { 503ae115bc7Smrj if (*c++ == '\n') { 504ae115bc7Smrj (*line)++; 505ae115bc7Smrj *next = c; 506ae115bc7Smrj return (NULL); 507ae115bc7Smrj } 508ae115bc7Smrj } 509ae115bc7Smrj 510ae115bc7Smrj /* 511ae115bc7Smrj * Grab the value of the property to set. 512ae115bc7Smrj */ 513ae115bc7Smrj 514ae115bc7Smrj /* 515ae115bc7Smrj * Check first for end of file. Finding one now would 516ae115bc7Smrj * also indicate a NULL property. 517ae115bc7Smrj */ 518ae115bc7Smrj if (*c == '\0') { 519ae115bc7Smrj *next = c; 520ae115bc7Smrj return (NULL); 521ae115bc7Smrj } 522ae115bc7Smrj 523ae115bc7Smrj /* 524ae115bc7Smrj * Value may be quoted, in which case we assume the end of the value 525ae115bc7Smrj * comes with a closing quote. 526ae115bc7Smrj * 527ae115bc7Smrj * We also allow escaped quote characters inside the quoted value. 528ae115bc7Smrj * 529ae115bc7Smrj * For obvious reasons we do not attempt to parse variable references. 530ae115bc7Smrj */ 531ae115bc7Smrj if (*c == '"' || *c == '\'') { 532ae115bc7Smrj quote = *c; 533ae115bc7Smrj c++; 534ae115bc7Smrj strbegin = c; 535ae115bc7Smrj result = c; 536ae115bc7Smrj while (*c != quote) { 537ae115bc7Smrj if (*c == '\\') { 538ae115bc7Smrj c++; 539ae115bc7Smrj } 540d92a527cSMark Logan if (*c == '\0') { 541ae115bc7Smrj break; 542ae115bc7Smrj } 543ae115bc7Smrj *result++ = *c++; 544ae115bc7Smrj } 545ae115bc7Smrj 546ae115bc7Smrj /* 547ae115bc7Smrj * Throw fatal exception if no end quote found. 548ae115bc7Smrj */ 549ae115bc7Smrj if (*c != quote) { 550ae115bc7Smrj exit(_error(NO_PERROR, badeof, bd->name, *line)); 551ae115bc7Smrj } 552ae115bc7Smrj 553ae115bc7Smrj *result = '\0'; /* Terminate the result */ 554ae115bc7Smrj c++; /* and step past the close quote */ 555ae115bc7Smrj } else { 556ae115bc7Smrj strbegin = c; 557ae115bc7Smrj while (*c && !isspace(*c)) 558ae115bc7Smrj c++; 559ae115bc7Smrj } 560ae115bc7Smrj 561ae115bc7Smrj /* 562ae115bc7Smrj * Check again for end of file. Finding one now is okay. 563ae115bc7Smrj */ 564ae115bc7Smrj if (*c == '\0') { 565ae115bc7Smrj *next = c; 566ae115bc7Smrj return (strbegin); 567ae115bc7Smrj } 568ae115bc7Smrj 569ae115bc7Smrj *c++ = '\0'; 570ae115bc7Smrj *next = c; 571ae115bc7Smrj return (strbegin); 572ae115bc7Smrj } 573ae115bc7Smrj 574ae115bc7Smrj /* 575ae115bc7Smrj * Add a command to the benv list. 576ae115bc7Smrj */ 577ae115bc7Smrj static void 578ae115bc7Smrj add_cmd(benv_des_t *bd, char *last, char **next, int *line) 579ae115bc7Smrj { 580ae115bc7Smrj char *cmd, *name, *val; 581ae115bc7Smrj 582ae115bc7Smrj while (*next <= last && **next != COMM) { 583ae115bc7Smrj if ((cmd = parse_cmd(bd, next, line)) == NULL) 584ae115bc7Smrj break; 585ae115bc7Smrj name = parse_name(bd, next, line); 586ae115bc7Smrj val = parse_value(bd, next, line); 587ae115bc7Smrj add_bent(bd->elist, NULL, cmd, name, val); 588ae115bc7Smrj (*line)++; 589ae115bc7Smrj }; 5903b133becSGangadhar Mylapuram 591ae115bc7Smrj } 592ae115bc7Smrj 593ae115bc7Smrj /* 594ae115bc7Smrj * Parse the benv (bootenv.rc) file and break it into a benv 595ae115bc7Smrj * list. List entries may be comment blocks or commands. 596ae115bc7Smrj */ 597ae115bc7Smrj static void 598ae115bc7Smrj parse_benv(benv_des_t *bd) 599ae115bc7Smrj { 600ae115bc7Smrj int line; 601ae115bc7Smrj char *pbase, *pend; 602ae115bc7Smrj char *tok, *tnext; 603ae115bc7Smrj 604ae115bc7Smrj line = 1; 605ae115bc7Smrj pbase = (char *)bd->adr; 606ae115bc7Smrj pend = pbase + bd->len; 607ae115bc7Smrj 608d92a527cSMark Logan for (tok = tnext = pbase; tnext < pend && '\0' != *tnext; tok = tnext) 609ae115bc7Smrj if (*tok == COMM) 610ae115bc7Smrj add_comm(bd, tok, pend, &tnext, &line); 611ae115bc7Smrj else 612ae115bc7Smrj add_cmd(bd, pend, &tnext, &line); 613ae115bc7Smrj } 614ae115bc7Smrj 615ae115bc7Smrj static void 616ae115bc7Smrj write_benv(benv_des_t *bd) 617ae115bc7Smrj { 618ae115bc7Smrj FILE *fp; 619ae115bc7Smrj eplist_t *list, *e; 620ae115bc7Smrj benv_ent_t *bent; 621ae115bc7Smrj char *name; 622ae115bc7Smrj 623ae115bc7Smrj list = bd->elist; 624ae115bc7Smrj 625ae115bc7Smrj if (list->next == list) 626ae115bc7Smrj return; 627ae115bc7Smrj 628ae115bc7Smrj if ((fp = fopen(bd->name, "w")) == NULL) 629ae115bc7Smrj exit(_error(PERROR, "cannot open %s", bd->name)); 630ae115bc7Smrj 631ae115bc7Smrj for (e = list->next; e != list; e = e->next) { 632ae115bc7Smrj bent = (benv_ent_t *)e->item; 633ae115bc7Smrj name = bent->name; 634ae115bc7Smrj if (name) { 635ae115bc7Smrj if (bent->val) { 636ae115bc7Smrj (void) fprintf(fp, "%s %s ", 637ae115bc7Smrj bent->cmd, bent->name); 638ae115bc7Smrj put_quoted(fp, bent->val); 639ae115bc7Smrj (void) fprintf(fp, "\n"); 640ae115bc7Smrj } else { 641ae115bc7Smrj (void) fprintf(fp, "%s %s\n", 642ae115bc7Smrj bent->cmd, bent->name); 643ae115bc7Smrj } 644ae115bc7Smrj } else { 645ae115bc7Smrj (void) fprintf(fp, "%s\n", bent->cmd); 646ae115bc7Smrj } 647ae115bc7Smrj } 648ae115bc7Smrj 649ae115bc7Smrj (void) fclose(fp); 650ae115bc7Smrj } 651ae115bc7Smrj 652ae115bc7Smrj static char * 653ae115bc7Smrj get_line(void) 654ae115bc7Smrj { 655ae115bc7Smrj int c; 656ae115bc7Smrj char *nl; 657ae115bc7Smrj static char line[256]; 658ae115bc7Smrj 659ae115bc7Smrj if (fgets(line, sizeof (line), stdin) != NULL) { 660ae115bc7Smrj /* 661ae115bc7Smrj * Remove newline if present, 662ae115bc7Smrj * otherwise discard rest of line. 663ae115bc7Smrj */ 664ae115bc7Smrj if (nl = strchr(line, '\n')) 665ae115bc7Smrj *nl = 0; 666ae115bc7Smrj else 667ae115bc7Smrj while ((c = getchar()) != '\n' && c != EOF) 668ae115bc7Smrj ; 669ae115bc7Smrj return (line); 670ae115bc7Smrj } else 671ae115bc7Smrj return (NULL); 672ae115bc7Smrj } 673ae115bc7Smrj 674ae115bc7Smrj int 675ae115bc7Smrj main(int argc, char **argv) 676ae115bc7Smrj { 677ae115bc7Smrj int c; 678ae115bc7Smrj int updates = 0; 679ae115bc7Smrj char *usage = "Usage: %s [-v] [-f prom-device]" 680ae115bc7Smrj " [variable[=value] ...]"; 681ae115bc7Smrj eplist_t *elist; 682ae115bc7Smrj benv_des_t *bd; 683ae115bc7Smrj char *file = NULL; 684ae115bc7Smrj 68523a1cceaSRoger A. Faulkner setpname(argv[0]); 686ae115bc7Smrj 687ae115bc7Smrj while ((c = getopt(argc, argv, "f:Itv")) != -1) 688ae115bc7Smrj switch (c) { 689ae115bc7Smrj case 'v': 690ae115bc7Smrj verbose++; 691ae115bc7Smrj break; 692ae115bc7Smrj case 'f': 693ae115bc7Smrj file = optarg; 694ae115bc7Smrj break; 695ae115bc7Smrj case 't': 696ae115bc7Smrj test++; 697ae115bc7Smrj break; 698ae115bc7Smrj default: 699ae115bc7Smrj exit(_error(NO_PERROR, usage, argv[0])); 700ae115bc7Smrj } 701ae115bc7Smrj 702ae115bc7Smrj (void) uname(&uts_buf); 703ae115bc7Smrj bd = new_bd(); 704ae115bc7Smrj init_benv(bd, file); 705ae115bc7Smrj 706ae115bc7Smrj map_benv(bd); 707ae115bc7Smrj if (bd->len) { 708ae115bc7Smrj parse_benv(bd); 709ae115bc7Smrj unmap_benv(bd); 710ae115bc7Smrj } 711ae115bc7Smrj 712ae115bc7Smrj elist = bd->elist; 713ae115bc7Smrj 714ae115bc7Smrj if (optind >= argc) { 715ae115bc7Smrj print_vars(elist); 716ae115bc7Smrj return (0); 717ae115bc7Smrj } else 718ae115bc7Smrj while (optind < argc) { 719ae115bc7Smrj /* 720ae115bc7Smrj * If "-" specified, read variables from stdin; 721ae115bc7Smrj * otherwise, process each argument as a variable 722ae115bc7Smrj * print or set request. 723ae115bc7Smrj */ 724ae115bc7Smrj if (strcmp(argv[optind], "-") == 0) { 725ae115bc7Smrj char *line; 726ae115bc7Smrj 727ae115bc7Smrj while ((line = get_line()) != NULL) 728ae115bc7Smrj updates += proc_var(line, elist); 729ae115bc7Smrj clearerr(stdin); 730ae115bc7Smrj } else 731ae115bc7Smrj updates += proc_var(argv[optind], elist); 732ae115bc7Smrj 733ae115bc7Smrj optind++; 734ae115bc7Smrj } 735ae115bc7Smrj 736ae115bc7Smrj /* 737ae115bc7Smrj * don't write benv if we are processing delayed writes since 738ae115bc7Smrj * it is likely that the delayed writes changes bootenv.rc anyway... 739ae115bc7Smrj */ 740ae115bc7Smrj if (updates) 741ae115bc7Smrj write_benv(bd); 742ae115bc7Smrj close_kbenv(); 743ae115bc7Smrj 744ae115bc7Smrj return (0); 745ae115bc7Smrj } 746