blob: ce2ed47c05d0df0e14828808af433dcdc7caa75d [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;
62 char *name, *value;
63 char *p, *line;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080064
65 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
Andrew Jefferya72711a2023-04-18 18:19:41 +093066 line = strtok_r(NULL, "\n", &p)) {
Andrew Jefferyd30d7572023-04-18 14:51:51 +093067 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080068
69 /* trim leading space */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093070 for (; *line == ' ' || *line == '\t'; line++) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080071 ;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093072 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080073
74 /* skip comments */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093075 if (*line == '#') {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080076 continue;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +093077 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080078
Andrew Jefferyd30d7572023-04-18 14:51:51 +093079 name = malloc(strlen(line));
80 value = malloc(strlen(line));
81 if (name && value) {
82 rc = sscanf(line, "%[^ =] = %s ", name, value);
83 } else {
84 rc = -ENOMEM;
85 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080086
Andrew Jefferyd30d7572023-04-18 14:51:51 +093087 if (rc != 2) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080088 free(name);
89 free(value);
90 continue;
91 }
92
93 /* create a new item and add to our list */
94 item = malloc(sizeof(*item));
95 item->name = name;
96 item->value = value;
97 item->next = config->items;
98 config->items = item;
99 }
100}
101
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800102static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800103{
104 struct config *config;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800105 size_t size, len;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930106 ssize_t rc;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800107 char *buf;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800108
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800109 size = 4096;
110 len = 0;
111 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800112 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800113
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800114 for (;;) {
115 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800116 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800117 warn("Can't read from configuration file %s", filename);
118 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800119
120 } else if (!rc) {
121 break;
122 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800123 len += rc;
124 if (len == size) {
125 size <<= 1;
126 buf = realloc(buf, size + 1);
127 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800128 }
129 buf[len] = '\0';
130
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800131 config = malloc(sizeof(*config));
132 config->items = NULL;
133
134 config_parse(config, buf);
135
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800136out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800137 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800138 return config;
139}
140
141struct config *config_init(const char *filename)
142{
143 struct config *config;
144 int fd;
145
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930146 if (!filename) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800147 filename = config_default_filename;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930148 }
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800149
150 fd = open(filename, O_RDONLY);
151 if (fd < 0) {
152 warn("Can't open configuration file %s", filename);
153 return NULL;
154 }
155
156 config = config_init_fd(fd, filename);
157
158 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800159
160 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800161}
162
163void config_fini(struct config *config)
164{
165 struct config_item *item, *next;
166
167 for (item = config->items; item; item = next) {
168 next = item->next;
169 free(item->name);
170 free(item->value);
171 free(item);
172 }
173
174 free(config);
175}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800176
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700177struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930178 speed_t speed;
179 uint32_t baud;
180 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700181};
182
Andrew Jefferya72711a2023-04-18 18:19:41 +0930183#define TERM_SPEED(x) \
184 { \
185 B##x, x, #x \
186 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800187
Andrew Jefferya72711a2023-04-18 18:19:41 +0930188// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800189static const struct terminal_speed_name terminal_speeds[] = {
190 TERM_SPEED(50),
191 TERM_SPEED(75),
192 TERM_SPEED(110),
193 TERM_SPEED(134),
194 TERM_SPEED(150),
195 TERM_SPEED(200),
196 TERM_SPEED(300),
197 TERM_SPEED(600),
198 TERM_SPEED(1200),
199 TERM_SPEED(1800),
200 TERM_SPEED(2400),
201 TERM_SPEED(4800),
202 TERM_SPEED(9600),
203 TERM_SPEED(19200),
204 TERM_SPEED(38400),
205 TERM_SPEED(57600),
206 TERM_SPEED(115200),
207 TERM_SPEED(230400),
208 TERM_SPEED(460800),
209 TERM_SPEED(500000),
210 TERM_SPEED(576000),
211 TERM_SPEED(921600),
212 TERM_SPEED(1000000),
213 TERM_SPEED(1152000),
214 TERM_SPEED(1500000),
215 TERM_SPEED(2000000),
216 TERM_SPEED(2500000),
217 TERM_SPEED(3000000),
218 TERM_SPEED(3500000),
219 TERM_SPEED(4000000),
220};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930221// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800222
223int config_parse_baud(speed_t *speed, const char *baud_string)
224{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700225 size_t i;
226
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800227 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700228 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
229 *speed = terminal_speeds[i].speed;
230 return 0;
231 }
232 }
233 return -1;
234}
235
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800236uint32_t parse_baud_to_int(speed_t speed)
237{
238 size_t i;
239
240 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
241 if (terminal_speeds[i].speed == speed) {
242 return terminal_speeds[i].baud;
243 }
244 }
245 return 0;
246}
247
248speed_t parse_int_to_baud(uint32_t baud)
249{
250 size_t i;
251
252 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
253 if (terminal_speeds[i].baud == baud) {
254 return terminal_speeds[i].speed;
255 }
256 }
257 return 0;
258}
259
Kun Yi6424cc32018-06-14 14:09:28 -0700260int config_parse_logsize(const char *size_str, size_t *size)
261{
262 struct size_suffix_shift {
263 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930264 size_t shiftwidth;
265 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700266 };
267
268 const struct size_suffix_shift suffixes[] = {
269 { 10, 'k' },
270 { 20, 'M' },
271 { 30, 'G' },
272 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930273 const size_t num_suffixes =
274 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700275 size_t logsize;
276 char *suffix;
277 size_t i;
278
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930279 if (!size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700280 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930281 }
Kun Yi6424cc32018-06-14 14:09:28 -0700282
283 logsize = strtoul(size_str, &suffix, 0);
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930284 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
Kun Yi6424cc32018-06-14 14:09:28 -0700285 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930286 }
Kun Yi6424cc32018-06-14 14:09:28 -0700287
288 /* Ignore spaces between number and suffix */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930289 while (*suffix && isspace(*suffix)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700290 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930291 }
Kun Yi6424cc32018-06-14 14:09:28 -0700292
293 for (i = 0; i < num_suffixes; i++) {
294 if (*suffix == suffixes[i].unit) {
295 /*
296 * If logsize overflows, probably something was wrong.
297 * Return instead of clamping to an arbitrary value.
298 */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930299 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
Kun Yi6424cc32018-06-14 14:09:28 -0700300 return -1;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930301 }
Kun Yi6424cc32018-06-14 14:09:28 -0700302
303 logsize <<= suffixes[i].shiftwidth;
304 suffix++;
305 break;
306 }
307 }
308
309 /* Allow suffix like 'kB' */
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930310 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
Kun Yi6424cc32018-06-14 14:09:28 -0700311 suffix++;
Andrew Jeffery2834c5b2023-04-19 12:47:09 +0930312 }
Kun Yi6424cc32018-06-14 14:09:28 -0700313
314 if (*suffix) {
315 warn("Invalid suffix!");
316 return -1;
317 }
318
319 *size = logsize;
320 return 0;
321}
322
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800323#ifdef CONFIG_TEST
324int main(void)
325{
326 struct config_item *item;
327 struct config *config;
328
329 config = config_init_fd(STDIN_FILENO, "<stdin>");
330 if (!config)
331 return EXIT_FAILURE;
332
333 for (item = config->items; item; item = item->next)
334 printf("%s: %s\n", item->name, item->value);
335
336 config_fini(config);
337
338 return EXIT_SUCCESS;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800339}
340#endif