blob: 5a2f4f03b66599d4cae0535e61c9f0aa1ebb4e6e [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 Jeffery2834c5b2023-04-19 12:47:09 +093050 for (item = config->items; item; item = item->next) {
51 if (!strcasecmp(item->name, name)) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080052 return item->value;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093053 }
54 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080055
56 return NULL;
57}
58
59static void config_parse(struct config *config, char *buf)
60{
61 struct config_item *item;
Andrew Jefferyb70f8712023-04-19 12:53:34 +093062 char *name;
63 char *value;
64 char *p;
65 char *line;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080066
67 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
Andrew Jefferya72711a2023-04-18 18:19:41 +093068 line = strtok_r(NULL, "\n", &p)) {
Andrew Jefferyd30d7572023-04-18 14:51:51 +093069 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080070
71 /* trim leading space */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093072 for (; *line == ' ' || *line == '\t'; line++) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080073 ;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093074 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080075
76 /* skip comments */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093077 if (*line == '#') {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080078 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093079 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080080
Andrew Jefferyd30d7572023-04-18 14:51:51 +093081 name = malloc(strlen(line));
82 value = malloc(strlen(line));
83 if (name && value) {
84 rc = sscanf(line, "%[^ =] = %s ", name, value);
85 } else {
86 rc = -ENOMEM;
87 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080088
Andrew Jefferyd30d7572023-04-18 14:51:51 +093089 if (rc != 2) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080090 free(name);
91 free(value);
92 continue;
93 }
94
95 /* create a new item and add to our list */
96 item = malloc(sizeof(*item));
97 item->name = name;
98 item->value = value;
99 item->next = config->items;
100 config->items = item;
101 }
102}
103
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800104static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800105{
106 struct config *config;
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930107 size_t size;
108 size_t len;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930109 ssize_t rc;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800110 char *buf;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800111
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800112 size = 4096;
113 len = 0;
114 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800115 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800116
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800117 for (;;) {
118 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800119 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800120 warn("Can't read from configuration file %s", filename);
121 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800122
123 } else if (!rc) {
124 break;
125 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800126 len += rc;
127 if (len == size) {
128 size <<= 1;
129 buf = realloc(buf, size + 1);
130 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800131 }
132 buf[len] = '\0';
133
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800134 config = malloc(sizeof(*config));
135 config->items = NULL;
136
137 config_parse(config, buf);
138
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800139out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800140 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800141 return config;
142}
143
144struct config *config_init(const char *filename)
145{
146 struct config *config;
147 int fd;
148
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930149 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800150 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930151 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800152
153 fd = open(filename, O_RDONLY);
154 if (fd < 0) {
155 warn("Can't open configuration file %s", filename);
156 return NULL;
157 }
158
159 config = config_init_fd(fd, filename);
160
161 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800162
163 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800164}
165
166void config_fini(struct config *config)
167{
Andrew Jefferyb70f8712023-04-19 12:53:34 +0930168 struct config_item *item;
169 struct config_item *next;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800170
171 for (item = config->items; item; item = next) {
172 next = item->next;
173 free(item->name);
174 free(item->value);
175 free(item);
176 }
177
178 free(config);
179}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800180
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700181struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930182 speed_t speed;
183 uint32_t baud;
184 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700185};
186
Andrew Jefferya72711a2023-04-18 18:19:41 +0930187#define TERM_SPEED(x) \
188 { \
189 B##x, x, #x \
190 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800191
Andrew Jefferya72711a2023-04-18 18:19:41 +0930192// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800193static const struct terminal_speed_name terminal_speeds[] = {
194 TERM_SPEED(50),
195 TERM_SPEED(75),
196 TERM_SPEED(110),
197 TERM_SPEED(134),
198 TERM_SPEED(150),
199 TERM_SPEED(200),
200 TERM_SPEED(300),
201 TERM_SPEED(600),
202 TERM_SPEED(1200),
203 TERM_SPEED(1800),
204 TERM_SPEED(2400),
205 TERM_SPEED(4800),
206 TERM_SPEED(9600),
207 TERM_SPEED(19200),
208 TERM_SPEED(38400),
209 TERM_SPEED(57600),
210 TERM_SPEED(115200),
211 TERM_SPEED(230400),
212 TERM_SPEED(460800),
213 TERM_SPEED(500000),
214 TERM_SPEED(576000),
215 TERM_SPEED(921600),
216 TERM_SPEED(1000000),
217 TERM_SPEED(1152000),
218 TERM_SPEED(1500000),
219 TERM_SPEED(2000000),
220 TERM_SPEED(2500000),
221 TERM_SPEED(3000000),
222 TERM_SPEED(3500000),
223 TERM_SPEED(4000000),
224};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930225// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800226
227int config_parse_baud(speed_t *speed, const char *baud_string)
228{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700229 size_t i;
230
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800231 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700232 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
233 *speed = terminal_speeds[i].speed;
234 return 0;
235 }
236 }
237 return -1;
238}
239
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800240uint32_t parse_baud_to_int(speed_t speed)
241{
242 size_t i;
243
244 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
245 if (terminal_speeds[i].speed == speed) {
246 return terminal_speeds[i].baud;
247 }
248 }
249 return 0;
250}
251
252speed_t parse_int_to_baud(uint32_t baud)
253{
254 size_t i;
255
256 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
257 if (terminal_speeds[i].baud == baud) {
258 return terminal_speeds[i].speed;
259 }
260 }
261 return 0;
262}
263
Kun Yi6424cc32018-06-14 14:09:28 -0700264int config_parse_logsize(const char *size_str, size_t *size)
265{
266 struct size_suffix_shift {
267 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930268 size_t shiftwidth;
269 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700270 };
271
272 const struct size_suffix_shift suffixes[] = {
273 { 10, 'k' },
274 { 20, 'M' },
275 { 30, 'G' },
276 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930277 const size_t num_suffixes =
278 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700279 size_t logsize;
280 char *suffix;
281 size_t i;
282
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930283 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700284 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930285 }
Kun Yi6424cc32018-06-14 14:09:28 -0700286
287 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930288 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700289 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930290 }
Kun Yi6424cc32018-06-14 14:09:28 -0700291
292 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930293 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700294 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930295 }
Kun Yi6424cc32018-06-14 14:09:28 -0700296
297 for (i = 0; i < num_suffixes; i++) {
298 if (*suffix == suffixes[i].unit) {
299 /*
300 * If logsize overflows, probably something was wrong.
301 * Return instead of clamping to an arbitrary value.
302 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930303 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
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 logsize <<= suffixes[i].shiftwidth;
308 suffix++;
309 break;
310 }
311 }
312
313 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930314 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700315 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930316 }
Kun Yi6424cc32018-06-14 14:09:28 -0700317
318 if (*suffix) {
319 warn("Invalid suffix!");
320 return -1;
321 }
322
323 *size = logsize;
324 return 0;
325}
326
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800327#ifdef CONFIG_TEST
328int main(void)
329{
330 struct config_item *item;
331 struct config *config;
332
333 config = config_init_fd(STDIN_FILENO, "<stdin>");
334 if (!config)
335 return EXIT_FAILURE;
336
337 for (item = config->items; item; item = item->next)
338 printf("%s: %s\n", item->name, item->value);
339
340 config_fini(config);
341
342 return EXIT_SUCCESS;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800343}
344#endif