blob: 5f5edaf1ddb7dedf0ab14026e04e0204ad866f4e [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>
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +080032#include "console-server.h"
Jeremy Kerrd66195c2016-03-16 17:24:51 +080033
Jeremy Kerre440a402016-03-17 16:34:14 +080034static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
Jeremy Kerrd66195c2016-03-16 17:24:51 +080035
36struct config_item {
Andrew Jefferya72711a2023-04-18 18:19:41 +093037 char *name;
38 char *value;
39 struct config_item *next;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080040};
41
42struct config {
Andrew Jefferya72711a2023-04-18 18:19:41 +093043 struct config_item *items;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080044};
45
46const char *config_get_value(struct config *config, const char *name)
47{
48 struct config_item *item;
49
Andrew Jefferyba2af962023-05-02 15:02:56 +093050 if (!config) {
51 return NULL;
52 }
53
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093054 for (item = config->items; item; item = item->next) {
55 if (!strcasecmp(item->name, name)) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080056 return item->value;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093057 }
58 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080059
60 return NULL;
61}
62
63static void config_parse(struct config *config, char *buf)
64{
65 struct config_item *item;
Andrew Jefferyb70f8712023-04-19 12:53:34 +093066 char *name;
67 char *value;
68 char *p;
69 char *line;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080070
71 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
Andrew Jefferya72711a2023-04-18 18:19:41 +093072 line = strtok_r(NULL, "\n", &p)) {
Zev Weissacefe012023-09-12 19:12:22 -070073 char *end;
Andrew Jefferyd30d7572023-04-18 14:51:51 +093074 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080075
76 /* trim leading space */
Zev Weiss35f44fc2023-09-12 19:07:19 -070077 while (isspace(*line)) {
78 line++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093079 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080080
81 /* skip comments */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093082 if (*line == '#') {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080083 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093084 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080085
Andrew Jefferyd30d7572023-04-18 14:51:51 +093086 name = malloc(strlen(line));
87 value = malloc(strlen(line));
88 if (name && value) {
Zev Weissacefe012023-09-12 19:12:22 -070089 rc = sscanf(line, "%[^ =] = %[^#]s", name, value);
Andrew Jefferyd30d7572023-04-18 14:51:51 +093090 } else {
91 rc = -ENOMEM;
92 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080093
Andrew Jefferyd30d7572023-04-18 14:51:51 +093094 if (rc != 2) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080095 free(name);
96 free(value);
97 continue;
98 }
99
Zev Weissacefe012023-09-12 19:12:22 -0700100 /* trim trailing space */
101 end = value + strlen(value) - 1;
102 while (isspace(*end)) {
103 *end-- = '\0';
104 }
105
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800106 /* 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
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800115static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800116{
117 struct config *config;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930118 size_t size;
119 size_t len;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930120 ssize_t rc;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800121 char *buf;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800122
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800123 size = 4096;
124 len = 0;
125 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800126 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800127
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800128 for (;;) {
129 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800130 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800131 warn("Can't read from configuration file %s", filename);
132 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800133
134 } else if (!rc) {
135 break;
136 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800137 len += rc;
138 if (len == size) {
139 size <<= 1;
140 buf = realloc(buf, size + 1);
141 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800142 }
143 buf[len] = '\0';
144
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800145 config = malloc(sizeof(*config));
146 config->items = NULL;
147
148 config_parse(config, buf);
149
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800150out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800151 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800152 return config;
153}
154
155struct config *config_init(const char *filename)
156{
157 struct config *config;
158 int fd;
159
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930160 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800161 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930162 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800163
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);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800173
174 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800175}
176
177void config_fini(struct config *config)
178{
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930179 struct config_item *item;
180 struct config_item *next;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800181
Andrew Jefferyba2af962023-05-02 15:02:56 +0930182 if (!config) {
183 return;
184 }
185
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800186 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}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800195
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700196struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930197 speed_t speed;
198 uint32_t baud;
199 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700200};
201
Andrew Jefferya72711a2023-04-18 18:19:41 +0930202#define TERM_SPEED(x) \
203 { \
204 B##x, x, #x \
205 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800206
Andrew Jefferya72711a2023-04-18 18:19:41 +0930207// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800208static 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};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930240// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800241
242int config_parse_baud(speed_t *speed, const char *baud_string)
243{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700244 size_t i;
245
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800246 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700247 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
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800255uint32_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
267speed_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
Medicine Yehd6e8b642024-03-18 01:49:17 -0700279int config_parse_bytesize(const char *size_str, size_t *size)
Kun Yi6424cc32018-06-14 14:09:28 -0700280{
281 struct size_suffix_shift {
282 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930283 size_t shiftwidth;
284 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700285 };
286
287 const struct size_suffix_shift suffixes[] = {
288 { 10, 'k' },
289 { 20, 'M' },
290 { 30, 'G' },
291 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930292 const size_t num_suffixes =
293 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700294 size_t logsize;
295 char *suffix;
296 size_t i;
297
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930298 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700299 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930300 }
Kun Yi6424cc32018-06-14 14:09:28 -0700301
302 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930303 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700304 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930305 }
Kun Yi6424cc32018-06-14 14:09:28 -0700306
307 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930308 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700309 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930310 }
Kun Yi6424cc32018-06-14 14:09:28 -0700311
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 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930318 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700319 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930320 }
Kun Yi6424cc32018-06-14 14:09:28 -0700321
322 logsize <<= suffixes[i].shiftwidth;
323 suffix++;
324 break;
325 }
326 }
327
328 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930329 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700330 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930331 }
Kun Yi6424cc32018-06-14 14:09:28 -0700332
333 if (*suffix) {
334 warn("Invalid suffix!");
335 return -1;
336 }
337
338 *size = logsize;
339 return 0;
340}
341
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500342/* Default console id if not specified on command line or in config */
343#define DEFAULT_CONSOLE_ID "default"
344
345/* Get the console id */
346const 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
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500358 return DEFAULT_CONSOLE_ID;
359}
360
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800361#ifdef CONFIG_TEST
362int 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;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800377}
378#endif