/** * 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 <ctype.h> #include <err.h> #include <fcntl.h> #include <limits.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <strings.h> #include <termios.h> /* for speed_t */ #include <unistd.h> #include <sys/mman.h> #include <sys/stat.h> #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; 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, *value; char *p, *line; int rc; for (p = NULL, line = strtok_r(buf, "\n", &p); line; line = strtok_r(NULL, "\n", &p)) { /* trim leading space */ for (;*line == ' ' || *line == '\t'; line++) ; /* skip comments */ if (*line == '#') continue; name = value = NULL; rc = sscanf(line, "%m[^ =] = %ms ", &name, &value); if (rc != 2 || !strlen(name) || !strlen(value)) { free(name); free(value); continue; } /* 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, len; char *buf; int rc; 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, *next; 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} 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), }; 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_logsize(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; } #ifdef CONFIG_TEST int main(void) { struct config_item *item; struct config *config; config = config_init_fd(STDIN_FILENO, "<stdin>"); 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