1 /** 2 * Copyright © 2016 IBM Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <ctype.h> 18 #include <err.h> 19 #include <errno.h> 20 #include <fcntl.h> 21 #include <limits.h> 22 #include <stdint.h> 23 #include <stdio.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <strings.h> 27 #include <termios.h> /* for speed_t */ 28 #include <unistd.h> 29 30 #include <sys/mman.h> 31 #include <sys/stat.h> 32 33 #include <iniparser/iniparser.h> 34 35 #include "config.h" 36 #include "config-internal.h" 37 #include "util.h" 38 39 static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf"; 40 41 const char *config_get_value(struct config *config, const char *name) 42 { 43 char buf[CONFIG_MAX_KEY_LENGTH]; 44 int rc; 45 46 if (!config->dict) { 47 return NULL; 48 } 49 50 rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name); 51 if (rc < 0) { 52 return NULL; 53 } 54 55 if ((size_t)rc >= sizeof(buf)) { 56 return NULL; 57 } 58 59 const char *value = iniparser_getstring(config->dict, buf, NULL); 60 if (value && strlen(value) == 0) { 61 return NULL; 62 } 63 64 return value; 65 } 66 67 struct config *config_init(const char *filename) 68 { 69 struct config *config; 70 dictionary *dict; 71 72 if (!filename) { 73 filename = config_default_filename; 74 } 75 76 if (access(filename, R_OK) == 0) { 77 dict = iniparser_load(filename); 78 if (!dict) { 79 /* Assume this is a parse failure */ 80 return NULL; 81 } 82 } else { 83 /* If a config file was explicitly specified, then lack of access is always an error */ 84 if (filename != config_default_filename) { 85 warn("Failed to open configuration file at '%s'", 86 filename); 87 return NULL; 88 } 89 90 /* For the default config path, any result other than not-present is an error */ 91 if (errno != ENOENT && errno != ENOTDIR) { 92 warn("Failed to open configuration file at '%s'", 93 filename); 94 return NULL; 95 } 96 97 /* Config not present at default path, pretend its empty */ 98 dict = NULL; 99 } 100 101 config = malloc(sizeof(*config)); 102 if (!config) { 103 iniparser_freedict(dict); 104 return NULL; 105 } 106 107 config->dict = dict; 108 109 return config; 110 } 111 112 void config_fini(struct config *config) 113 { 114 if (!config) { 115 return; 116 } 117 118 if (config->dict) { 119 iniparser_freedict(config->dict); 120 } 121 122 free(config); 123 } 124 125 struct terminal_speed_name { 126 speed_t speed; 127 uint32_t baud; 128 const char *name; 129 }; 130 131 #define TERM_SPEED(x) \ 132 { \ 133 B##x, x, #x \ 134 } 135 136 // clang-format off 137 static const struct terminal_speed_name terminal_speeds[] = { 138 TERM_SPEED(50), 139 TERM_SPEED(75), 140 TERM_SPEED(110), 141 TERM_SPEED(134), 142 TERM_SPEED(150), 143 TERM_SPEED(200), 144 TERM_SPEED(300), 145 TERM_SPEED(600), 146 TERM_SPEED(1200), 147 TERM_SPEED(1800), 148 TERM_SPEED(2400), 149 TERM_SPEED(4800), 150 TERM_SPEED(9600), 151 TERM_SPEED(19200), 152 TERM_SPEED(38400), 153 TERM_SPEED(57600), 154 TERM_SPEED(115200), 155 TERM_SPEED(230400), 156 TERM_SPEED(460800), 157 TERM_SPEED(500000), 158 TERM_SPEED(576000), 159 TERM_SPEED(921600), 160 TERM_SPEED(1000000), 161 TERM_SPEED(1152000), 162 TERM_SPEED(1500000), 163 TERM_SPEED(2000000), 164 TERM_SPEED(2500000), 165 TERM_SPEED(3000000), 166 TERM_SPEED(3500000), 167 TERM_SPEED(4000000), 168 }; 169 // clang-format on 170 171 int config_parse_baud(speed_t *speed, const char *baud_string) 172 { 173 size_t i; 174 175 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 176 if (strcmp(baud_string, terminal_speeds[i].name) == 0) { 177 *speed = terminal_speeds[i].speed; 178 return 0; 179 } 180 } 181 return -1; 182 } 183 184 uint32_t parse_baud_to_int(speed_t speed) 185 { 186 size_t i; 187 188 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 189 if (terminal_speeds[i].speed == speed) { 190 return terminal_speeds[i].baud; 191 } 192 } 193 return 0; 194 } 195 196 speed_t parse_int_to_baud(uint32_t baud) 197 { 198 size_t i; 199 200 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 201 if (terminal_speeds[i].baud == baud) { 202 return terminal_speeds[i].speed; 203 } 204 } 205 return 0; 206 } 207 208 int config_parse_bytesize(const char *size_str, size_t *size) 209 { 210 struct size_suffix_shift { 211 /* Left shiftwidth corresponding to the suffix. */ 212 size_t shiftwidth; 213 int unit; 214 }; 215 216 const struct size_suffix_shift suffixes[] = { 217 { 10, 'k' }, 218 { 20, 'M' }, 219 { 30, 'G' }, 220 }; 221 const size_t num_suffixes = 222 sizeof(suffixes) / sizeof(struct size_suffix_shift); 223 size_t logsize; 224 char *suffix; 225 size_t i; 226 227 if (!size_str) { 228 return -1; 229 } 230 231 logsize = strtoul(size_str, &suffix, 0); 232 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) { 233 return -1; 234 } 235 236 /* Ignore spaces between number and suffix */ 237 while (*suffix && isspace(*suffix)) { 238 suffix++; 239 } 240 241 for (i = 0; i < num_suffixes; i++) { 242 if (*suffix == suffixes[i].unit) { 243 /* 244 * If logsize overflows, probably something was wrong. 245 * Return instead of clamping to an arbitrary value. 246 */ 247 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) { 248 return -1; 249 } 250 251 logsize <<= suffixes[i].shiftwidth; 252 suffix++; 253 break; 254 } 255 } 256 257 /* Allow suffix like 'kB' */ 258 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) { 259 suffix++; 260 } 261 262 if (*suffix) { 263 warn("Invalid suffix!"); 264 return -1; 265 } 266 267 *size = logsize; 268 return 0; 269 } 270 271 /* Default console id if not specified on command line or in config */ 272 #define DEFAULT_CONSOLE_ID "default" 273 274 /* Get the console id */ 275 const char *config_resolve_console_id(struct config *config, const char *id_arg) 276 { 277 const char *configured; 278 279 if (id_arg) { 280 return id_arg; 281 } 282 283 if ((configured = config_get_value(config, "console-id"))) { 284 return configured; 285 } 286 287 return DEFAULT_CONSOLE_ID; 288 } 289