blob: eb1a91379539b500676058628a9b21967cfd3ccf [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
wdenk05706fd2002-09-28 17:48:27 +00002/*
Wolfgang Denk460a9ff2010-06-20 23:33:59 +02003 * (C) Copyright 2000-2010
wdenk05706fd2002-09-28 17:48:27 +00004 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
5 *
6 * (C) Copyright 2001 Sysgo Real-Time Solutions, GmbH <www.elinos.com>
7 * Andreas Heppel <aheppel@sysgo.de>
wdenk05706fd2002-09-28 17:48:27 +00008 */
9
10#include <common.h>
Simon Glass1ea97892020-05-10 11:40:00 -060011#include <bootstage.h>
wdenk05706fd2002-09-28 17:48:27 +000012#include <command.h>
Simon Glass8fe40932019-08-01 09:46:44 -060013#include <env.h>
Simon Glass9d1f6192019-08-02 09:44:25 -060014#include <env_internal.h>
Simon Glass0f2af882020-05-10 11:40:05 -060015#include <log.h>
Simon Glass16ff5702019-11-14 12:57:19 -070016#include <sort.h>
Simon Glass3ba929a2020-10-30 21:38:53 -060017#include <asm/global_data.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060018#include <linux/printk.h>
wdenk05706fd2002-09-28 17:48:27 +000019#include <linux/stddef.h>
Wolfgang Denk460a9ff2010-06-20 23:33:59 +020020#include <search.h>
21#include <errno.h>
wdenk05706fd2002-09-28 17:48:27 +000022#include <malloc.h>
Simon Glass48b6c6b2019-11-14 12:57:16 -070023#include <u-boot/crc.h>
Rasmus Villemoescf8e5432021-04-21 11:06:54 +020024#include <dm/ofnode.h>
Marek Behún30044c52021-10-17 17:36:38 +020025#include <net.h>
26#include <watchdog.h>
wdenk05706fd2002-09-28 17:48:27 +000027
Wolfgang Denk6405a152006-03-31 18:32:53 +020028DECLARE_GLOBAL_DATA_PTR;
29
wdenk05706fd2002-09-28 17:48:27 +000030/************************************************************************
31 * Default settings to be used when no valid environment is found
32 */
Joe Hershberger81321142012-10-12 08:48:51 +000033#include <env_default.h>
wdenk05706fd2002-09-28 17:48:27 +000034
Gerlando Falautod3925952012-08-24 00:11:39 +000035struct hsearch_data env_htab = {
Joe Hershberger71497d02012-12-11 22:16:31 -060036 .change_ok = env_flags_validate,
Gerlando Falautod3925952012-08-24 00:11:39 +000037};
Mike Frysinger92d7a992010-12-08 06:26:04 -050038
Joe Hershberger864ec562012-12-11 22:16:22 -060039/*
Marek Behún30044c52021-10-17 17:36:38 +020040 * This env_set() function is defined in cmd/nvedit.c, since it calls
41 * _do_env_set(), whis is a static function in that file.
42 *
43 * int env_set(const char *varname, const char *varvalue);
44 */
45
46/**
47 * Set an environment variable to an integer value
48 *
49 * @param varname Environment variable to set
50 * @param value Value to set it to
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010051 * Return: 0 if ok, 1 on error
Marek Behún30044c52021-10-17 17:36:38 +020052 */
53int env_set_ulong(const char *varname, ulong value)
54{
55 /* TODO: this should be unsigned */
56 char *str = simple_itoa(value);
57
58 return env_set(varname, str);
59}
60
61/**
62 * Set an environment variable to an value in hex
63 *
64 * @param varname Environment variable to set
65 * @param value Value to set it to
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +010066 * Return: 0 if ok, 1 on error
Marek Behún30044c52021-10-17 17:36:38 +020067 */
68int env_set_hex(const char *varname, ulong value)
69{
70 char str[17];
71
72 sprintf(str, "%lx", value);
73 return env_set(varname, str);
74}
75
76ulong env_get_hex(const char *varname, ulong default_val)
77{
78 const char *s;
79 ulong value;
80 char *endp;
81
82 s = env_get(varname);
83 if (s)
84 value = hextoul(s, &endp);
85 if (!s || endp == s)
86 return default_val;
87
88 return value;
89}
90
91int eth_env_get_enetaddr(const char *name, uint8_t *enetaddr)
92{
93 string_to_enetaddr(env_get(name), enetaddr);
94 return is_valid_ethaddr(enetaddr);
95}
96
97int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr)
98{
99 char buf[ARP_HLEN_ASCII + 1];
100
101 if (eth_env_get_enetaddr(name, (uint8_t *)buf))
102 return -EEXIST;
103
104 sprintf(buf, "%pM", enetaddr);
105
106 return env_set(name, buf);
107}
108
109/*
110 * Look up variable from environment,
111 * return address of storage for that variable,
112 * or NULL if not found
113 */
114char *env_get(const char *name)
115{
116 if (gd->flags & GD_FLG_ENV_READY) { /* after import into hashtable */
117 struct env_entry e, *ep;
118
Stefan Roese80877fa2022-09-02 14:10:46 +0200119 schedule();
Marek Behún30044c52021-10-17 17:36:38 +0200120
121 e.key = name;
122 e.data = NULL;
123 hsearch_r(e, ENV_FIND, &ep, &env_htab, 0);
124
125 return ep ? ep->data : NULL;
126 }
127
128 /* restricted capabilities before import */
Marek Behúne087a462021-11-04 00:23:22 +0100129 if (env_get_f(name, (char *)(gd->env_buf), sizeof(gd->env_buf)) >= 0)
Marek Behún30044c52021-10-17 17:36:38 +0200130 return (char *)(gd->env_buf);
131
132 return NULL;
133}
134
135/*
136 * Like env_get, but prints an error if envvar isn't defined in the
137 * environment. It always returns what env_get does, so it can be used in
138 * place of env_get without changing error handling otherwise.
139 */
140char *from_env(const char *envvar)
141{
142 char *ret;
143
144 ret = env_get(envvar);
145
146 if (!ret)
147 printf("missing environment variable: %s\n", envvar);
148
149 return ret;
150}
151
Marek Behúnc20046f2021-11-04 00:23:23 +0100152static int env_get_from_linear(const char *env, const char *name, char *buf,
153 unsigned len)
Marek Behún30044c52021-10-17 17:36:38 +0200154{
Marek Behúnc20046f2021-11-04 00:23:23 +0100155 const char *p, *end;
Marek Behún30044c52021-10-17 17:36:38 +0200156 size_t name_len;
157
158 if (name == NULL || *name == '\0')
159 return -1;
160
161 name_len = strlen(name);
162
Marek Behún30044c52021-10-17 17:36:38 +0200163 for (p = env; *p != '\0'; p = end + 1) {
164 const char *value;
165 unsigned res;
166
167 for (end = p; *end != '\0'; ++end)
168 if (end - env >= CONFIG_ENV_SIZE)
169 return -1;
170
171 if (strncmp(name, p, name_len) || p[name_len] != '=')
172 continue;
173 value = &p[name_len + 1];
174
175 res = end - value;
176 memcpy(buf, value, min(len, res + 1));
177
178 if (len <= res) {
179 buf[len - 1] = '\0';
180 printf("env_buf [%u bytes] too small for value of \"%s\"\n",
181 len, name);
182 }
183
184 return res;
185 }
186
187 return -1;
188}
189
Marek Behúnc20046f2021-11-04 00:23:23 +0100190/*
191 * Look up variable from environment for restricted C runtime env.
192 */
193int env_get_f(const char *name, char *buf, unsigned len)
194{
195 const char *env;
196
197 if (gd->env_valid == ENV_INVALID)
198 env = default_environment;
199 else
200 env = (const char *)gd->env_addr;
201
202 return env_get_from_linear(env, name, buf, len);
203}
204
Marek Behún30044c52021-10-17 17:36:38 +0200205/**
206 * Decode the integer value of an environment variable and return it.
207 *
208 * @param name Name of environment variable
209 * @param base Number base to use (normally 10, or 16 for hex)
210 * @param default_val Default value to return if the variable is not
211 * found
Heinrich Schuchardt47b4c022022-01-19 18:05:50 +0100212 * Return: the decoded value, or default_val if not found
Marek Behún30044c52021-10-17 17:36:38 +0200213 */
214ulong env_get_ulong(const char *name, int base, ulong default_val)
215{
216 /*
217 * We can use env_get() here, even before relocation, since the
218 * environment variable value is an integer and thus short.
219 */
220 const char *str = env_get(name);
221
222 return str ? simple_strtoul(str, NULL, base) : default_val;
223}
224
225/*
Joe Hershberger864ec562012-12-11 22:16:22 -0600226 * Read an environment variable as a boolean
227 * Return -1 if variable does not exist (default to true)
228 */
Simon Glass22c34c22017-08-03 12:22:13 -0600229int env_get_yesno(const char *var)
Joe Hershberger864ec562012-12-11 22:16:22 -0600230{
Simon Glass64b723f2017-08-03 12:22:12 -0600231 char *s = env_get(var);
Joe Hershberger864ec562012-12-11 22:16:22 -0600232
233 if (s == NULL)
234 return -1;
235 return (*s == '1' || *s == 'y' || *s == 'Y' || *s == 't' || *s == 'T') ?
236 1 : 0;
237}
238
Simon Glass46b530a2021-10-21 21:08:52 -0600239bool env_get_autostart(void)
240{
241 return env_get_yesno("autostart") == 1;
242}
243
Joe Hershberger6fe26c92012-12-11 22:16:34 -0600244/*
245 * Look up the variable from the default environment
246 */
Simon Glassda1a1342017-08-03 12:22:15 -0600247char *env_get_default(const char *name)
Joe Hershberger6fe26c92012-12-11 22:16:34 -0600248{
Marek Behúnc20046f2021-11-04 00:23:23 +0100249 if (env_get_from_linear(default_environment, name,
250 (char *)(gd->env_buf),
251 sizeof(gd->env_buf)) >= 0)
252 return (char *)(gd->env_buf);
Joe Hershberger6fe26c92012-12-11 22:16:34 -0600253
Marek Behúnc20046f2021-11-04 00:23:23 +0100254 return NULL;
Joe Hershberger6fe26c92012-12-11 22:16:34 -0600255}
256
Simon Glass97385862019-08-01 09:47:00 -0600257void env_set_default(const char *s, int flags)
Harald Welte72eb50a2008-07-07 15:40:39 +0800258{
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200259 if (s) {
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300260 if ((flags & H_INTERACTIVE) == 0) {
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200261 printf("*** Warning - %s, "
Yaniv Levinskyb2bb9bc2018-06-24 19:16:57 +0300262 "using default environment\n\n", s);
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200263 } else {
264 puts(s);
265 }
266 } else {
Maxime Ripard12e6eac2018-01-23 21:16:57 +0100267 debug("Using default environment\n");
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200268 }
269
Marek Vasutab6b15a2020-07-07 20:51:34 +0200270 flags |= H_DEFAULT;
Marek Behún73d25342021-10-22 15:47:24 +0200271 if (himport_r(&env_htab, default_environment,
Alexander Holler3e12be72014-07-14 17:49:55 +0200272 sizeof(default_environment), '\0', flags, 0,
Marek Behún08c6b042021-11-04 00:23:21 +0100273 0, NULL) == 0) {
Quentin Schulz4e9d34cf2018-07-09 19:16:25 +0200274 pr_err("## Error: Environment import failed: errno = %d\n",
275 errno);
Marek Behún08c6b042021-11-04 00:23:21 +0100276 return;
277 }
Igor Grinberg3e773592011-11-07 01:14:11 +0000278
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200279 gd->flags |= GD_FLG_ENV_READY;
Michal Simek32bb7c82016-05-30 16:06:54 +0200280 gd->flags |= GD_FLG_ENV_DEFAULT;
Harald Welte72eb50a2008-07-07 15:40:39 +0800281}
282
Gerlando Falautofe9f49d2012-08-24 00:11:41 +0000283
284/* [re]set individual variables to their value in the default environment */
Simon Glasseec97962019-08-01 09:46:56 -0600285int env_set_default_vars(int nvars, char * const vars[], int flags)
Gerlando Falautofe9f49d2012-08-24 00:11:41 +0000286{
287 /*
288 * Special use-case: import from default environment
289 * (and use \0 as a separator)
290 */
Marek Vasutab6b15a2020-07-07 20:51:34 +0200291 flags |= H_NOCLEAR | H_DEFAULT;
Marek Behún73d25342021-10-22 15:47:24 +0200292 return himport_r(&env_htab, default_environment,
Joe Hershbergera46f7702012-12-11 22:16:19 -0600293 sizeof(default_environment), '\0',
Yaniv Levinsky23840d12018-06-24 19:16:55 +0300294 flags, 0, nvars, vars);
Gerlando Falautofe9f49d2012-08-24 00:11:41 +0000295}
296
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200297/*
298 * Check if CRC is valid and (if yes) import the environment.
299 * Note that "buf" may or may not be aligned.
300 */
Marek Vasutdfe4b7e2020-07-07 20:51:35 +0200301int env_import(const char *buf, int check, int flags)
wdenk05706fd2002-09-28 17:48:27 +0000302{
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200303 env_t *ep = (env_t *)buf;
wdenk05706fd2002-09-28 17:48:27 +0000304
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200305 if (check) {
306 uint32_t crc;
307
308 memcpy(&crc, &ep->crc, sizeof(crc));
309
310 if (crc32(0, ep->data, ENV_SIZE) != crc) {
Simon Glass97385862019-08-01 09:47:00 -0600311 env_set_default("bad CRC", 0);
Sam Protsenkoc3097882019-01-18 21:19:03 +0200312 return -ENOMSG; /* needed for env_load() */
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200313 }
314 }
wdenk05706fd2002-09-28 17:48:27 +0000315
Marek Vasutdfe4b7e2020-07-07 20:51:35 +0200316 if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', flags, 0,
Joe Hershbergera46f7702012-12-11 22:16:19 -0600317 0, NULL)) {
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200318 gd->flags |= GD_FLG_ENV_READY;
Simon Goldschmidt32c3eb52018-01-31 14:47:10 +0100319 return 0;
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200320 }
321
Masahiro Yamada81e10422017-09-16 14:10:41 +0900322 pr_err("Cannot import environment: errno = %d\n", errno);
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200323
Simon Glass97385862019-08-01 09:47:00 -0600324 env_set_default("import failed", 0);
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200325
Simon Goldschmidt32c3eb52018-01-31 14:47:10 +0100326 return -EIO;
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200327}
328
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000329#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
330static unsigned char env_flags;
331
Heiko Schocher30651132020-10-10 10:28:04 +0200332int env_check_redund(const char *buf1, int buf1_read_fail,
333 const char *buf2, int buf2_read_fail)
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000334{
Brandon Maier61374b02020-12-17 17:19:18 -0600335 int crc1_ok = 0, crc2_ok = 0;
Heiko Schocher30651132020-10-10 10:28:04 +0200336 env_t *tmp_env1, *tmp_env2;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000337
338 tmp_env1 = (env_t *)buf1;
339 tmp_env2 = (env_t *)buf2;
340
Simon Goldschmidte07096e2018-01-31 14:47:11 +0100341 if (buf1_read_fail && buf2_read_fail) {
342 puts("*** Error - No Valid Environment Area found\n");
Brandon Maier61374b02020-12-17 17:19:18 -0600343 return -EIO;
Simon Goldschmidte07096e2018-01-31 14:47:11 +0100344 } else if (buf1_read_fail || buf2_read_fail) {
345 puts("*** Warning - some problems detected ");
346 puts("reading environment; recovered successfully\n");
347 }
348
Brandon Maier61374b02020-12-17 17:19:18 -0600349 if (!buf1_read_fail)
350 crc1_ok = crc32(0, tmp_env1->data, ENV_SIZE) ==
351 tmp_env1->crc;
352 if (!buf2_read_fail)
353 crc2_ok = crc32(0, tmp_env2->data, ENV_SIZE) ==
354 tmp_env2->crc;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000355
356 if (!crc1_ok && !crc2_ok) {
Ashok Reddy Somae50e0d52023-07-04 00:16:07 -0600357 gd->env_valid = ENV_INVALID;
Sam Protsenkoc3097882019-01-18 21:19:03 +0200358 return -ENOMSG; /* needed for env_load() */
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000359 } else if (crc1_ok && !crc2_ok) {
Simon Glass1f39d0b2017-08-20 04:45:15 -0600360 gd->env_valid = ENV_VALID;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000361 } else if (!crc1_ok && crc2_ok) {
Simon Glass1f39d0b2017-08-20 04:45:15 -0600362 gd->env_valid = ENV_REDUND;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000363 } else {
364 /* both ok - check serial */
365 if (tmp_env1->flags == 255 && tmp_env2->flags == 0)
Simon Glass1f39d0b2017-08-20 04:45:15 -0600366 gd->env_valid = ENV_REDUND;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000367 else if (tmp_env2->flags == 255 && tmp_env1->flags == 0)
Simon Glass1f39d0b2017-08-20 04:45:15 -0600368 gd->env_valid = ENV_VALID;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000369 else if (tmp_env1->flags > tmp_env2->flags)
Simon Glass1f39d0b2017-08-20 04:45:15 -0600370 gd->env_valid = ENV_VALID;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000371 else if (tmp_env2->flags > tmp_env1->flags)
Simon Glass1f39d0b2017-08-20 04:45:15 -0600372 gd->env_valid = ENV_REDUND;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000373 else /* flags are equal - almost impossible */
Simon Glass1f39d0b2017-08-20 04:45:15 -0600374 gd->env_valid = ENV_VALID;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000375 }
376
Heiko Schocher30651132020-10-10 10:28:04 +0200377 return 0;
378}
379
380int env_import_redund(const char *buf1, int buf1_read_fail,
381 const char *buf2, int buf2_read_fail,
382 int flags)
383{
384 env_t *ep;
385 int ret;
386
387 ret = env_check_redund(buf1, buf1_read_fail, buf2, buf2_read_fail);
388
389 if (ret == -EIO) {
390 env_set_default("bad env area", 0);
391 return -EIO;
Heiko Schocher30651132020-10-10 10:28:04 +0200392 } else if (ret == -ENOMSG) {
393 env_set_default("bad CRC", 0);
394 return -ENOMSG;
395 }
396
Simon Glass1f39d0b2017-08-20 04:45:15 -0600397 if (gd->env_valid == ENV_VALID)
Heiko Schocher30651132020-10-10 10:28:04 +0200398 ep = (env_t *)buf1;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000399 else
Heiko Schocher30651132020-10-10 10:28:04 +0200400 ep = (env_t *)buf2;
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000401
402 env_flags = ep->flags;
Heiko Schocher30651132020-10-10 10:28:04 +0200403
Marek Vasutdfe4b7e2020-07-07 20:51:35 +0200404 return env_import((char *)ep, 0, flags);
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000405}
406#endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
407
Robert P. J. Dayc5b1e5d2016-09-07 14:27:59 -0400408/* Export the environment and generate CRC for it. */
Marek Vasutd73c1292014-03-05 19:59:50 +0100409int env_export(env_t *env_out)
410{
411 char *res;
412 ssize_t len;
413
414 res = (char *)env_out->data;
415 len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
416 if (len < 0) {
Masahiro Yamada81e10422017-09-16 14:10:41 +0900417 pr_err("Cannot export environment: errno = %d\n", errno);
Marek Vasutd73c1292014-03-05 19:59:50 +0100418 return 1;
419 }
Marek Vasut486112d2014-03-05 19:59:51 +0100420
Marek Vasutd73c1292014-03-05 19:59:50 +0100421 env_out->crc = crc32(0, env_out->data, ENV_SIZE);
422
Fiach Antaw57ea7f72017-01-25 18:53:11 +1000423#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
424 env_out->flags = ++env_flags; /* increase the serial */
425#endif
426
Marek Vasutd73c1292014-03-05 19:59:50 +0100427 return 0;
428}
429
Igor Grinberg3e773592011-11-07 01:14:11 +0000430void env_relocate(void)
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200431{
Simon Glass1f39d0b2017-08-20 04:45:15 -0600432 if (gd->env_valid == ENV_INVALID) {
Ilya Yanokf7a2c552012-09-18 00:22:50 +0000433#if defined(CONFIG_ENV_IS_NOWHERE) || defined(CONFIG_SPL_BUILD)
434 /* Environment not changable */
Simon Glass97385862019-08-01 09:47:00 -0600435 env_set_default(NULL, 0);
wdenk05706fd2002-09-28 17:48:27 +0000436#else
Simon Glass0169e6b2012-02-13 13:51:18 +0000437 bootstage_error(BOOTSTAGE_ID_NET_CHECKSUM);
Simon Glass97385862019-08-01 09:47:00 -0600438 env_set_default("bad CRC", 0);
Lei Wene0909be2010-10-10 12:36:40 +0800439#endif
Wolfgang Denk460a9ff2010-06-20 23:33:59 +0200440 } else {
Simon Glass17539572017-08-03 12:22:07 -0600441 env_load();
wdenk05706fd2002-09-28 17:48:27 +0000442 }
wdenk05706fd2002-09-28 17:48:27 +0000443}
wdenk3902d702004-04-15 18:22:41 +0000444
Boris Brezillon619fc682018-12-05 09:26:50 +0100445#ifdef CONFIG_AUTO_COMPLETE
446int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf,
447 bool dollar_comp)
wdenk3902d702004-04-15 18:22:41 +0000448{
Simon Glass1a236862019-08-02 09:44:18 -0600449 struct env_entry *match;
Mike Frysinger8d882322010-12-17 16:51:59 -0500450 int found, idx;
wdenk3902d702004-04-15 18:22:41 +0000451
Boris Brezillon619fc682018-12-05 09:26:50 +0100452 if (dollar_comp) {
453 /*
454 * When doing $ completion, the first character should
455 * obviously be a '$'.
456 */
457 if (var[0] != '$')
458 return 0;
459
460 var++;
461
462 /*
463 * The second one, if present, should be a '{', as some
464 * configuration of the u-boot shell expand ${var} but not
465 * $var.
466 */
467 if (var[0] == '{')
468 var++;
469 else if (var[0] != '\0')
470 return 0;
471 }
472
Mike Frysinger8d882322010-12-17 16:51:59 -0500473 idx = 0;
wdenk3902d702004-04-15 18:22:41 +0000474 found = 0;
475 cmdv[0] = NULL;
476
Boris Brezillon619fc682018-12-05 09:26:50 +0100477
Mike Frysinger8d882322010-12-17 16:51:59 -0500478 while ((idx = hmatch_r(var, idx, &match, &env_htab))) {
479 int vallen = strlen(match->key) + 1;
wdenk3902d702004-04-15 18:22:41 +0000480
Boris Brezillon619fc682018-12-05 09:26:50 +0100481 if (found >= maxv - 2 ||
482 bufsz < vallen + (dollar_comp ? 3 : 0))
wdenk3902d702004-04-15 18:22:41 +0000483 break;
Mike Frysinger8d882322010-12-17 16:51:59 -0500484
wdenk3902d702004-04-15 18:22:41 +0000485 cmdv[found++] = buf;
Boris Brezillon619fc682018-12-05 09:26:50 +0100486
487 /* Add the '${' prefix to each var when doing $ completion. */
488 if (dollar_comp) {
489 strcpy(buf, "${");
490 buf += 2;
491 bufsz -= 3;
492 }
493
Mike Frysinger8d882322010-12-17 16:51:59 -0500494 memcpy(buf, match->key, vallen);
495 buf += vallen;
496 bufsz -= vallen;
Boris Brezillon619fc682018-12-05 09:26:50 +0100497
498 if (dollar_comp) {
499 /*
500 * This one is a bit odd: vallen already contains the
501 * '\0' character but we need to add the '}' suffix,
502 * hence the buf - 1 here. strcpy() will add the '\0'
503 * character just after '}'. buf is then incremented
504 * to account for the extra '}' we just added.
505 */
506 strcpy(buf - 1, "}");
507 buf++;
508 }
wdenk3902d702004-04-15 18:22:41 +0000509 }
510
Mike Frysinger8d882322010-12-17 16:51:59 -0500511 qsort(cmdv, found, sizeof(cmdv[0]), strcmp_compar);
512
513 if (idx)
Boris Brezillon619fc682018-12-05 09:26:50 +0100514 cmdv[found++] = dollar_comp ? "${...}" : "...";
Igor Grinberg3e773592011-11-07 01:14:11 +0000515
wdenk3902d702004-04-15 18:22:41 +0000516 cmdv[found] = NULL;
517 return found;
518}
519#endif
Rasmus Villemoescf8e5432021-04-21 11:06:54 +0200520
521#ifdef CONFIG_ENV_IMPORT_FDT
522void env_import_fdt(void)
523{
524 const char *path;
525 struct ofprop prop;
526 ofnode node;
527 int res;
528
529 path = env_get("env_fdt_path");
530 if (!path || !path[0])
531 return;
532
533 node = ofnode_path(path);
534 if (!ofnode_valid(node)) {
535 printf("Warning: device tree node '%s' not found\n", path);
536 return;
537 }
538
Simon Glassfec058d2022-09-06 20:27:13 -0600539 for (res = ofnode_first_property(node, &prop);
Rasmus Villemoescf8e5432021-04-21 11:06:54 +0200540 !res;
Simon Glassfec058d2022-09-06 20:27:13 -0600541 res = ofnode_next_property(&prop)) {
Rasmus Villemoescf8e5432021-04-21 11:06:54 +0200542 const char *name, *val;
543
Simon Glassd0aff8b2022-09-06 20:27:14 -0600544 val = ofprop_get_property(&prop, &name, NULL);
Rasmus Villemoescf8e5432021-04-21 11:06:54 +0200545 env_set(name, val);
546 }
547}
548#endif