/**************************************************************************** * apps/system/cfgdata/cfgdata_main.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include /**************************************************************************** * Private data ****************************************************************************/ static const char *g_config_dev = "/dev/config"; /**************************************************************************** * Private Functions ****************************************************************************/ /**************************************************************************** * Print usage information ****************************************************************************/ static void cfgdatacmd_help(void) { printf("\nUsage: cfgdata [arguments]\n"); printf("Where is one of:\n\n"); printf(" all: show all config entries\n"); printf(" print: display a specific config entry\n"); printf(" set: set or change a config entry\n"); printf(" unset: delete a config entry\n"); printf(" format: delete all config entries\n\n"); printf("Syntax for 'set' cmd:\n"); #ifdef CONFIG_MTD_CONFIG_NAMED printf(" set name [hex_byte,hex_byte,etc.]\n"); printf(" set name \"string\"\n\n"); #else printf(" set id,instance [bytes]\n"); printf(" set id,instance \"string\"\n\n"); #endif printf("Syntax for 'print' cmd:\n"); #ifdef CONFIG_MTD_CONFIG_NAMED printf(" print name\n"); #else printf(" print id,instance\n"); #endif printf("Syntax for 'unset' cmd:\n"); #ifdef CONFIG_MTD_CONFIG_NAMED printf(" unset name\n"); #else printf(" unset id,instance\n"); #endif } /**************************************************************************** * Parse out the id,inst,name tokens ****************************************************************************/ #ifndef CONFIG_MTD_CONFIG_NAMED static int cfgdatacmd_idtok(int startpos, char *token) { while (token[startpos] != ',' && token[startpos] != '\0') { startpos++; } if (token[startpos] != ',') { /* Error in format */ printf("Expected config identifier in 'id,instance' format\n"); return 0; } /* return, skipping the ',' */ return startpos + 1; } #endif /**************************************************************************** * Set a config item value * * config set 1,0,wr_width_cs0 [0x3] * config set 1,1,wr_width_cs1 [0x2] * ****************************************************************************/ static void cfgdatacmd_parse_byte_array(struct config_data_s *cfg, int argc, char *argv[]) { int x; int c; int count; int val; /* Start with arg3 */ x = 3; c = 1; count = 0; /* Loop for all remaining arguments until ']' found */ while (x < argc && argv[x][c] != ']' && argv[x][c] != '\0') { /* Count this item */ count++; /* Skip to next item */ while (argv[x][c] != ',' && argv[x][c] != ']' && argv[x][c] != 0) { c++; } /* Test for comma separator */ if (argv[x][c] == ',') { c++; } /* Test for space separated items */ if (argv[x][c] == 0) { x++; c = 0; } } /* Test if static stack space allocation is big enough for data */ if (count > cfg->len) { /* Perform dynamic memory allocation */ cfg->configdata = (FAR uint8_t *)malloc(count); cfg->len = count; } /* Count determined. Start with arg3 again and parse the bytes */ x = 3; c = 1; count = 0; /* Loop for all remaining arguments until ']' found */ while (x < argc && argv[x][c] != ']' && argv[x][c] != '\0') { /* Parse this item */ if (strncmp(&argv[x][c], "0x", 2) == 0) { /* Hex byte */ sscanf(&argv[x][c + 2], "%x", &val); cfg->configdata[count] = (uint8_t)val; } else { /* Decimal value */ cfg->configdata[count] = (uint8_t)atoi(&argv[x][c]); } /* Increment the count */ count++; /* Skip to next item */ while (argv[x][c] != ',' && argv[x][c] != ']' && argv[x][c] != 0) { c++; } /* Test for comma separator */ if (argv[x][c] == ',') { c++; } /* Test for space separated items */ if (argv[x][c] == 0) { x++; c = 0; } } cfg->len = count; } /**************************************************************************** * Set a config item value * * config set 1,0,wr_width_cs0 [0x3] * config set 1,1,wr_width_cs1 [0x2] * ****************************************************************************/ static void cfgdatacmd_set(int argc, char *argv[]) { int ret; int fd; int x; struct config_data_s cfg; uint8_t data[32]; #ifdef CONFIG_MTD_CONFIG_NAMED /* Copy the name to the cfg struct */ strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); #else /* Parse the id and instance */ cfg.id = atoi(argv[2]); /* Advance past ',' to instance number */ x = cfgdatacmd_idtok(0, argv[2]); if (x == 0) { return; } /* Convert instance to integer */ cfg.instance = atoi(&argv[2][x]); #endif /* Test if data is an array of bytes or simple string */ if (argv[3][0] == '[') { /* It is an array of bytes. Count the number of bytes */ cfg.configdata = data; cfg.len = sizeof(data); cfgdatacmd_parse_byte_array(&cfg, argc, argv); } else { bool isnumber = true; /* It is a simple string. Test if it looks like a number */ cfg.configdata = data; if (strncmp(argv[3], "0x", 2) == 0) { /* Test for all hex digit values */ for (x = 2; x < strlen(argv[3]); x++) { if (!isxdigit(argv[3][x])) { isnumber = false; break; } } if (isnumber) { sscanf(&argv[3][2], "%" SCNx32, (int32_t *)&cfg.configdata); cfg.len = 4; } } else { /* Test for all hex digit values */ for (x = 0; x < strlen(argv[3]); x++) { if (!isdigit(argv[3][x])) { isnumber = false; break; } } if (isnumber) { int32_t temp = atoi(argv[3]); *((int32_t *)cfg.configdata) = temp; cfg.len = 4; } } if (!isnumber) { /* Point to the string and calculate the length */ cfg.configdata = (FAR uint8_t *)argv[3]; cfg.len = strlen(argv[3]) + 1; } } /* Now open the /dev/config file and set the config item */ if ((fd = open(g_config_dev, 0)) < 2) { /* Display error */ printf("error: unable to open %s\n", g_config_dev); return; } ret = ioctl(fd, CFGDIOC_SETCONFIG, (unsigned long)(uintptr_t)&cfg); /* Close the file and report error if any */ close(fd); if (ret != OK) { printf("Error %d setting config entry\n", errno); } /* Free the cfg.configdata if needed */ if (cfg.configdata != (FAR uint8_t *)argv[3] && cfg.configdata != data) { free(cfg.configdata); } } /**************************************************************************** * Unset a config item value ****************************************************************************/ static void cfgdatacmd_unset(int argc, char *argv[]) { int ret; int fd; struct config_data_s cfg; #ifdef CONFIG_MTD_CONFIG_NAMED /* Copy the name to the cfg struct */ strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); #else int x; /* Parse the id and instance */ cfg.id = atoi(argv[2]); /* Advance past ',' to instance number */ x = cfgdatacmd_idtok(0, argv[2]); if (x == 0) { return; } /* Convert instance to integer */ cfg.instance = atoi(&argv[2][x]); #endif cfg.configdata = NULL; cfg.len = 0; /* Try to open the /dev/config file */ if ((fd = open(g_config_dev, 0)) < 2) { /* Display error */ printf("error: unable to open %s\n", g_config_dev); return; } /* Delete the config item */ ret = ioctl(fd, CFGDIOC_DELCONFIG, (unsigned long)(uintptr_t)&cfg); close(fd); if (ret != OK) { printf("Error deletign config entry '%s'\n", argv[2]); } } /**************************************************************************** * Print a config item value * * config print 1,1 * config print wr_width_cs0 * ****************************************************************************/ static void cfgdatacmd_print(int argc, char *argv[]) { int ret; int fd; int x; struct config_data_s cfg; bool isstring; #ifdef CONFIG_MTD_CONFIG_NAMED /* Copy the name to the cfg struct */ strlcpy(cfg.name, argv[2], CONFIG_MTD_CONFIG_NAME_LEN); #else /* Parse the id and instance */ cfg.id = atoi(argv[2]); /* Advance past ',' to instance number */ x = cfgdatacmd_idtok(0, argv[2]); if (x == 0) { return; } /* Convert instance to integer */ cfg.instance = atoi(&argv[2][x]); #endif /* Try to open the /dev/config file */ if ((fd = open(g_config_dev, O_RDONLY)) < 2) { /* Display error */ printf("error: unable to open %s\n", g_config_dev); return; } cfg.configdata = (FAR uint8_t *)malloc(256); cfg.len = 256; if (cfg.configdata == NULL) { printf("Error allocating buffer\n"); return; } /* Get the config item */ ret = ioctl(fd, CFGDIOC_GETCONFIG, (unsigned long)(uintptr_t)&cfg); close(fd); if (ret != OK) { printf("Error reading config entry '%s'\n", argv[2]); free(cfg.configdata); return; } /* Display the data */ isstring = cfg.configdata[cfg.len - 1] == 0; for (x = 0; x < cfg.len - 1; x++) { /* Test for all ascii characters */ if (cfg.configdata[x] < ' ' || cfg.configdata[x] > '~') { isstring = false; break; } } /* Display the data */ if (isstring) { printf("%s\n", cfg.configdata); } else { /* Loop though all bytes and display them */ for (x = 0; x < cfg.len; x++) { /* Print the next byte */ printf("0x%02X ", cfg.configdata[x]); if (((x + 1) & 7) == 0 && x + 1 != cfg.len) { printf("\n"); } } printf("\n"); } free(cfg.configdata); } /**************************************************************************** * Enumerate and display all config items ****************************************************************************/ static void cfgdatacmd_show_all_config_items(void) { int ret; int fd; int x; struct config_data_s cfg; char fmtstr[24]; bool isstring; /* Try to open the /dev/config file */ if ((fd = open(g_config_dev, 0)) < 2) { /* Display error */ printf("error: unable to open %s\n", g_config_dev); return; } /* Print header */ #ifdef CONFIG_MTD_CONFIG_NAMED snprintf(fmtstr, sizeof(fmtstr), "%%-%ds%%-6sData\n", CONFIG_MTD_CONFIG_NAME_LEN); printf(fmtstr, "Name", "Len"); snprintf(fmtstr, sizeof(fmtstr), "%%-%ds%%-6d", CONFIG_MTD_CONFIG_NAME_LEN); #else strlcpy(fmtstr, "%-6s%-6s%-6sData\n", sizeof(fmtstr)); printf(fmtstr, "ID", "Inst", "Len"); strlcpy(fmtstr, "%-6d%-6d%-6d", sizeof(fmtstr)); #endif /* Get the first config item */ cfg.configdata = (FAR uint8_t *)malloc(256); cfg.len = 256; if (cfg.configdata == NULL) { printf("Error allocating buffer\n"); return; } ret = ioctl(fd, CFGDIOC_FIRSTCONFIG, (unsigned long)(uintptr_t)&cfg); while (ret != -1) { /* Print this entry */ #ifdef CONFIG_MTD_CONFIG_NAMED printf(fmtstr, cfg.name, cfg.len); #else printf(fmtstr, cfg.id, cfg.instance, cfg.len); #endif /* Test if data is a string */ isstring = cfg.configdata[cfg.len - 1] == 0; for (x = 0; x < cfg.len - 1; x++) { /* Test for all ascii characters */ if (cfg.configdata[x] < ' ' || cfg.configdata[x] > '~') { isstring = false; break; } } /* Display the data */ if (isstring) { printf("%s\n", cfg.configdata); } else { char fmtstr2[10]; #ifdef CONFIG_MTD_CONFIG_NAMED snprintf(fmtstr2, sizeof(fmtstr2), "\n%ds", CONFIG_MTD_CONFIG_NAME_LEN + 6); #else strlcpy(fmtstr2, "\n%18s", sizeof(fmtstr2)); #endif /* Loop though all bytes and display them */ for (x = 0; x < cfg.len; x++) { /* Print the next byte */ printf("0x%02X ", cfg.configdata[x]); if (((x + 1) & 7) == 0 && x + 1 != cfg.len) { printf(fmtstr2, " "); } } printf("\n"); } /* Get the next config item */ cfg.len = 256; ret = ioctl(fd, CFGDIOC_NEXTCONFIG, (unsigned long)(uintptr_t)&cfg); } close(fd); free(cfg.configdata); } /**************************************************************************** * Erase all config items ****************************************************************************/ static void cfgdatacmd_format(void) { int fd; int ret; /* Try to open the /dev/config file */ if ((fd = open(g_config_dev, 0)) < 2) { /* Display error */ printf("error: unable to open %s\n", g_config_dev); return; } ret = ioctl(fd, MTDIOC_BULKERASE, 0); close(fd); if (ret != OK) { printf("Error %d config format\n", errno); } } /**************************************************************************** * Public Functions ****************************************************************************/ int main(int argc, FAR char *argv[]) { /* Argument given? */ if (argc == 1) { /* Show usage info and exit */ cfgdatacmd_help(); return 0; } /* Test for "all" cmd */ if (strcmp(argv[1], "all") == 0) { /* Print the existing config items */ cfgdatacmd_show_all_config_items(); return 0; } /* Test for "set" cmd */ if (strcmp(argv[1], "set") == 0) { if (argc < 4) { printf("At least 2 arguments needed for 'set' command\n"); return 0; } /* Call the routine to set a config item */ cfgdatacmd_set(argc, argv); return 0; } /* Test for "print" cmd */ if (strcmp(argv[1], "print") == 0) { /* Test for print all */ if (strcmp(argv[2], "all") == 0) { cfgdatacmd_show_all_config_items(); } else { /* Call the routine to print a config item */ cfgdatacmd_print(argc, argv); } return 0; } /* Test for "unset" cmd */ if (strcmp(argv[1], "unset") == 0) { if (argc < 3) { printf("Need 1 argument for 'unset' command\n"); return 0; } /* Call the routine to set a config item */ cfgdatacmd_unset(argc, argv); return 0; } /* Test for "format" cmd */ if (strcmp(argv[1], "format") == 0) { /* Call the routine to erase all config items */ cfgdatacmd_format(); return 0; } /* Unknown cmd */ printf("Unknown config command: %s\n", argv[1]); return 0; }