16aff3115Swdenk /* 2bc11756dSGrant Erickson * (C) Copyright 2000-2008 36aff3115Swdenk * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 46aff3115Swdenk * 51a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 66aff3115Swdenk */ 76aff3115Swdenk 86aff3115Swdenk /* 93bac3513Swdenk * Command line user interface to firmware (=U-Boot) environment. 106aff3115Swdenk * 116aff3115Swdenk * Implements: 12a8a752c0SMarek Vasut * fw_printenv [ -a key ] [[ -n name ] | [ name ... ]] 13bc11756dSGrant Erickson * - prints the value of a single environment variable 14bc11756dSGrant Erickson * "name", the ``name=value'' pairs of one or more 15bc11756dSGrant Erickson * environment variables "name", or the whole 16bc11756dSGrant Erickson * environment if no names are specified. 17a8a752c0SMarek Vasut * fw_setenv [ -a key ] name [ value ... ] 186aff3115Swdenk * - If a name without any values is given, the variable 196aff3115Swdenk * with this name is deleted from the environment; 206aff3115Swdenk * otherwise, all "value" arguments are concatenated, 21bc11756dSGrant Erickson * separated by single blank characters, and the 226aff3115Swdenk * resulting string is assigned to the environment 236aff3115Swdenk * variable "name" 24a8a752c0SMarek Vasut * 25a8a752c0SMarek Vasut * If '-a key' is specified, the env block is encrypted with AES 128 CBC. 26a8a752c0SMarek Vasut * The 'key' argument is in the format of 32 hexadecimal numbers (16 bytes 27a8a752c0SMarek Vasut * of AES key), eg. '-a aabbccddeeff00112233445566778899'. 286aff3115Swdenk */ 296aff3115Swdenk 30e4a223f0SJoe Hershberger #include <fcntl.h> 31e4a223f0SJoe Hershberger #include <getopt.h> 326aff3115Swdenk #include <stdio.h> 336aff3115Swdenk #include <string.h> 346aff3115Swdenk #include <stdlib.h> 35e4a223f0SJoe Hershberger #include <sys/file.h> 36e4a223f0SJoe Hershberger #include <unistd.h> 376aff3115Swdenk #include "fw_env.h" 386aff3115Swdenk 396aff3115Swdenk #define CMD_PRINTENV "fw_printenv" 406aff3115Swdenk #define CMD_SETENV "fw_setenv" 41b92ae3afSAndreas Fenkart static int do_printenv; 426aff3115Swdenk 43bd7b26f8SStefano Babic static struct option long_options[] = { 44b92ae3afSAndreas Fenkart {"aes", required_argument, NULL, 'a'}, 45b92ae3afSAndreas Fenkart {"config", required_argument, NULL, 'c'}, 46bd7b26f8SStefano Babic {"help", no_argument, NULL, 'h'}, 47b92ae3afSAndreas Fenkart {"script", required_argument, NULL, 's'}, 48b92ae3afSAndreas Fenkart {"noheader", required_argument, NULL, 'n'}, 49bd7b26f8SStefano Babic {NULL, 0, NULL, 0} 50bd7b26f8SStefano Babic }; 51bd7b26f8SStefano Babic 52371ee137SAndreas Fenkart struct common_args common_args; 5307ce9440SAndreas Fenkart struct printenv_args printenv_args; 5407ce9440SAndreas Fenkart struct setenv_args setenv_args; 5507ce9440SAndreas Fenkart 56b92ae3afSAndreas Fenkart void usage_printenv(void) 57bd7b26f8SStefano Babic { 58bd7b26f8SStefano Babic 59b92ae3afSAndreas Fenkart fprintf(stderr, 60b92ae3afSAndreas Fenkart "Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n" 61b92ae3afSAndreas Fenkart "Print variables from U-Boot environment\n" 62b92ae3afSAndreas Fenkart "\n" 63b92ae3afSAndreas Fenkart " -h, --help print this help.\n" 64b92ae3afSAndreas Fenkart #ifdef CONFIG_ENV_AES 65b92ae3afSAndreas Fenkart " -a, --aes aes key to access environment\n" 669884f44cSMichael Heimpold #endif 67b92ae3afSAndreas Fenkart #ifdef CONFIG_FILE 68b92ae3afSAndreas Fenkart " -c, --config configuration file, default:" CONFIG_FILE "\n" 69b92ae3afSAndreas Fenkart #endif 70b92ae3afSAndreas Fenkart " -n, --noheader do not repeat variable name in output\n" 71b92ae3afSAndreas Fenkart "\n"); 72b92ae3afSAndreas Fenkart } 73b92ae3afSAndreas Fenkart 74b92ae3afSAndreas Fenkart void usage_setenv(void) 75b92ae3afSAndreas Fenkart { 76b92ae3afSAndreas Fenkart fprintf(stderr, 77b92ae3afSAndreas Fenkart "Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n" 78b92ae3afSAndreas Fenkart "Modify variables in U-Boot environment\n" 79bd7b26f8SStefano Babic "\n" 80b92ae3afSAndreas Fenkart " -h, --help print this help.\n" 81b92ae3afSAndreas Fenkart #ifdef CONFIG_ENV_AES 82b92ae3afSAndreas Fenkart " -a, --aes aes key to access environment\n" 83b92ae3afSAndreas Fenkart #endif 84b92ae3afSAndreas Fenkart #ifdef CONFIG_FILE 85b92ae3afSAndreas Fenkart " -c, --config configuration file, default:" CONFIG_FILE "\n" 86b92ae3afSAndreas Fenkart #endif 87b92ae3afSAndreas Fenkart " -s, --script batch mode to minimize writes\n" 88bd7b26f8SStefano Babic "\n" 89b92ae3afSAndreas Fenkart "Examples:\n" 90b92ae3afSAndreas Fenkart " fw_setenv foo bar set variable foo equal bar\n" 91b92ae3afSAndreas Fenkart " fw_setenv foo clear variable foo\n" 92b92ae3afSAndreas Fenkart " fw_setenv --script file run batch script\n" 93b92ae3afSAndreas Fenkart "\n" 94b92ae3afSAndreas Fenkart "Script Syntax:\n" 95b92ae3afSAndreas Fenkart " key [space] value\n" 96*0e280659SVagrant Cascadian " lines starting with '#' are treated as comment\n" 97b92ae3afSAndreas Fenkart "\n" 98b92ae3afSAndreas Fenkart " A variable without value will be deleted. Any number of spaces are\n" 99b92ae3afSAndreas Fenkart " allowed between key and value. Space inside of the value is treated\n" 100b92ae3afSAndreas Fenkart " as part of the value itself.\n" 101b92ae3afSAndreas Fenkart "\n" 102b92ae3afSAndreas Fenkart "Script Example:\n" 103b92ae3afSAndreas Fenkart " netdev eth0\n" 104b92ae3afSAndreas Fenkart " kernel_addr 400000\n" 105b92ae3afSAndreas Fenkart " foo empty empty empty empty empty empty\n" 106b92ae3afSAndreas Fenkart " bar\n" 107b92ae3afSAndreas Fenkart "\n"); 108bd7b26f8SStefano Babic } 109bd7b26f8SStefano Babic 110af93e3d8SAndreas Fenkart static void parse_common_args(int argc, char *argv[]) 1116aff3115Swdenk { 112bd7b26f8SStefano Babic int c; 1136aff3115Swdenk 114371ee137SAndreas Fenkart #ifdef CONFIG_FILE 115371ee137SAndreas Fenkart common_args.config_file = CONFIG_FILE; 116371ee137SAndreas Fenkart #endif 117371ee137SAndreas Fenkart 118af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, ":a:c:h", long_options, NULL)) != 119af93e3d8SAndreas Fenkart EOF) { 120bd7b26f8SStefano Babic switch (c) { 121a8a752c0SMarek Vasut case 'a': 122371ee137SAndreas Fenkart if (parse_aes_key(optarg, common_args.aes_key)) { 123371ee137SAndreas Fenkart fprintf(stderr, "AES key parse error\n"); 124af93e3d8SAndreas Fenkart exit(EXIT_FAILURE); 125371ee137SAndreas Fenkart } 126371ee137SAndreas Fenkart common_args.aes_flag = 1; 127a8a752c0SMarek Vasut break; 128371ee137SAndreas Fenkart #ifdef CONFIG_FILE 1299884f44cSMichael Heimpold case 'c': 130371ee137SAndreas Fenkart common_args.config_file = optarg; 1319884f44cSMichael Heimpold break; 132371ee137SAndreas Fenkart #endif 13307ce9440SAndreas Fenkart case 'h': 134b92ae3afSAndreas Fenkart do_printenv ? usage_printenv() : usage_setenv(); 13507ce9440SAndreas Fenkart exit(EXIT_SUCCESS); 13607ce9440SAndreas Fenkart break; 137af93e3d8SAndreas Fenkart default: 138af93e3d8SAndreas Fenkart /* ignore unknown options */ 139af93e3d8SAndreas Fenkart break; 140af93e3d8SAndreas Fenkart } 141af93e3d8SAndreas Fenkart } 142af93e3d8SAndreas Fenkart 143af93e3d8SAndreas Fenkart /* Reset getopt for the next pass. */ 144af93e3d8SAndreas Fenkart opterr = 1; 145af93e3d8SAndreas Fenkart optind = 1; 146af93e3d8SAndreas Fenkart } 147af93e3d8SAndreas Fenkart 148af93e3d8SAndreas Fenkart int parse_printenv_args(int argc, char *argv[]) 149af93e3d8SAndreas Fenkart { 150af93e3d8SAndreas Fenkart int c; 151af93e3d8SAndreas Fenkart 152af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 153af93e3d8SAndreas Fenkart 154af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != 155af93e3d8SAndreas Fenkart EOF) { 156af93e3d8SAndreas Fenkart switch (c) { 157af93e3d8SAndreas Fenkart case 'n': 158af93e3d8SAndreas Fenkart printenv_args.name_suppress = 1; 159af93e3d8SAndreas Fenkart break; 160af93e3d8SAndreas Fenkart case 'a': 161af93e3d8SAndreas Fenkart case 'c': 162af93e3d8SAndreas Fenkart case 'h': 163af93e3d8SAndreas Fenkart /* ignore common options */ 164af93e3d8SAndreas Fenkart break; 16507ce9440SAndreas Fenkart default: /* '?' */ 166b92ae3afSAndreas Fenkart usage_printenv(); 16707ce9440SAndreas Fenkart exit(EXIT_FAILURE); 16807ce9440SAndreas Fenkart break; 16907ce9440SAndreas Fenkart } 17007ce9440SAndreas Fenkart } 17107ce9440SAndreas Fenkart return 0; 17207ce9440SAndreas Fenkart } 17307ce9440SAndreas Fenkart 17407ce9440SAndreas Fenkart int parse_setenv_args(int argc, char *argv[]) 17507ce9440SAndreas Fenkart { 17607ce9440SAndreas Fenkart int c; 17707ce9440SAndreas Fenkart 178af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 179371ee137SAndreas Fenkart 180af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != 181af93e3d8SAndreas Fenkart EOF) { 18207ce9440SAndreas Fenkart switch (c) { 183bd7b26f8SStefano Babic case 's': 18407ce9440SAndreas Fenkart setenv_args.script_file = optarg; 185bd7b26f8SStefano Babic break; 186af93e3d8SAndreas Fenkart case 'a': 187af93e3d8SAndreas Fenkart case 'c': 188bd7b26f8SStefano Babic case 'h': 189af93e3d8SAndreas Fenkart /* ignore common options */ 19007ce9440SAndreas Fenkart break; 19129ccd7c3SDaniel Hobi default: /* '?' */ 192b92ae3afSAndreas Fenkart usage_setenv(); 19307ce9440SAndreas Fenkart exit(EXIT_FAILURE); 19407ce9440SAndreas Fenkart break; 195bd7b26f8SStefano Babic } 196bd7b26f8SStefano Babic } 19707ce9440SAndreas Fenkart return 0; 19807ce9440SAndreas Fenkart } 19907ce9440SAndreas Fenkart 20007ce9440SAndreas Fenkart int main(int argc, char *argv[]) 20107ce9440SAndreas Fenkart { 20207ce9440SAndreas Fenkart const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; 20307ce9440SAndreas Fenkart int lockfd = -1; 20407ce9440SAndreas Fenkart int retval = EXIT_SUCCESS; 205b92ae3afSAndreas Fenkart char *_cmdname; 20607ce9440SAndreas Fenkart 207b92ae3afSAndreas Fenkart _cmdname = *argv; 208b92ae3afSAndreas Fenkart if (strrchr(_cmdname, '/') != NULL) 209b92ae3afSAndreas Fenkart _cmdname = strrchr(_cmdname, '/') + 1; 21007ce9440SAndreas Fenkart 211b92ae3afSAndreas Fenkart if (strcmp(_cmdname, CMD_PRINTENV) == 0) { 212b92ae3afSAndreas Fenkart do_printenv = 1; 213b92ae3afSAndreas Fenkart } else if (strcmp(_cmdname, CMD_SETENV) == 0) { 214b92ae3afSAndreas Fenkart do_printenv = 0; 21507ce9440SAndreas Fenkart } else { 21607ce9440SAndreas Fenkart fprintf(stderr, 21707ce9440SAndreas Fenkart "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n", 218b92ae3afSAndreas Fenkart CMD_PRINTENV, CMD_SETENV, _cmdname); 219b92ae3afSAndreas Fenkart exit(EXIT_FAILURE); 220b92ae3afSAndreas Fenkart } 221b92ae3afSAndreas Fenkart 222b92ae3afSAndreas Fenkart if (do_printenv) { 223b92ae3afSAndreas Fenkart if (parse_printenv_args(argc, argv)) 224b92ae3afSAndreas Fenkart exit(EXIT_FAILURE); 225b92ae3afSAndreas Fenkart } else { 226b92ae3afSAndreas Fenkart if (parse_setenv_args(argc, argv)) 22707ce9440SAndreas Fenkart exit(EXIT_FAILURE); 22807ce9440SAndreas Fenkart } 22907ce9440SAndreas Fenkart 2301ce68697SAndreas Fenkart /* shift parsed flags, jump to non-option arguments */ 2311ce68697SAndreas Fenkart argc -= optind; 2321ce68697SAndreas Fenkart argv += optind; 2331ce68697SAndreas Fenkart 23407ce9440SAndreas Fenkart lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 23507ce9440SAndreas Fenkart if (-1 == lockfd) { 23607ce9440SAndreas Fenkart fprintf(stderr, "Error opening lock file %s\n", lockname); 23707ce9440SAndreas Fenkart return EXIT_FAILURE; 23807ce9440SAndreas Fenkart } 23907ce9440SAndreas Fenkart 24007ce9440SAndreas Fenkart if (-1 == flock(lockfd, LOCK_EX)) { 24107ce9440SAndreas Fenkart fprintf(stderr, "Error locking file %s\n", lockname); 24207ce9440SAndreas Fenkart close(lockfd); 24307ce9440SAndreas Fenkart return EXIT_FAILURE; 24407ce9440SAndreas Fenkart } 245bd7b26f8SStefano Babic 246b92ae3afSAndreas Fenkart if (do_printenv) { 247bc11756dSGrant Erickson if (fw_printenv(argc, argv) != 0) 248e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 249b92ae3afSAndreas Fenkart } else { 25007ce9440SAndreas Fenkart if (!setenv_args.script_file) { 2516aff3115Swdenk if (fw_setenv(argc, argv) != 0) 252e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 253bd7b26f8SStefano Babic } else { 25407ce9440SAndreas Fenkart if (fw_parse_script(setenv_args.script_file) != 0) 255e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 256bd7b26f8SStefano Babic } 257e4a223f0SJoe Hershberger } 258e4a223f0SJoe Hershberger 259e4a223f0SJoe Hershberger flock(lockfd, LOCK_UN); 260e4a223f0SJoe Hershberger close(lockfd); 261e4a223f0SJoe Hershberger return retval; 2626aff3115Swdenk } 263