xref: /rk3399_rockchip-uboot/tools/env/fw_env_main.c (revision 1ce686978c03d4fd025c7e93b7a18d4a87f547ec)
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 
42 static struct option long_options[] = {
43 	{"script", required_argument, NULL, 's'},
44 	{"help", no_argument, NULL, 'h'},
45 	{NULL, 0, NULL, 0}
46 };
47 
48 struct common_args common_args;
49 struct printenv_args printenv_args;
50 struct setenv_args setenv_args;
51 
52 void usage(void)
53 {
54 
55 	fprintf(stderr, "fw_printenv/fw_setenv, "
56 		"a command line interface to U-Boot environment\n\n"
57 #ifndef CONFIG_FILE
58 		"usage:\tfw_printenv [-a key] [-n] [variable name]\n"
59 		"\tfw_setenv [-a key] [variable name] [variable value]\n"
60 #else
61 		"usage:\tfw_printenv [-c /my/fw_env.config] [-a key] [-n] [variable name]\n"
62 		"\tfw_setenv [-c /my/fw_env.config] [-a key] [variable name] [variable value]\n"
63 #endif
64 		"\tfw_setenv -s [ file ]\n"
65 		"\tfw_setenv -s - < [ file ]\n\n"
66 		"The file passed as argument contains only pairs "
67 		"name / value\n"
68 		"Example:\n"
69 		"# Any line starting with # is treated as comment\n"
70 		"\n"
71 		"\t      netdev         eth0\n"
72 		"\t      kernel_addr    400000\n"
73 		"\t      var1\n"
74 		"\t      var2          The quick brown fox jumps over the "
75 		"lazy dog\n"
76 		"\n"
77 		"A variable without value will be dropped. It is possible\n"
78 		"to put any number of spaces between the fields, but any\n"
79 		"space inside the value is treated as part of the value "
80 		"itself.\n\n"
81 	);
82 }
83 
84 int parse_printenv_args(int argc, char *argv[])
85 {
86 	int c;
87 
88 #ifdef CONFIG_FILE
89 	common_args.config_file = CONFIG_FILE;
90 #endif
91 
92 	while ((c = getopt_long (argc, argv, "a:c:ns:h",
93 		long_options, NULL)) != EOF) {
94 		switch (c) {
95 		case 'a':
96 			if (parse_aes_key(optarg, common_args.aes_key)) {
97 				fprintf(stderr, "AES key parse error\n");
98 				return EXIT_FAILURE;
99 			}
100 			common_args.aes_flag = 1;
101 			break;
102 #ifdef CONFIG_FILE
103 		case 'c':
104 			common_args.config_file = optarg;
105 			break;
106 #endif
107 		case 'n':
108 			printenv_args.name_suppress = 1;
109 			break;
110 		case 'h':
111 			usage();
112 			exit(EXIT_SUCCESS);
113 			break;
114 		default: /* '?' */
115 			usage();
116 			exit(EXIT_FAILURE);
117 			break;
118 		}
119 	}
120 	return 0;
121 }
122 
123 int parse_setenv_args(int argc, char *argv[])
124 {
125 	int c;
126 
127 #ifdef CONFIG_FILE
128 	common_args.config_file = CONFIG_FILE;
129 #endif
130 
131 	while ((c = getopt_long (argc, argv, "a:c:ns:h",
132 		long_options, NULL)) != EOF) {
133 		switch (c) {
134 		case 'a':
135 			if (parse_aes_key(optarg, common_args.aes_key)) {
136 				fprintf(stderr, "AES key parse error\n");
137 				return EXIT_FAILURE;
138 			}
139 			common_args.aes_flag = 1;
140 			break;
141 #ifdef CONFIG_FILE
142 		case 'c':
143 			common_args.config_file = optarg;
144 			break;
145 #endif
146 		case 's':
147 			setenv_args.script_file = optarg;
148 			break;
149 		case 'h':
150 			usage();
151 			exit(EXIT_SUCCESS);
152 			break;
153 		default: /* '?' */
154 			usage();
155 			exit(EXIT_FAILURE);
156 			break;
157 		}
158 	}
159 	return 0;
160 }
161 
162 int main(int argc, char *argv[])
163 {
164 	char *cmdname = *argv;
165 	const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
166 	int lockfd = -1;
167 	int retval = EXIT_SUCCESS;
168 
169 	if (strrchr(cmdname, '/') != NULL)
170 		cmdname = strrchr(cmdname, '/') + 1;
171 
172 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
173 		if (parse_printenv_args(argc, argv))
174 			exit(EXIT_FAILURE);
175 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
176 		if (parse_setenv_args(argc, argv))
177 			exit(EXIT_FAILURE);
178 	} else {
179 		fprintf(stderr,
180 			"Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n",
181 			CMD_PRINTENV, CMD_SETENV, cmdname);
182 		exit(EXIT_FAILURE);
183 	}
184 
185 	/* shift parsed flags, jump to non-option arguments */
186 	argc -= optind;
187 	argv += optind;
188 
189 	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
190 	if (-1 == lockfd) {
191 		fprintf(stderr, "Error opening lock file %s\n", lockname);
192 		return EXIT_FAILURE;
193 	}
194 
195 	if (-1 == flock(lockfd, LOCK_EX)) {
196 		fprintf(stderr, "Error locking file %s\n", lockname);
197 		close(lockfd);
198 		return EXIT_FAILURE;
199 	}
200 
201 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
202 		if (fw_printenv(argc, argv) != 0)
203 			retval = EXIT_FAILURE;
204 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
205 		if (!setenv_args.script_file) {
206 			if (fw_setenv(argc, argv) != 0)
207 				retval = EXIT_FAILURE;
208 		} else {
209 			if (fw_parse_script(setenv_args.script_file) != 0)
210 				retval = EXIT_FAILURE;
211 		}
212 	}
213 
214 	flock(lockfd, LOCK_UN);
215 	close(lockfd);
216 	return retval;
217 }
218