diff --git a/lib/posix/shell/CMakeLists.txt b/lib/posix/shell/CMakeLists.txt index b6dfe6a565..8951083655 100644 --- a/lib/posix/shell/CMakeLists.txt +++ b/lib/posix/shell/CMakeLists.txt @@ -3,3 +3,4 @@ zephyr_library_sources_ifdef(CONFIG_POSIX_SHELL posix_shell.c) zephyr_library_sources_ifdef(CONFIG_POSIX_UNAME_SHELL uname.c) +zephyr_library_sources_ifdef(CONFIG_POSIX_ENV_SHELL env.c) diff --git a/lib/posix/shell/Kconfig b/lib/posix/shell/Kconfig index d7116b492a..294d97a8b7 100644 --- a/lib/posix/shell/Kconfig +++ b/lib/posix/shell/Kconfig @@ -10,6 +10,7 @@ config POSIX_SHELL help Compile the parent `posix` shell command. +rsource "Kconfig.env" rsource "Kconfig.uname" endif # SHELL diff --git a/lib/posix/shell/Kconfig.env b/lib/posix/shell/Kconfig.env new file mode 100644 index 0000000000..d2d5fd53b3 --- /dev/null +++ b/lib/posix/shell/Kconfig.env @@ -0,0 +1,9 @@ +# Copyright (c) 2024 Meta +# SPDX-License-Identifier: Apache-2.0 + +config POSIX_ENV_SHELL + bool "Support for shell" + select POSIX_ENV + select POSIX_SHELL + help + This shell provides access to system environment variables. diff --git a/lib/posix/shell/env.c b/lib/posix/shell/env.c new file mode 100644 index 0000000000..48b3b2a94e --- /dev/null +++ b/lib/posix/shell/env.c @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2023, Meta + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "posix_shell.h" + +#include +#include +#include + +#include + +#define HELP_ENV_GET "[NAME]" +#define HELP_ENV_SET "NAME VALUE | NAME=VALUE" +#define HELP_ENV_UNSET "NAME.." + +static int cmd_env_get(const struct shell *sh, size_t argc, char **argv) +{ + const char *name; + const char *value; + + switch (argc) { + case 1: { + extern char **environ; + /* list all environment variables */ + if (environ != NULL) { + for (char **envp = environ; *envp != NULL; ++envp) { + shell_print(sh, "%s", *envp); + } + } + } break; + case 2: + /* list a specific environment variable */ + name = argv[1]; + value = getenv(name); + if (value != NULL) { + shell_print(sh, "%s", value); + } + break; + default: + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static bool is_shell_env_name(const char *name) +{ + char c; + + if (name == NULL || name[0] == '\0') { + return false; + } + + for (size_t i = 0, N = strlen(name); i < N; ++i) { + c = name[i]; + + if (c == '_') { + continue; + } + + if (isalpha(c)) { + continue; + } + + if (i > 0 && isdigit(c)) { + continue; + } + + return false; + } + + return true; +} + +static int cmd_env_set(const struct shell *sh, size_t argc, char **argv) +{ + int ret; + char *value; + const char *name; + + switch (argc) { + case 2: + name = argv[1]; + value = strchr(argv[1], '='); + if (value != NULL) { + *value = '\0'; + ++value; + } + break; + case 3: + name = argv[1]; + value = argv[2]; + break; + default: + return EXIT_FAILURE; + } + + /* silently drop "poorly conditioned" environment variables */ + if (!is_shell_env_name(name)) { + shell_print(sh, "bad name"); + return EXIT_SUCCESS; + } + + ret = setenv(name, value, 1); + if (ret == -1) { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + +static int cmd_env_unset(const struct shell *sh, size_t argc, char **argv) +{ + for (--argc, ++argv; argc > 0; --argc, ++argv) { + (void)unsetenv(argv[0]); + } + + return EXIT_SUCCESS; +} + +SHELL_STATIC_SUBCMD_SET_CREATE(sub_env, SHELL_CMD(set, NULL, HELP_ENV_SET, cmd_env_set), + SHELL_CMD(get, NULL, HELP_ENV_GET, cmd_env_get), + SHELL_CMD(unset, NULL, HELP_ENV_UNSET, cmd_env_unset), + SHELL_SUBCMD_SET_END /* Array terminated. */ +); + +POSIX_CMD_ADD(env, &sub_env, "Print system information", NULL, 1, 255);