blob: 5cdd76b42e2e6047d67f762d38d88757882f86d9 [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 {
37 char *name;
38 char *value;
39 struct config_item *next;
40};
41
42struct config {
43 struct config_item *items;
44};
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;
64 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 */
68 for (;*line == ' ' || *line == '\t'; line++)
69 ;
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;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800102 char *buf;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800103 int rc;
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 }
126 buf[len] = '\0';
127
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800128 config = malloc(sizeof(*config));
129 config->items = NULL;
130
131 config_parse(config, buf);
132
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800133out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800134 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800135 return config;
136}
137
138struct config *config_init(const char *filename)
139{
140 struct config *config;
141 int fd;
142
143 if (!filename)
144 filename = config_default_filename;
145
146 fd = open(filename, O_RDONLY);
147 if (fd < 0) {
148 warn("Can't open configuration file %s", filename);
149 return NULL;
150 }
151
152 config = config_init_fd(fd, filename);
153
154 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800155
156 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800157}
158
159void config_fini(struct config *config)
160{
161 struct config_item *item, *next;
162
163 for (item = config->items; item; item = next) {
164 next = item->next;
165 free(item->name);
166 free(item->value);
167 free(item);
168 }
169
170 free(config);
171}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800172
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700173struct terminal_speed_name {
174 speed_t speed;
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800175 uint32_t baud;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700176 const char *name;
177};
178
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800179#define TERM_SPEED(x) { B##x, x, #x}
180
181static const struct terminal_speed_name terminal_speeds[] = {
182 TERM_SPEED(50),
183 TERM_SPEED(75),
184 TERM_SPEED(110),
185 TERM_SPEED(134),
186 TERM_SPEED(150),
187 TERM_SPEED(200),
188 TERM_SPEED(300),
189 TERM_SPEED(600),
190 TERM_SPEED(1200),
191 TERM_SPEED(1800),
192 TERM_SPEED(2400),
193 TERM_SPEED(4800),
194 TERM_SPEED(9600),
195 TERM_SPEED(19200),
196 TERM_SPEED(38400),
197 TERM_SPEED(57600),
198 TERM_SPEED(115200),
199 TERM_SPEED(230400),
200 TERM_SPEED(460800),
201 TERM_SPEED(500000),
202 TERM_SPEED(576000),
203 TERM_SPEED(921600),
204 TERM_SPEED(1000000),
205 TERM_SPEED(1152000),
206 TERM_SPEED(1500000),
207 TERM_SPEED(2000000),
208 TERM_SPEED(2500000),
209 TERM_SPEED(3000000),
210 TERM_SPEED(3500000),
211 TERM_SPEED(4000000),
212};
213
214int config_parse_baud(speed_t *speed, const char *baud_string)
215{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700216 size_t i;
217
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800218 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700219 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
220 *speed = terminal_speeds[i].speed;
221 return 0;
222 }
223 }
224 return -1;
225}
226
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800227uint32_t parse_baud_to_int(speed_t speed)
228{
229 size_t i;
230
231 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
232 if (terminal_speeds[i].speed == speed) {
233 return terminal_speeds[i].baud;
234 }
235 }
236 return 0;
237}
238
239speed_t parse_int_to_baud(uint32_t baud)
240{
241 size_t i;
242
243 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
244 if (terminal_speeds[i].baud == baud) {
245 return terminal_speeds[i].speed;
246 }
247 }
248 return 0;
249}
250
Kun Yi6424cc32018-06-14 14:09:28 -0700251int config_parse_logsize(const char *size_str, size_t *size)
252{
253 struct size_suffix_shift {
254 /* Left shiftwidth corresponding to the suffix. */
255 size_t shiftwidth;
256 int unit;
257 };
258
259 const struct size_suffix_shift suffixes[] = {
260 { 10, 'k' },
261 { 20, 'M' },
262 { 30, 'G' },
263 };
264 const size_t num_suffixes = sizeof(suffixes) /
265 sizeof(struct size_suffix_shift);
266 size_t logsize;
267 char *suffix;
268 size_t i;
269
270 if (!size_str)
271 return -1;
272
273 logsize = strtoul(size_str, &suffix, 0);
274 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str)
275 return -1;
276
277 /* Ignore spaces between number and suffix */
278 while (*suffix && isspace(*suffix))
279 suffix++;
280
281 for (i = 0; i < num_suffixes; i++) {
282 if (*suffix == suffixes[i].unit) {
283 /*
284 * If logsize overflows, probably something was wrong.
285 * Return instead of clamping to an arbitrary value.
286 */
287 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth))
288 return -1;
289
290 logsize <<= suffixes[i].shiftwidth;
291 suffix++;
292 break;
293 }
294 }
295
296 /* Allow suffix like 'kB' */
297 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix)))
298 suffix++;
299
300 if (*suffix) {
301 warn("Invalid suffix!");
302 return -1;
303 }
304
305 *size = logsize;
306 return 0;
307}
308
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800309#ifdef CONFIG_TEST
310int main(void)
311{
312 struct config_item *item;
313 struct config *config;
314
315 config = config_init_fd(STDIN_FILENO, "<stdin>");
316 if (!config)
317 return EXIT_FAILURE;
318
319 for (item = config->items; item; item = item->next)
320 printf("%s: %s\n", item->name, item->value);
321
322 config_fini(config);
323
324 return EXIT_SUCCESS;
325
326}
327#endif