blob: 6fc840ce601eb6a72f5d5680e29b58216e312b38 [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
50 for (item = config->items; item; item = item->next)
51 if (!strcasecmp(item->name, name))
52 return item->value;
53
54 return NULL;
55}
56
57static void config_parse(struct config *config, char *buf)
58{
59 struct config_item *item;
60 char *name, *value;
61 char *p, *line;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080062
63 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
Andrew Jefferya72711a2023-04-18 18:19:41 +093064 line = strtok_r(NULL, "\n", &p)) {
Andrew Jefferyd30d7572023-04-18 14:51:51 +093065 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080066
67 /* trim leading space */
Andrew Jefferya72711a2023-04-18 18:19:41 +093068 for (; *line == ' ' || *line == '\t'; line++)
Jeremy Kerrd66195c2016-03-16 17:24:51 +080069 ;
70
71 /* skip comments */
72 if (*line == '#')
73 continue;
74
Andrew Jefferyd30d7572023-04-18 14:51:51 +093075 name = malloc(strlen(line));
76 value = malloc(strlen(line));
77 if (name && value) {
78 rc = sscanf(line, "%[^ =] = %s ", name, value);
79 } else {
80 rc = -ENOMEM;
81 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +080082
Andrew Jefferyd30d7572023-04-18 14:51:51 +093083 if (rc != 2) {
Jeremy Kerrd66195c2016-03-16 17:24:51 +080084 free(name);
85 free(value);
86 continue;
87 }
88
89 /* create a new item and add to our list */
90 item = malloc(sizeof(*item));
91 item->name = name;
92 item->value = value;
93 item->next = config->items;
94 config->items = item;
95 }
96}
97
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080098static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +080099{
100 struct config *config;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800101 size_t size, len;
Andrew Jeffery5c359cc2023-04-18 22:50:07 +0930102 ssize_t rc;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800103 char *buf;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800104
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800105 size = 4096;
106 len = 0;
107 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800108 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800109
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800110 for (;;) {
111 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800112 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800113 warn("Can't read from configuration file %s", filename);
114 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800115
116 } else if (!rc) {
117 break;
118 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800119 len += rc;
120 if (len == size) {
121 size <<= 1;
122 buf = realloc(buf, size + 1);
123 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800124 }
125 buf[len] = '\0';
126
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800127 config = malloc(sizeof(*config));
128 config->items = NULL;
129
130 config_parse(config, buf);
131
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800132out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800133 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800134 return config;
135}
136
137struct config *config_init(const char *filename)
138{
139 struct config *config;
140 int fd;
141
142 if (!filename)
143 filename = config_default_filename;
144
145 fd = open(filename, O_RDONLY);
146 if (fd < 0) {
147 warn("Can't open configuration file %s", filename);
148 return NULL;
149 }
150
151 config = config_init_fd(fd, filename);
152
153 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800154
155 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800156}
157
158void config_fini(struct config *config)
159{
160 struct config_item *item, *next;
161
162 for (item = config->items; item; item = next) {
163 next = item->next;
164 free(item->name);
165 free(item->value);
166 free(item);
167 }
168
169 free(config);
170}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800171
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700172struct terminal_speed_name {
Andrew Jefferya72711a2023-04-18 18:19:41 +0930173 speed_t speed;
174 uint32_t baud;
175 const char *name;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700176};
177
Andrew Jefferya72711a2023-04-18 18:19:41 +0930178#define TERM_SPEED(x) \
179 { \
180 B##x, x, #x \
181 }
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800182
Andrew Jefferya72711a2023-04-18 18:19:41 +0930183// clang-format off
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800184static const struct terminal_speed_name terminal_speeds[] = {
185 TERM_SPEED(50),
186 TERM_SPEED(75),
187 TERM_SPEED(110),
188 TERM_SPEED(134),
189 TERM_SPEED(150),
190 TERM_SPEED(200),
191 TERM_SPEED(300),
192 TERM_SPEED(600),
193 TERM_SPEED(1200),
194 TERM_SPEED(1800),
195 TERM_SPEED(2400),
196 TERM_SPEED(4800),
197 TERM_SPEED(9600),
198 TERM_SPEED(19200),
199 TERM_SPEED(38400),
200 TERM_SPEED(57600),
201 TERM_SPEED(115200),
202 TERM_SPEED(230400),
203 TERM_SPEED(460800),
204 TERM_SPEED(500000),
205 TERM_SPEED(576000),
206 TERM_SPEED(921600),
207 TERM_SPEED(1000000),
208 TERM_SPEED(1152000),
209 TERM_SPEED(1500000),
210 TERM_SPEED(2000000),
211 TERM_SPEED(2500000),
212 TERM_SPEED(3000000),
213 TERM_SPEED(3500000),
214 TERM_SPEED(4000000),
215};
Andrew Jefferya72711a2023-04-18 18:19:41 +0930216// clang-format on
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800217
218int config_parse_baud(speed_t *speed, const char *baud_string)
219{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700220 size_t i;
221
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800222 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700223 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
224 *speed = terminal_speeds[i].speed;
225 return 0;
226 }
227 }
228 return -1;
229}
230
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800231uint32_t parse_baud_to_int(speed_t speed)
232{
233 size_t i;
234
235 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
236 if (terminal_speeds[i].speed == speed) {
237 return terminal_speeds[i].baud;
238 }
239 }
240 return 0;
241}
242
243speed_t parse_int_to_baud(uint32_t baud)
244{
245 size_t i;
246
247 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
248 if (terminal_speeds[i].baud == baud) {
249 return terminal_speeds[i].speed;
250 }
251 }
252 return 0;
253}
254
Kun Yi6424cc32018-06-14 14:09:28 -0700255int config_parse_logsize(const char *size_str, size_t *size)
256{
257 struct size_suffix_shift {
258 /* Left shiftwidth corresponding to the suffix. */
Andrew Jefferya72711a2023-04-18 18:19:41 +0930259 size_t shiftwidth;
260 int unit;
Kun Yi6424cc32018-06-14 14:09:28 -0700261 };
262
263 const struct size_suffix_shift suffixes[] = {
264 { 10, 'k' },
265 { 20, 'M' },
266 { 30, 'G' },
267 };
Andrew Jefferya72711a2023-04-18 18:19:41 +0930268 const size_t num_suffixes =
269 sizeof(suffixes) / sizeof(struct size_suffix_shift);
Kun Yi6424cc32018-06-14 14:09:28 -0700270 size_t logsize;
271 char *suffix;
272 size_t i;
273
274 if (!size_str)
275 return -1;
276
277 logsize = strtoul(size_str, &suffix, 0);
278 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str)
279 return -1;
280
281 /* Ignore spaces between number and suffix */
282 while (*suffix && isspace(*suffix))
283 suffix++;
284
285 for (i = 0; i < num_suffixes; i++) {
286 if (*suffix == suffixes[i].unit) {
287 /*
288 * If logsize overflows, probably something was wrong.
289 * Return instead of clamping to an arbitrary value.
290 */
291 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth))
292 return -1;
293
294 logsize <<= suffixes[i].shiftwidth;
295 suffix++;
296 break;
297 }
298 }
299
300 /* Allow suffix like 'kB' */
301 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix)))
302 suffix++;
303
304 if (*suffix) {
305 warn("Invalid suffix!");
306 return -1;
307 }
308
309 *size = logsize;
310 return 0;
311}
312
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800313#ifdef CONFIG_TEST
314int main(void)
315{
316 struct config_item *item;
317 struct config *config;
318
319 config = config_init_fd(STDIN_FILENO, "<stdin>");
320 if (!config)
321 return EXIT_FAILURE;
322
323 for (item = config->items; item; item = item->next)
324 printf("%s: %s\n", item->name, item->value);
325
326 config_fini(config);
327
328 return EXIT_SUCCESS;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800329}
330#endif