env.c revision 329099
1139749Simp/*
276479Swpaul * Copyright (c) 2015 Netflix, Inc. All Rights Reserved.
376479Swpaul *
476479Swpaul * Redistribution and use in source and binary forms, with or without
576479Swpaul * modification, are permitted provided that the following conditions
676479Swpaul * are met:
776479Swpaul * 1. Redistributions of source code must retain the above copyright
876479Swpaul *    notice, this list of conditions and the following disclaimer.
976479Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1076479Swpaul *    notice, this list of conditions and the following disclaimer in the
1176479Swpaul *    documentation and/or other materials provided with the distribution.
1276479Swpaul *
1376479Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1476479Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1576479Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1676479Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1776479Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1876479Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1976479Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2076479Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2176479Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2276479Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2376479Swpaul * SUCH DAMAGE.
2476479Swpaul */
2576479Swpaul
2676479Swpaul#include <sys/cdefs.h>
2776479Swpaul__FBSDID("$FreeBSD: stable/11/sys/boot/efi/libefi/env.c 329099 2018-02-10 04:37:44Z kevans $");
2876479Swpaul
2976479Swpaul#include <sys/param.h>
3076479Swpaul#include <stand.h>
3176479Swpaul#include <string.h>
3276479Swpaul#include <efi.h>
3376479Swpaul#include <efilib.h>
34119418Sobrien#include <uuid.h>
35119418Sobrien#include <stdbool.h>
36119418Sobrien#include "bootstrap.h"
3776479Swpaul#ifdef BOOT_FORTH
3876479Swpaul#include "ficl.h"
3976479Swpaul#endif
4076479Swpaul
4176479Swpaul/*
4276479Swpaul * Simple wrappers to the underlying UEFI functions.
4376479Swpaul * See http://wiki.phoenix.com/wiki/index.php/EFI_RUNTIME_SERVICES
4476479Swpaul * for details.
4576479Swpaul */
4676479SwpaulEFI_STATUS
4776479Swpaulefi_get_next_variable_name(UINTN *variable_name_size, CHAR16 *variable_name,
4876479Swpaul    EFI_GUID *vendor_guid)
4976479Swpaul{
5076479Swpaul	return (RS->GetNextVariableName(variable_name_size, variable_name,
5176479Swpaul	    vendor_guid));
5276479Swpaul}
5376479Swpaul
5476479SwpaulEFI_STATUS
5576479Swpaulefi_get_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid,
5676479Swpaul    UINT32 *attributes, UINTN *data_size, void *data)
5776479Swpaul{
5876479Swpaul	return (RS->GetVariable(variable_name, vendor_guid, attributes,
5976479Swpaul	    data_size, data));
6076479Swpaul}
6176479Swpaul
6276479SwpaulEFI_STATUS
6376479Swpaulefi_set_variable(CHAR16 *variable_name, EFI_GUID *vendor_guid,
6476479Swpaul    UINT32 attributes, UINTN data_size, void *data)
6576479Swpaul{
6676479Swpaul	return (RS->SetVariable(variable_name, vendor_guid, attributes,
6776479Swpaul	    data_size, data));
6876479Swpaul}
6976479Swpaul
7076479Swpaulvoid
7176479Swpaulefi_init_environment(void)
7276479Swpaul{
7378323Swpaul	char var[128];
7478323Swpaul
7578323Swpaul	snprintf(var, sizeof(var), "%d.%02d", ST->Hdr.Revision >> 16,
7678323Swpaul	    ST->Hdr.Revision & 0xffff);
7778323Swpaul	env_setenv("efi-version", EV_VOLATILE, var, env_noset, env_nounset);
7878323Swpaul}
7978323Swpaul
8078323SwpaulCOMMAND_SET(efishow, "efi-show", "print some or all EFI variables", command_efi_show);
8178323Swpaul
8278323Swpaulstatic int
8378323Swpaulefi_print_var(CHAR16 *varnamearg, EFI_GUID *matchguid, int lflag)
8478323Swpaul{
8578323Swpaul	UINTN		datasz, i;
8678323Swpaul	EFI_STATUS	status;
8778323Swpaul	UINT32		attr;
8878323Swpaul	CHAR16		*data;
8976479Swpaul	char		*str;
9076479Swpaul	uint32_t	uuid_status;
91150968Sglebius	int		is_ascii;
92150968Sglebius
93150968Sglebius	datasz = 0;
94150968Sglebius	status = RS->GetVariable(varnamearg, matchguid, &attr,
9576479Swpaul	    &datasz, NULL);
9676479Swpaul	if (status != EFI_BUFFER_TOO_SMALL) {
9776479Swpaul		printf("Can't get the variable: error %#lx\n",
9876479Swpaul		    EFI_ERROR_CODE(status));
9976479Swpaul		return (CMD_ERROR);
100129879Sphk	}
10176479Swpaul	data = malloc(datasz);
10276479Swpaul	status = RS->GetVariable(varnamearg, matchguid, &attr,
10376479Swpaul	    &datasz, data);
10476479Swpaul	if (status != EFI_SUCCESS) {
10576479Swpaul		printf("Can't get the variable: error %#lx\n",
10676479Swpaul		    EFI_ERROR_CODE(status));
10776479Swpaul		return (CMD_ERROR);
10876479Swpaul	}
10976479Swpaul	uuid_to_string((uuid_t *)matchguid, &str, &uuid_status);
11076479Swpaul	if (lflag) {
11176479Swpaul		printf("%s 0x%x %S", str, attr, varnamearg);
11276479Swpaul	} else {
11376479Swpaul		printf("%s 0x%x %S=", str, attr, varnamearg);
11476479Swpaul		is_ascii = 1;
11576479Swpaul		free(str);
11676479Swpaul		str = (char *)data;
11776479Swpaul		for (i = 0; i < datasz - 1; i++) {
11876479Swpaul			/* Quick hack to see if this ascii-ish string printable range plus tab, cr and lf */
11976479Swpaul			if ((str[i] < 32 || str[i] > 126) && str[i] != 9 && str[i] != 10 && str[i] != 13) {
12076479Swpaul				is_ascii = 0;
12176479Swpaul				break;
12276479Swpaul			}
12376479Swpaul		}
124119285Simp		if (str[datasz - 1] != '\0')
125119285Simp			is_ascii = 0;
12676479Swpaul		if (is_ascii)
12776479Swpaul			printf("%s", str);
12876479Swpaul		else {
12976522Swpaul			for (i = 0; i < datasz / 2; i++) {
13076479Swpaul				if (isalnum(data[i]) || isspace(data[i]))
131113506Smdodd					printf("%c", data[i]);
132113506Smdodd				else
13376479Swpaul					printf("\\x%02x", data[i]);
13476479Swpaul			}
135151545Simp		}
13676479Swpaul	}
13776479Swpaul	free(data);
13876479Swpaul	if (pager_output("\n"))
13976479Swpaul		return (CMD_WARN);
14076479Swpaul	return (CMD_OK);
14176479Swpaul}
14276479Swpaul
14376479Swpaulstatic int
14476479Swpaulcommand_efi_show(int argc, char *argv[])
14576479Swpaul{
14676479Swpaul	/*
14776479Swpaul	 * efi-show [-a]
14876479Swpaul	 *	print all the env
14999497Salfred	 * efi-show -u UUID
15099497Salfred	 *	print all the env vars tagged with UUID
15199497Salfred	 * efi-show -v var
15276479Swpaul	 *	search all the env vars and print the ones matching var
15399497Salfred	 * eif-show -u UUID -v var
15499497Salfred	 * eif-show UUID var
155135254Salc	 *	print all the env vars that match UUID and var
156135250Swpaul	 */
157135250Swpaul	/* NB: We assume EFI_GUID is the same as uuid_t */
15899497Salfred	int		aflag = 0, gflag = 0, lflag = 0, vflag = 0;
15999497Salfred	int		ch, rv;
16099497Salfred	unsigned	i;
16199497Salfred	EFI_STATUS	status;
16299497Salfred	EFI_GUID	varguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
163135250Swpaul	EFI_GUID	matchguid = { 0,0,0,{0,0,0,0,0,0,0,0} };
16499497Salfred	uint32_t	uuid_status;
16599497Salfred	CHAR16		*varname;
166135250Swpaul	CHAR16		*newnm;
16799497Salfred	CHAR16		varnamearg[128];
16899497Salfred	UINTN		varalloc;
169173839Syongari	UINTN		varsz;
17099497Salfred
171151296Sjhb	while ((ch = getopt(argc, argv, "ag:lv:")) != -1) {
17299497Salfred		switch (ch) {
17376479Swpaul		case 'a':
17499497Salfred			aflag = 1;
17599497Salfred			break;
17699497Salfred		case 'g':
17799497Salfred			gflag = 1;
17899497Salfred			uuid_from_string(optarg, (uuid_t *)&matchguid,
17976479Swpaul			    &uuid_status);
18099497Salfred			if (uuid_status != uuid_s_ok) {
18199497Salfred				printf("uid %s could not be parsed\n", optarg);
18299497Salfred				return (CMD_ERROR);
18399497Salfred			}
18476479Swpaul			break;
18599497Salfred		case 'l':
18699497Salfred			lflag = 1;
18799497Salfred			break;
18876479Swpaul		case 'v':
18999497Salfred			vflag = 1;
19099497Salfred			if (strlen(optarg) >= nitems(varnamearg)) {
19199497Salfred				printf("Variable %s is longer than %zd characters\n",
19299497Salfred				    optarg, nitems(varnamearg));
19376479Swpaul				return (CMD_ERROR);
19476479Swpaul			}
19576479Swpaul			for (i = 0; i < strlen(optarg); i++)
19676479Swpaul				varnamearg[i] = optarg[i];
19776479Swpaul			varnamearg[i] = 0;
19876479Swpaul			break;
19976479Swpaul		default:
20076479Swpaul			printf("Invalid argument %c\n", ch);
20176479Swpaul			return (CMD_ERROR);
20276479Swpaul		}
20376479Swpaul	}
20476479Swpaul
20576479Swpaul	if (aflag && (gflag || vflag)) {
20676479Swpaul		printf("-a isn't compatible with -v or -u\n");
20776479Swpaul		return (CMD_ERROR);
20876479Swpaul	}
20976479Swpaul
21076479Swpaul	if (aflag && optind < argc) {
21176479Swpaul		printf("-a doesn't take any args\n");
21276479Swpaul		return (CMD_ERROR);
21376479Swpaul	}
21476479Swpaul
21576479Swpaul	if (optind == argc)
21676479Swpaul		aflag = 1;
21776479Swpaul
21876479Swpaul	argc -= optind;
21976479Swpaul	argv += optind;
22076479Swpaul
22176479Swpaul	pager_open();
22276479Swpaul	if (vflag && gflag) {
22376479Swpaul		rv = efi_print_var(varnamearg, &matchguid, lflag);
22476479Swpaul		pager_close();
22576479Swpaul		return (rv);
22676479Swpaul	}
22776479Swpaul
22876479Swpaul	if (argc == 2) {
229113506Smdodd		optarg = argv[0];
23076479Swpaul		if (strlen(optarg) >= nitems(varnamearg)) {
23176479Swpaul			printf("Variable %s is longer than %zd characters\n",
23276479Swpaul			    optarg, nitems(varnamearg));
23376479Swpaul			pager_close();
23476479Swpaul			return (CMD_ERROR);
23576479Swpaul		}
23676479Swpaul		for (i = 0; i < strlen(optarg); i++)
23776479Swpaul			varnamearg[i] = optarg[i];
23876479Swpaul		varnamearg[i] = 0;
23976479Swpaul		optarg = argv[1];
24076479Swpaul		uuid_from_string(optarg, (uuid_t *)&matchguid,
241106696Salfred		    &uuid_status);
24276479Swpaul		if (uuid_status != uuid_s_ok) {
24376479Swpaul			printf("uid %s could not be parsed\n", optarg);
244106696Salfred			pager_close();
24576479Swpaul			return (CMD_ERROR);
24699497Salfred		}
247192288Syongari		rv = efi_print_var(varnamearg, &matchguid, lflag);
24876479Swpaul		pager_close();
24976479Swpaul		return (rv);
25076479Swpaul	}
25176479Swpaul
25276479Swpaul	if (argc > 0) {
25376479Swpaul		printf("Too many args %d\n", argc);
25476479Swpaul		pager_close();
25576479Swpaul		return (CMD_ERROR);
25676479Swpaul	}
25799497Salfred
258192288Syongari	/*
25976479Swpaul	 * Initiate the search -- note the standard takes pain
260192289Syongari	 * to specify the initial call must be a poiner to a NULL
26176479Swpaul	 * character.
26276479Swpaul	 */
26376479Swpaul	varalloc = 1024;
26476479Swpaul	varname = malloc(varalloc);
26576479Swpaul	if (varname == NULL) {
26676479Swpaul		printf("Can't allocate memory to get variables\n");
26776479Swpaul		pager_close();
26876479Swpaul		return (CMD_ERROR);
26976479Swpaul	}
27076479Swpaul	varname[0] = 0;
27176479Swpaul	while (1) {
27276479Swpaul		varsz = varalloc;
27376479Swpaul		status = RS->GetNextVariableName(&varsz, varname, &varguid);
27476479Swpaul		if (status == EFI_BUFFER_TOO_SMALL) {
27576479Swpaul			varalloc = varsz;
27676479Swpaul			newnm = realloc(varname, varalloc);
27776479Swpaul			if (newnm == NULL) {
27876479Swpaul				printf("Can't allocate memory to get variables\n");
27976479Swpaul				free(varname);
28076479Swpaul				pager_close();
28176479Swpaul				return (CMD_ERROR);
28276479Swpaul			}
28376479Swpaul			varname = newnm;
28476479Swpaul			continue; /* Try again with bigger buffer */
28576479Swpaul		}
28699497Salfred		if (status != EFI_SUCCESS)
287192288Syongari			break;
28876479Swpaul		if (aflag) {
289192289Syongari			if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
29076479Swpaul				break;
29176479Swpaul			continue;
29276479Swpaul		}
29376479Swpaul		if (vflag) {
29476479Swpaul			if (wcscmp(varnamearg, varname) == 0) {
29576479Swpaul				if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
29676479Swpaul					break;
29776479Swpaul				continue;
29876479Swpaul			}
29976479Swpaul		}
30076479Swpaul		if (gflag) {
30176479Swpaul			if (memcmp(&varguid, &matchguid, sizeof(varguid)) == 0) {
30276479Swpaul				if (efi_print_var(varname, &varguid, lflag) != CMD_OK)
30376479Swpaul					break;
30476479Swpaul				continue;
30576479Swpaul			}
30676479Swpaul		}
30776479Swpaul	}
30876479Swpaul	free(varname);
30976479Swpaul	pager_close();
31076479Swpaul
31176479Swpaul	return (CMD_OK);
31276479Swpaul}
31376479Swpaul
31476479SwpaulCOMMAND_SET(efiset, "efi-set", "set EFI variables", command_efi_set);
31599497Salfred
316192288Syongaristatic int
31776479Swpaulcommand_efi_set(int argc, char *argv[])
318192289Syongari{
31976479Swpaul	char *uuid, *var, *val;
32076479Swpaul	CHAR16 wvar[128];
32176479Swpaul	EFI_GUID guid;
32276479Swpaul	uint32_t status;
32376479Swpaul	EFI_STATUS err;
32476479Swpaul
32576479Swpaul	if (argc != 4) {
32676479Swpaul		printf("efi-set uuid var new-value\n");
32776479Swpaul		return (CMD_ERROR);
32876479Swpaul	}
32976479Swpaul	uuid = argv[1];
33076479Swpaul	var = argv[2];
33176479Swpaul	val = argv[3];
33276479Swpaul	uuid_from_string(uuid, (uuid_t *)&guid, &status);
33376479Swpaul	if (status != uuid_s_ok) {
33476479Swpaul		printf("Invalid uuid %s %d\n", uuid, status);
33576479Swpaul		return (CMD_ERROR);
33676479Swpaul	}
33776479Swpaul	cpy8to16(var, wvar, sizeof(wvar));
33876479Swpaul	err = RS->SetVariable(wvar, &guid,
33976479Swpaul	    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,
34076479Swpaul	    strlen(val) + 1, val);
34176479Swpaul	if (EFI_ERROR(err)) {
34276479Swpaul		printf("Failed to set variable: error %lu\n", EFI_ERROR_CODE(err));
34376479Swpaul		return (CMD_ERROR);
34476479Swpaul	}
34576479Swpaul	return (CMD_OK);
34676479Swpaul}
34776479Swpaul
34876479SwpaulCOMMAND_SET(efiunset, "efi-unset", "delete / unset EFI variables", command_efi_unset);
34976479Swpaul
35076479Swpaulstatic int
35176479Swpaulcommand_efi_unset(int argc, char *argv[])
35276479Swpaul{
35376479Swpaul	char *uuid, *var;
35476479Swpaul	CHAR16 wvar[128];
35576479Swpaul	EFI_GUID guid;
35676479Swpaul	uint32_t status;
35776479Swpaul	EFI_STATUS err;
35876479Swpaul
35976479Swpaul	if (argc != 3) {
36099497Salfred		printf("efi-unset uuid var\n");
361192288Syongari		return (CMD_ERROR);
36276479Swpaul	}
36376479Swpaul	uuid = argv[1];
36476479Swpaul	var = argv[2];
36576479Swpaul	uuid_from_string(uuid, (uuid_t *)&guid, &status);
36676479Swpaul	if (status != uuid_s_ok) {
36776479Swpaul		printf("Invalid uuid %s\n", uuid);
36876479Swpaul		return (CMD_ERROR);
36976479Swpaul	}
37076479Swpaul	cpy8to16(var, wvar, sizeof(wvar));
37176479Swpaul	err = RS->SetVariable(wvar, &guid, 0, 0, NULL);
37276479Swpaul	if (EFI_ERROR(err)) {
37376479Swpaul		printf("Failed to unset variable: error %lu\n", EFI_ERROR_CODE(err));
37476479Swpaul		return (CMD_ERROR);
37576479Swpaul	}
37676479Swpaul	return (CMD_OK);
37776479Swpaul}
37876479Swpaul
37976479Swpaul#ifdef BOOT_FORTH
38076479Swpaul/*
38199497Salfred * FreeBSD's loader interaction words and extras
382192288Syongari *
38376479Swpaul *	efi-setenv  ( value n name n guid n attr -- 0 | -1)
384192289Syongari * 	efi-getenv  ( guid n addr n -- addr' n' | -1 )
38576479Swpaul * 	efi-unsetenv ( name n guid n'' -- )
38676479Swpaul */
38776479Swpaul
38876479Swpaul/*
38976479Swpaul * efi-setenv
39076479Swpaul * 	efi-setenv  ( value n name n guid n attr -- 0 | -1)
39176479Swpaul *
39276479Swpaul * Set environment variables using the SetVariable EFI runtime service.
39376479Swpaul *
39476479Swpaul * Value and guid are passed through in binary form (so guid needs to be
39576479Swpaul * converted to binary form from its string form). Name is converted from
39676479Swpaul * ASCII to CHAR16. Since ficl doesn't have support for internationalization,
39776479Swpaul * there's no native CHAR16 interface provided.
39876479Swpaul *
39976479Swpaul * attr is an int in the bitmask of the following attributes for this variable.
40076479Swpaul *
40199497Salfred *	1	Non volatile
402192288Syongari *	2	Boot service access
40376479Swpaul *	4	Run time access
40476479Swpaul * (corresponding to the same bits in the UEFI spec).
40576479Swpaul */
40676479Swpaulstatic void
40776479SwpaulficlEfiSetenv(FICL_VM *pVM)
40876479Swpaul{
40976479Swpaul	char	*value = NULL, *guid = NULL;
41076479Swpaul	CHAR16	*name = NULL;
41176479Swpaul	int	i;
41276479Swpaul	char	*namep, *valuep, *guidp;
41376479Swpaul	int	names, values, guids, attr;
41476479Swpaul	EFI_STATUS status;
41576479Swpaul	uuid_t	u;
41676479Swpaul	uint32_t ustatus;
41776479Swpaul	bool	error = true;
41876479Swpaul
41976479Swpaul#if FICL_ROBUST > 1
42076479Swpaul	vmCheckStack(pVM, 6, 0);
42176479Swpaul#endif
42276479Swpaul	attr = stackPopINT(pVM->pStack);
42376479Swpaul	guids = stackPopINT(pVM->pStack);
42499497Salfred	guidp = (char*)stackPopPtr(pVM->pStack);
425192288Syongari	names = stackPopINT(pVM->pStack);
42676479Swpaul	namep = (char*)stackPopPtr(pVM->pStack);
427135250Swpaul	values = stackPopINT(pVM->pStack);
42876479Swpaul	valuep = (char*)stackPopPtr(pVM->pStack);
42976479Swpaul
43076479Swpaul	guid = (char*)ficlMalloc(guids);
43176479Swpaul	if (guid == NULL)
43276479Swpaul		goto out;
43376479Swpaul	memcpy(guid, guidp, guids);
43476479Swpaul	uuid_from_string(guid, &u, &ustatus);
43576479Swpaul	if (ustatus != uuid_s_ok) {
43676479Swpaul		stackPushINT(pVM->pStack, -1);
43776479Swpaul		goto out;
43876479Swpaul	}
43976479Swpaul
44076479Swpaul	name = ficlMalloc((names + 1) * sizeof(CHAR16));
44176479Swpaul	if (name == NULL)
44276479Swpaul		goto out;
44376479Swpaul	for (i = 0; i < names; i++)
44476479Swpaul		name[i] = namep[i];
44576479Swpaul	name[names] = 0;
44676479Swpaul
44776479Swpaul	value = ficlMalloc(values + 1);
44876479Swpaul	if (value == NULL)
44976479Swpaul		goto out;
45076479Swpaul	memcpy(value, valuep, values);
45176479Swpaul
45276479Swpaul	status = efi_set_variable(name, (EFI_GUID *)&u, attr, values, value);
45376479Swpaul	if (status == EFI_SUCCESS)
45476479Swpaul		stackPushINT(pVM->pStack, 0);
45576479Swpaul	else
45676479Swpaul		stackPushINT(pVM->pStack, -1);
45776479Swpaul	error = false;
45876479Swpaulout:
45976479Swpaul	ficlFree(name);
46076479Swpaul	ficlFree(value);
46176479Swpaul	ficlFree(guid);
46276479Swpaul
46376479Swpaul	if (error == true)
46476479Swpaul		vmThrowErr(pVM, "Error: out of memory");
465109058Smbr}
46676479Swpaul
46776479Swpaulstatic void
46876479SwpaulficlEfiGetenv(FICL_VM *pVM)
46976479Swpaul{
47076479Swpaul	char	*name, *value;
47176479Swpaul	char	*namep;
47276479Swpaul	int	names;
47376479Swpaul
47476479Swpaul#if FICL_ROBUST > 1
47576479Swpaul	vmCheckStack(pVM, 2, 2);
47676479Swpaul#endif
47776479Swpaul	names = stackPopINT(pVM->pStack);
47876479Swpaul	namep = (char*) stackPopPtr(pVM->pStack);
47976479Swpaul
48076479Swpaul	name = (char*) ficlMalloc(names+1);
48176479Swpaul	if (name == NULL)
48276479Swpaul		vmThrowErr(pVM, "Error: out of memory");
48376479Swpaul	strncpy(name, namep, names);
48476479Swpaul	name[names] = '\0';
48576479Swpaul
48676479Swpaul	value = getenv(name);
48776479Swpaul	ficlFree(name);
48876479Swpaul
48976479Swpaul	if(value != NULL) {
49076479Swpaul		stackPushPtr(pVM->pStack, value);
49176479Swpaul		stackPushINT(pVM->pStack, strlen(value));
49276479Swpaul	} else
49376479Swpaul		stackPushINT(pVM->pStack, -1);
49476479Swpaul}
49576479Swpaul
49676479Swpaulstatic void
49776479SwpaulficlEfiUnsetenv(FICL_VM *pVM)
49876479Swpaul{
49976479Swpaul	char	*name;
50076479Swpaul	char	*namep;
50176479Swpaul	int	names;
50276479Swpaul
50376479Swpaul#if FICL_ROBUST > 1
50476479Swpaul	vmCheckStack(pVM, 2, 0);
50576479Swpaul#endif
50676479Swpaul	names = stackPopINT(pVM->pStack);
50776479Swpaul	namep = (char*) stackPopPtr(pVM->pStack);
50876479Swpaul
50976479Swpaul	name = (char*) ficlMalloc(names+1);
51099497Salfred	if (name == NULL)
511192288Syongari		vmThrowErr(pVM, "Error: out of memory");
51276479Swpaul	strncpy(name, namep, names);
51376479Swpaul	name[names] = '\0';
51476479Swpaul
51576479Swpaul	unsetenv(name);
51676479Swpaul	ficlFree(name);
51776479Swpaul}
51876479Swpaul
51976479Swpaul/**************************************************************************
52076479Swpaul** Add FreeBSD UEFI platform extensions into the system dictionary
52176479Swpaul**************************************************************************/
52276479Swpaulvoid ficlEfiCompilePlatform(FICL_SYSTEM *pSys)
52376479Swpaul{
52476479Swpaul	FICL_DICT *dp = pSys->dp;
52576479Swpaul	assert (dp);
52676479Swpaul
52776479Swpaul	dictAppendWord(dp, "efi-setenv",    ficlEfiSetenv,	FW_DEFAULT);
52876479Swpaul	dictAppendWord(dp, "efi-getenv",    ficlEfiGetenv,	FW_DEFAULT);
52976479Swpaul	dictAppendWord(dp, "efi-unsetenv",  ficlEfiUnsetenv,    FW_DEFAULT);
53076479Swpaul}
53176479Swpaul
53276479SwpaulFICL_COMPILE_SET(ficlEfiCompilePlatform);
53376479Swpaul
53476479Swpaul#endif	/* BOOT_FORTH */
53576479Swpaul