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