xref: /openbmc/u-boot/tools/env/fw_env_main.c (revision c6b89f31806df06a5d7b688a65f9d2e6e6119a55)
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 <version.h>
38  #include "fw_env_private.h"
39  #include "fw_env.h"
40  
41  #define CMD_PRINTENV	"fw_printenv"
42  #define CMD_SETENV	"fw_setenv"
43  static int do_printenv;
44  
45  static struct option long_options[] = {
46  	{"config", required_argument, NULL, 'c'},
47  	{"help", no_argument, NULL, 'h'},
48  	{"script", required_argument, NULL, 's'},
49  	{"noheader", no_argument, NULL, 'n'},
50  	{"lock", required_argument, NULL, 'l'},
51  	{"version", no_argument, NULL, 'v'},
52  	{NULL, 0, NULL, 0}
53  };
54  
55  static struct env_opts env_opts;
56  
57  /* setenv options */
58  static int noheader;
59  
60  /* getenv options */
61  static char *script_file;
62  
63  void usage_printenv(void)
64  {
65  
66  	fprintf(stderr,
67  		"Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n"
68  		"Print variables from U-Boot environment\n"
69  		"\n"
70  		" -h, --help           print this help.\n"
71  		" -v, --version        display version\n"
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_env_set(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  		" -v, --version        display version\n"
88  #ifdef CONFIG_FILE
89  		" -c, --config         configuration file, default:" CONFIG_FILE "\n"
90  #endif
91  		" -l, --lock           lock node, default:/var/lock\n"
92  		" -s, --script         batch mode to minimize writes\n"
93  		"\n"
94  		"Examples:\n"
95  		"  fw_setenv foo bar   set variable foo equal bar\n"
96  		"  fw_setenv foo       clear variable foo\n"
97  		"  fw_setenv --script file run batch script\n"
98  		"\n"
99  		"Script Syntax:\n"
100  		"  key [space] value\n"
101  		"  lines starting with '#' are treated as comment\n"
102  		"\n"
103  		"  A variable without value will be deleted. Any number of spaces are\n"
104  		"  allowed between key and value. Space inside of the value is treated\n"
105  		"  as part of the value itself.\n"
106  		"\n"
107  		"Script Example:\n"
108  		"  netdev         eth0\n"
109  		"  kernel_addr    400000\n"
110  		"  foo            empty empty empty    empty empty empty\n"
111  		"  bar\n"
112  		"\n");
113  }
114  
115  static void parse_common_args(int argc, char *argv[])
116  {
117  	int c;
118  
119  #ifdef CONFIG_FILE
120  	env_opts.config_file = CONFIG_FILE;
121  #endif
122  
123  	while ((c = getopt_long(argc, argv, ":a:c:l:h:v", long_options, NULL)) !=
124  	       EOF) {
125  		switch (c) {
126  #ifdef CONFIG_FILE
127  		case 'c':
128  			env_opts.config_file = optarg;
129  			break;
130  #endif
131  		case 'l':
132  			env_opts.lockname = optarg;
133  			break;
134  		case 'h':
135  			do_printenv ? usage_printenv() : usage_env_set();
136  			exit(EXIT_SUCCESS);
137  			break;
138  		case 'v':
139  			fprintf(stderr, "Compiled with " U_BOOT_VERSION "\n");
140  			exit(EXIT_SUCCESS);
141  			break;
142  		default:
143  			/* ignore unknown options */
144  			break;
145  		}
146  	}
147  
148  	/* Reset getopt for the next pass. */
149  	opterr = 1;
150  	optind = 1;
151  }
152  
153  int parse_printenv_args(int argc, char *argv[])
154  {
155  	int c;
156  
157  	parse_common_args(argc, argv);
158  
159  	while ((c = getopt_long(argc, argv, "a:c:ns:l:h:v", long_options, NULL))
160  		!= EOF) {
161  		switch (c) {
162  		case 'n':
163  			noheader = 1;
164  			break;
165  		case 'a':
166  		case 'c':
167  		case 'h':
168  		case 'l':
169  			/* ignore common options */
170  			break;
171  		default: /* '?' */
172  			usage_printenv();
173  			exit(EXIT_FAILURE);
174  			break;
175  		}
176  	}
177  	return 0;
178  }
179  
180  int parse_setenv_args(int argc, char *argv[])
181  {
182  	int c;
183  
184  	parse_common_args(argc, argv);
185  
186  	while ((c = getopt_long(argc, argv, "a:c:ns:l:h:v", long_options, NULL))
187  		!= EOF) {
188  		switch (c) {
189  		case 's':
190  			script_file = optarg;
191  			break;
192  		case 'a':
193  		case 'c':
194  		case 'h':
195  		case 'l':
196  			/* ignore common options */
197  			break;
198  		default: /* '?' */
199  			usage_env_set();
200  			exit(EXIT_FAILURE);
201  			break;
202  		}
203  	}
204  	return 0;
205  }
206  
207  int main(int argc, char *argv[])
208  {
209  	char *lockname = "/var/lock/" CMD_PRINTENV ".lock";
210  	int lockfd = -1;
211  	int retval = EXIT_SUCCESS;
212  	char *_cmdname;
213  
214  	_cmdname = *argv;
215  	if (strrchr(_cmdname, '/') != NULL)
216  		_cmdname = strrchr(_cmdname, '/') + 1;
217  
218  	if (strcmp(_cmdname, CMD_PRINTENV) == 0) {
219  		do_printenv = 1;
220  	} else if (strcmp(_cmdname, CMD_SETENV) == 0) {
221  		do_printenv = 0;
222  	} else {
223  		fprintf(stderr,
224  			"Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n",
225  			CMD_PRINTENV, CMD_SETENV, _cmdname);
226  		exit(EXIT_FAILURE);
227  	}
228  
229  	if (do_printenv) {
230  		if (parse_printenv_args(argc, argv))
231  			exit(EXIT_FAILURE);
232  	} else {
233  		if (parse_setenv_args(argc, argv))
234  			exit(EXIT_FAILURE);
235  	}
236  
237  	/* shift parsed flags, jump to non-option arguments */
238  	argc -= optind;
239  	argv += optind;
240  
241  	if (env_opts.lockname) {
242  		lockname = malloc(sizeof(env_opts.lockname) +
243  				sizeof(CMD_PRINTENV) + 10);
244  		if (!lockname) {
245  			fprintf(stderr, "Unable allocate memory");
246  			exit(EXIT_FAILURE);
247  		}
248  
249  		sprintf(lockname, "%s/%s.lock",
250  			env_opts.lockname, CMD_PRINTENV);
251  	}
252  
253  	lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666);
254  	if (-1 == lockfd) {
255  		fprintf(stderr, "Error opening lock file %s\n", lockname);
256  		return EXIT_FAILURE;
257  	}
258  
259  	if (-1 == flock(lockfd, LOCK_EX)) {
260  		fprintf(stderr, "Error locking file %s\n", lockname);
261  		close(lockfd);
262  		return EXIT_FAILURE;
263  	}
264  
265  	if (do_printenv) {
266  		if (fw_printenv(argc, argv, noheader, &env_opts) != 0)
267  			retval = EXIT_FAILURE;
268  	} else {
269  		if (!script_file) {
270  			if (fw_env_set(argc, argv, &env_opts) != 0)
271  				retval = EXIT_FAILURE;
272  		} else {
273  			if (fw_parse_script(script_file, &env_opts) != 0)
274  				retval = EXIT_FAILURE;
275  		}
276  	}
277  
278  	if (env_opts.lockname)
279  		free(lockname);
280  
281  	flock(lockfd, LOCK_UN);
282  	close(lockfd);
283  	return retval;
284  }
285