1 /*
2 * Copyright (c) 2023, Meta
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "posix_shell.h"
8
9 #include <ctype.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <zephyr/shell/shell.h>
14
15 #define HELP_ENV_GET "[NAME]"
16 #define HELP_ENV_SET "NAME VALUE | NAME=VALUE"
17 #define HELP_ENV_UNSET "NAME.."
18
cmd_env_get(const struct shell * sh,size_t argc,char ** argv)19 static int cmd_env_get(const struct shell *sh, size_t argc, char **argv)
20 {
21 const char *name;
22 const char *value;
23
24 switch (argc) {
25 case 1: {
26 extern char **environ;
27 /* list all environment variables */
28 if (environ != NULL) {
29 for (char **envp = environ; *envp != NULL; ++envp) {
30 shell_print(sh, "%s", *envp);
31 }
32 }
33 } break;
34 case 2:
35 /* list a specific environment variable */
36 name = argv[1];
37 value = getenv(name);
38 if (value != NULL) {
39 shell_print(sh, "%s", value);
40 }
41 break;
42 default:
43 return EXIT_FAILURE;
44 }
45
46 return EXIT_SUCCESS;
47 }
48
is_shell_env_name(const char * name)49 static bool is_shell_env_name(const char *name)
50 {
51 char c;
52
53 if (name == NULL || name[0] == '\0') {
54 return false;
55 }
56
57 for (size_t i = 0, N = strlen(name); i < N; ++i) {
58 c = name[i];
59
60 if (c == '_') {
61 continue;
62 }
63
64 if (isalpha(c)) {
65 continue;
66 }
67
68 if (i > 0 && isdigit(c)) {
69 continue;
70 }
71
72 return false;
73 }
74
75 return true;
76 }
77
cmd_env_set(const struct shell * sh,size_t argc,char ** argv)78 static int cmd_env_set(const struct shell *sh, size_t argc, char **argv)
79 {
80 int ret;
81 char *value;
82 const char *name;
83
84 switch (argc) {
85 case 2:
86 name = argv[1];
87 value = strchr(argv[1], '=');
88 if (value != NULL) {
89 *value = '\0';
90 ++value;
91 }
92 break;
93 case 3:
94 name = argv[1];
95 value = argv[2];
96 break;
97 default:
98 return EXIT_FAILURE;
99 }
100
101 /* silently drop "poorly conditioned" environment variables */
102 if (!is_shell_env_name(name)) {
103 shell_print(sh, "bad name");
104 return EXIT_SUCCESS;
105 }
106
107 ret = setenv(name, value, 1);
108 if (ret == -1) {
109 return EXIT_FAILURE;
110 }
111
112 return EXIT_SUCCESS;
113 }
114
cmd_env_unset(const struct shell * sh,size_t argc,char ** argv)115 static int cmd_env_unset(const struct shell *sh, size_t argc, char **argv)
116 {
117 for (--argc, ++argv; argc > 0; --argc, ++argv) {
118 (void)unsetenv(argv[0]);
119 }
120
121 return EXIT_SUCCESS;
122 }
123
124 SHELL_STATIC_SUBCMD_SET_CREATE(sub_env, SHELL_CMD(set, NULL, HELP_ENV_SET, cmd_env_set),
125 SHELL_CMD(get, NULL, HELP_ENV_GET, cmd_env_get),
126 SHELL_CMD(unset, NULL, HELP_ENV_UNSET, cmd_env_unset),
127 SHELL_SUBCMD_SET_END /* Array terminated. */
128 );
129
130 POSIX_CMD_ADD(env, &sub_env, "Print system information", NULL, 1, 255);
131