/** * 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 "console-server.h" static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf"; struct config_item { char *name; char *value; struct config_item *next; }; struct config { struct config_item *items; }; const char *config_get_value(struct config *config, const char *name) { struct config_item *item; if (!config) { return NULL; } for (item = config->items; item; item = item->next) { if (!strcasecmp(item->name, name)) { return item->value; } } return NULL; } static void config_parse(struct config *config, char *buf) { struct config_item *item; char *name; char *value; char *p; char *line; for (p = NULL, line = strtok_r(buf, "\n", &p); line; line = strtok_r(NULL, "\n", &p)) { char *end; int rc; /* trim leading space */ while (isspace(*line)) { line++; } /* skip comments */ if (*line == '#') { continue; } name = malloc(strlen(line)); value = malloc(strlen(line)); if (name && value) { rc = sscanf(line, "%[^ =] = %[^#]s", name, value); } else { rc = -ENOMEM; } if (rc != 2) { free(name); free(value); continue; } /* trim trailing space */ end = value + strlen(value) - 1; while (isspace(*end)) { *end-- = '\0'; } /* create a new item and add to our list */ item = malloc(sizeof(*item)); item->name = name; item->value = value; item->next = config->items; config->items = item; } } static struct config *config_init_fd(int fd, const char *filename) { struct config *config; size_t size; size_t len; ssize_t rc; char *buf; size = 4096; len = 0; buf = malloc(size + 1); config = NULL; for (;;) { rc = read(fd, buf + len, size - len); if (rc < 0) { warn("Can't read from configuration file %s", filename); goto out_free; } else if (!rc) { break; } len += rc; if (len == size) { size <<= 1; buf = realloc(buf, size + 1); } } buf[len] = '\0'; config = malloc(sizeof(*config)); config->items = NULL; config_parse(config, buf); out_free: free(buf); return config; } struct config *config_init(const char *filename) { struct config *config; int fd; if (!filename) { filename = config_default_filename; } fd = open(filename, O_RDONLY); if (fd < 0) { warn("Can't open configuration file %s", filename); return NULL; } config = config_init_fd(fd, filename); close(fd); return config; } void config_fini(struct config *config) { struct config_item *item; struct config_item *next; if (!config) { return; } for (item = config->items; item; item = next) { next = item->next; free(item->name); free(item->value); free(item); } 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; } #ifdef CONFIG_TEST int main(void) { struct config_item *item; struct config *config; config = config_init_fd(STDIN_FILENO, ""); if (!config) return EXIT_FAILURE; for (item = config->items; item; item = item->next) printf("%s: %s\n", item->name, item->value); config_fini(config); return EXIT_SUCCESS; } #endif