xref: /rk3399_rockchip-uboot/tools/env/fw_env_main.c (revision af93e3d8ababbca05f94ed3ad89e3e277b31ffd5)
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 static void parse_common_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:h", long_options, NULL)) !=
93 	       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 				exit(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 'h':
108 			usage();
109 			exit(EXIT_SUCCESS);
110 			break;
111 		default:
112 			/* ignore unknown options */
113 			break;
114 		}
115 	}
116 
117 	/* Reset getopt for the next pass. */
118 	opterr = 1;
119 	optind = 1;
120 }
121 
122 int parse_printenv_args(int argc, char *argv[])
123 {
124 	int c;
125 
126 	parse_common_args(argc, argv);
127 
128 	while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) !=
129 	       EOF) {
130 		switch (c) {
131 		case 'n':
132 			printenv_args.name_suppress = 1;
133 			break;
134 		case 'a':
135 		case 'c':
136 		case 'h':
137 			/* ignore common options */
138 			break;
139 		default: /* '?' */
140 			usage();
141 			exit(EXIT_FAILURE);
142 			break;
143 		}
144 	}
145 	return 0;
146 }
147 
148 int parse_setenv_args(int argc, char *argv[])
149 {
150 	int c;
151 
152 	parse_common_args(argc, argv);
153 
154 	while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) !=
155 	       EOF) {
156 		switch (c) {
157 		case 's':
158 			setenv_args.script_file = optarg;
159 			break;
160 		case 'a':
161 		case 'c':
162 		case 'h':
163 			/* ignore common options */
164 			break;
165 		default: /* '?' */
166 			usage();
167 			exit(EXIT_FAILURE);
168 			break;
169 		}
170 	}
171 	return 0;
172 }
173 
174 int main(int argc, char *argv[])
175 {
176 	char *cmdname = *argv;
177 	const char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
178 	int lockfd = -1;
179 	int retval = EXIT_SUCCESS;
180 
181 	if (strrchr(cmdname, '/') != NULL)
182 		cmdname = strrchr(cmdname, '/') + 1;
183 
184 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
185 		if (parse_printenv_args(argc, argv))
186 			exit(EXIT_FAILURE);
187 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
188 		if (parse_setenv_args(argc, argv))
189 			exit(EXIT_FAILURE);
190 	} else {
191 		fprintf(stderr,
192 			"Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n",
193 			CMD_PRINTENV, CMD_SETENV, cmdname);
194 		exit(EXIT_FAILURE);
195 	}
196 
197 	/* shift parsed flags, jump to non-option arguments */
198 	argc -= optind;
199 	argv += optind;
200 
201 	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
202 	if (-1 == lockfd) {
203 		fprintf(stderr, "Error opening lock file %s\n", lockname);
204 		return EXIT_FAILURE;
205 	}
206 
207 	if (-1 == flock(lockfd, LOCK_EX)) {
208 		fprintf(stderr, "Error locking file %s\n", lockname);
209 		close(lockfd);
210 		return EXIT_FAILURE;
211 	}
212 
213 	if (strcmp(cmdname, CMD_PRINTENV) == 0) {
214 		if (fw_printenv(argc, argv) != 0)
215 			retval = EXIT_FAILURE;
216 	} else if (strcmp(cmdname, CMD_SETENV) == 0) {
217 		if (!setenv_args.script_file) {
218 			if (fw_setenv(argc, argv) != 0)
219 				retval = EXIT_FAILURE;
220 		} else {
221 			if (fw_parse_script(setenv_args.script_file) != 0)
222 				retval = EXIT_FAILURE;
223 		}
224 	}
225 
226 	flock(lockfd, LOCK_UN);
227 	close(lockfd);
228 	return retval;
229 }
230