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