blob: 39c8771e4d4f32e64496c6e11494ec3fc9509884 [file] [log] [blame]
wdenk34b613e2002-12-17 01:51:00 +00001/*
Grant Erickson73a4e5e2008-05-06 20:16:15 -07002 * (C) Copyright 2000-2008
wdenk34b613e2002-12-17 01:51:00 +00003 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4 *
Wolfgang Denkbd8ec7e2013-10-07 13:07:26 +02005 * SPDX-License-Identifier: GPL-2.0+
wdenk34b613e2002-12-17 01:51:00 +00006 */
7
8/*
wdenkef5fe752003-03-12 10:41:04 +00009 * Command line user interface to firmware (=U-Boot) environment.
wdenk34b613e2002-12-17 01:51:00 +000010 *
11 * Implements:
Marek Vasut05ed2a52014-03-05 19:59:52 +010012 * fw_printenv [ -a key ] [[ -n name ] | [ name ... ]]
Grant Erickson73a4e5e2008-05-06 20:16:15 -070013 * - 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.
Marek Vasut05ed2a52014-03-05 19:59:52 +010017 * fw_setenv [ -a key ] name [ value ... ]
wdenk34b613e2002-12-17 01:51:00 +000018 * - 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,
Grant Erickson73a4e5e2008-05-06 20:16:15 -070021 * separated by single blank characters, and the
wdenk34b613e2002-12-17 01:51:00 +000022 * resulting string is assigned to the environment
23 * variable "name"
Marek Vasut05ed2a52014-03-05 19:59:52 +010024 *
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'.
wdenk34b613e2002-12-17 01:51:00 +000028 */
29
Joe Hershberger3f1f1752012-10-03 09:38:49 +000030#include <fcntl.h>
31#include <getopt.h>
wdenk34b613e2002-12-17 01:51:00 +000032#include <stdio.h>
33#include <string.h>
34#include <stdlib.h>
Joe Hershberger3f1f1752012-10-03 09:38:49 +000035#include <sys/file.h>
36#include <unistd.h>
wdenk34b613e2002-12-17 01:51:00 +000037#include "fw_env.h"
38
39#define CMD_PRINTENV "fw_printenv"
40#define CMD_SETENV "fw_setenv"
41
Stefano Babicada628b2010-05-24 12:08:16 +020042static struct option long_options[] = {
43 {"script", required_argument, NULL, 's'},
44 {"help", no_argument, NULL, 'h'},
45 {NULL, 0, NULL, 0}
46};
47
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +010048struct common_args common_args;
Andreas Fenkart33e91772015-12-09 13:13:23 +010049struct printenv_args printenv_args;
50struct setenv_args setenv_args;
51
Stefano Babicada628b2010-05-24 12:08:16 +020052void usage(void)
53{
54
55 fprintf(stderr, "fw_printenv/fw_setenv, "
56 "a command line interface to U-Boot environment\n\n"
Michael Heimpold211e17b2015-10-27 22:34:49 +010057#ifndef CONFIG_FILE
Marek Vasut05ed2a52014-03-05 19:59:52 +010058 "usage:\tfw_printenv [-a key] [-n] [variable name]\n"
59 "\tfw_setenv [-a key] [variable name] [variable value]\n"
Michael Heimpold211e17b2015-10-27 22:34:49 +010060#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
Stefano Babicada628b2010-05-24 12:08:16 +020064 "\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
Andreas Fenkart6726fc42015-12-09 13:13:26 +010084static void parse_common_args(int argc, char *argv[])
wdenk34b613e2002-12-17 01:51:00 +000085{
Stefano Babicada628b2010-05-24 12:08:16 +020086 int c;
wdenk34b613e2002-12-17 01:51:00 +000087
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +010088#ifdef CONFIG_FILE
89 common_args.config_file = CONFIG_FILE;
90#endif
91
Andreas Fenkart6726fc42015-12-09 13:13:26 +010092 while ((c = getopt_long(argc, argv, ":a:c:h", long_options, NULL)) !=
93 EOF) {
Stefano Babicada628b2010-05-24 12:08:16 +020094 switch (c) {
Marek Vasut05ed2a52014-03-05 19:59:52 +010095 case 'a':
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +010096 if (parse_aes_key(optarg, common_args.aes_key)) {
97 fprintf(stderr, "AES key parse error\n");
Andreas Fenkart6726fc42015-12-09 13:13:26 +010098 exit(EXIT_FAILURE);
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +010099 }
100 common_args.aes_flag = 1;
Marek Vasut05ed2a52014-03-05 19:59:52 +0100101 break;
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +0100102#ifdef CONFIG_FILE
Michael Heimpold211e17b2015-10-27 22:34:49 +0100103 case 'c':
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +0100104 common_args.config_file = optarg;
Michael Heimpold211e17b2015-10-27 22:34:49 +0100105 break;
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +0100106#endif
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100107 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
122int 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) {
Daniel Hobi6c554262010-09-15 19:46:26 +0200131 case 'n':
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +0100132 printenv_args.name_suppress = 1;
Daniel Hobi6c554262010-09-15 19:46:26 +0200133 break;
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100134 case 'a':
135 case 'c':
Andreas Fenkart33e91772015-12-09 13:13:23 +0100136 case 'h':
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100137 /* ignore common options */
Andreas Fenkart33e91772015-12-09 13:13:23 +0100138 break;
139 default: /* '?' */
140 usage();
141 exit(EXIT_FAILURE);
142 break;
143 }
144 }
145 return 0;
146}
147
148int parse_setenv_args(int argc, char *argv[])
149{
150 int c;
151
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100152 parse_common_args(argc, argv);
Andreas Fenkartaa01f8d2015-12-09 13:13:24 +0100153
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100154 while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) !=
155 EOF) {
Andreas Fenkart33e91772015-12-09 13:13:23 +0100156 switch (c) {
Stefano Babicada628b2010-05-24 12:08:16 +0200157 case 's':
Andreas Fenkart33e91772015-12-09 13:13:23 +0100158 setenv_args.script_file = optarg;
Stefano Babicada628b2010-05-24 12:08:16 +0200159 break;
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100160 case 'a':
161 case 'c':
Stefano Babicada628b2010-05-24 12:08:16 +0200162 case 'h':
Andreas Fenkart6726fc42015-12-09 13:13:26 +0100163 /* ignore common options */
Andreas Fenkart33e91772015-12-09 13:13:23 +0100164 break;
Daniel Hobi6a20a322010-09-16 14:36:09 +0200165 default: /* '?' */
Andreas Fenkart33e91772015-12-09 13:13:23 +0100166 usage();
167 exit(EXIT_FAILURE);
168 break;
Stefano Babicada628b2010-05-24 12:08:16 +0200169 }
170 }
Andreas Fenkart33e91772015-12-09 13:13:23 +0100171 return 0;
172}
173
174int 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;
Stefano Babicada628b2010-05-24 12:08:16 +0200183
wdenk34b613e2002-12-17 01:51:00 +0000184 if (strcmp(cmdname, CMD_PRINTENV) == 0) {
Andreas Fenkart33e91772015-12-09 13:13:23 +0100185 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
Andreas Fenkart14908ef2015-12-09 13:13:25 +0100197 /* shift parsed flags, jump to non-option arguments */
198 argc -= optind;
199 argv += optind;
200
Andreas Fenkart33e91772015-12-09 13:13:23 +0100201 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) {
Joe Hershberger3f1f1752012-10-03 09:38:49 +0000214 if (fw_printenv(argc, argv) != 0)
215 retval = EXIT_FAILURE;
wdenk34b613e2002-12-17 01:51:00 +0000216 } else if (strcmp(cmdname, CMD_SETENV) == 0) {
Andreas Fenkart33e91772015-12-09 13:13:23 +0100217 if (!setenv_args.script_file) {
Stefano Babicada628b2010-05-24 12:08:16 +0200218 if (fw_setenv(argc, argv) != 0)
Joe Hershberger3f1f1752012-10-03 09:38:49 +0000219 retval = EXIT_FAILURE;
Stefano Babicada628b2010-05-24 12:08:16 +0200220 } else {
Andreas Fenkart33e91772015-12-09 13:13:23 +0100221 if (fw_parse_script(setenv_args.script_file) != 0)
Joe Hershberger3f1f1752012-10-03 09:38:49 +0000222 retval = EXIT_FAILURE;
Stefano Babicada628b2010-05-24 12:08:16 +0200223 }
wdenk34b613e2002-12-17 01:51:00 +0000224 }
225
Joe Hershberger3f1f1752012-10-03 09:38:49 +0000226 flock(lockfd, LOCK_UN);
227 close(lockfd);
228 return retval;
wdenk34b613e2002-12-17 01:51:00 +0000229}