blob: 51ab0f3b3fe87da888022ee70b50204485f62854 [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>
19#include <fcntl.h>
Kun Yi6424cc32018-06-14 14:09:28 -070020#include <limits.h>
Jeremy Kerrd66195c2016-03-16 17:24:51 +080021#include <stdint.h>
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <strings.h>
Benjamin Fairfcbdea92018-06-04 14:19:25 -070026#include <termios.h> /* for speed_t */
Jeremy Kerrd66195c2016-03-16 17:24:51 +080027#include <unistd.h>
28
29#include <sys/mman.h>
30#include <sys/stat.h>
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +080031#include "console-server.h"
Jeremy Kerrd66195c2016-03-16 17:24:51 +080032
Jeremy Kerre440a402016-03-17 16:34:14 +080033static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
Jeremy Kerrd66195c2016-03-16 17:24:51 +080034
35struct config_item {
36 char *name;
37 char *value;
38 struct config_item *next;
39};
40
41struct config {
42 struct config_item *items;
43};
44
45const char *config_get_value(struct config *config, const char *name)
46{
47 struct config_item *item;
48
49 for (item = config->items; item; item = item->next)
50 if (!strcasecmp(item->name, name))
51 return item->value;
52
53 return NULL;
54}
55
56static void config_parse(struct config *config, char *buf)
57{
58 struct config_item *item;
59 char *name, *value;
60 char *p, *line;
61 int rc;
62
63 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
64 line = strtok_r(NULL, "\n", &p)) {
65
66 /* trim leading space */
67 for (;*line == ' ' || *line == '\t'; line++)
68 ;
69
70 /* skip comments */
71 if (*line == '#')
72 continue;
73
74 name = value = NULL;
75
76 rc = sscanf(line, "%m[^ =] = %ms ", &name, &value);
77 if (rc != 2 || !strlen(name) || !strlen(value)) {
78 free(name);
79 free(value);
80 continue;
81 }
82
83 /* create a new item and add to our list */
84 item = malloc(sizeof(*item));
85 item->name = name;
86 item->value = value;
87 item->next = config->items;
88 config->items = item;
89 }
90}
91
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080092static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +080093{
94 struct config *config;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080095 size_t size, len;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080096 char *buf;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080097 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080098
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080099 size = 4096;
100 len = 0;
101 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800102 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800103
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800104 for (;;) {
105 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800106 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800107 warn("Can't read from configuration file %s", filename);
108 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800109
110 } else if (!rc) {
111 break;
112 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800113 len += rc;
114 if (len == size) {
115 size <<= 1;
116 buf = realloc(buf, size + 1);
117 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800118
119 }
120 buf[len] = '\0';
121
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800122 config = malloc(sizeof(*config));
123 config->items = NULL;
124
125 config_parse(config, buf);
126
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800127out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800128 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800129 return config;
130}
131
132struct config *config_init(const char *filename)
133{
134 struct config *config;
135 int fd;
136
137 if (!filename)
138 filename = config_default_filename;
139
140 fd = open(filename, O_RDONLY);
141 if (fd < 0) {
142 warn("Can't open configuration file %s", filename);
143 return NULL;
144 }
145
146 config = config_init_fd(fd, filename);
147
148 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800149
150 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800151}
152
153void config_fini(struct config *config)
154{
155 struct config_item *item, *next;
156
157 for (item = config->items; item; item = next) {
158 next = item->next;
159 free(item->name);
160 free(item->value);
161 free(item);
162 }
163
164 free(config);
165}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800166
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700167struct terminal_speed_name {
168 speed_t speed;
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800169 uint32_t baud;
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700170 const char *name;
171};
172
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800173#define TERM_SPEED(x) { B##x, x, #x}
174
175static const struct terminal_speed_name terminal_speeds[] = {
176 TERM_SPEED(50),
177 TERM_SPEED(75),
178 TERM_SPEED(110),
179 TERM_SPEED(134),
180 TERM_SPEED(150),
181 TERM_SPEED(200),
182 TERM_SPEED(300),
183 TERM_SPEED(600),
184 TERM_SPEED(1200),
185 TERM_SPEED(1800),
186 TERM_SPEED(2400),
187 TERM_SPEED(4800),
188 TERM_SPEED(9600),
189 TERM_SPEED(19200),
190 TERM_SPEED(38400),
191 TERM_SPEED(57600),
192 TERM_SPEED(115200),
193 TERM_SPEED(230400),
194 TERM_SPEED(460800),
195 TERM_SPEED(500000),
196 TERM_SPEED(576000),
197 TERM_SPEED(921600),
198 TERM_SPEED(1000000),
199 TERM_SPEED(1152000),
200 TERM_SPEED(1500000),
201 TERM_SPEED(2000000),
202 TERM_SPEED(2500000),
203 TERM_SPEED(3000000),
204 TERM_SPEED(3500000),
205 TERM_SPEED(4000000),
206};
207
208int config_parse_baud(speed_t *speed, const char *baud_string)
209{
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700210 size_t i;
211
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800212 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700213 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
214 *speed = terminal_speeds[i].speed;
215 return 0;
216 }
217 }
218 return -1;
219}
220
Cheng C Yangf9c8f6c2019-03-04 18:39:52 +0800221uint32_t parse_baud_to_int(speed_t speed)
222{
223 size_t i;
224
225 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
226 if (terminal_speeds[i].speed == speed) {
227 return terminal_speeds[i].baud;
228 }
229 }
230 return 0;
231}
232
233speed_t parse_int_to_baud(uint32_t baud)
234{
235 size_t i;
236
237 for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
238 if (terminal_speeds[i].baud == baud) {
239 return terminal_speeds[i].speed;
240 }
241 }
242 return 0;
243}
244
Kun Yi6424cc32018-06-14 14:09:28 -0700245int config_parse_logsize(const char *size_str, size_t *size)
246{
247 struct size_suffix_shift {
248 /* Left shiftwidth corresponding to the suffix. */
249 size_t shiftwidth;
250 int unit;
251 };
252
253 const struct size_suffix_shift suffixes[] = {
254 { 10, 'k' },
255 { 20, 'M' },
256 { 30, 'G' },
257 };
258 const size_t num_suffixes = sizeof(suffixes) /
259 sizeof(struct size_suffix_shift);
260 size_t logsize;
261 char *suffix;
262 size_t i;
263
264 if (!size_str)
265 return -1;
266
267 logsize = strtoul(size_str, &suffix, 0);
268 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str)
269 return -1;
270
271 /* Ignore spaces between number and suffix */
272 while (*suffix && isspace(*suffix))
273 suffix++;
274
275 for (i = 0; i < num_suffixes; i++) {
276 if (*suffix == suffixes[i].unit) {
277 /*
278 * If logsize overflows, probably something was wrong.
279 * Return instead of clamping to an arbitrary value.
280 */
281 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth))
282 return -1;
283
284 logsize <<= suffixes[i].shiftwidth;
285 suffix++;
286 break;
287 }
288 }
289
290 /* Allow suffix like 'kB' */
291 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix)))
292 suffix++;
293
294 if (*suffix) {
295 warn("Invalid suffix!");
296 return -1;
297 }
298
299 *size = logsize;
300 return 0;
301}
302
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800303#ifdef CONFIG_TEST
304int main(void)
305{
306 struct config_item *item;
307 struct config *config;
308
309 config = config_init_fd(STDIN_FILENO, "<stdin>");
310 if (!config)
311 return EXIT_FAILURE;
312
313 for (item = config->items; item; item = item->next)
314 printf("%s: %s\n", item->name, item->value);
315
316 config_fini(config);
317
318 return EXIT_SUCCESS;
319
320}
321#endif