17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate * CDDL HEADER START
37c478bd9Sstevel@tonic-gate *
47c478bd9Sstevel@tonic-gate * 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.
77c478bd9Sstevel@tonic-gate *
87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate * and limitations under the License.
127c478bd9Sstevel@tonic-gate *
137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate *
197c478bd9Sstevel@tonic-gate * CDDL HEADER END
207c478bd9Sstevel@tonic-gate */
2123a1cceaSRoger A. Faulkner
227c478bd9Sstevel@tonic-gate /*
23c262cbbcSToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com>
247d59361aSGangadhar Mylapuram * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include "benv.h"
287c478bd9Sstevel@tonic-gate #include <ctype.h>
297c478bd9Sstevel@tonic-gate #include <stdarg.h>
30b713c91eSToomas Soome #include <stdbool.h>
317c478bd9Sstevel@tonic-gate #include <sys/mman.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
33ae115bc7Smrj #include <signal.h>
34ae115bc7Smrj #include <sys/wait.h>
35b713c91eSToomas Soome #include <libzfsbootenv.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate /*
387c478bd9Sstevel@tonic-gate * Usage: % eeprom [-v] [-f prom_dev] [-]
397c478bd9Sstevel@tonic-gate * % eeprom [-v] [-f prom_dev] field[=value] ...
407c478bd9Sstevel@tonic-gate */
417c478bd9Sstevel@tonic-gate
427c478bd9Sstevel@tonic-gate extern void get_kbenv(void);
437c478bd9Sstevel@tonic-gate extern void close_kbenv(void);
447c478bd9Sstevel@tonic-gate extern caddr_t get_propval(char *name, char *node);
4523a1cceaSRoger A. Faulkner extern void setpname(char *prog);
463b133becSGangadhar Mylapuram extern char *getbootcmd(void);
477c478bd9Sstevel@tonic-gate
487c478bd9Sstevel@tonic-gate char *boottree;
497c478bd9Sstevel@tonic-gate struct utsname uts_buf;
507c478bd9Sstevel@tonic-gate
517c478bd9Sstevel@tonic-gate static int test;
527c478bd9Sstevel@tonic-gate int verbose;
537c478bd9Sstevel@tonic-gate
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate * Concatenate a NULL terminated list of strings into
567c478bd9Sstevel@tonic-gate * a single string.
577c478bd9Sstevel@tonic-gate */
587c478bd9Sstevel@tonic-gate char *
strcats(char * s,...)597c478bd9Sstevel@tonic-gate strcats(char *s, ...)
607c478bd9Sstevel@tonic-gate {
617c478bd9Sstevel@tonic-gate char *cp, *ret;
627c478bd9Sstevel@tonic-gate size_t len;
637c478bd9Sstevel@tonic-gate va_list ap;
647c478bd9Sstevel@tonic-gate
657c478bd9Sstevel@tonic-gate va_start(ap, s);
667c478bd9Sstevel@tonic-gate for (ret = NULL, cp = s; cp; cp = va_arg(ap, char *)) {
677c478bd9Sstevel@tonic-gate if (ret == NULL) {
687c478bd9Sstevel@tonic-gate ret = strdup(s);
697c478bd9Sstevel@tonic-gate len = strlen(ret) + 1;
707c478bd9Sstevel@tonic-gate } else {
717c478bd9Sstevel@tonic-gate len += strlen(cp);
727c478bd9Sstevel@tonic-gate ret = realloc(ret, len);
73ae115bc7Smrj (void) strcat(ret, cp);
747c478bd9Sstevel@tonic-gate }
757c478bd9Sstevel@tonic-gate }
767c478bd9Sstevel@tonic-gate va_end(ap);
777c478bd9Sstevel@tonic-gate
787c478bd9Sstevel@tonic-gate return (ret);
797c478bd9Sstevel@tonic-gate }
807c478bd9Sstevel@tonic-gate
817c478bd9Sstevel@tonic-gate eplist_t *
new_list(void)827c478bd9Sstevel@tonic-gate new_list(void)
837c478bd9Sstevel@tonic-gate {
847c478bd9Sstevel@tonic-gate eplist_t *list;
857c478bd9Sstevel@tonic-gate
867c478bd9Sstevel@tonic-gate list = (eplist_t *)malloc(sizeof (eplist_t));
877c478bd9Sstevel@tonic-gate (void) memset(list, 0, sizeof (eplist_t));
887c478bd9Sstevel@tonic-gate
897c478bd9Sstevel@tonic-gate list->next = list;
907c478bd9Sstevel@tonic-gate list->prev = list;
917c478bd9Sstevel@tonic-gate list->item = NULL;
927c478bd9Sstevel@tonic-gate
937c478bd9Sstevel@tonic-gate return (list);
947c478bd9Sstevel@tonic-gate }
957c478bd9Sstevel@tonic-gate
967c478bd9Sstevel@tonic-gate void
add_item(void * item,eplist_t * list)977c478bd9Sstevel@tonic-gate add_item(void *item, eplist_t *list)
987c478bd9Sstevel@tonic-gate {
997c478bd9Sstevel@tonic-gate eplist_t *entry;
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate entry = (eplist_t *)malloc(sizeof (eplist_t));
1027c478bd9Sstevel@tonic-gate (void) memset(entry, 0, sizeof (eplist_t));
1037c478bd9Sstevel@tonic-gate entry->item = item;
1047c478bd9Sstevel@tonic-gate
1057c478bd9Sstevel@tonic-gate entry->next = list;
1067c478bd9Sstevel@tonic-gate entry->prev = list->prev;
1077c478bd9Sstevel@tonic-gate list->prev->next = entry;
1087c478bd9Sstevel@tonic-gate list->prev = entry;
1097c478bd9Sstevel@tonic-gate }
1107c478bd9Sstevel@tonic-gate
1117c478bd9Sstevel@tonic-gate typedef struct benv_ent {
1127c478bd9Sstevel@tonic-gate char *cmd;
1137c478bd9Sstevel@tonic-gate char *name;
1147c478bd9Sstevel@tonic-gate char *val;
1157c478bd9Sstevel@tonic-gate } benv_ent_t;
1167c478bd9Sstevel@tonic-gate
1177c478bd9Sstevel@tonic-gate typedef struct benv_des {
1187c478bd9Sstevel@tonic-gate char *name;
1197c478bd9Sstevel@tonic-gate int fd;
1207c478bd9Sstevel@tonic-gate caddr_t adr;
1217c478bd9Sstevel@tonic-gate size_t len;
1227c478bd9Sstevel@tonic-gate eplist_t *elist;
1237c478bd9Sstevel@tonic-gate } benv_des_t;
1247c478bd9Sstevel@tonic-gate
1257c478bd9Sstevel@tonic-gate static benv_des_t *
new_bd(void)1267c478bd9Sstevel@tonic-gate new_bd(void)
1277c478bd9Sstevel@tonic-gate {
1287c478bd9Sstevel@tonic-gate
1297c478bd9Sstevel@tonic-gate benv_des_t *bd;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate bd = (benv_des_t *)malloc(sizeof (benv_des_t));
1327c478bd9Sstevel@tonic-gate (void) memset(bd, 0, sizeof (benv_des_t));
1337c478bd9Sstevel@tonic-gate
1347c478bd9Sstevel@tonic-gate bd->elist = new_list();
1357c478bd9Sstevel@tonic-gate
1367c478bd9Sstevel@tonic-gate return (bd);
1377c478bd9Sstevel@tonic-gate }
1387c478bd9Sstevel@tonic-gate
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate * Create a new entry. Comment entries have NULL names.
1417c478bd9Sstevel@tonic-gate */
1427c478bd9Sstevel@tonic-gate static benv_ent_t *
new_bent(char * comm,char * cmd,char * name,char * val)1437c478bd9Sstevel@tonic-gate new_bent(char *comm, char *cmd, char *name, char *val)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate benv_ent_t *bent;
1467c478bd9Sstevel@tonic-gate
1477c478bd9Sstevel@tonic-gate bent = (benv_ent_t *)malloc(sizeof (benv_ent_t));
1487c478bd9Sstevel@tonic-gate (void) memset(bent, 0, sizeof (benv_ent_t));
1497c478bd9Sstevel@tonic-gate
1507c478bd9Sstevel@tonic-gate if (comm) {
1517c478bd9Sstevel@tonic-gate bent->cmd = strdup(comm);
1527c478bd9Sstevel@tonic-gate comm = NULL;
1537c478bd9Sstevel@tonic-gate } else {
1547c478bd9Sstevel@tonic-gate bent->cmd = strdup(cmd);
1557c478bd9Sstevel@tonic-gate bent->name = strdup(name);
1567c478bd9Sstevel@tonic-gate if (val)
1577c478bd9Sstevel@tonic-gate bent->val = strdup(val);
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate return (bent);
1617c478bd9Sstevel@tonic-gate }
1627c478bd9Sstevel@tonic-gate
1637c478bd9Sstevel@tonic-gate /*
1647c478bd9Sstevel@tonic-gate * Add a new entry to the benv entry list. Entries can be
1657c478bd9Sstevel@tonic-gate * comments or commands.
1667c478bd9Sstevel@tonic-gate */
1677c478bd9Sstevel@tonic-gate static void
add_bent(eplist_t * list,char * comm,char * cmd,char * name,char * val)1687c478bd9Sstevel@tonic-gate add_bent(eplist_t *list, char *comm, char *cmd, char *name, char *val)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate benv_ent_t *bent;
1717c478bd9Sstevel@tonic-gate
1727c478bd9Sstevel@tonic-gate bent = new_bent(comm, cmd, name, val);
1737c478bd9Sstevel@tonic-gate add_item((void *)bent, list);
1747c478bd9Sstevel@tonic-gate }
1757c478bd9Sstevel@tonic-gate
1767c478bd9Sstevel@tonic-gate static benv_ent_t *
get_var(char * name,eplist_t * list)1777c478bd9Sstevel@tonic-gate get_var(char *name, eplist_t *list)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate eplist_t *e;
1807c478bd9Sstevel@tonic-gate benv_ent_t *p;
1817c478bd9Sstevel@tonic-gate
1827c478bd9Sstevel@tonic-gate for (e = list->next; e != list; e = e->next) {
1837c478bd9Sstevel@tonic-gate p = (benv_ent_t *)e->item;
1847c478bd9Sstevel@tonic-gate if (p->name != NULL && strcmp(p->name, name) == 0)
1857c478bd9Sstevel@tonic-gate return (p);
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate
1887c478bd9Sstevel@tonic-gate return (NULL);
1897c478bd9Sstevel@tonic-gate }
1907c478bd9Sstevel@tonic-gate
1917c478bd9Sstevel@tonic-gate static void
print_var(char * name,eplist_t * list)1927c478bd9Sstevel@tonic-gate print_var(char *name, eplist_t *list)
1937c478bd9Sstevel@tonic-gate {
1947c478bd9Sstevel@tonic-gate benv_ent_t *p;
1957d59361aSGangadhar Mylapuram char *bootcmd;
1967c478bd9Sstevel@tonic-gate
197c262cbbcSToomas Soome if (strcmp(name, "bootcmd") == 0) {
1987d59361aSGangadhar Mylapuram bootcmd = getbootcmd();
1997d59361aSGangadhar Mylapuram (void) printf("%s=%s\n", name, bootcmd ? bootcmd : "");
2007d59361aSGangadhar Mylapuram } else if ((p = get_var(name, list)) == NULL) {
201ae115bc7Smrj (void) printf("%s: data not available.\n", name);
2027d59361aSGangadhar Mylapuram } else {
203ae115bc7Smrj (void) printf("%s=%s\n", name, p->val ? p->val : "");
2047d59361aSGangadhar Mylapuram }
2057c478bd9Sstevel@tonic-gate }
2067c478bd9Sstevel@tonic-gate
2077c478bd9Sstevel@tonic-gate static void
print_vars(eplist_t * list)2087c478bd9Sstevel@tonic-gate print_vars(eplist_t *list)
2097c478bd9Sstevel@tonic-gate {
2107c478bd9Sstevel@tonic-gate eplist_t *e;
2117c478bd9Sstevel@tonic-gate benv_ent_t *p;
2127c478bd9Sstevel@tonic-gate
2137c478bd9Sstevel@tonic-gate for (e = list->next; e != list; e = e->next) {
2147c478bd9Sstevel@tonic-gate p = (benv_ent_t *)e->item;
215ae115bc7Smrj if (p->name != NULL) {
216ae115bc7Smrj (void) printf("%s=%s\n", p->name, p->val ? p->val : "");
217ae115bc7Smrj }
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate }
2207c478bd9Sstevel@tonic-gate
2217c478bd9Sstevel@tonic-gate /*
2227c478bd9Sstevel@tonic-gate * Write a string to a file, quoted appropriately. We use single
2237c478bd9Sstevel@tonic-gate * quotes to prevent any variable expansion. Of course, we backslash-quote
2247c478bd9Sstevel@tonic-gate * any single quotes or backslashes.
2257c478bd9Sstevel@tonic-gate */
2267c478bd9Sstevel@tonic-gate static void
put_quoted(FILE * fp,char * val)2277c478bd9Sstevel@tonic-gate put_quoted(FILE *fp, char *val)
2287c478bd9Sstevel@tonic-gate {
229ae115bc7Smrj (void) putc('\'', fp);
2307c478bd9Sstevel@tonic-gate while (*val) {
2317c478bd9Sstevel@tonic-gate switch (*val) {
2327c478bd9Sstevel@tonic-gate case '\'':
2337c478bd9Sstevel@tonic-gate case '\\':
234ae115bc7Smrj (void) putc('\\', fp);
2357c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
2367c478bd9Sstevel@tonic-gate default:
237ae115bc7Smrj (void) putc(*val, fp);
2387c478bd9Sstevel@tonic-gate break;
2397c478bd9Sstevel@tonic-gate }
2407c478bd9Sstevel@tonic-gate val++;
2417c478bd9Sstevel@tonic-gate }
242ae115bc7Smrj (void) putc('\'', fp);
2437c478bd9Sstevel@tonic-gate }
2447c478bd9Sstevel@tonic-gate
245455710d3Srscott /*
246455710d3Srscott * Returns 1 if bootenv.rc was modified, 0 otherwise.
247455710d3Srscott */
248455710d3Srscott static int
set_var(char * name,char * val,eplist_t * list)2497c478bd9Sstevel@tonic-gate set_var(char *name, char *val, eplist_t *list)
2507c478bd9Sstevel@tonic-gate {
2517c478bd9Sstevel@tonic-gate benv_ent_t *p;
2527c478bd9Sstevel@tonic-gate
2537d59361aSGangadhar Mylapuram if (strcmp(name, "bootcmd") == 0)
2547d59361aSGangadhar Mylapuram return (0);
2557d59361aSGangadhar Mylapuram
2567c478bd9Sstevel@tonic-gate if (verbose) {
257ae115bc7Smrj (void) printf("old:");
2587c478bd9Sstevel@tonic-gate print_var(name, list);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate
2617c478bd9Sstevel@tonic-gate if ((p = get_var(name, list)) != NULL) {
2627c478bd9Sstevel@tonic-gate free(p->val);
2637c478bd9Sstevel@tonic-gate p->val = strdup(val);
2647c478bd9Sstevel@tonic-gate } else
2657c478bd9Sstevel@tonic-gate add_bent(list, NULL, "setprop", name, val);
2667c478bd9Sstevel@tonic-gate
2677c478bd9Sstevel@tonic-gate if (verbose) {
268ae115bc7Smrj (void) printf("new:");
2697c478bd9Sstevel@tonic-gate print_var(name, list);
2707c478bd9Sstevel@tonic-gate }
271455710d3Srscott return (1);
2727c478bd9Sstevel@tonic-gate }
2737c478bd9Sstevel@tonic-gate
2747c478bd9Sstevel@tonic-gate /*
275455710d3Srscott * Returns 1 if bootenv.rc is modified or 0 if no modification was
276455710d3Srscott * necessary. This allows us to implement non super-user look-up of
277455710d3Srscott * variables by name without the user being yelled at for trying to
278455710d3Srscott * modify the bootenv.rc file.
2797c478bd9Sstevel@tonic-gate */
2807c478bd9Sstevel@tonic-gate static int
proc_var(char * name,eplist_t * list)2817c478bd9Sstevel@tonic-gate proc_var(char *name, eplist_t *list)
2827c478bd9Sstevel@tonic-gate {
2837c478bd9Sstevel@tonic-gate register char *val;
2847c478bd9Sstevel@tonic-gate
2857c478bd9Sstevel@tonic-gate if ((val = strchr(name, '=')) == NULL) {
2867c478bd9Sstevel@tonic-gate print_var(name, list);
2877c478bd9Sstevel@tonic-gate return (0);
2887c478bd9Sstevel@tonic-gate } else {
2897c478bd9Sstevel@tonic-gate *val++ = '\0';
290455710d3Srscott return (set_var(name, val, list));
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate }
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate static void
init_benv(benv_des_t * bd,char * file)2957c478bd9Sstevel@tonic-gate init_benv(benv_des_t *bd, char *file)
2967c478bd9Sstevel@tonic-gate {
2977c478bd9Sstevel@tonic-gate get_kbenv();
2987c478bd9Sstevel@tonic-gate
2997c478bd9Sstevel@tonic-gate if (test)
3007c478bd9Sstevel@tonic-gate boottree = "/tmp";
3017c478bd9Sstevel@tonic-gate else if ((boottree = (char *)get_propval("boottree", "chosen")) == NULL)
3027c478bd9Sstevel@tonic-gate boottree = strcats("/boot", NULL);
3037c478bd9Sstevel@tonic-gate
3047c478bd9Sstevel@tonic-gate if (file != NULL)
3057c478bd9Sstevel@tonic-gate bd->name = file;
3067c478bd9Sstevel@tonic-gate else
3077c478bd9Sstevel@tonic-gate bd->name = strcats(boottree, "/solaris/bootenv.rc", NULL);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate
3107c478bd9Sstevel@tonic-gate static void
map_benv(benv_des_t * bd)3117c478bd9Sstevel@tonic-gate map_benv(benv_des_t *bd)
3127c478bd9Sstevel@tonic-gate {
3137c478bd9Sstevel@tonic-gate if ((bd->fd = open(bd->name, O_RDONLY)) == -1)
3147c478bd9Sstevel@tonic-gate if (errno == ENOENT)
3157c478bd9Sstevel@tonic-gate return;
3167c478bd9Sstevel@tonic-gate else
3177c478bd9Sstevel@tonic-gate exit(_error(PERROR, "cannot open %s", bd->name));
3187c478bd9Sstevel@tonic-gate
3197c478bd9Sstevel@tonic-gate if ((bd->len = (size_t)lseek(bd->fd, 0, SEEK_END)) == 0) {
3207c478bd9Sstevel@tonic-gate if (close(bd->fd) == -1)
3217c478bd9Sstevel@tonic-gate exit(_error(PERROR, "close error on %s", bd->name));
3227c478bd9Sstevel@tonic-gate return;
3237c478bd9Sstevel@tonic-gate }
3247c478bd9Sstevel@tonic-gate
3257c478bd9Sstevel@tonic-gate (void) lseek(bd->fd, 0, SEEK_SET);
3267c478bd9Sstevel@tonic-gate
3277c478bd9Sstevel@tonic-gate if ((bd->adr = mmap((caddr_t)0, bd->len, (PROT_READ | PROT_WRITE),
3287c478bd9Sstevel@tonic-gate MAP_PRIVATE, bd->fd, 0)) == MAP_FAILED)
3297c478bd9Sstevel@tonic-gate exit(_error(PERROR, "cannot map %s", bd->name));
3307c478bd9Sstevel@tonic-gate }
3317c478bd9Sstevel@tonic-gate
3327c478bd9Sstevel@tonic-gate static void
unmap_benv(benv_des_t * bd)3337c478bd9Sstevel@tonic-gate unmap_benv(benv_des_t *bd)
3347c478bd9Sstevel@tonic-gate {
3357c478bd9Sstevel@tonic-gate if (munmap(bd->adr, bd->len) == -1)
3367c478bd9Sstevel@tonic-gate exit(_error(PERROR, "unmap error on %s", bd->name));
3377c478bd9Sstevel@tonic-gate
3387c478bd9Sstevel@tonic-gate if (close(bd->fd) == -1)
3397c478bd9Sstevel@tonic-gate exit(_error(PERROR, "close error on %s", bd->name));
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate #define NL '\n'
3437c478bd9Sstevel@tonic-gate #define COMM '#'
3447c478bd9Sstevel@tonic-gate
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate * Add a comment block to the benv list.
3477c478bd9Sstevel@tonic-gate */
3487c478bd9Sstevel@tonic-gate static void
add_comm(benv_des_t * bd,char * base,char * last,char ** next,int * line)3497c478bd9Sstevel@tonic-gate add_comm(benv_des_t *bd, char *base, char *last, char **next, int *line)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate int nl, lines;
3527c478bd9Sstevel@tonic-gate char *p;
3537c478bd9Sstevel@tonic-gate
3547c478bd9Sstevel@tonic-gate nl = 0;
3557c478bd9Sstevel@tonic-gate for (p = base, lines = 0; p < last; p++) {
3567c478bd9Sstevel@tonic-gate if (*p == NL) {
3577c478bd9Sstevel@tonic-gate nl++;
3587c478bd9Sstevel@tonic-gate lines++;
3597c478bd9Sstevel@tonic-gate } else if (nl) {
3607c478bd9Sstevel@tonic-gate if (*p != COMM)
3617c478bd9Sstevel@tonic-gate break;
3627c478bd9Sstevel@tonic-gate nl = 0;
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate }
365619456cbSToomas Soome *(p - 1) = '\0';
3667c478bd9Sstevel@tonic-gate add_bent(bd->elist, base, NULL, NULL, NULL);
3677c478bd9Sstevel@tonic-gate *next = p;
3687c478bd9Sstevel@tonic-gate *line += lines;
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate
3717c478bd9Sstevel@tonic-gate /*
3727c478bd9Sstevel@tonic-gate * Parse out an operator (setprop) from the boot environment
3737c478bd9Sstevel@tonic-gate */
3747c478bd9Sstevel@tonic-gate static char *
parse_cmd(benv_des_t * bd,char ** next,int * line)3757c478bd9Sstevel@tonic-gate parse_cmd(benv_des_t *bd, char **next, int *line)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate char *strbegin;
3787c478bd9Sstevel@tonic-gate char *badeof = "unexpected EOF in %s line %d";
3797c478bd9Sstevel@tonic-gate char *syntax = "syntax error in %s line %d";
3807c478bd9Sstevel@tonic-gate char *c = *next;
3817c478bd9Sstevel@tonic-gate
3827c478bd9Sstevel@tonic-gate /*
3837c478bd9Sstevel@tonic-gate * Skip spaces or tabs. New lines increase the line count.
3847c478bd9Sstevel@tonic-gate */
3857c478bd9Sstevel@tonic-gate while (isspace(*c)) {
3867c478bd9Sstevel@tonic-gate if (*c++ == '\n')
3877c478bd9Sstevel@tonic-gate (*line)++;
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate * Check for a the setprop command. Currently that's all we
3927c478bd9Sstevel@tonic-gate * seem to support.
3937c478bd9Sstevel@tonic-gate *
3947c478bd9Sstevel@tonic-gate * XXX need support for setbinprop?
3957c478bd9Sstevel@tonic-gate */
3967c478bd9Sstevel@tonic-gate
3977c478bd9Sstevel@tonic-gate /*
3987c478bd9Sstevel@tonic-gate * Check first for end of file. Finding one now would be okay.
3997c478bd9Sstevel@tonic-gate * We should also bail if we are at the start of a comment.
4007c478bd9Sstevel@tonic-gate */
4017c478bd9Sstevel@tonic-gate if (*c == '\0' || *c == COMM) {
4027c478bd9Sstevel@tonic-gate *next = c;
4037c478bd9Sstevel@tonic-gate return (NULL);
4047c478bd9Sstevel@tonic-gate }
4057c478bd9Sstevel@tonic-gate
4067c478bd9Sstevel@tonic-gate strbegin = c;
4077c478bd9Sstevel@tonic-gate while (*c && !isspace(*c))
4087c478bd9Sstevel@tonic-gate c++;
4097c478bd9Sstevel@tonic-gate
4107c478bd9Sstevel@tonic-gate /*
4117c478bd9Sstevel@tonic-gate * Check again for end of file. Finding one now would NOT be okay.
4127c478bd9Sstevel@tonic-gate */
4137c478bd9Sstevel@tonic-gate if (*c == '\0') {
4147c478bd9Sstevel@tonic-gate exit(_error(NO_PERROR, badeof, bd->name, *line));
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate
4177c478bd9Sstevel@tonic-gate *c++ = '\0';
4187c478bd9Sstevel@tonic-gate *next = c;
4197c478bd9Sstevel@tonic-gate
4207c478bd9Sstevel@tonic-gate /*
4217c478bd9Sstevel@tonic-gate * Last check is to make sure the command is a setprop!
4227c478bd9Sstevel@tonic-gate */
4237c478bd9Sstevel@tonic-gate if (strcmp(strbegin, "setprop") != 0) {
4247c478bd9Sstevel@tonic-gate exit(_error(NO_PERROR, syntax, bd->name, *line));
4257c478bd9Sstevel@tonic-gate /* NOTREACHED */
4267c478bd9Sstevel@tonic-gate }
4277c478bd9Sstevel@tonic-gate return (strbegin);
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate
4307c478bd9Sstevel@tonic-gate /*
4317c478bd9Sstevel@tonic-gate * Parse out the name (LHS) of a setprop from the boot environment
4327c478bd9Sstevel@tonic-gate */
4337c478bd9Sstevel@tonic-gate static char *
parse_name(benv_des_t * bd,char ** next,int * line)4347c478bd9Sstevel@tonic-gate parse_name(benv_des_t *bd, char **next, int *line)
4357c478bd9Sstevel@tonic-gate {
4367c478bd9Sstevel@tonic-gate char *strbegin;
4377c478bd9Sstevel@tonic-gate char *badeof = "unexpected EOF in %s line %d";
4387c478bd9Sstevel@tonic-gate char *syntax = "syntax error in %s line %d";
4397c478bd9Sstevel@tonic-gate char *c = *next;
4407c478bd9Sstevel@tonic-gate
4417c478bd9Sstevel@tonic-gate /*
4427c478bd9Sstevel@tonic-gate * Skip spaces or tabs. No tolerance for new lines now.
4437c478bd9Sstevel@tonic-gate */
4447c478bd9Sstevel@tonic-gate while (isspace(*c)) {
4457c478bd9Sstevel@tonic-gate if (*c++ == '\n')
4467c478bd9Sstevel@tonic-gate exit(_error(NO_PERROR, syntax, bd->name, *line));
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate
4497c478bd9Sstevel@tonic-gate /*
4507c478bd9Sstevel@tonic-gate * Grab a name for the property to set.
4517c478bd9Sstevel@tonic-gate */
4527c478bd9Sstevel@tonic-gate
4537c478bd9Sstevel@tonic-gate /*
4547c478bd9Sstevel@tonic-gate * Check first for end of file. Finding one now would NOT be okay.
4557c478bd9Sstevel@tonic-gate */
4567c478bd9Sstevel@tonic-gate if (*c == '\0') {
4577c478bd9Sstevel@tonic-gate exit(_error(NO_PERROR, badeof, bd->name, *line));
4587c478bd9Sstevel@tonic-gate }
4597c478bd9Sstevel@tonic-gate
4607c478bd9Sstevel@tonic-gate strbegin = c;
4617c478bd9Sstevel@tonic-gate while (*c && !isspace(*c))
4627c478bd9Sstevel@tonic-gate c++;
4637c478bd9Sstevel@tonic-gate
4647c478bd9Sstevel@tonic-gate /*
4657c478bd9Sstevel@tonic-gate * At this point in parsing we have 'setprop name'. What follows
4667c478bd9Sstevel@tonic-gate * is a newline, other whitespace, or EOF. Most of the time we
4677c478bd9Sstevel@tonic-gate * want to replace a white space character with a NULL to terminate
4687c478bd9Sstevel@tonic-gate * the name, and then continue on processing. A newline here provides
4697c478bd9Sstevel@tonic-gate * the most grief. If we just replace it with a null we'll
4707c478bd9Sstevel@tonic-gate * potentially get the setprop on the next line as the value of this
4717c478bd9Sstevel@tonic-gate * setprop! So, if the last thing we see is a newline we'll have to
4727c478bd9Sstevel@tonic-gate * dup the string.
4737c478bd9Sstevel@tonic-gate */
4747c478bd9Sstevel@tonic-gate if (isspace(*c)) {
4757c478bd9Sstevel@tonic-gate if (*c == '\n') {
4767c478bd9Sstevel@tonic-gate *c = '\0';
4777c478bd9Sstevel@tonic-gate strbegin = strdup(strbegin);
4787c478bd9Sstevel@tonic-gate *c = '\n';
4797c478bd9Sstevel@tonic-gate } else {
4807c478bd9Sstevel@tonic-gate *c++ = '\0';
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate
4847c478bd9Sstevel@tonic-gate *next = c;
4857c478bd9Sstevel@tonic-gate return (strbegin);
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate /*
4897c478bd9Sstevel@tonic-gate * Parse out the value (RHS) of a setprop line from the boot environment
4907c478bd9Sstevel@tonic-gate */
4917c478bd9Sstevel@tonic-gate static char *
parse_value(benv_des_t * bd,char ** next,int * line)4927c478bd9Sstevel@tonic-gate parse_value(benv_des_t *bd, char **next, int *line)
4937c478bd9Sstevel@tonic-gate {
4947c478bd9Sstevel@tonic-gate char *strbegin;
4957c478bd9Sstevel@tonic-gate char *badeof = "unexpected EOF in %s line %d";
4967c478bd9Sstevel@tonic-gate char *result;
4977c478bd9Sstevel@tonic-gate char *c = *next;
4987c478bd9Sstevel@tonic-gate char quote;
4997c478bd9Sstevel@tonic-gate
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate * Skip spaces or tabs. A newline here would indicate a
5027c478bd9Sstevel@tonic-gate * NULL property value.
5037c478bd9Sstevel@tonic-gate */
5047c478bd9Sstevel@tonic-gate while (isspace(*c)) {
5057c478bd9Sstevel@tonic-gate if (*c++ == '\n') {
5067c478bd9Sstevel@tonic-gate (*line)++;
5077c478bd9Sstevel@tonic-gate *next = c;
5087c478bd9Sstevel@tonic-gate return (NULL);
5097c478bd9Sstevel@tonic-gate }
5107c478bd9Sstevel@tonic-gate }
5117c478bd9Sstevel@tonic-gate
5127c478bd9Sstevel@tonic-gate /*
5137c478bd9Sstevel@tonic-gate * Grab the value of the property to set.
5147c478bd9Sstevel@tonic-gate */
5157c478bd9Sstevel@tonic-gate
5167c478bd9Sstevel@tonic-gate /*
5177c478bd9Sstevel@tonic-gate * Check first for end of file. Finding one now would
5187c478bd9Sstevel@tonic-gate * also indicate a NULL property.
5197c478bd9Sstevel@tonic-gate */
5207c478bd9Sstevel@tonic-gate if (*c == '\0') {
5217c478bd9Sstevel@tonic-gate *next = c;
5227c478bd9Sstevel@tonic-gate return (NULL);
5237c478bd9Sstevel@tonic-gate }
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate * Value may be quoted, in which case we assume the end of the value
5277c478bd9Sstevel@tonic-gate * comes with a closing quote.
5287c478bd9Sstevel@tonic-gate *
5297c478bd9Sstevel@tonic-gate * We also allow escaped quote characters inside the quoted value.
5307c478bd9Sstevel@tonic-gate *
5317c478bd9Sstevel@tonic-gate * For obvious reasons we do not attempt to parse variable references.
5327c478bd9Sstevel@tonic-gate */
5337c478bd9Sstevel@tonic-gate if (*c == '"' || *c == '\'') {
5347c478bd9Sstevel@tonic-gate quote = *c;
5357c478bd9Sstevel@tonic-gate c++;
5367c478bd9Sstevel@tonic-gate strbegin = c;
5377c478bd9Sstevel@tonic-gate result = c;
5387c478bd9Sstevel@tonic-gate while (*c != quote) {
5397c478bd9Sstevel@tonic-gate if (*c == '\\') {
5407c478bd9Sstevel@tonic-gate c++;
5417c478bd9Sstevel@tonic-gate }
542d92a527cSMark Logan if (*c == '\0') {
5437c478bd9Sstevel@tonic-gate break;
5447c478bd9Sstevel@tonic-gate }
5457c478bd9Sstevel@tonic-gate *result++ = *c++;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate
5487c478bd9Sstevel@tonic-gate /*
5497c478bd9Sstevel@tonic-gate * Throw fatal exception if no end quote found.
5507c478bd9Sstevel@tonic-gate */
5517c478bd9Sstevel@tonic-gate if (*c != quote) {
5527c478bd9Sstevel@tonic-gate exit(_error(NO_PERROR, badeof, bd->name, *line));
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate
5557c478bd9Sstevel@tonic-gate *result = '\0'; /* Terminate the result */
5567c478bd9Sstevel@tonic-gate c++; /* and step past the close quote */
5577c478bd9Sstevel@tonic-gate } else {
5587c478bd9Sstevel@tonic-gate strbegin = c;
5597c478bd9Sstevel@tonic-gate while (*c && !isspace(*c))
5607c478bd9Sstevel@tonic-gate c++;
5617c478bd9Sstevel@tonic-gate }
5627c478bd9Sstevel@tonic-gate
5637c478bd9Sstevel@tonic-gate /*
5647c478bd9Sstevel@tonic-gate * Check again for end of file. Finding one now is okay.
5657c478bd9Sstevel@tonic-gate */
5667c478bd9Sstevel@tonic-gate if (*c == '\0') {
5677c478bd9Sstevel@tonic-gate *next = c;
5687c478bd9Sstevel@tonic-gate return (strbegin);
5697c478bd9Sstevel@tonic-gate }
5707c478bd9Sstevel@tonic-gate
5717c478bd9Sstevel@tonic-gate *c++ = '\0';
5727c478bd9Sstevel@tonic-gate *next = c;
5737c478bd9Sstevel@tonic-gate return (strbegin);
5747c478bd9Sstevel@tonic-gate }
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate /*
5777c478bd9Sstevel@tonic-gate * Add a command to the benv list.
5787c478bd9Sstevel@tonic-gate */
5797c478bd9Sstevel@tonic-gate static void
add_cmd(benv_des_t * bd,char * last,char ** next,int * line)5807c478bd9Sstevel@tonic-gate add_cmd(benv_des_t *bd, char *last, char **next, int *line)
5817c478bd9Sstevel@tonic-gate {
5827c478bd9Sstevel@tonic-gate char *cmd, *name, *val;
5837c478bd9Sstevel@tonic-gate
5847c478bd9Sstevel@tonic-gate while (*next <= last && **next != COMM) {
5857c478bd9Sstevel@tonic-gate if ((cmd = parse_cmd(bd, next, line)) == NULL)
5867c478bd9Sstevel@tonic-gate break;
5877c478bd9Sstevel@tonic-gate name = parse_name(bd, next, line);
5887c478bd9Sstevel@tonic-gate val = parse_value(bd, next, line);
5897c478bd9Sstevel@tonic-gate add_bent(bd->elist, NULL, cmd, name, val);
5907c478bd9Sstevel@tonic-gate (*line)++;
5917c478bd9Sstevel@tonic-gate };
5923b133becSGangadhar Mylapuram
5937c478bd9Sstevel@tonic-gate }
5947c478bd9Sstevel@tonic-gate
5957c478bd9Sstevel@tonic-gate /*
5967c478bd9Sstevel@tonic-gate * Parse the benv (bootenv.rc) file and break it into a benv
5977c478bd9Sstevel@tonic-gate * list. List entries may be comment blocks or commands.
5987c478bd9Sstevel@tonic-gate */
5997c478bd9Sstevel@tonic-gate static void
parse_benv(benv_des_t * bd)6007c478bd9Sstevel@tonic-gate parse_benv(benv_des_t *bd)
6017c478bd9Sstevel@tonic-gate {
6027c478bd9Sstevel@tonic-gate int line;
6037c478bd9Sstevel@tonic-gate char *pbase, *pend;
6047c478bd9Sstevel@tonic-gate char *tok, *tnext;
6057c478bd9Sstevel@tonic-gate
6067c478bd9Sstevel@tonic-gate line = 1;
6077c478bd9Sstevel@tonic-gate pbase = (char *)bd->adr;
6087c478bd9Sstevel@tonic-gate pend = pbase + bd->len;
6097c478bd9Sstevel@tonic-gate
610d92a527cSMark Logan for (tok = tnext = pbase; tnext < pend && '\0' != *tnext; tok = tnext)
6117c478bd9Sstevel@tonic-gate if (*tok == COMM)
6127c478bd9Sstevel@tonic-gate add_comm(bd, tok, pend, &tnext, &line);
6137c478bd9Sstevel@tonic-gate else
6147c478bd9Sstevel@tonic-gate add_cmd(bd, pend, &tnext, &line);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate static void
write_benv(benv_des_t * bd)6187c478bd9Sstevel@tonic-gate write_benv(benv_des_t *bd)
6197c478bd9Sstevel@tonic-gate {
6207c478bd9Sstevel@tonic-gate FILE *fp;
6217c478bd9Sstevel@tonic-gate eplist_t *list, *e;
6227c478bd9Sstevel@tonic-gate benv_ent_t *bent;
6237c478bd9Sstevel@tonic-gate char *name;
6247c478bd9Sstevel@tonic-gate
6257c478bd9Sstevel@tonic-gate list = bd->elist;
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate if (list->next == list)
6287c478bd9Sstevel@tonic-gate return;
6297c478bd9Sstevel@tonic-gate
6307c478bd9Sstevel@tonic-gate if ((fp = fopen(bd->name, "w")) == NULL)
6317c478bd9Sstevel@tonic-gate exit(_error(PERROR, "cannot open %s", bd->name));
6327c478bd9Sstevel@tonic-gate
6337c478bd9Sstevel@tonic-gate for (e = list->next; e != list; e = e->next) {
6347c478bd9Sstevel@tonic-gate bent = (benv_ent_t *)e->item;
6357c478bd9Sstevel@tonic-gate name = bent->name;
636ae115bc7Smrj if (name) {
637ae115bc7Smrj if (bent->val) {
638ae115bc7Smrj (void) fprintf(fp, "%s %s ",
639455710d3Srscott bent->cmd, bent->name);
6407c478bd9Sstevel@tonic-gate put_quoted(fp, bent->val);
641ae115bc7Smrj (void) fprintf(fp, "\n");
642ae115bc7Smrj } else {
643ae115bc7Smrj (void) fprintf(fp, "%s %s\n",
644455710d3Srscott bent->cmd, bent->name);
645ae115bc7Smrj }
646ae115bc7Smrj } else {
647ae115bc7Smrj (void) fprintf(fp, "%s\n", bent->cmd);
648ae115bc7Smrj }
6497c478bd9Sstevel@tonic-gate }
6507c478bd9Sstevel@tonic-gate
651ae115bc7Smrj (void) fclose(fp);
6527c478bd9Sstevel@tonic-gate }
6537c478bd9Sstevel@tonic-gate
6547c478bd9Sstevel@tonic-gate static char *
get_line(void)6557c478bd9Sstevel@tonic-gate get_line(void)
6567c478bd9Sstevel@tonic-gate {
6577c478bd9Sstevel@tonic-gate int c;
6587c478bd9Sstevel@tonic-gate char *nl;
6597c478bd9Sstevel@tonic-gate static char line[256];
6607c478bd9Sstevel@tonic-gate
6617c478bd9Sstevel@tonic-gate if (fgets(line, sizeof (line), stdin) != NULL) {
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate * Remove newline if present,
6647c478bd9Sstevel@tonic-gate * otherwise discard rest of line.
6657c478bd9Sstevel@tonic-gate */
6667c478bd9Sstevel@tonic-gate if (nl = strchr(line, '\n'))
6677c478bd9Sstevel@tonic-gate *nl = 0;
6687c478bd9Sstevel@tonic-gate else
6697c478bd9Sstevel@tonic-gate while ((c = getchar()) != '\n' && c != EOF)
6707c478bd9Sstevel@tonic-gate ;
6717c478bd9Sstevel@tonic-gate return (line);
6727c478bd9Sstevel@tonic-gate } else
6737c478bd9Sstevel@tonic-gate return (NULL);
6747c478bd9Sstevel@tonic-gate }
6757c478bd9Sstevel@tonic-gate
676b713c91eSToomas Soome static int
add_pair(const char * name,const char * nvlist,const char * key,const char * type,const char * value)677b713c91eSToomas Soome add_pair(const char *name, const char *nvlist, const char *key,
678b713c91eSToomas Soome const char *type, const char *value)
679b713c91eSToomas Soome {
680b713c91eSToomas Soome void *data, *nv;
681b713c91eSToomas Soome size_t size;
682b713c91eSToomas Soome int rv;
683b713c91eSToomas Soome char *end;
684b713c91eSToomas Soome
685b713c91eSToomas Soome rv = lzbe_nvlist_get(name, nvlist, &nv);
686b713c91eSToomas Soome if (rv != 0)
687b713c91eSToomas Soome return (rv);
688b713c91eSToomas Soome
689b713c91eSToomas Soome data = NULL;
690b713c91eSToomas Soome rv = EINVAL;
691b713c91eSToomas Soome if (strcmp(type, "DATA_TYPE_STRING") == 0) {
692b713c91eSToomas Soome data = (void *)(uintptr_t)value;
693b713c91eSToomas Soome size = strlen(data) + 1;
694b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, data, size);
695b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_UINT64") == 0) {
696b713c91eSToomas Soome uint64_t v;
697b713c91eSToomas Soome
698b713c91eSToomas Soome v = strtoull(value, &end, 0);
699b713c91eSToomas Soome if (errno != 0 || *end != '\0')
700b713c91eSToomas Soome goto done;
701b713c91eSToomas Soome size = sizeof (v);
702b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
703b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_INT64") == 0) {
704b713c91eSToomas Soome int64_t v;
705b713c91eSToomas Soome
706b713c91eSToomas Soome v = strtoll(value, &end, 0);
707b713c91eSToomas Soome if (errno != 0 || *end != '\0')
708b713c91eSToomas Soome goto done;
709b713c91eSToomas Soome size = sizeof (v);
710b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
711b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_UINT32") == 0) {
712b713c91eSToomas Soome u_longlong_t lv;
713b713c91eSToomas Soome uint32_t v;
714b713c91eSToomas Soome
715b713c91eSToomas Soome lv = strtoull(value, &end, 0);
716b713c91eSToomas Soome if (errno != 0 || *end != '\0')
717b713c91eSToomas Soome goto done;
718b713c91eSToomas Soome if (lv > UINT32_MAX)
719b713c91eSToomas Soome goto done;
720b713c91eSToomas Soome v = lv;
721b713c91eSToomas Soome size = sizeof (v);
722b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
723b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_INT32") == 0) {
724b713c91eSToomas Soome longlong_t lv;
725b713c91eSToomas Soome int32_t v;
726b713c91eSToomas Soome
727b713c91eSToomas Soome lv = strtoll(value, &end, 0);
728b713c91eSToomas Soome if (errno != 0 || *end != '\0')
729b713c91eSToomas Soome goto done;
730b713c91eSToomas Soome if (lv < INT32_MIN || lv > INT32_MAX)
731b713c91eSToomas Soome goto done;
732b713c91eSToomas Soome v = lv;
733b713c91eSToomas Soome size = sizeof (v);
734b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
735b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_UINT16") == 0) {
736b713c91eSToomas Soome uint32_t lv;
737b713c91eSToomas Soome uint16_t v;
738b713c91eSToomas Soome
739b713c91eSToomas Soome lv = strtoul(value, &end, 0);
740b713c91eSToomas Soome if (errno != 0 || *end != '\0')
741b713c91eSToomas Soome goto done;
742b713c91eSToomas Soome if (lv > UINT16_MAX)
743b713c91eSToomas Soome goto done;
744b713c91eSToomas Soome v = lv;
745b713c91eSToomas Soome size = sizeof (v);
746b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
747b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_INT16") == 0) {
748b713c91eSToomas Soome int32_t lv;
749b713c91eSToomas Soome int16_t v;
750b713c91eSToomas Soome
751f816551bSToomas Soome lv = strtol(value, &end, 0);
752b713c91eSToomas Soome if (errno != 0 || *end != '\0')
753b713c91eSToomas Soome goto done;
754b713c91eSToomas Soome if (lv < INT16_MIN || lv > INT16_MAX)
755b713c91eSToomas Soome goto done;
756b713c91eSToomas Soome v = lv;
757b713c91eSToomas Soome size = sizeof (v);
758b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
759b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_UINT8") == 0) {
760b713c91eSToomas Soome uint32_t lv;
761b713c91eSToomas Soome uint8_t v;
762b713c91eSToomas Soome
763b713c91eSToomas Soome lv = strtoul(value, &end, 0);
764b713c91eSToomas Soome if (errno != 0 || *end != '\0')
765b713c91eSToomas Soome goto done;
766b713c91eSToomas Soome if (lv > UINT8_MAX)
767b713c91eSToomas Soome goto done;
768b713c91eSToomas Soome v = lv;
769b713c91eSToomas Soome size = sizeof (v);
770b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
771b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_INT8") == 0) {
772b713c91eSToomas Soome int32_t lv;
773b713c91eSToomas Soome int8_t v;
774b713c91eSToomas Soome
775b713c91eSToomas Soome lv = strtol(value, &end, 0);
776b713c91eSToomas Soome if (errno != 0 || *end != '\0')
777b713c91eSToomas Soome goto done;
778b713c91eSToomas Soome if (lv < INT8_MIN || lv > INT8_MAX)
779b713c91eSToomas Soome goto done;
780b713c91eSToomas Soome v = lv;
781b713c91eSToomas Soome size = sizeof (v);
782b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
783b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_BYTE") == 0) {
784b713c91eSToomas Soome uint32_t lv;
785b713c91eSToomas Soome uint8_t v;
786b713c91eSToomas Soome
787b713c91eSToomas Soome lv = strtoul(value, &end, 0);
788b713c91eSToomas Soome if (errno != 0 || *end != '\0')
789b713c91eSToomas Soome goto done;
790b713c91eSToomas Soome if (lv > UINT8_MAX)
791b713c91eSToomas Soome goto done;
792b713c91eSToomas Soome v = lv;
793b713c91eSToomas Soome size = sizeof (v);
794b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
795b713c91eSToomas Soome } else if (strcmp(type, "DATA_TYPE_BOOLEAN_VALUE") == 0) {
796b713c91eSToomas Soome int32_t v;
797b713c91eSToomas Soome
798b713c91eSToomas Soome v = strtol(value, &end, 0);
799b713c91eSToomas Soome if (errno != 0 || *end != '\0') {
800b713c91eSToomas Soome if (strcasecmp(value, "YES") == 0)
801b713c91eSToomas Soome v = 1;
802b713c91eSToomas Soome else if (strcasecmp(value, "NO") == 0)
803b713c91eSToomas Soome v = 0;
804b713c91eSToomas Soome else if (strcasecmp(value, "true") == 0)
805b713c91eSToomas Soome v = 1;
806b713c91eSToomas Soome else if (strcasecmp(value, "false") == 0)
807b713c91eSToomas Soome v = 0;
808b713c91eSToomas Soome else goto done;
809b713c91eSToomas Soome }
810b713c91eSToomas Soome size = sizeof (v);
811b713c91eSToomas Soome rv = lzbe_add_pair(nv, key, type, &v, size);
812b713c91eSToomas Soome }
813b713c91eSToomas Soome
814b713c91eSToomas Soome if (rv == 0)
815b713c91eSToomas Soome rv = lzbe_nvlist_set(name, nvlist, nv);
816b713c91eSToomas Soome
817b713c91eSToomas Soome done:
818b713c91eSToomas Soome lzbe_nvlist_free(nv);
819b713c91eSToomas Soome return (rv);
820b713c91eSToomas Soome }
821b713c91eSToomas Soome
822b713c91eSToomas Soome static int
delete_pair(const char * name,const char * nvlist,const char * key)823b713c91eSToomas Soome delete_pair(const char *name, const char *nvlist, const char *key)
824b713c91eSToomas Soome {
825b713c91eSToomas Soome void *nv;
826b713c91eSToomas Soome int rv;
827b713c91eSToomas Soome
828b713c91eSToomas Soome rv = lzbe_nvlist_get(name, nvlist, &nv);
829b713c91eSToomas Soome if (rv == 0)
830b713c91eSToomas Soome rv = lzbe_remove_pair(nv, key);
831b713c91eSToomas Soome
832b713c91eSToomas Soome if (rv == 0)
833b713c91eSToomas Soome rv = lzbe_nvlist_set(name, nvlist, nv);
834b713c91eSToomas Soome
835b713c91eSToomas Soome lzbe_nvlist_free(nv);
836b713c91eSToomas Soome return (rv);
837b713c91eSToomas Soome }
838b713c91eSToomas Soome
839b713c91eSToomas Soome static int
usage(char * name)840b713c91eSToomas Soome usage(char *name)
841b713c91eSToomas Soome {
842b713c91eSToomas Soome char *usage = "Usage: %s [-v] [-f prom-device]"
843b713c91eSToomas Soome " [variable[=value] ...]\n"
844b713c91eSToomas Soome "%s [-z pool] [-d key] [-k key -t type -v value] [-p]\n"
845b713c91eSToomas Soome "%s [-z pool] -n nvlist [-d key] [-k key -t type -v value] [-p]\n";
846b713c91eSToomas Soome
847b713c91eSToomas Soome return (_error(NO_PERROR, usage, name, name, name));
848b713c91eSToomas Soome }
849b713c91eSToomas Soome
8507c478bd9Sstevel@tonic-gate int
main(int argc,char ** argv)8517c478bd9Sstevel@tonic-gate main(int argc, char **argv)
8527c478bd9Sstevel@tonic-gate {
8537c478bd9Sstevel@tonic-gate int c;
8547c478bd9Sstevel@tonic-gate int updates = 0;
8557c478bd9Sstevel@tonic-gate eplist_t *elist;
8567c478bd9Sstevel@tonic-gate benv_des_t *bd;
8577c478bd9Sstevel@tonic-gate char *file = NULL;
858b713c91eSToomas Soome bool bootenv, bootenv_print, bootenv_delete;
859b713c91eSToomas Soome char *name, *key, *type, *nvlist, *value;
860b713c91eSToomas Soome lzbe_flags_t flag = lzbe_add;
861b713c91eSToomas Soome
862b713c91eSToomas Soome nvlist = NULL;
863b713c91eSToomas Soome name = "rpool";
864b713c91eSToomas Soome key = NULL;
865b713c91eSToomas Soome type = NULL;
866b713c91eSToomas Soome value = NULL;
867b713c91eSToomas Soome bootenv = false;
868b713c91eSToomas Soome bootenv_print = false;
869b713c91eSToomas Soome bootenv_delete = false;
8707c478bd9Sstevel@tonic-gate
87123a1cceaSRoger A. Faulkner setpname(argv[0]);
8727c478bd9Sstevel@tonic-gate
873b713c91eSToomas Soome while ((c = getopt(argc, argv, "bd:f:k:n:prt:v:z:")) != -1)
8747c478bd9Sstevel@tonic-gate switch (c) {
875b713c91eSToomas Soome case 'b':
876b713c91eSToomas Soome bootenv = true;
877b713c91eSToomas Soome break;
878b713c91eSToomas Soome case 'd':
879b713c91eSToomas Soome if (bootenv) {
880b713c91eSToomas Soome bootenv_delete = true;
881b713c91eSToomas Soome key = optarg;
882b713c91eSToomas Soome } else {
883b713c91eSToomas Soome exit(usage(argv[0]));
884b713c91eSToomas Soome }
8857c478bd9Sstevel@tonic-gate break;
8867c478bd9Sstevel@tonic-gate case 'f':
8877c478bd9Sstevel@tonic-gate file = optarg;
8887c478bd9Sstevel@tonic-gate break;
889b713c91eSToomas Soome case 'k':
890b713c91eSToomas Soome if (bootenv)
891b713c91eSToomas Soome key = optarg;
892b713c91eSToomas Soome else
893b713c91eSToomas Soome exit(usage(argv[0]));
894b713c91eSToomas Soome break;
895b713c91eSToomas Soome case 'n':
896b713c91eSToomas Soome if (bootenv)
897b713c91eSToomas Soome nvlist = optarg;
898b713c91eSToomas Soome else
899b713c91eSToomas Soome exit(usage(argv[0]));
900b713c91eSToomas Soome break;
901b713c91eSToomas Soome case 'p':
902b713c91eSToomas Soome if (bootenv)
903b713c91eSToomas Soome bootenv_print = true;
904b713c91eSToomas Soome else
905b713c91eSToomas Soome exit(usage(argv[0]));
906b713c91eSToomas Soome break;
907b713c91eSToomas Soome case 'r':
908b713c91eSToomas Soome if (bootenv)
909b713c91eSToomas Soome flag = lzbe_replace;
910b713c91eSToomas Soome else
911b713c91eSToomas Soome exit(usage(argv[0]));
912b713c91eSToomas Soome break;
9137c478bd9Sstevel@tonic-gate case 't':
914b713c91eSToomas Soome if (bootenv)
915b713c91eSToomas Soome type = optarg;
916b713c91eSToomas Soome else
917b713c91eSToomas Soome test++;
918b713c91eSToomas Soome break;
919b713c91eSToomas Soome case 'v':
920b713c91eSToomas Soome if (bootenv)
921b713c91eSToomas Soome value = optarg;
922b713c91eSToomas Soome else
923b713c91eSToomas Soome verbose++;
924b713c91eSToomas Soome break;
925b713c91eSToomas Soome case 'z':
926b713c91eSToomas Soome if (bootenv)
927b713c91eSToomas Soome name = optarg;
928b713c91eSToomas Soome else
929b713c91eSToomas Soome exit(usage(argv[0]));
9307c478bd9Sstevel@tonic-gate break;
9317c478bd9Sstevel@tonic-gate default:
932b713c91eSToomas Soome exit(usage(argv[0]));
933b713c91eSToomas Soome }
934b713c91eSToomas Soome
935b713c91eSToomas Soome argc -= optind;
936b713c91eSToomas Soome argv += optind;
937*aa88555eSToomas Soome optind = 0;
938b713c91eSToomas Soome
939b713c91eSToomas Soome if (bootenv) {
940b713c91eSToomas Soome int rv = 0;
941b713c91eSToomas Soome
942b713c91eSToomas Soome if (argc == 1)
943*aa88555eSToomas Soome value = argv[optind];
944b713c91eSToomas Soome
945b713c91eSToomas Soome if (bootenv_print)
946b713c91eSToomas Soome return (lzbe_bootenv_print(name, nvlist, stdout));
947b713c91eSToomas Soome
948b713c91eSToomas Soome if (key != NULL || value != NULL) {
949b713c91eSToomas Soome if (type == NULL)
950b713c91eSToomas Soome type = "DATA_TYPE_STRING";
951b713c91eSToomas Soome
952b713c91eSToomas Soome if (bootenv_delete)
953b713c91eSToomas Soome rv = delete_pair(name, nvlist, key);
954b713c91eSToomas Soome else if (key == NULL)
955b713c91eSToomas Soome rv = lzbe_set_boot_device(name, flag, value);
956b713c91eSToomas Soome else
957b713c91eSToomas Soome rv = add_pair(name, nvlist, key, type, value);
958b713c91eSToomas Soome
959b713c91eSToomas Soome if (rv == 0)
960b713c91eSToomas Soome printf("zfs bootenv is successfully written\n");
961b713c91eSToomas Soome else
962b713c91eSToomas Soome printf("error: %s\n", strerror(rv));
9637c478bd9Sstevel@tonic-gate }
964b713c91eSToomas Soome return (rv);
965b713c91eSToomas Soome }
9667c478bd9Sstevel@tonic-gate
9677c478bd9Sstevel@tonic-gate (void) uname(&uts_buf);
9687c478bd9Sstevel@tonic-gate bd = new_bd();
9697c478bd9Sstevel@tonic-gate init_benv(bd, file);
9707c478bd9Sstevel@tonic-gate
9717c478bd9Sstevel@tonic-gate map_benv(bd);
9727c478bd9Sstevel@tonic-gate if (bd->len) {
9737c478bd9Sstevel@tonic-gate parse_benv(bd);
9747c478bd9Sstevel@tonic-gate unmap_benv(bd);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate
9777c478bd9Sstevel@tonic-gate elist = bd->elist;
9787c478bd9Sstevel@tonic-gate
979ae115bc7Smrj if (optind >= argc) {
9807c478bd9Sstevel@tonic-gate print_vars(elist);
9817c478bd9Sstevel@tonic-gate return (0);
982*aa88555eSToomas Soome } else {
9837c478bd9Sstevel@tonic-gate while (optind < argc) {
9847c478bd9Sstevel@tonic-gate /*
9857c478bd9Sstevel@tonic-gate * If "-" specified, read variables from stdin;
9867c478bd9Sstevel@tonic-gate * otherwise, process each argument as a variable
9877c478bd9Sstevel@tonic-gate * print or set request.
9887c478bd9Sstevel@tonic-gate */
9897c478bd9Sstevel@tonic-gate if (strcmp(argv[optind], "-") == 0) {
9907c478bd9Sstevel@tonic-gate char *line;
9917c478bd9Sstevel@tonic-gate
9927c478bd9Sstevel@tonic-gate while ((line = get_line()) != NULL)
9937c478bd9Sstevel@tonic-gate updates += proc_var(line, elist);
9947c478bd9Sstevel@tonic-gate clearerr(stdin);
9957c478bd9Sstevel@tonic-gate } else
9967c478bd9Sstevel@tonic-gate updates += proc_var(argv[optind], elist);
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate optind++;
9997c478bd9Sstevel@tonic-gate }
1000*aa88555eSToomas Soome }
10017c478bd9Sstevel@tonic-gate
10027c478bd9Sstevel@tonic-gate /*
10037c478bd9Sstevel@tonic-gate * don't write benv if we are processing delayed writes since
10047c478bd9Sstevel@tonic-gate * it is likely that the delayed writes changes bootenv.rc anyway...
10057c478bd9Sstevel@tonic-gate */
1006ae115bc7Smrj if (updates)
10077c478bd9Sstevel@tonic-gate write_benv(bd);
10087c478bd9Sstevel@tonic-gate close_kbenv();
10097c478bd9Sstevel@tonic-gate
10107c478bd9Sstevel@tonic-gate return (0);
10117c478bd9Sstevel@tonic-gate }
1012