blob: 615c49894ac6625dfe5c7d505574d840d647b5b4 [file] [log] [blame]
Jeremy Kerr9326d772016-03-17 17:15:02 +08001/**
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 */
Jeremy Kerrd66195c2016-03-16 17:24:51 +080016
Kun Yi6424cc32018-06-14 14:09:28 -070017#include <ctype.h>
Jeremy Kerrd66195c2016-03-16 17:24:51 +080018#include <err.h>
Andrew Jefferyd30d7572023-04-18 14:51:51 +093019#include <errno.h>
Jeremy Kerrd66195c2016-03-16 17:24:51 +080020#include <fcntl.h>
Kun Yi6424cc32018-06-14 14:09:28 -070021#include <limits.h>
Jeremy Kerrd66195c2016-03-16 17:24:51 +080022#include <stdint.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <strings.h>
Benjamin Fairfcbdea92018-06-04 14:19:25 -070027#include <termios.h> /* for speed_t */
Jeremy Kerrd66195c2016-03-16 17:24:51 +080028#include <unistd.h>
29
30#include <sys/mman.h>
31#include <sys/stat.h>
Alexander Hansen1e04f442024-06-12 16:35:58 +020032
33#include <iniparser/iniparser.h>
34
Alexander Hansen1e04f442024-06-12 16:35:58 +020035#include "config-internal.h"
Alexander Hansene3a083e2024-07-08 15:30:35 +020036#include "config.h"
Alexander Hansene3f1aa12024-07-10 11:57:17 +020037#include "util.h"
Jeremy Kerrd66195c2016-03-16 17:24:51 +080038
Jeremy Kerre440a402016-03-17 16:34:14 +080039static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
Jeremy Kerrd66195c2016-03-16 17:24:51 +080040
Jeremy Kerrd66195c2016-03-16 17:24:51 +080041const char *config_get_value(struct config *config, const char *name)
42{
Alexander Hansen1e04f442024-06-12 16:35:58 +020043 char buf[CONFIG_MAX_KEY_LENGTH];
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093044 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080045
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093046 if (!config->dict) {
47 return NULL;
48 }
49
50 rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name);
Alexander Hansen1e04f442024-06-12 16:35:58 +020051 if (rc < 0) {
Andrew Jefferyba2af962023-05-02 15:02:56 +093052 return NULL;
53 }
54
Alexander Hansen1e04f442024-06-12 16:35:58 +020055 if ((size_t)rc >= sizeof(buf)) {
56 return NULL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093057 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080058
Alexander Hansen1e04f442024-06-12 16:35:58 +020059 const char *value = iniparser_getstring(config->dict, buf, NULL);
Alexander Hansen1e04f442024-06-12 16:35:58 +020060 if (value && strlen(value) == 0) {
61 return NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080062 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080063
Alexander Hansen1e04f442024-06-12 16:35:58 +020064 return value;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080065}
66
67struct config *config_init(const char *filename)
68{
69 struct config *config;
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093070 dictionary *dict;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080071
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093072 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080073 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093074 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080075
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093076 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 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080089
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093090 /* 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 }
Alexander Hansen1e04f442024-06-12 16:35:58 +020096
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093097 /* Config not present at default path, pretend its empty */
98 dict = NULL;
Alexander Hansen1e04f442024-06-12 16:35:58 +020099 }
100
101 config = malloc(sizeof(*config));
Andrew Jefferyd659cfc2024-07-10 09:42:50 +0930102 if (!config) {
103 iniparser_freedict(dict);
104 return NULL;
Alexander Hansen1e04f442024-06-12 16:35:58 +0200105 }
106
Andrew Jefferyd659cfc2024-07-10 09:42:50 +0930107 config->dict = dict;
108
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800109 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800110}
111
Alexander Hansene3a083e2024-07-08 15:30:35 +0200112const 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
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800133void config_fini(struct config *config)
134{
Andrew Jefferyba2af962023-05-02 15:02:56 +0930135 if (!config) {
136 return;
137 }
138
Alexander Hansen1e04f442024-06-12 16:35:58 +0200139 if (config->dict) {
140 iniparser_freedict(config->dict);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800141 }
142
143 free(config);
144}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800145
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700146struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930147 speed_t speed;
148 uint32_t baud;
149 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700150};
151
Andrew Jefferya72711a2023-04-18 18:19:41 +0930152#define TERM_SPEED(x) \
153 { \
154 B##x, x, #x \
155 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800156
Andrew Jefferya72711a2023-04-18 18:19:41 +0930157// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800158static const struct terminal_speed_name terminal_speeds[] = {
159 TERM_SPEED(50),
160 TERM_SPEED(75),
161 TERM_SPEED(110),
162 TERM_SPEED(134),
163 TERM_SPEED(150),
164 TERM_SPEED(200),
165 TERM_SPEED(300),
166 TERM_SPEED(600),
167 TERM_SPEED(1200),
168 TERM_SPEED(1800),
169 TERM_SPEED(2400),
170 TERM_SPEED(4800),
171 TERM_SPEED(9600),
172 TERM_SPEED(19200),
173 TERM_SPEED(38400),
174 TERM_SPEED(57600),
175 TERM_SPEED(115200),
176 TERM_SPEED(230400),
177 TERM_SPEED(460800),
178 TERM_SPEED(500000),
179 TERM_SPEED(576000),
180 TERM_SPEED(921600),
181 TERM_SPEED(1000000),
182 TERM_SPEED(1152000),
183 TERM_SPEED(1500000),
184 TERM_SPEED(2000000),
185 TERM_SPEED(2500000),
186 TERM_SPEED(3000000),
187 TERM_SPEED(3500000),
188 TERM_SPEED(4000000),
189};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930190// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800191
192int config_parse_baud(speed_t *speed, const char *baud_string)
193{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700194 size_t i;
195
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800196 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700197 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
198 *speed = terminal_speeds[i].speed;
199 return 0;
200 }
201 }
202 return -1;
203}
204
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800205uint32_t parse_baud_to_int(speed_t speed)
206{
207 size_t i;
208
209 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
210 if (terminal_speeds[i].speed == speed) {
211 return terminal_speeds[i].baud;
212 }
213 }
214 return 0;
215}
216
217speed_t parse_int_to_baud(uint32_t baud)
218{
219 size_t i;
220
221 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
222 if (terminal_speeds[i].baud == baud) {
223 return terminal_speeds[i].speed;
224 }
225 }
226 return 0;
227}
228
Medicine Yehd6e8b642024-03-18 01:49:17 -0700229int config_parse_bytesize(const char *size_str, size_t *size)
Kun Yi6424cc32018-06-14 14:09:28 -0700230{
231 struct size_suffix_shift {
232 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930233 size_t shiftwidth;
234 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700235 };
236
237 const struct size_suffix_shift suffixes[] = {
238 { 10, 'k' },
239 { 20, 'M' },
240 { 30, 'G' },
241 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930242 const size_t num_suffixes =
243 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700244 size_t logsize;
245 char *suffix;
246 size_t i;
247
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930248 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700249 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930250 }
Kun Yi6424cc32018-06-14 14:09:28 -0700251
252 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930253 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700254 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930255 }
Kun Yi6424cc32018-06-14 14:09:28 -0700256
257 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930258 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700259 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930260 }
Kun Yi6424cc32018-06-14 14:09:28 -0700261
262 for (i = 0; i < num_suffixes; i++) {
263 if (*suffix == suffixes[i].unit) {
264 /*
265 * If logsize overflows, probably something was wrong.
266 * Return instead of clamping to an arbitrary value.
267 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930268 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700269 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930270 }
Kun Yi6424cc32018-06-14 14:09:28 -0700271
272 logsize <<= suffixes[i].shiftwidth;
273 suffix++;
274 break;
275 }
276 }
277
278 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930279 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700280 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930281 }
Kun Yi6424cc32018-06-14 14:09:28 -0700282
283 if (*suffix) {
284 warn("Invalid suffix!");
285 return -1;
286 }
287
288 *size = logsize;
289 return 0;
290}
291
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500292/* Default console id if not specified on command line or in config */
293#define DEFAULT_CONSOLE_ID "default"
294
295/* Get the console id */
296const char *config_resolve_console_id(struct config *config, const char *id_arg)
297{
298 const char *configured;
299
300 if (id_arg) {
301 return id_arg;
302 }
303
304 if ((configured = config_get_value(config, "console-id"))) {
305 return configured;
306 }
307
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500308 return DEFAULT_CONSOLE_ID;
309}
Alexander Hansene3a083e2024-07-08 15:30:35 +0200310
311int config_count_sections(struct config *config)
312{
313 return iniparser_getnsec(config->dict);
314}
315
316const char *config_get_section_name(struct config *config, int i)
317{
318 return iniparser_getsecname(config->dict, i);
319}