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 #include "console-server.h" 33 34 static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf"; 35 36 struct config_item { 37 char *name; 38 char *value; 39 struct config_item *next; 40 }; 41 42 struct config { 43 struct config_item *items; 44 }; 45 46 const char *config_get_value(struct config *config, const char *name) 47 { 48 struct config_item *item; 49 50 if (!config) { 51 return NULL; 52 } 53 54 for (item = config->items; item; item = item->next) { 55 if (!strcasecmp(item->name, name)) { 56 return item->value; 57 } 58 } 59 60 return NULL; 61 } 62 63 static void config_parse(struct config *config, char *buf) 64 { 65 struct config_item *item; 66 char *name; 67 char *value; 68 char *p; 69 char *line; 70 71 for (p = NULL, line = strtok_r(buf, "\n", &p); line; 72 line = strtok_r(NULL, "\n", &p)) { 73 char *end; 74 int rc; 75 76 /* trim leading space */ 77 while (isspace(*line)) { 78 line++; 79 } 80 81 /* skip comments */ 82 if (*line == '#') { 83 continue; 84 } 85 86 name = malloc(strlen(line)); 87 value = malloc(strlen(line)); 88 if (name && value) { 89 rc = sscanf(line, "%[^ =] = %[^#]s", name, value); 90 } else { 91 rc = -ENOMEM; 92 } 93 94 if (rc != 2) { 95 free(name); 96 free(value); 97 continue; 98 } 99 100 /* trim trailing space */ 101 end = value + strlen(value) - 1; 102 while (isspace(*end)) { 103 *end-- = '\0'; 104 } 105 106 /* create a new item and add to our list */ 107 item = malloc(sizeof(*item)); 108 item->name = name; 109 item->value = value; 110 item->next = config->items; 111 config->items = item; 112 } 113 } 114 115 static struct config *config_init_fd(int fd, const char *filename) 116 { 117 struct config *config; 118 size_t size; 119 size_t len; 120 ssize_t rc; 121 char *buf; 122 123 size = 4096; 124 len = 0; 125 buf = malloc(size + 1); 126 config = NULL; 127 128 for (;;) { 129 rc = read(fd, buf + len, size - len); 130 if (rc < 0) { 131 warn("Can't read from configuration file %s", filename); 132 goto out_free; 133 134 } else if (!rc) { 135 break; 136 } 137 len += rc; 138 if (len == size) { 139 size <<= 1; 140 buf = realloc(buf, size + 1); 141 } 142 } 143 buf[len] = '\0'; 144 145 config = malloc(sizeof(*config)); 146 config->items = NULL; 147 148 config_parse(config, buf); 149 150 out_free: 151 free(buf); 152 return config; 153 } 154 155 struct config *config_init(const char *filename) 156 { 157 struct config *config; 158 int fd; 159 160 if (!filename) { 161 filename = config_default_filename; 162 } 163 164 fd = open(filename, O_RDONLY); 165 if (fd < 0) { 166 warn("Can't open configuration file %s", filename); 167 return NULL; 168 } 169 170 config = config_init_fd(fd, filename); 171 172 close(fd); 173 174 return config; 175 } 176 177 void config_fini(struct config *config) 178 { 179 struct config_item *item; 180 struct config_item *next; 181 182 if (!config) { 183 return; 184 } 185 186 for (item = config->items; item; item = next) { 187 next = item->next; 188 free(item->name); 189 free(item->value); 190 free(item); 191 } 192 193 free(config); 194 } 195 196 struct terminal_speed_name { 197 speed_t speed; 198 uint32_t baud; 199 const char *name; 200 }; 201 202 #define TERM_SPEED(x) \ 203 { \ 204 B##x, x, #x \ 205 } 206 207 // clang-format off 208 static const struct terminal_speed_name terminal_speeds[] = { 209 TERM_SPEED(50), 210 TERM_SPEED(75), 211 TERM_SPEED(110), 212 TERM_SPEED(134), 213 TERM_SPEED(150), 214 TERM_SPEED(200), 215 TERM_SPEED(300), 216 TERM_SPEED(600), 217 TERM_SPEED(1200), 218 TERM_SPEED(1800), 219 TERM_SPEED(2400), 220 TERM_SPEED(4800), 221 TERM_SPEED(9600), 222 TERM_SPEED(19200), 223 TERM_SPEED(38400), 224 TERM_SPEED(57600), 225 TERM_SPEED(115200), 226 TERM_SPEED(230400), 227 TERM_SPEED(460800), 228 TERM_SPEED(500000), 229 TERM_SPEED(576000), 230 TERM_SPEED(921600), 231 TERM_SPEED(1000000), 232 TERM_SPEED(1152000), 233 TERM_SPEED(1500000), 234 TERM_SPEED(2000000), 235 TERM_SPEED(2500000), 236 TERM_SPEED(3000000), 237 TERM_SPEED(3500000), 238 TERM_SPEED(4000000), 239 }; 240 // clang-format on 241 242 int config_parse_baud(speed_t *speed, const char *baud_string) 243 { 244 size_t i; 245 246 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 247 if (strcmp(baud_string, terminal_speeds[i].name) == 0) { 248 *speed = terminal_speeds[i].speed; 249 return 0; 250 } 251 } 252 return -1; 253 } 254 255 uint32_t parse_baud_to_int(speed_t speed) 256 { 257 size_t i; 258 259 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 260 if (terminal_speeds[i].speed == speed) { 261 return terminal_speeds[i].baud; 262 } 263 } 264 return 0; 265 } 266 267 speed_t parse_int_to_baud(uint32_t baud) 268 { 269 size_t i; 270 271 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 272 if (terminal_speeds[i].baud == baud) { 273 return terminal_speeds[i].speed; 274 } 275 } 276 return 0; 277 } 278 279 int config_parse_logsize(const char *size_str, size_t *size) 280 { 281 struct size_suffix_shift { 282 /* Left shiftwidth corresponding to the suffix. */ 283 size_t shiftwidth; 284 int unit; 285 }; 286 287 const struct size_suffix_shift suffixes[] = { 288 { 10, 'k' }, 289 { 20, 'M' }, 290 { 30, 'G' }, 291 }; 292 const size_t num_suffixes = 293 sizeof(suffixes) / sizeof(struct size_suffix_shift); 294 size_t logsize; 295 char *suffix; 296 size_t i; 297 298 if (!size_str) { 299 return -1; 300 } 301 302 logsize = strtoul(size_str, &suffix, 0); 303 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) { 304 return -1; 305 } 306 307 /* Ignore spaces between number and suffix */ 308 while (*suffix && isspace(*suffix)) { 309 suffix++; 310 } 311 312 for (i = 0; i < num_suffixes; i++) { 313 if (*suffix == suffixes[i].unit) { 314 /* 315 * If logsize overflows, probably something was wrong. 316 * Return instead of clamping to an arbitrary value. 317 */ 318 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) { 319 return -1; 320 } 321 322 logsize <<= suffixes[i].shiftwidth; 323 suffix++; 324 break; 325 } 326 } 327 328 /* Allow suffix like 'kB' */ 329 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) { 330 suffix++; 331 } 332 333 if (*suffix) { 334 warn("Invalid suffix!"); 335 return -1; 336 } 337 338 *size = logsize; 339 return 0; 340 } 341 342 /* Default console id if not specified on command line or in config */ 343 #define DEFAULT_CONSOLE_ID "default" 344 345 /* Get the console id */ 346 const char *config_resolve_console_id(struct config *config, const char *id_arg) 347 { 348 const char *configured; 349 350 if (id_arg) { 351 return id_arg; 352 } 353 354 if ((configured = config_get_value(config, "console-id"))) { 355 return configured; 356 } 357 358 return DEFAULT_CONSOLE_ID; 359 } 360 361 #ifdef CONFIG_TEST 362 int main(void) 363 { 364 struct config_item *item; 365 struct config *config; 366 367 config = config_init_fd(STDIN_FILENO, "<stdin>"); 368 if (!config) 369 return EXIT_FAILURE; 370 371 for (item = config->items; item; item = item->next) 372 printf("%s: %s\n", item->name, item->value); 373 374 config_fini(config); 375 376 return EXIT_SUCCESS; 377 } 378 #endif 379