xref: /openbmc/u-boot/tools/env/fw_env_main.c (revision 51cb23d4)
1 /*
2  * (C) Copyright 2000-2008
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * SPDX-License-Identifier:	GPL-2.0+
6  */
7 
8 /*
9  * Command line user interface to firmware (=U-Boot) environment.
10  *
11  * Implements:
12  *	fw_printenv [ -a key ] [[ -n name ] | [ name ... ]]
13  *              - prints the value of a single environment variable
14  *                "name", the ``name=value'' pairs of one or more
15  *                environment variables "name", or the whole
16  *                environment if no names are specified.
17  *	fw_setenv [ -a key ] name [ value ... ]
18  *		- If a name without any values is given, the variable
19  *		  with this name is deleted from the environment;
20  *		  otherwise, all "value" arguments are concatenated,
21  *		  separated by single blank characters, and the
22  *		  resulting string is assigned to the environment
23  *		  variable "name"
24  *
25  * If '-a key' is specified, the env block is encrypted with AES 128 CBC.
26  * The 'key' argument is in the format of 32 hexadecimal numbers (16 bytes
27  * of AES key), eg. '-a aabbccddeeff00112233445566778899'.
28  */
29 
30 #include <fcntl.h>
31 #include <getopt.h>
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <sys/file.h>
36 #include <unistd.h>
37 #include "fw_env.h"
38 
39 #define CMD_PRINTENV	"fw_printenv"
40 #define CMD_SETENV	"fw_setenv"
41 static int do_printenv;
42 
43 static struct option long_options[] = {
44 	{"aes", required_argument, NULL, 'a'},
45 	{"config", required_argument, NULL, 'c'},
46 	{"help", no_argument, NULL, 'h'},
47 	{"script", required_argument, NULL, 's'},
48 	{"noheader", required_argument, NULL, 'n'},
49 	{"lock", required_argument, NULL, 'l'},
50 	{NULL, 0, NULL, 0}
51 };
52 
53 static struct env_opts env_opts;
54 
55 /* setenv options */
56 static int noheader;
57 
58 /* getenv options */
59 static char *script_file;
60 
61 void usage_printenv(void)
62 {
63 
64 	fprintf(stderr,
65 		"Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n"
66 		"Print variables from U-Boot environment\n"
67 		"\n"
68 		" -h, --help           print this help.\n"
69 #ifdef CONFIG_ENV_AES
70 		" -a, --aes            aes key to access environment\n"
71 #endif
72 #ifdef CONFIG_FILE
73 		" -c, --config         configuration file, default:" CONFIG_FILE "\n"
74 #endif
75 		" -n, --noheader       do not repeat variable name in output\n"
76 		" -l, --lock           lock node, default:/var/lock\n"
77 		"\n");
78 }
79 
80 void usage_setenv(void)
81 {
82 	fprintf(stderr,
83 		"Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n"
84 		"Modify variables in U-Boot environment\n"
85 		"\n"
86 		" -h, --help           print this help.\n"
87 #ifdef CONFIG_ENV_AES
88 		" -a, --aes            aes key to access environment\n"
89 #endif
90 #ifdef CONFIG_FILE
91 		" -c, --config         configuration file, default:" CONFIG_FILE "\n"
92 #endif
93 		" -l, --lock           lock node, default:/var/lock\n"
94 		" -s, --script         batch mode to minimize writes\n"
95 		"\n"
96 		"Examples:\n"
97 		"  fw_setenv foo bar   set variable foo equal bar\n"
98 		"  fw_setenv foo       clear variable foo\n"
99 		"  fw_setenv --script file run batch script\n"
100 		"\n"
101 		"Script Syntax:\n"
102 		"  key [space] value\n"
103 		"  lines starting with '#' are treated as comment\n"
104 		"\n"
105 		"  A variable without value will be deleted. Any number of spaces are\n"
106 		"  allowed between key and value. Space inside of the value is treated\n"
107 		"  as part of the value itself.\n"
108 		"\n"
109 		"Script Example:\n"
110 		"  netdev         eth0\n"
111 		"  kernel_addr    400000\n"
112 		"  foo            empty empty empty    empty empty empty\n"
113 		"  bar\n"
114 		"\n");
115 }
116 
117 static void parse_common_args(int argc, char *argv[])
118 {
119 	int c;
120 
121 #ifdef CONFIG_FILE
122 	env_opts.config_file = CONFIG_FILE;
123 #endif
124 
125 	while ((c = getopt_long(argc, argv, ":a:c:l:h", long_options, NULL)) !=
126 	       EOF) {
127 		switch (c) {
128 		case 'a':
129 			if (parse_aes_key(optarg, env_opts.aes_key)) {
130 				fprintf(stderr, "AES key parse error\n");
131 				exit(EXIT_FAILURE);
132 			}
133 			env_opts.aes_flag = 1;
134 			break;
135 #ifdef CONFIG_FILE
136 		case 'c':
137 			env_opts.config_file = optarg;
138 			break;
139 #endif
140 		case 'l':
141 			env_opts.lockname = optarg;
142 			break;
143 		case 'h':
144 			do_printenv ? usage_printenv() : usage_setenv();
145 			exit(EXIT_SUCCESS);
146 			break;
147 		default:
148 			/* ignore unknown options */
149 			break;
150 		}
151 	}
152 
153 	/* Reset getopt for the next pass. */
154 	opterr = 1;
155 	optind = 1;
156 }
157 
158 int parse_printenv_args(int argc, char *argv[])
159 {
160 	int c;
161 
162 	parse_common_args(argc, argv);
163 
164 	while ((c = getopt_long(argc, argv, "a:c:ns:l:h", long_options, NULL))
165 		!= EOF) {
166 		switch (c) {
167 		case 'n':
168 			noheader = 1;
169 			break;
170 		case 'a':
171 		case 'c':
172 		case 'h':
173 		case 'l':
174 			/* ignore common options */
175 			break;
176 		default: /* '?' */
177 			usage_printenv();
178 			exit(EXIT_FAILURE);
179 			break;
180 		}
181 	}
182 	return 0;
183 }
184 
185 int parse_setenv_args(int argc, char *argv[])
186 {
187 	int c;
188 
189 	parse_common_args(argc, argv);
190 
191 	while ((c = getopt_long(argc, argv, "a:c:ns:l:h", long_options, NULL))
192 		!= EOF) {
193 		switch (c) {
194 		case 's':
195 			script_file = optarg;
196 			break;
197 		case 'a':
198 		case 'c':
199 		case 'h':
200 		case 'l':
201 			/* ignore common options */
202 			break;
203 		default: /* '?' */
204 			usage_setenv();
205 			exit(EXIT_FAILURE);
206 			break;
207 		}
208 	}
209 	return 0;
210 }
211 
212 int main(int argc, char *argv[])
213 {
214 	char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
215 	int lockfd = -1;
216 	int retval = EXIT_SUCCESS;
217 	char *_cmdname;
218 
219 	_cmdname = *argv;
220 	if (strrchr(_cmdname, '/') != NULL)
221 		_cmdname = strrchr(_cmdname, '/') + 1;
222 
223 	if (strcmp(_cmdname, CMD_PRINTENV) == 0) {
224 		do_printenv = 1;
225 	} else if (strcmp(_cmdname, CMD_SETENV) == 0) {
226 		do_printenv = 0;
227 	} else {
228 		fprintf(stderr,
229 			"Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n",
230 			CMD_PRINTENV, CMD_SETENV, _cmdname);
231 		exit(EXIT_FAILURE);
232 	}
233 
234 	if (do_printenv) {
235 		if (parse_printenv_args(argc, argv))
236 			exit(EXIT_FAILURE);
237 	} else {
238 		if (parse_setenv_args(argc, argv))
239 			exit(EXIT_FAILURE);
240 	}
241 
242 	/* shift parsed flags, jump to non-option arguments */
243 	argc -= optind;
244 	argv += optind;
245 
246 	if (env_opts.lockname) {
247 		lockname = malloc(sizeof(env_opts.lockname) +
248 				sizeof(CMD_PRINTENV) + 10);
249 		if (!lockname) {
250 			fprintf(stderr, "Unable allocate memory");
251 			exit(EXIT_FAILURE);
252 		}
253 
254 		sprintf(lockname, "%s/%s.lock",
255 			env_opts.lockname, CMD_PRINTENV);
256 	}
257 
258 	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
259 	if (-1 == lockfd) {
260 		fprintf(stderr, "Error opening lock file %s\n", lockname);
261 		return EXIT_FAILURE;
262 	}
263 
264 	if (-1 == flock(lockfd, LOCK_EX)) {
265 		fprintf(stderr, "Error locking file %s\n", lockname);
266 		close(lockfd);
267 		return EXIT_FAILURE;
268 	}
269 
270 	if (do_printenv) {
271 		if (fw_printenv(argc, argv, noheader, &env_opts) != 0)
272 			retval = EXIT_FAILURE;
273 	} else {
274 		if (!script_file) {
275 			if (fw_setenv(argc, argv, &env_opts) != 0)
276 				retval = EXIT_FAILURE;
277 		} else {
278 			if (fw_parse_script(script_file, &env_opts) != 0)
279 				retval = EXIT_FAILURE;
280 		}
281 	}
282 
283 	if (env_opts.lockname)
284 		free(lockname);
285 
286 	flock(lockfd, LOCK_UN);
287 	close(lockfd);
288 	return retval;
289 }
290