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