xref: /illumos-gate/usr/src/cmd/eeprom/i386/benv.c (revision aa88555e)
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