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'}, 49*d40dbfb7SB, Ravi {"lock", required_argument, NULL, 'l'}, 50bd7b26f8SStefano Babic {NULL, 0, NULL, 0} 51bd7b26f8SStefano Babic }; 52bd7b26f8SStefano Babic 5381974f44SAndreas Fenkart static struct env_opts env_opts; 5481974f44SAndreas Fenkart 5581974f44SAndreas Fenkart /* setenv options */ 5681974f44SAndreas Fenkart static int noheader; 5781974f44SAndreas Fenkart 5881974f44SAndreas Fenkart /* getenv options */ 5981974f44SAndreas Fenkart static char *script_file; 6081974f44SAndreas Fenkart 61b92ae3afSAndreas Fenkart void usage_printenv(void) 62bd7b26f8SStefano Babic { 63bd7b26f8SStefano Babic 64b92ae3afSAndreas Fenkart fprintf(stderr, 65b92ae3afSAndreas Fenkart "Usage: fw_printenv [OPTIONS]... [VARIABLE]...\n" 66b92ae3afSAndreas Fenkart "Print variables from U-Boot environment\n" 67b92ae3afSAndreas Fenkart "\n" 68b92ae3afSAndreas Fenkart " -h, --help print this help.\n" 69b92ae3afSAndreas Fenkart #ifdef CONFIG_ENV_AES 70b92ae3afSAndreas Fenkart " -a, --aes aes key to access environment\n" 719884f44cSMichael Heimpold #endif 72b92ae3afSAndreas Fenkart #ifdef CONFIG_FILE 73b92ae3afSAndreas Fenkart " -c, --config configuration file, default:" CONFIG_FILE "\n" 74b92ae3afSAndreas Fenkart #endif 75b92ae3afSAndreas Fenkart " -n, --noheader do not repeat variable name in output\n" 76*d40dbfb7SB, Ravi " -l, --lock lock node, default:/var/lock\n" 77b92ae3afSAndreas Fenkart "\n"); 78b92ae3afSAndreas Fenkart } 79b92ae3afSAndreas Fenkart 80b92ae3afSAndreas Fenkart void usage_setenv(void) 81b92ae3afSAndreas Fenkart { 82b92ae3afSAndreas Fenkart fprintf(stderr, 83b92ae3afSAndreas Fenkart "Usage: fw_setenv [OPTIONS]... [VARIABLE]...\n" 84b92ae3afSAndreas Fenkart "Modify variables in U-Boot environment\n" 85bd7b26f8SStefano Babic "\n" 86b92ae3afSAndreas Fenkart " -h, --help print this help.\n" 87b92ae3afSAndreas Fenkart #ifdef CONFIG_ENV_AES 88b92ae3afSAndreas Fenkart " -a, --aes aes key to access environment\n" 89b92ae3afSAndreas Fenkart #endif 90b92ae3afSAndreas Fenkart #ifdef CONFIG_FILE 91b92ae3afSAndreas Fenkart " -c, --config configuration file, default:" CONFIG_FILE "\n" 92b92ae3afSAndreas Fenkart #endif 93*d40dbfb7SB, Ravi " -l, --lock lock node, default:/var/lock\n" 94b92ae3afSAndreas Fenkart " -s, --script batch mode to minimize writes\n" 95bd7b26f8SStefano Babic "\n" 96b92ae3afSAndreas Fenkart "Examples:\n" 97b92ae3afSAndreas Fenkart " fw_setenv foo bar set variable foo equal bar\n" 98b92ae3afSAndreas Fenkart " fw_setenv foo clear variable foo\n" 99b92ae3afSAndreas Fenkart " fw_setenv --script file run batch script\n" 100b92ae3afSAndreas Fenkart "\n" 101b92ae3afSAndreas Fenkart "Script Syntax:\n" 102b92ae3afSAndreas Fenkart " key [space] value\n" 1030e280659SVagrant Cascadian " lines starting with '#' are treated as comment\n" 104b92ae3afSAndreas Fenkart "\n" 105b92ae3afSAndreas Fenkart " A variable without value will be deleted. Any number of spaces are\n" 106b92ae3afSAndreas Fenkart " allowed between key and value. Space inside of the value is treated\n" 107b92ae3afSAndreas Fenkart " as part of the value itself.\n" 108b92ae3afSAndreas Fenkart "\n" 109b92ae3afSAndreas Fenkart "Script Example:\n" 110b92ae3afSAndreas Fenkart " netdev eth0\n" 111b92ae3afSAndreas Fenkart " kernel_addr 400000\n" 112b92ae3afSAndreas Fenkart " foo empty empty empty empty empty empty\n" 113b92ae3afSAndreas Fenkart " bar\n" 114b92ae3afSAndreas Fenkart "\n"); 115bd7b26f8SStefano Babic } 116bd7b26f8SStefano Babic 117af93e3d8SAndreas Fenkart static void parse_common_args(int argc, char *argv[]) 1186aff3115Swdenk { 119bd7b26f8SStefano Babic int c; 1206aff3115Swdenk 121371ee137SAndreas Fenkart #ifdef CONFIG_FILE 12281974f44SAndreas Fenkart env_opts.config_file = CONFIG_FILE; 123371ee137SAndreas Fenkart #endif 124371ee137SAndreas Fenkart 125*d40dbfb7SB, Ravi while ((c = getopt_long(argc, argv, ":a:c:l:h", long_options, NULL)) != 126af93e3d8SAndreas Fenkart EOF) { 127bd7b26f8SStefano Babic switch (c) { 128a8a752c0SMarek Vasut case 'a': 12981974f44SAndreas Fenkart if (parse_aes_key(optarg, env_opts.aes_key)) { 130371ee137SAndreas Fenkart fprintf(stderr, "AES key parse error\n"); 131af93e3d8SAndreas Fenkart exit(EXIT_FAILURE); 132371ee137SAndreas Fenkart } 13381974f44SAndreas Fenkart env_opts.aes_flag = 1; 134a8a752c0SMarek Vasut break; 135371ee137SAndreas Fenkart #ifdef CONFIG_FILE 1369884f44cSMichael Heimpold case 'c': 13781974f44SAndreas Fenkart env_opts.config_file = optarg; 1389884f44cSMichael Heimpold break; 139371ee137SAndreas Fenkart #endif 140*d40dbfb7SB, Ravi case 'l': 141*d40dbfb7SB, Ravi env_opts.lockname = optarg; 142*d40dbfb7SB, Ravi break; 14307ce9440SAndreas Fenkart case 'h': 144b92ae3afSAndreas Fenkart do_printenv ? usage_printenv() : usage_setenv(); 14507ce9440SAndreas Fenkart exit(EXIT_SUCCESS); 14607ce9440SAndreas Fenkart break; 147af93e3d8SAndreas Fenkart default: 148af93e3d8SAndreas Fenkart /* ignore unknown options */ 149af93e3d8SAndreas Fenkart break; 150af93e3d8SAndreas Fenkart } 151af93e3d8SAndreas Fenkart } 152af93e3d8SAndreas Fenkart 153af93e3d8SAndreas Fenkart /* Reset getopt for the next pass. */ 154af93e3d8SAndreas Fenkart opterr = 1; 155af93e3d8SAndreas Fenkart optind = 1; 156af93e3d8SAndreas Fenkart } 157af93e3d8SAndreas Fenkart 158af93e3d8SAndreas Fenkart int parse_printenv_args(int argc, char *argv[]) 159af93e3d8SAndreas Fenkart { 160af93e3d8SAndreas Fenkart int c; 161af93e3d8SAndreas Fenkart 162af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 163af93e3d8SAndreas Fenkart 164*d40dbfb7SB, Ravi while ((c = getopt_long(argc, argv, "a:c:ns:l:h", long_options, NULL)) 165*d40dbfb7SB, Ravi != EOF) { 166af93e3d8SAndreas Fenkart switch (c) { 167af93e3d8SAndreas Fenkart case 'n': 16881974f44SAndreas Fenkart noheader = 1; 169af93e3d8SAndreas Fenkart break; 170af93e3d8SAndreas Fenkart case 'a': 171af93e3d8SAndreas Fenkart case 'c': 172af93e3d8SAndreas Fenkart case 'h': 173*d40dbfb7SB, Ravi case 'l': 174af93e3d8SAndreas Fenkart /* ignore common options */ 175af93e3d8SAndreas Fenkart break; 17607ce9440SAndreas Fenkart default: /* '?' */ 177b92ae3afSAndreas Fenkart usage_printenv(); 17807ce9440SAndreas Fenkart exit(EXIT_FAILURE); 17907ce9440SAndreas Fenkart break; 18007ce9440SAndreas Fenkart } 18107ce9440SAndreas Fenkart } 18207ce9440SAndreas Fenkart return 0; 18307ce9440SAndreas Fenkart } 18407ce9440SAndreas Fenkart 18507ce9440SAndreas Fenkart int parse_setenv_args(int argc, char *argv[]) 18607ce9440SAndreas Fenkart { 18707ce9440SAndreas Fenkart int c; 18807ce9440SAndreas Fenkart 189af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 190371ee137SAndreas Fenkart 191*d40dbfb7SB, Ravi while ((c = getopt_long(argc, argv, "a:c:ns:l:h", long_options, NULL)) 192*d40dbfb7SB, Ravi != EOF) { 19307ce9440SAndreas Fenkart switch (c) { 194bd7b26f8SStefano Babic case 's': 19581974f44SAndreas Fenkart script_file = optarg; 196bd7b26f8SStefano Babic break; 197af93e3d8SAndreas Fenkart case 'a': 198af93e3d8SAndreas Fenkart case 'c': 199bd7b26f8SStefano Babic case 'h': 200*d40dbfb7SB, Ravi case 'l': 201af93e3d8SAndreas Fenkart /* ignore common options */ 20207ce9440SAndreas Fenkart break; 20329ccd7c3SDaniel Hobi default: /* '?' */ 204b92ae3afSAndreas Fenkart usage_setenv(); 20507ce9440SAndreas Fenkart exit(EXIT_FAILURE); 20607ce9440SAndreas Fenkart break; 207bd7b26f8SStefano Babic } 208bd7b26f8SStefano Babic } 20907ce9440SAndreas Fenkart return 0; 21007ce9440SAndreas Fenkart } 21107ce9440SAndreas Fenkart 21207ce9440SAndreas Fenkart int main(int argc, char *argv[]) 21307ce9440SAndreas Fenkart { 214*d40dbfb7SB, Ravi char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; 21507ce9440SAndreas Fenkart int lockfd = -1; 21607ce9440SAndreas Fenkart int retval = EXIT_SUCCESS; 217b92ae3afSAndreas Fenkart char *_cmdname; 21807ce9440SAndreas Fenkart 219b92ae3afSAndreas Fenkart _cmdname = *argv; 220b92ae3afSAndreas Fenkart if (strrchr(_cmdname, '/') != NULL) 221b92ae3afSAndreas Fenkart _cmdname = strrchr(_cmdname, '/') + 1; 22207ce9440SAndreas Fenkart 223b92ae3afSAndreas Fenkart if (strcmp(_cmdname, CMD_PRINTENV) == 0) { 224b92ae3afSAndreas Fenkart do_printenv = 1; 225b92ae3afSAndreas Fenkart } else if (strcmp(_cmdname, CMD_SETENV) == 0) { 226b92ae3afSAndreas Fenkart do_printenv = 0; 22707ce9440SAndreas Fenkart } else { 22807ce9440SAndreas Fenkart fprintf(stderr, 22907ce9440SAndreas Fenkart "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n", 230b92ae3afSAndreas Fenkart CMD_PRINTENV, CMD_SETENV, _cmdname); 231b92ae3afSAndreas Fenkart exit(EXIT_FAILURE); 232b92ae3afSAndreas Fenkart } 233b92ae3afSAndreas Fenkart 234b92ae3afSAndreas Fenkart if (do_printenv) { 235b92ae3afSAndreas Fenkart if (parse_printenv_args(argc, argv)) 236b92ae3afSAndreas Fenkart exit(EXIT_FAILURE); 237b92ae3afSAndreas Fenkart } else { 238b92ae3afSAndreas Fenkart if (parse_setenv_args(argc, argv)) 23907ce9440SAndreas Fenkart exit(EXIT_FAILURE); 24007ce9440SAndreas Fenkart } 24107ce9440SAndreas Fenkart 2421ce68697SAndreas Fenkart /* shift parsed flags, jump to non-option arguments */ 2431ce68697SAndreas Fenkart argc -= optind; 2441ce68697SAndreas Fenkart argv += optind; 2451ce68697SAndreas Fenkart 246*d40dbfb7SB, Ravi if (env_opts.lockname) { 247*d40dbfb7SB, Ravi lockname = malloc(sizeof(env_opts.lockname) + 248*d40dbfb7SB, Ravi sizeof(CMD_PRINTENV) + 10); 249*d40dbfb7SB, Ravi if (!lockname) { 250*d40dbfb7SB, Ravi fprintf(stderr, "Unable allocate memory"); 251*d40dbfb7SB, Ravi exit(EXIT_FAILURE); 252*d40dbfb7SB, Ravi } 253*d40dbfb7SB, Ravi 254*d40dbfb7SB, Ravi sprintf(lockname, "%s/%s.lock", 255*d40dbfb7SB, Ravi env_opts.lockname, CMD_PRINTENV); 256*d40dbfb7SB, Ravi } 257*d40dbfb7SB, Ravi 25807ce9440SAndreas Fenkart lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 25907ce9440SAndreas Fenkart if (-1 == lockfd) { 26007ce9440SAndreas Fenkart fprintf(stderr, "Error opening lock file %s\n", lockname); 26107ce9440SAndreas Fenkart return EXIT_FAILURE; 26207ce9440SAndreas Fenkart } 26307ce9440SAndreas Fenkart 26407ce9440SAndreas Fenkart if (-1 == flock(lockfd, LOCK_EX)) { 26507ce9440SAndreas Fenkart fprintf(stderr, "Error locking file %s\n", lockname); 26607ce9440SAndreas Fenkart close(lockfd); 26707ce9440SAndreas Fenkart return EXIT_FAILURE; 26807ce9440SAndreas Fenkart } 269bd7b26f8SStefano Babic 270b92ae3afSAndreas Fenkart if (do_printenv) { 27181974f44SAndreas Fenkart if (fw_printenv(argc, argv, noheader, &env_opts) != 0) 272e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 273b92ae3afSAndreas Fenkart } else { 27481974f44SAndreas Fenkart if (!script_file) { 27581974f44SAndreas Fenkart if (fw_setenv(argc, argv, &env_opts) != 0) 276e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 277bd7b26f8SStefano Babic } else { 27881974f44SAndreas Fenkart if (fw_parse_script(script_file, &env_opts) != 0) 279e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 280bd7b26f8SStefano Babic } 281e4a223f0SJoe Hershberger } 282e4a223f0SJoe Hershberger 283*d40dbfb7SB, Ravi if (env_opts.lockname) 284*d40dbfb7SB, Ravi free(lockname); 285*d40dbfb7SB, Ravi 286e4a223f0SJoe Hershberger flock(lockfd, LOCK_UN); 287e4a223f0SJoe Hershberger close(lockfd); 288e4a223f0SJoe Hershberger return retval; 2896aff3115Swdenk } 290