benv.c revision c262cbbc8301f7c884fd4800056ee51ba75d931c
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2016 Toomas Soome <tsoome@me.com>
*/
#include "benv.h"
#include <ctype.h>
#include <stdarg.h>
#include <unistd.h>
#include <signal.h>
/*
* Usage: % eeprom [-v] [-f prom_dev] [-]
* % eeprom [-v] [-f prom_dev] field[=value] ...
*/
extern void get_kbenv(void);
extern void close_kbenv(void);
extern char *getbootcmd(void);
char *boottree;
static int test;
int verbose;
/*
* Concatenate a NULL terminated list of strings into
* a single string.
*/
char *
strcats(char *s, ...)
{
} else {
}
}
return (ret);
}
eplist_t *
new_list(void)
{
return (list);
}
void
{
}
typedef struct benv_ent {
char *cmd;
char *name;
char *val;
} benv_ent_t;
typedef struct benv_des {
char *name;
int fd;
} benv_des_t;
static benv_des_t *
new_bd(void)
{
benv_des_t *bd;
return (bd);
}
/*
* Create a new entry. Comment entries have NULL names.
*/
static benv_ent_t *
{
if (comm) {
} else {
if (val)
}
return (bent);
}
/*
* Add a new entry to the benv entry list. Entries can be
* comments or commands.
*/
static void
{
}
static benv_ent_t *
{
eplist_t *e;
benv_ent_t *p;
p = (benv_ent_t *)e->item;
return (p);
}
return (NULL);
}
static void
{
benv_ent_t *p;
char *bootcmd;
bootcmd = getbootcmd();
} else {
}
}
static void
{
eplist_t *e;
benv_ent_t *p;
p = (benv_ent_t *)e->item;
}
}
}
/*
* Write a string to a file, quoted appropriately. We use single
* quotes to prevent any variable expansion. Of course, we backslash-quote
* any single quotes or backslashes.
*/
static void
{
while (*val) {
switch (*val) {
case '\'':
case '\\':
/* FALLTHROUGH */
default:
break;
}
val++;
}
}
/*
* Returns 1 if bootenv.rc was modified, 0 otherwise.
*/
static int
{
benv_ent_t *p;
return (0);
if (verbose) {
(void) printf("old:");
}
} else
if (verbose) {
(void) printf("new:");
}
return (1);
}
/*
* Returns 1 if bootenv.rc is modified or 0 if no modification was
* necessary. This allows us to implement non super-user look-up of
* variables by name without the user being yelled at for trying to
* modify the bootenv.rc file.
*/
static int
{
register char *val;
return (0);
} else {
*val++ = '\0';
}
}
static void
{
get_kbenv();
if (test)
boottree = "/tmp";
else
}
static void
{
return;
else
return;
}
}
static void
{
}
#define NL '\n'
#define COMM '#'
/*
* Add a comment block to the benv list.
*/
static void
{
char *p;
nl = 0;
if (*p == NL) {
nl++;
lines++;
} else if (nl) {
if (*p != COMM)
break;
nl = 0;
}
}
*(p - 1) = NULL;
*next = p;
}
/*
* Parse out an operator (setprop) from the boot environment
*/
static char *
{
char *strbegin;
char *badeof = "unexpected EOF in %s line %d";
char *syntax = "syntax error in %s line %d";
char *c = *next;
/*
* Skip spaces or tabs. New lines increase the line count.
*/
while (isspace(*c)) {
if (*c++ == '\n')
(*line)++;
}
/*
* Check for a the setprop command. Currently that's all we
* seem to support.
*
* XXX need support for setbinprop?
*/
/*
* Check first for end of file. Finding one now would be okay.
* We should also bail if we are at the start of a comment.
*/
if (*c == '\0' || *c == COMM) {
*next = c;
return (NULL);
}
strbegin = c;
while (*c && !isspace(*c))
c++;
/*
* Check again for end of file. Finding one now would NOT be okay.
*/
if (*c == '\0') {
}
*c++ = '\0';
*next = c;
/*
* Last check is to make sure the command is a setprop!
*/
/* NOTREACHED */
}
return (strbegin);
}
/*
* Parse out the name (LHS) of a setprop from the boot environment
*/
static char *
{
char *strbegin;
char *badeof = "unexpected EOF in %s line %d";
char *syntax = "syntax error in %s line %d";
char *c = *next;
/*
* Skip spaces or tabs. No tolerance for new lines now.
*/
while (isspace(*c)) {
if (*c++ == '\n')
}
/*
* Grab a name for the property to set.
*/
/*
* Check first for end of file. Finding one now would NOT be okay.
*/
if (*c == '\0') {
}
strbegin = c;
while (*c && !isspace(*c))
c++;
/*
* At this point in parsing we have 'setprop name'. What follows
* is a newline, other whitespace, or EOF. Most of the time we
* want to replace a white space character with a NULL to terminate
* the name, and then continue on processing. A newline here provides
* the most grief. If we just replace it with a null we'll
* potentially get the setprop on the next line as the value of this
* setprop! So, if the last thing we see is a newline we'll have to
* dup the string.
*/
if (isspace(*c)) {
if (*c == '\n') {
*c = '\0';
*c = '\n';
} else {
*c++ = '\0';
}
}
*next = c;
return (strbegin);
}
/*
* Parse out the value (RHS) of a setprop line from the boot environment
*/
static char *
{
char *strbegin;
char *badeof = "unexpected EOF in %s line %d";
char *result;
char *c = *next;
char quote;
/*
* Skip spaces or tabs. A newline here would indicate a
* NULL property value.
*/
while (isspace(*c)) {
if (*c++ == '\n') {
(*line)++;
*next = c;
return (NULL);
}
}
/*
* Grab the value of the property to set.
*/
/*
* Check first for end of file. Finding one now would
* also indicate a NULL property.
*/
if (*c == '\0') {
*next = c;
return (NULL);
}
/*
* Value may be quoted, in which case we assume the end of the value
* comes with a closing quote.
*
* We also allow escaped quote characters inside the quoted value.
*
* For obvious reasons we do not attempt to parse variable references.
*/
if (*c == '"' || *c == '\'') {
quote = *c;
c++;
strbegin = c;
result = c;
while (*c != quote) {
if (*c == '\\') {
c++;
}
if (*c == '\0') {
break;
}
*result++ = *c++;
}
/*
* Throw fatal exception if no end quote found.
*/
if (*c != quote) {
}
c++; /* and step past the close quote */
} else {
strbegin = c;
while (*c && !isspace(*c))
c++;
}
/*
* Check again for end of file. Finding one now is okay.
*/
if (*c == '\0') {
*next = c;
return (strbegin);
}
*c++ = '\0';
*next = c;
return (strbegin);
}
/*
* Add a command to the benv list.
*/
static void
{
break;
(*line)++;
};
}
/*
* Parse the benv (bootenv.rc) file and break it into a benv
* list. List entries may be comment blocks or commands.
*/
static void
{
int line;
line = 1;
else
}
static void
{
char *name;
return;
if (name) {
} else {
}
} else {
}
}
}
static char *
get_line(void)
{
int c;
char *nl;
static char line[256];
/*
* Remove newline if present,
* otherwise discard rest of line.
*/
*nl = 0;
else
;
return (line);
} else
return (NULL);
}
int
{
int c;
int updates = 0;
char *usage = "Usage: %s [-v] [-f prom-device]"
" [variable[=value] ...]";
benv_des_t *bd;
switch (c) {
case 'v':
verbose++;
break;
case 'f':
break;
case 't':
test++;
break;
default:
}
parse_benv(bd);
unmap_benv(bd);
}
return (0);
} else
/*
* If "-" specified, read variables from stdin;
* otherwise, process each argument as a variable
* print or set request.
*/
char *line;
} else
optind++;
}
/*
* don't write benv if we are processing delayed writes since
* it is likely that the delayed writes changes bootenv.rc anyway...
*/
if (updates)
write_benv(bd);
close_kbenv();
return (0);
}