1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * (C) Copyright 2000-2008 4 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 5 */ 6 7 /* 8 * Command line user interface to firmware (=U-Boot) environment. 9 * 10 * Implements: 11 * fw_printenv [ -a key ] [[ -n name ] | [ name ... ]] 12 * - prints the value of a single environment variable 13 * "name", the ``name=value'' pairs of one or more 14 * environment variables "name", or the whole 15 * environment if no names are specified. 16 * fw_setenv [ -a key ] name [ value ... ] 17 * - If a name without any values is given, the variable 18 * with this name is deleted from the environment; 19 * otherwise, all "value" arguments are concatenated, 20 * separated by single blank characters, and the 21 * resulting string is assigned to the environment 22 * variable "name" 23 * 24 * If '-a key' is specified, the env block is encrypted with AES 128 CBC. 25 * The 'key' argument is in the format of 32 hexadecimal numbers (16 bytes 26 * of AES key), eg. '-a aabbccddeeff00112233445566778899'. 27 */ 28 29 #include <fcntl.h> 30 #include <getopt.h> 31 #include <stdio.h> 32 #include <string.h> 33 #include <stdlib.h> 34 #include <sys/file.h> 35 #include <unistd.h> 36 #include <version.h> 37 #include "fw_env_private.h" 38 #include "fw_env.h" 39 40 #define CMD_PRINTENV "fw_printenv" 41 #define CMD_SETENV "fw_setenv" 42 static int do_printenv; 43 44 static struct option long_options[] = { 45 {"config", required_argument, NULL, 'c'}, 46 {"help", no_argument, NULL, 'h'}, 47 {"script", required_argument, NULL, 's'}, 48 {"noheader", no_argument, NULL, 'n'}, 49 {"lock", required_argument, NULL, 'l'}, 50 {"version", no_argument, NULL, 'v'}, 51 {NULL, 0, NULL, 0} 52 }; 53 54 static struct env_opts env_opts; 55 56 /* setenv options */ 57 static int noheader; 58 59 /* getenv options */ 60 static char *script_file; 61 62 void usage_printenv(void) 63 { 64 65 fprintf(stderr, 66 "Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n" 67 "Print variables from U-Boot environment\n" 68 "\n" 69 " -h, --help print this help.\n" 70 " -v, --version display version\n" 71 #ifdef CONFIG_FILE 72 " -c, --config configuration file, default:" CONFIG_FILE "\n" 73 #endif 74 " -n, --noheader do not repeat variable name in output\n" 75 " -l, --lock lock node, default:/var/lock\n" 76 "\n"); 77 } 78 79 void usage_env_set(void) 80 { 81 fprintf(stderr, 82 "Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n" 83 "Modify variables in U-Boot environment\n" 84 "\n" 85 " -h, --help print this help.\n" 86 " -v, --version display version\n" 87 #ifdef CONFIG_FILE 88 " -c, --config configuration file, default:" CONFIG_FILE "\n" 89 #endif 90 " -l, --lock lock node, default:/var/lock\n" 91 " -s, --script batch mode to minimize writes\n" 92 "\n" 93 "Examples:\n" 94 " fw_setenv foo bar set variable foo equal bar\n" 95 " fw_setenv foo clear variable foo\n" 96 " fw_setenv --script file run batch script\n" 97 "\n" 98 "Script Syntax:\n" 99 " key [space] value\n" 100 " lines starting with '#' are treated as comment\n" 101 "\n" 102 " A variable without value will be deleted. Any number of spaces are\n" 103 " allowed between key and value. Space inside of the value is treated\n" 104 " as part of the value itself.\n" 105 "\n" 106 "Script Example:\n" 107 " netdev eth0\n" 108 " kernel_addr 400000\n" 109 " foo empty empty empty empty empty empty\n" 110 " bar\n" 111 "\n"); 112 } 113 114 static void parse_common_args(int argc, char *argv[]) 115 { 116 int c; 117 118 #ifdef CONFIG_FILE 119 env_opts.config_file = CONFIG_FILE; 120 #endif 121 122 while ((c = getopt_long(argc, argv, ":a:c:l:h:v", long_options, NULL)) != 123 EOF) { 124 switch (c) { 125 #ifdef CONFIG_FILE 126 case 'c': 127 env_opts.config_file = optarg; 128 break; 129 #endif 130 case 'l': 131 env_opts.lockname = optarg; 132 break; 133 case 'h': 134 do_printenv ? usage_printenv() : usage_env_set(); 135 exit(EXIT_SUCCESS); 136 break; 137 case 'v': 138 fprintf(stderr, "Compiled with " U_BOOT_VERSION "\n"); 139 exit(EXIT_SUCCESS); 140 break; 141 default: 142 /* ignore unknown options */ 143 break; 144 } 145 } 146 147 /* Reset getopt for the next pass. */ 148 opterr = 1; 149 optind = 1; 150 } 151 152 int parse_printenv_args(int argc, char *argv[]) 153 { 154 int c; 155 156 parse_common_args(argc, argv); 157 158 while ((c = getopt_long(argc, argv, "a:c:ns:l:h:v", long_options, NULL)) 159 != EOF) { 160 switch (c) { 161 case 'n': 162 noheader = 1; 163 break; 164 case 'a': 165 case 'c': 166 case 'h': 167 case 'l': 168 /* ignore common options */ 169 break; 170 default: /* '?' */ 171 usage_printenv(); 172 exit(EXIT_FAILURE); 173 break; 174 } 175 } 176 return 0; 177 } 178 179 int parse_setenv_args(int argc, char *argv[]) 180 { 181 int c; 182 183 parse_common_args(argc, argv); 184 185 while ((c = getopt_long(argc, argv, "a:c:ns:l:h:v", long_options, NULL)) 186 != EOF) { 187 switch (c) { 188 case 's': 189 script_file = optarg; 190 break; 191 case 'a': 192 case 'c': 193 case 'h': 194 case 'l': 195 /* ignore common options */ 196 break; 197 default: /* '?' */ 198 usage_env_set(); 199 exit(EXIT_FAILURE); 200 break; 201 } 202 } 203 return 0; 204 } 205 206 int main(int argc, char *argv[]) 207 { 208 char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; 209 int lockfd = -1; 210 int retval = EXIT_SUCCESS; 211 char *_cmdname; 212 213 _cmdname = *argv; 214 if (strrchr(_cmdname, '/') != NULL) 215 _cmdname = strrchr(_cmdname, '/') + 1; 216 217 if (strcmp(_cmdname, CMD_PRINTENV) == 0) { 218 do_printenv = 1; 219 } else if (strcmp(_cmdname, CMD_SETENV) == 0) { 220 do_printenv = 0; 221 } else { 222 fprintf(stderr, 223 "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n", 224 CMD_PRINTENV, CMD_SETENV, _cmdname); 225 exit(EXIT_FAILURE); 226 } 227 228 if (do_printenv) { 229 if (parse_printenv_args(argc, argv)) 230 exit(EXIT_FAILURE); 231 } else { 232 if (parse_setenv_args(argc, argv)) 233 exit(EXIT_FAILURE); 234 } 235 236 /* shift parsed flags, jump to non-option arguments */ 237 argc -= optind; 238 argv += optind; 239 240 if (env_opts.lockname) { 241 lockname = malloc(strlen(env_opts.lockname) + 242 sizeof(CMD_PRINTENV) + 10); 243 if (!lockname) { 244 fprintf(stderr, "Unable allocate memory"); 245 exit(EXIT_FAILURE); 246 } 247 248 sprintf(lockname, "%s/%s.lock", 249 env_opts.lockname, CMD_PRINTENV); 250 } 251 252 lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 253 if (-1 == lockfd) { 254 fprintf(stderr, "Error opening lock file %s\n", lockname); 255 return EXIT_FAILURE; 256 } 257 258 if (-1 == flock(lockfd, LOCK_EX)) { 259 fprintf(stderr, "Error locking file %s\n", lockname); 260 close(lockfd); 261 return EXIT_FAILURE; 262 } 263 264 if (do_printenv) { 265 if (fw_printenv(argc, argv, noheader, &env_opts) != 0) 266 retval = EXIT_FAILURE; 267 } else { 268 if (!script_file) { 269 if (fw_env_set(argc, argv, &env_opts) != 0) 270 retval = EXIT_FAILURE; 271 } else { 272 if (fw_parse_script(script_file, &env_opts) != 0) 273 retval = EXIT_FAILURE; 274 } 275 } 276 277 if (env_opts.lockname) 278 free(lockname); 279 280 flock(lockfd, LOCK_UN); 281 close(lockfd); 282 return retval; 283 } 284