39c8771e4d4f32e64496c6e11494ec3fc9509884
[oweals/u-boot.git] / tools / env / fw_env_main.c
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 }