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" 416aff3115Swdenk 42bd7b26f8SStefano Babic static struct option long_options[] = { 43bd7b26f8SStefano Babic {"script", required_argument, NULL, 's'}, 44bd7b26f8SStefano Babic {"help", no_argument, NULL, 'h'}, 45bd7b26f8SStefano Babic {NULL, 0, NULL, 0} 46bd7b26f8SStefano Babic }; 47bd7b26f8SStefano Babic 48371ee137SAndreas Fenkart struct common_args common_args; 4907ce9440SAndreas Fenkart struct printenv_args printenv_args; 5007ce9440SAndreas Fenkart struct setenv_args setenv_args; 5107ce9440SAndreas Fenkart 52bd7b26f8SStefano Babic void usage(void) 53bd7b26f8SStefano Babic { 54bd7b26f8SStefano Babic 55bd7b26f8SStefano Babic fprintf(stderr, "fw_printenv/fw_setenv, " 56bd7b26f8SStefano Babic "a command line interface to U-Boot environment\n\n" 579884f44cSMichael Heimpold #ifndef CONFIG_FILE 58a8a752c0SMarek Vasut "usage:\tfw_printenv [-a key] [-n] [variable name]\n" 59a8a752c0SMarek Vasut "\tfw_setenv [-a key] [variable name] [variable value]\n" 609884f44cSMichael Heimpold #else 619884f44cSMichael Heimpold "usage:\tfw_printenv [-c /my/fw_env.config] [-a key] [-n] [variable name]\n" 629884f44cSMichael Heimpold "\tfw_setenv [-c /my/fw_env.config] [-a key] [variable name] [variable value]\n" 639884f44cSMichael Heimpold #endif 64bd7b26f8SStefano Babic "\tfw_setenv -s [ file ]\n" 65bd7b26f8SStefano Babic "\tfw_setenv -s - < [ file ]\n\n" 66bd7b26f8SStefano Babic "The file passed as argument contains only pairs " 67bd7b26f8SStefano Babic "name / value\n" 68bd7b26f8SStefano Babic "Example:\n" 69bd7b26f8SStefano Babic "# Any line starting with # is treated as comment\n" 70bd7b26f8SStefano Babic "\n" 71bd7b26f8SStefano Babic "\t netdev eth0\n" 72bd7b26f8SStefano Babic "\t kernel_addr 400000\n" 73bd7b26f8SStefano Babic "\t var1\n" 74bd7b26f8SStefano Babic "\t var2 The quick brown fox jumps over the " 75bd7b26f8SStefano Babic "lazy dog\n" 76bd7b26f8SStefano Babic "\n" 77bd7b26f8SStefano Babic "A variable without value will be dropped. It is possible\n" 78bd7b26f8SStefano Babic "to put any number of spaces between the fields, but any\n" 79bd7b26f8SStefano Babic "space inside the value is treated as part of the value " 80bd7b26f8SStefano Babic "itself.\n\n" 81bd7b26f8SStefano Babic ); 82bd7b26f8SStefano Babic } 83bd7b26f8SStefano Babic 84*af93e3d8SAndreas Fenkart static void parse_common_args(int argc, char *argv[]) 856aff3115Swdenk { 86bd7b26f8SStefano Babic int c; 876aff3115Swdenk 88371ee137SAndreas Fenkart #ifdef CONFIG_FILE 89371ee137SAndreas Fenkart common_args.config_file = CONFIG_FILE; 90371ee137SAndreas Fenkart #endif 91371ee137SAndreas Fenkart 92*af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, ":a:c:h", long_options, NULL)) != 93*af93e3d8SAndreas Fenkart EOF) { 94bd7b26f8SStefano Babic switch (c) { 95a8a752c0SMarek Vasut case 'a': 96371ee137SAndreas Fenkart if (parse_aes_key(optarg, common_args.aes_key)) { 97371ee137SAndreas Fenkart fprintf(stderr, "AES key parse error\n"); 98*af93e3d8SAndreas Fenkart exit(EXIT_FAILURE); 99371ee137SAndreas Fenkart } 100371ee137SAndreas Fenkart common_args.aes_flag = 1; 101a8a752c0SMarek Vasut break; 102371ee137SAndreas Fenkart #ifdef CONFIG_FILE 1039884f44cSMichael Heimpold case 'c': 104371ee137SAndreas Fenkart common_args.config_file = optarg; 1059884f44cSMichael Heimpold break; 106371ee137SAndreas Fenkart #endif 10707ce9440SAndreas Fenkart case 'h': 10807ce9440SAndreas Fenkart usage(); 10907ce9440SAndreas Fenkart exit(EXIT_SUCCESS); 11007ce9440SAndreas Fenkart break; 111*af93e3d8SAndreas Fenkart default: 112*af93e3d8SAndreas Fenkart /* ignore unknown options */ 113*af93e3d8SAndreas Fenkart break; 114*af93e3d8SAndreas Fenkart } 115*af93e3d8SAndreas Fenkart } 116*af93e3d8SAndreas Fenkart 117*af93e3d8SAndreas Fenkart /* Reset getopt for the next pass. */ 118*af93e3d8SAndreas Fenkart opterr = 1; 119*af93e3d8SAndreas Fenkart optind = 1; 120*af93e3d8SAndreas Fenkart } 121*af93e3d8SAndreas Fenkart 122*af93e3d8SAndreas Fenkart int parse_printenv_args(int argc, char *argv[]) 123*af93e3d8SAndreas Fenkart { 124*af93e3d8SAndreas Fenkart int c; 125*af93e3d8SAndreas Fenkart 126*af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 127*af93e3d8SAndreas Fenkart 128*af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != 129*af93e3d8SAndreas Fenkart EOF) { 130*af93e3d8SAndreas Fenkart switch (c) { 131*af93e3d8SAndreas Fenkart case 'n': 132*af93e3d8SAndreas Fenkart printenv_args.name_suppress = 1; 133*af93e3d8SAndreas Fenkart break; 134*af93e3d8SAndreas Fenkart case 'a': 135*af93e3d8SAndreas Fenkart case 'c': 136*af93e3d8SAndreas Fenkart case 'h': 137*af93e3d8SAndreas Fenkart /* ignore common options */ 138*af93e3d8SAndreas Fenkart break; 13907ce9440SAndreas Fenkart default: /* '?' */ 14007ce9440SAndreas Fenkart usage(); 14107ce9440SAndreas Fenkart exit(EXIT_FAILURE); 14207ce9440SAndreas Fenkart break; 14307ce9440SAndreas Fenkart } 14407ce9440SAndreas Fenkart } 14507ce9440SAndreas Fenkart return 0; 14607ce9440SAndreas Fenkart } 14707ce9440SAndreas Fenkart 14807ce9440SAndreas Fenkart int parse_setenv_args(int argc, char *argv[]) 14907ce9440SAndreas Fenkart { 15007ce9440SAndreas Fenkart int c; 15107ce9440SAndreas Fenkart 152*af93e3d8SAndreas Fenkart parse_common_args(argc, argv); 153371ee137SAndreas Fenkart 154*af93e3d8SAndreas Fenkart while ((c = getopt_long(argc, argv, "a:c:ns:h", long_options, NULL)) != 155*af93e3d8SAndreas Fenkart EOF) { 15607ce9440SAndreas Fenkart switch (c) { 157bd7b26f8SStefano Babic case 's': 15807ce9440SAndreas Fenkart setenv_args.script_file = optarg; 159bd7b26f8SStefano Babic break; 160*af93e3d8SAndreas Fenkart case 'a': 161*af93e3d8SAndreas Fenkart case 'c': 162bd7b26f8SStefano Babic case 'h': 163*af93e3d8SAndreas Fenkart /* ignore common options */ 16407ce9440SAndreas Fenkart break; 16529ccd7c3SDaniel Hobi default: /* '?' */ 16607ce9440SAndreas Fenkart usage(); 16707ce9440SAndreas Fenkart exit(EXIT_FAILURE); 16807ce9440SAndreas Fenkart break; 169bd7b26f8SStefano Babic } 170bd7b26f8SStefano Babic } 17107ce9440SAndreas Fenkart return 0; 17207ce9440SAndreas Fenkart } 17307ce9440SAndreas Fenkart 17407ce9440SAndreas Fenkart int main(int argc, char *argv[]) 17507ce9440SAndreas Fenkart { 17607ce9440SAndreas Fenkart char *cmdname = *argv; 17707ce9440SAndreas Fenkart const char *lockname = "/var/lock/" CMD_PRINTENV ".lock"; 17807ce9440SAndreas Fenkart int lockfd = -1; 17907ce9440SAndreas Fenkart int retval = EXIT_SUCCESS; 18007ce9440SAndreas Fenkart 18107ce9440SAndreas Fenkart if (strrchr(cmdname, '/') != NULL) 18207ce9440SAndreas Fenkart cmdname = strrchr(cmdname, '/') + 1; 18307ce9440SAndreas Fenkart 18407ce9440SAndreas Fenkart if (strcmp(cmdname, CMD_PRINTENV) == 0) { 18507ce9440SAndreas Fenkart if (parse_printenv_args(argc, argv)) 18607ce9440SAndreas Fenkart exit(EXIT_FAILURE); 18707ce9440SAndreas Fenkart } else if (strcmp(cmdname, CMD_SETENV) == 0) { 18807ce9440SAndreas Fenkart if (parse_setenv_args(argc, argv)) 18907ce9440SAndreas Fenkart exit(EXIT_FAILURE); 19007ce9440SAndreas Fenkart } else { 19107ce9440SAndreas Fenkart fprintf(stderr, 19207ce9440SAndreas Fenkart "Identity crisis - may be called as `%s' or as `%s' but not as `%s'\n", 19307ce9440SAndreas Fenkart CMD_PRINTENV, CMD_SETENV, cmdname); 19407ce9440SAndreas Fenkart exit(EXIT_FAILURE); 19507ce9440SAndreas Fenkart } 19607ce9440SAndreas Fenkart 1971ce68697SAndreas Fenkart /* shift parsed flags, jump to non-option arguments */ 1981ce68697SAndreas Fenkart argc -= optind; 1991ce68697SAndreas Fenkart argv += optind; 2001ce68697SAndreas Fenkart 20107ce9440SAndreas Fenkart lockfd = open(lockname, O_WRONLY | O_CREAT | O_TRUNC, 0666); 20207ce9440SAndreas Fenkart if (-1 == lockfd) { 20307ce9440SAndreas Fenkart fprintf(stderr, "Error opening lock file %s\n", lockname); 20407ce9440SAndreas Fenkart return EXIT_FAILURE; 20507ce9440SAndreas Fenkart } 20607ce9440SAndreas Fenkart 20707ce9440SAndreas Fenkart if (-1 == flock(lockfd, LOCK_EX)) { 20807ce9440SAndreas Fenkart fprintf(stderr, "Error locking file %s\n", lockname); 20907ce9440SAndreas Fenkart close(lockfd); 21007ce9440SAndreas Fenkart return EXIT_FAILURE; 21107ce9440SAndreas Fenkart } 212bd7b26f8SStefano Babic 2136aff3115Swdenk if (strcmp(cmdname, CMD_PRINTENV) == 0) { 214bc11756dSGrant Erickson if (fw_printenv(argc, argv) != 0) 215e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 2166aff3115Swdenk } else if (strcmp(cmdname, CMD_SETENV) == 0) { 21707ce9440SAndreas Fenkart if (!setenv_args.script_file) { 2186aff3115Swdenk if (fw_setenv(argc, argv) != 0) 219e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 220bd7b26f8SStefano Babic } else { 22107ce9440SAndreas Fenkart if (fw_parse_script(setenv_args.script_file) != 0) 222e4a223f0SJoe Hershberger retval = EXIT_FAILURE; 223bd7b26f8SStefano Babic } 224e4a223f0SJoe Hershberger } 225e4a223f0SJoe Hershberger 226e4a223f0SJoe Hershberger flock(lockfd, LOCK_UN); 227e4a223f0SJoe Hershberger close(lockfd); 228e4a223f0SJoe Hershberger return retval; 2296aff3115Swdenk } 230