blob: 3d7bd202805ae8e65a2ba0bee4cacbe4aa5bfd41 [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)) {
Andrew Jefferyd30d7572023-04-18 14:51:51 +093073 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080074
75 /* trim leading space */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093076 for (; *line == ' ' || *line == '\t'; line++) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080077 ;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093078 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080079
80 /* skip comments */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093081 if (*line == '#') {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080082 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093083 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080084
Andrew Jefferyd30d7572023-04-18 14:51:51 +093085 name = malloc(strlen(line));
86 value = malloc(strlen(line));
87 if (name && value) {
88 rc = sscanf(line, "%[^ =] = %s ", name, value);
89 } else {
90 rc = -ENOMEM;
91 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080092
Andrew Jefferyd30d7572023-04-18 14:51:51 +093093 if (rc != 2) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080094 free(name);
95 free(value);
96 continue;
97 }
98
99 /* create a new item and add to our list */
100 item = malloc(sizeof(*item));
101 item->name = name;
102 item->value = value;
103 item->next = config->items;
104 config->items = item;
105 }
106}
107
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800108static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800109{
110 struct config *config;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930111 size_t size;
112 size_t len;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930113 ssize_t rc;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800114 char *buf;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800115
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800116 size = 4096;
117 len = 0;
118 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800119 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800120
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800121 for (;;) {
122 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800123 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800124 warn("Can't read from configuration file %s", filename);
125 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800126
127 } else if (!rc) {
128 break;
129 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800130 len += rc;
131 if (len == size) {
132 size <<= 1;
133 buf = realloc(buf, size + 1);
134 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800135 }
136 buf[len] = '\0';
137
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800138 config = malloc(sizeof(*config));
139 config->items = NULL;
140
141 config_parse(config, buf);
142
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800143out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800144 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800145 return config;
146}
147
148struct config *config_init(const char *filename)
149{
150 struct config *config;
151 int fd;
152
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930153 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800154 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930155 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800156
157 fd = open(filename, O_RDONLY);
158 if (fd < 0) {
159 warn("Can't open configuration file %s", filename);
160 return NULL;
161 }
162
163 config = config_init_fd(fd, filename);
164
165 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800166
167 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800168}
169
170void config_fini(struct config *config)
171{
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930172 struct config_item *item;
173 struct config_item *next;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800174
Andrew Jefferyba2af962023-05-02 15:02:56 +0930175 if (!config) {
176 return;
177 }
178
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800179 for (item = config->items; item; item = next) {
180 next = item->next;
181 free(item->name);
182 free(item->value);
183 free(item);
184 }
185
186 free(config);
187}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800188
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700189struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930190 speed_t speed;
191 uint32_t baud;
192 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700193};
194
Andrew Jefferya72711a2023-04-18 18:19:41 +0930195#define TERM_SPEED(x) \
196 { \
197 B##x, x, #x \
198 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800199
Andrew Jefferya72711a2023-04-18 18:19:41 +0930200// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800201static const struct terminal_speed_name terminal_speeds[] = {
202 TERM_SPEED(50),
203 TERM_SPEED(75),
204 TERM_SPEED(110),
205 TERM_SPEED(134),
206 TERM_SPEED(150),
207 TERM_SPEED(200),
208 TERM_SPEED(300),
209 TERM_SPEED(600),
210 TERM_SPEED(1200),
211 TERM_SPEED(1800),
212 TERM_SPEED(2400),
213 TERM_SPEED(4800),
214 TERM_SPEED(9600),
215 TERM_SPEED(19200),
216 TERM_SPEED(38400),
217 TERM_SPEED(57600),
218 TERM_SPEED(115200),
219 TERM_SPEED(230400),
220 TERM_SPEED(460800),
221 TERM_SPEED(500000),
222 TERM_SPEED(576000),
223 TERM_SPEED(921600),
224 TERM_SPEED(1000000),
225 TERM_SPEED(1152000),
226 TERM_SPEED(1500000),
227 TERM_SPEED(2000000),
228 TERM_SPEED(2500000),
229 TERM_SPEED(3000000),
230 TERM_SPEED(3500000),
231 TERM_SPEED(4000000),
232};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930233// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800234
235int config_parse_baud(speed_t *speed, const char *baud_string)
236{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700237 size_t i;
238
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800239 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700240 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
241 *speed = terminal_speeds[i].speed;
242 return 0;
243 }
244 }
245 return -1;
246}
247
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800248uint32_t parse_baud_to_int(speed_t speed)
249{
250 size_t i;
251
252 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
253 if (terminal_speeds[i].speed == speed) {
254 return terminal_speeds[i].baud;
255 }
256 }
257 return 0;
258}
259
260speed_t parse_int_to_baud(uint32_t baud)
261{
262 size_t i;
263
264 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
265 if (terminal_speeds[i].baud == baud) {
266 return terminal_speeds[i].speed;
267 }
268 }
269 return 0;
270}
271
Kun Yi6424cc32018-06-14 14:09:28 -0700272int config_parse_logsize(const char *size_str, size_t *size)
273{
274 struct size_suffix_shift {
275 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930276 size_t shiftwidth;
277 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700278 };
279
280 const struct size_suffix_shift suffixes[] = {
281 { 10, 'k' },
282 { 20, 'M' },
283 { 30, 'G' },
284 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930285 const size_t num_suffixes =
286 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700287 size_t logsize;
288 char *suffix;
289 size_t i;
290
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930291 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700292 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930293 }
Kun Yi6424cc32018-06-14 14:09:28 -0700294
295 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930296 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700297 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930298 }
Kun Yi6424cc32018-06-14 14:09:28 -0700299
300 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930301 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700302 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930303 }
Kun Yi6424cc32018-06-14 14:09:28 -0700304
305 for (i = 0; i < num_suffixes; i++) {
306 if (*suffix == suffixes[i].unit) {
307 /*
308 * If logsize overflows, probably something was wrong.
309 * Return instead of clamping to an arbitrary value.
310 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930311 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700312 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930313 }
Kun Yi6424cc32018-06-14 14:09:28 -0700314
315 logsize <<= suffixes[i].shiftwidth;
316 suffix++;
317 break;
318 }
319 }
320
321 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930322 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700323 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930324 }
Kun Yi6424cc32018-06-14 14:09:28 -0700325
326 if (*suffix) {
327 warn("Invalid suffix!");
328 return -1;
329 }
330
331 *size = logsize;
332 return 0;
333}
334
Ninad Palsule5ba20b52023-05-12 14:03:15 -0500335/* Default console id if not specified on command line or in config */
336#define DEFAULT_CONSOLE_ID "default"
337
338/* Get the console id */
339const char *config_resolve_console_id(struct config *config, const char *id_arg)
340{
341 const char *configured;
342
343 if (id_arg) {
344 return id_arg;
345 }
346
347 if ((configured = config_get_value(config, "console-id"))) {
348 return configured;
349 }
350
351 if ((configured = config_get_value(config, "socket-id"))) {
352 return configured;
353 }
354
355 return DEFAULT_CONSOLE_ID;
356}
357
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800358#ifdef CONFIG_TEST
359int main(void)
360{
361 struct config_item *item;
362 struct config *config;
363
364 config = config_init_fd(STDIN_FILENO, "<stdin>");
365 if (!config)
366 return EXIT_FAILURE;
367
368 for (item = config->items; item; item = item->next)
369 printf("%s: %s\n", item->name, item->value);
370
371 config_fini(config);
372
373 return EXIT_SUCCESS;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800374}
375#endif