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