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-internal.h" 36 #include "config.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 const char *config_get_section_value(struct config *config, const char *secname, 113 const char *name) 114 { 115 char buf[CONFIG_MAX_KEY_LENGTH]; 116 int rc; 117 118 rc = snprintf(buf, sizeof(buf), "%s:%s", secname, name); 119 if (rc < 0) { 120 return NULL; 121 } 122 123 if ((size_t)rc >= sizeof(buf)) { 124 // error / key too long for the buffer 125 warnx("config: section:key too long for buffer: '%s':'%s'", 126 secname, name); 127 return NULL; 128 } 129 130 return iniparser_getstring(config->dict, buf, NULL); 131 } 132 133 void config_fini(struct config *config) 134 { 135 if (!config) { 136 return; 137 } 138 139 if (config->dict) { 140 iniparser_freedict(config->dict); 141 } 142 143 free(config); 144 } 145 146 struct terminal_speed_name { 147 speed_t speed; 148 uint32_t baud; 149 const char *name; 150 }; 151 152 #define TERM_SPEED(x) { B##x, x, #x } 153 154 // clang-format off 155 static const struct terminal_speed_name terminal_speeds[] = { 156 TERM_SPEED(50), 157 TERM_SPEED(75), 158 TERM_SPEED(110), 159 TERM_SPEED(134), 160 TERM_SPEED(150), 161 TERM_SPEED(200), 162 TERM_SPEED(300), 163 TERM_SPEED(600), 164 TERM_SPEED(1200), 165 TERM_SPEED(1800), 166 TERM_SPEED(2400), 167 TERM_SPEED(4800), 168 TERM_SPEED(9600), 169 TERM_SPEED(19200), 170 TERM_SPEED(38400), 171 TERM_SPEED(57600), 172 TERM_SPEED(115200), 173 TERM_SPEED(230400), 174 TERM_SPEED(460800), 175 TERM_SPEED(500000), 176 TERM_SPEED(576000), 177 TERM_SPEED(921600), 178 TERM_SPEED(1000000), 179 TERM_SPEED(1152000), 180 TERM_SPEED(1500000), 181 TERM_SPEED(2000000), 182 TERM_SPEED(2500000), 183 TERM_SPEED(3000000), 184 TERM_SPEED(3500000), 185 TERM_SPEED(4000000), 186 }; 187 // clang-format on 188 189 int config_parse_baud(speed_t *speed, const char *baud_string) 190 { 191 size_t i; 192 193 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 194 if (strcmp(baud_string, terminal_speeds[i].name) == 0) { 195 *speed = terminal_speeds[i].speed; 196 return 0; 197 } 198 } 199 return -1; 200 } 201 202 uint32_t parse_baud_to_int(speed_t speed) 203 { 204 size_t i; 205 206 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 207 if (terminal_speeds[i].speed == speed) { 208 return terminal_speeds[i].baud; 209 } 210 } 211 return 0; 212 } 213 214 speed_t parse_int_to_baud(uint32_t baud) 215 { 216 size_t i; 217 218 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) { 219 if (terminal_speeds[i].baud == baud) { 220 return terminal_speeds[i].speed; 221 } 222 } 223 return 0; 224 } 225 226 int config_parse_bytesize(const char *size_str, size_t *size) 227 { 228 struct size_suffix_shift { 229 /* Left shiftwidth corresponding to the suffix. */ 230 size_t shiftwidth; 231 int unit; 232 }; 233 234 const struct size_suffix_shift suffixes[] = { 235 { 10, 'k' }, 236 { 20, 'M' }, 237 { 30, 'G' }, 238 }; 239 const size_t num_suffixes = 240 sizeof(suffixes) / sizeof(struct size_suffix_shift); 241 size_t logsize; 242 char *suffix; 243 size_t i; 244 245 if (!size_str) { 246 return -1; 247 } 248 249 logsize = strtoul(size_str, &suffix, 0); 250 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) { 251 return -1; 252 } 253 254 /* Ignore spaces between number and suffix */ 255 while (*suffix && isspace(*suffix)) { 256 suffix++; 257 } 258 259 for (i = 0; i < num_suffixes; i++) { 260 if (*suffix == suffixes[i].unit) { 261 /* 262 * If logsize overflows, probably something was wrong. 263 * Return instead of clamping to an arbitrary value. 264 */ 265 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) { 266 return -1; 267 } 268 269 logsize <<= suffixes[i].shiftwidth; 270 suffix++; 271 break; 272 } 273 } 274 275 /* Allow suffix like 'kB' */ 276 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) { 277 suffix++; 278 } 279 280 if (*suffix) { 281 warn("Invalid suffix!"); 282 return -1; 283 } 284 285 *size = logsize; 286 return 0; 287 } 288 289 /* Default console id if not specified on command line or in config */ 290 #define DEFAULT_CONSOLE_ID "default" 291 292 /* Get the console id */ 293 const char *config_resolve_console_id(struct config *config, const char *id_arg) 294 { 295 const char *configured; 296 297 if (id_arg) { 298 return id_arg; 299 } 300 301 if ((configured = config_get_value(config, "console-id"))) { 302 return configured; 303 } 304 305 return DEFAULT_CONSOLE_ID; 306 } 307 308 int config_count_sections(struct config *config) 309 { 310 return iniparser_getnsec(config->dict); 311 } 312 313 const char *config_get_section_name(struct config *config, int i) 314 { 315 return iniparser_getsecname(config->dict, i); 316 } 317