blob: 15c08bc99c6aa4a25f26a24491e428877cce74e0 [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
35#include "config.h"
36#include "config-internal.h"
37
38#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
Jeremy Kerrd66195c2016-03-16 17:24:51 +080039
Jeremy Kerre440a402016-03-17 16:34:14 +080040static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
Jeremy Kerrd66195c2016-03-16 17:24:51 +080041
Jeremy Kerrd66195c2016-03-16 17:24:51 +080042const char *config_get_value(struct config *config, const char *name)
43{
Alexander Hansen1e04f442024-06-12 16:35:58 +020044 char buf[CONFIG_MAX_KEY_LENGTH];
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093045 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080046
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093047 if (!config->dict) {
48 return NULL;
49 }
50
51 rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name);
Alexander Hansen1e04f442024-06-12 16:35:58 +020052 if (rc < 0) {
Andrew Jefferyba2af962023-05-02 15:02:56 +093053 return NULL;
54 }
55
Alexander Hansen1e04f442024-06-12 16:35:58 +020056 if ((size_t)rc >= sizeof(buf)) {
57 return NULL;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093058 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080059
Alexander Hansen1e04f442024-06-12 16:35:58 +020060 const char *value = iniparser_getstring(config->dict, buf, NULL);
Alexander Hansen1e04f442024-06-12 16:35:58 +020061 if (value && strlen(value) == 0) {
62 return NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080063 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080064
Alexander Hansen1e04f442024-06-12 16:35:58 +020065 return value;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080066}
67
68struct config *config_init(const char *filename)
69{
70 struct config *config;
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093071 dictionary *dict;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080072
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093073 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080074 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093075 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080076
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093077 if (access(filename, R_OK) == 0) {
78 dict = iniparser_load(filename);
79 if (!dict) {
80 /* Assume this is a parse failure */
81 return NULL;
82 }
83 } else {
84 /* If a config file was explicitly specified, then lack of access is always an error */
85 if (filename != config_default_filename) {
86 warn("Failed to open configuration file at '%s'",
87 filename);
88 return NULL;
89 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080090
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093091 /* For the default config path, any result other than not-present is an error */
92 if (errno != ENOENT && errno != ENOTDIR) {
93 warn("Failed to open configuration file at '%s'",
94 filename);
95 return NULL;
96 }
Alexander Hansen1e04f442024-06-12 16:35:58 +020097
Andrew Jefferyd659cfc2024-07-10 09:42:50 +093098 /* Config not present at default path, pretend its empty */
99 dict = NULL;
Alexander Hansen1e04f442024-06-12 16:35:58 +0200100 }
101
102 config = malloc(sizeof(*config));
Andrew Jefferyd659cfc2024-07-10 09:42:50 +0930103 if (!config) {
104 iniparser_freedict(dict);
105 return NULL;
Alexander Hansen1e04f442024-06-12 16:35:58 +0200106 }
107
Andrew Jefferyd659cfc2024-07-10 09:42:50 +0930108 config->dict = dict;
109
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800110 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800111}
112
113void config_fini(struct config *config)
114{
Andrew Jefferyba2af962023-05-02 15:02:56 +0930115 if (!config) {
116 return;
117 }
118
Alexander Hansen1e04f442024-06-12 16:35:58 +0200119 if (config->dict) {
120 iniparser_freedict(config->dict);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800121 }
122
123 free(config);
124}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800125
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700126struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930127 speed_t speed;
128 uint32_t baud;
129 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700130};
131
Andrew Jefferya72711a2023-04-18 18:19:41 +0930132#define TERM_SPEED(x) \
133 { \
134 B##x, x, #x \
135 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800136
Andrew Jefferya72711a2023-04-18 18:19:41 +0930137// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800138static const struct terminal_speed_name terminal_speeds[] = {
139 TERM_SPEED(50),
140 TERM_SPEED(75),
141 TERM_SPEED(110),
142 TERM_SPEED(134),
143 TERM_SPEED(150),
144 TERM_SPEED(200),
145 TERM_SPEED(300),
146 TERM_SPEED(600),
147 TERM_SPEED(1200),
148 TERM_SPEED(1800),
149 TERM_SPEED(2400),
150 TERM_SPEED(4800),
151 TERM_SPEED(9600),
152 TERM_SPEED(19200),
153 TERM_SPEED(38400),
154 TERM_SPEED(57600),
155 TERM_SPEED(115200),
156 TERM_SPEED(230400),
157 TERM_SPEED(460800),
158 TERM_SPEED(500000),
159 TERM_SPEED(576000),
160 TERM_SPEED(921600),
161 TERM_SPEED(1000000),
162 TERM_SPEED(1152000),
163 TERM_SPEED(1500000),
164 TERM_SPEED(2000000),
165 TERM_SPEED(2500000),
166 TERM_SPEED(3000000),
167 TERM_SPEED(3500000),
168 TERM_SPEED(4000000),
169};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930170// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800171
172int config_parse_baud(speed_t *speed, const char *baud_string)
173{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700174 size_t i;
175
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800176 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700177 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
178 *speed = terminal_speeds[i].speed;
179 return 0;
180 }
181 }
182 return -1;
183}
184
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800185uint32_t parse_baud_to_int(speed_t speed)
186{
187 size_t i;
188
189 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
190 if (terminal_speeds[i].speed == speed) {
191 return terminal_speeds[i].baud;
192 }
193 }
194 return 0;
195}
196
197speed_t parse_int_to_baud(uint32_t baud)
198{
199 size_t i;
200
201 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
202 if (terminal_speeds[i].baud == baud) {
203 return terminal_speeds[i].speed;
204 }
205 }
206 return 0;
207}
208
Medicine Yehd6e8b642024-03-18 01:49:17 -0700209int config_parse_bytesize(const char *size_str, size_t *size)
Kun Yi6424cc32018-06-14 14:09:28 -0700210{
211 struct size_suffix_shift {
212 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930213 size_t shiftwidth;
214 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700215 };
216
217 const struct size_suffix_shift suffixes[] = {
218 { 10, 'k' },
219 { 20, 'M' },
220 { 30, 'G' },
221 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930222 const size_t num_suffixes =
223 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700224 size_t logsize;
225 char *suffix;
226 size_t i;
227
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930228 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700229 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930230 }
Kun Yi6424cc32018-06-14 14:09:28 -0700231
232 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930233 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700234 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930235 }
Kun Yi6424cc32018-06-14 14:09:28 -0700236
237 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930238 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700239 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930240 }
Kun Yi6424cc32018-06-14 14:09:28 -0700241
242 for (i = 0; i < num_suffixes; i++) {
243 if (*suffix == suffixes[i].unit) {
244 /*
245 * If logsize overflows, probably something was wrong.
246 * Return instead of clamping to an arbitrary value.
247 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930248 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
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 <<= suffixes[i].shiftwidth;
253 suffix++;
254 break;
255 }
256 }
257
258 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930259 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700260 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930261 }
Kun Yi6424cc32018-06-14 14:09:28 -0700262
263 if (*suffix) {
264 warn("Invalid suffix!");
265 return -1;
266 }
267
268 *size = logsize;
269 return 0;
270}
271
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500272/* Default console id if not specified on command line or in config */
273#define DEFAULT_CONSOLE_ID "default"
274
275/* Get the console id */
276const char *config_resolve_console_id(struct config *config, const char *id_arg)
277{
278 const char *configured;
279
280 if (id_arg) {
281 return id_arg;
282 }
283
284 if ((configured = config_get_value(config, "console-id"))) {
285 return configured;
286 }
287
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500288 return DEFAULT_CONSOLE_ID;
289}