/** * Copyright © 2016 IBM Corporation * * Licensed 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. */ #include #include #include #include #include #include #include #include #include #include #include /* for speed_t */ #include #include #include #include #include "config-internal.h" #include "config.h" #include "util.h" static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf"; const char *config_get_value(struct config *config, const char *name) { char buf[CONFIG_MAX_KEY_LENGTH]; int rc; if (!config->dict) { return NULL; } rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name); if (rc < 0) { return NULL; } if ((size_t)rc >= sizeof(buf)) { return NULL; } const char *value = iniparser_getstring(config->dict, buf, NULL); if (value && strlen(value) == 0) { return NULL; } return value; } struct config *config_init(const char *filename) { struct config *config; dictionary *dict; if (!filename) { filename = config_default_filename; } if (access(filename, R_OK) == 0) { dict = iniparser_load(filename); if (!dict) { /* Assume this is a parse failure */ return NULL; } } else { /* If a config file was explicitly specified, then lack of access is always an error */ if (filename != config_default_filename) { warn("Failed to open configuration file at '%s'", filename); return NULL; } /* For the default config path, any result other than not-present is an error */ if (errno != ENOENT && errno != ENOTDIR) { warn("Failed to open configuration file at '%s'", filename); return NULL; } /* Config not present at default path, pretend its empty */ dict = NULL; } config = malloc(sizeof(*config)); if (!config) { iniparser_freedict(dict); return NULL; } config->dict = dict; return config; } const char *config_get_section_value(struct config *config, const char *secname, const char *name) { char buf[CONFIG_MAX_KEY_LENGTH]; int rc; rc = snprintf(buf, sizeof(buf), "%s:%s", secname, name); if (rc < 0) { return NULL; } if ((size_t)rc >= sizeof(buf)) { // error / key too long for the buffer warnx("config: section:key too long for buffer: '%s':'%s'", secname, name); return NULL; } return iniparser_getstring(config->dict, buf, NULL); } void config_fini(struct config *config) { if (!config) { return; } if (config->dict) { iniparser_freedict(config->dict); } free(config); } struct terminal_speed_name { speed_t speed; uint32_t baud; const char *name; }; #define TERM_SPEED(x) { B##x, x, #x } // clang-format off static const struct terminal_speed_name terminal_speeds[] = { TERM_SPEED(50), TERM_SPEED(75), TERM_SPEED(110), TERM_SPEED(134), TERM_SPEED(150), TERM_SPEED(200), TERM_SPEED(300), TERM_SPEED(600), TERM_SPEED(1200), TERM_SPEED(1800), TERM_SPEED(2400), TERM_SPEED(4800), TERM_SPEED(9600), TERM_SPEED(19200), TERM_SPEED(38400), TERM_SPEED(57600), TERM_SPEED(115200), TERM_SPEED(230400), TERM_SPEED(460800), TERM_SPEED(500000), TERM_SPEED(576000), TERM_SPEED(921600), TERM_SPEED(1000000), TERM_SPEED(1152000), TERM_SPEED(1500000), TERM_SPEED(2000000), TERM_SPEED(2500000), TERM_SPEED(3000000), TERM_SPEED(3500000), TERM_SPEED(4000000), }; // clang-format on int config_parse_baud(speed_t *speed, const char *baud_string) { size_t i; for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { if (strcmp(baud_string, terminal_speeds[i].name) == 0) { *speed = terminal_speeds[i].speed; return 0; } } return -1; } uint32_t parse_baud_to_int(speed_t speed) { size_t i; for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { if (terminal_speeds[i].speed == speed) { return terminal_speeds[i].baud; } } return 0; } speed_t parse_int_to_baud(uint32_t baud) { size_t i; for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { if (terminal_speeds[i].baud == baud) { return terminal_speeds[i].speed; } } return 0; } int config_parse_bytesize(const char *size_str, size_t *size) { struct size_suffix_shift { /* Left shiftwidth corresponding to the suffix. */ size_t shiftwidth; int unit; }; const struct size_suffix_shift suffixes[] = { { 10, 'k' }, { 20, 'M' }, { 30, 'G' }, }; const size_t num_suffixes = sizeof(suffixes) / sizeof(struct size_suffix_shift); size_t logsize; char *suffix; size_t i; if (!size_str) { return -1; } logsize = strtoul(size_str, &suffix, 0); if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) { return -1; } /* Ignore spaces between number and suffix */ while (*suffix && isspace(*suffix)) { suffix++; } for (i = 0; i < num_suffixes; i++) { if (*suffix == suffixes[i].unit) { /* * If logsize overflows, probably something was wrong. * Return instead of clamping to an arbitrary value. */ if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) { return -1; } logsize <<= suffixes[i].shiftwidth; suffix++; break; } } /* Allow suffix like 'kB' */ while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) { suffix++; } if (*suffix) { warn("Invalid suffix!"); return -1; } *size = logsize; return 0; } /* Default console id if not specified on command line or in config */ #define DEFAULT_CONSOLE_ID "default" /* Get the console id */ const char *config_resolve_console_id(struct config *config, const char *id_arg) { const char *configured; if (id_arg) { return id_arg; } if ((configured = config_get_value(config, "console-id"))) { return configured; } return DEFAULT_CONSOLE_ID; } int config_count_sections(struct config *config) { return iniparser_getnsec(config->dict); } const char *config_get_section_name(struct config *config, int i) { return iniparser_getsecname(config->dict, i); }