blob: f5653dc13fceabdafea09249d70ef8c80946ab6d [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>
31
Jeremy Kerre440a402016-03-17 16:34:14 +080032static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
Jeremy Kerrd66195c2016-03-16 17:24:51 +080033
34struct config_item {
35 char *name;
36 char *value;
37 struct config_item *next;
38};
39
40struct config {
41 struct config_item *items;
42};
43
44const char *config_get_value(struct config *config, const char *name)
45{
46 struct config_item *item;
47
48 for (item = config->items; item; item = item->next)
49 if (!strcasecmp(item->name, name))
50 return item->value;
51
52 return NULL;
53}
54
55static void config_parse(struct config *config, char *buf)
56{
57 struct config_item *item;
58 char *name, *value;
59 char *p, *line;
60 int rc;
61
62 for (p = NULL, line = strtok_r(buf, "\n", &p); line;
63 line = strtok_r(NULL, "\n", &p)) {
64
65 /* trim leading space */
66 for (;*line == ' ' || *line == '\t'; line++)
67 ;
68
69 /* skip comments */
70 if (*line == '#')
71 continue;
72
73 name = value = NULL;
74
75 rc = sscanf(line, "%m[^ =] = %ms ", &name, &value);
76 if (rc != 2 || !strlen(name) || !strlen(value)) {
77 free(name);
78 free(value);
79 continue;
80 }
81
82 /* create a new item and add to our list */
83 item = malloc(sizeof(*item));
84 item->name = name;
85 item->value = value;
86 item->next = config->items;
87 config->items = item;
88 }
89}
90
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080091static struct config *config_init_fd(int fd, const char *filename)
Jeremy Kerrd66195c2016-03-16 17:24:51 +080092{
93 struct config *config;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080094 size_t size, len;
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080095 char *buf;
Jeremy Kerr6c8d7812016-03-17 15:05:45 +080096 int rc;
Jeremy Kerrd66195c2016-03-16 17:24:51 +080097
Jeremy Kerr2eb56f52016-03-17 14:55:14 +080098 size = 4096;
99 len = 0;
100 buf = malloc(size + 1);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800101 config = NULL;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800102
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800103 for (;;) {
104 rc = read(fd, buf + len, size - len);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800105 if (rc < 0) {
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800106 warn("Can't read from configuration file %s", filename);
107 goto out_free;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800108
109 } else if (!rc) {
110 break;
111 }
Jeremy Kerr2eb56f52016-03-17 14:55:14 +0800112 len += rc;
113 if (len == size) {
114 size <<= 1;
115 buf = realloc(buf, size + 1);
116 }
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800117
118 }
119 buf[len] = '\0';
120
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800121 config = malloc(sizeof(*config));
122 config->items = NULL;
123
124 config_parse(config, buf);
125
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800126out_free:
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800127 free(buf);
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800128 return config;
129}
130
131struct config *config_init(const char *filename)
132{
133 struct config *config;
134 int fd;
135
136 if (!filename)
137 filename = config_default_filename;
138
139 fd = open(filename, O_RDONLY);
140 if (fd < 0) {
141 warn("Can't open configuration file %s", filename);
142 return NULL;
143 }
144
145 config = config_init_fd(fd, filename);
146
147 close(fd);
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800148
149 return config;
Jeremy Kerrd66195c2016-03-16 17:24:51 +0800150}
151
152void config_fini(struct config *config)
153{
154 struct config_item *item, *next;
155
156 for (item = config->items; item; item = next) {
157 next = item->next;
158 free(item->name);
159 free(item->value);
160 free(item);
161 }
162
163 free(config);
164}
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800165
Benjamin Fairfcbdea92018-06-04 14:19:25 -0700166struct terminal_speed_name {
167 speed_t speed;
168 const char *name;
169};
170
171int config_parse_baud(speed_t *speed, const char *baud_string) {
172 const struct terminal_speed_name terminal_speeds[] = {
173 { B50, "50" },
174 { B75, "75" },
175 { B110, "110" },
176 { B134, "134" },
177 { B150, "150" },
178 { B200, "200" },
179 { B300, "300" },
180 { B600, "600" },
181 { B1200, "1200" },
182 { B1800, "1800" },
183 { B2400, "2400" },
184 { B4800, "4800" },
185 { B9600, "9600" },
186 { B19200, "19200" },
187 { B38400, "38400" },
188 { B57600, "57600" },
189 { B115200, "115200" },
190 { B230400, "230400" },
191 { B460800, "460800" },
192 { B500000, "500000" },
193 { B576000, "576000" },
194 { B921600, "921600" },
195 { B1000000, "1000000" },
196 { B1152000, "1152000" },
197 { B1500000, "1500000" },
198 { B2000000, "2000000" },
199 { B2500000, "2500000" },
200 { B3000000, "3000000" },
201 { B3500000, "3500000" },
202 { B4000000, "4000000" },
203 };
204 const size_t num_terminal_speeds = sizeof(terminal_speeds) /
205 sizeof(struct terminal_speed_name);
206 size_t i;
207
208 for (i = 0; i < num_terminal_speeds; i++) {
209 if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
210 *speed = terminal_speeds[i].speed;
211 return 0;
212 }
213 }
214 return -1;
215}
216
Kun Yi6424cc32018-06-14 14:09:28 -0700217int config_parse_logsize(const char *size_str, size_t *size)
218{
219 struct size_suffix_shift {
220 /* Left shiftwidth corresponding to the suffix. */
221 size_t shiftwidth;
222 int unit;
223 };
224
225 const struct size_suffix_shift suffixes[] = {
226 { 10, 'k' },
227 { 20, 'M' },
228 { 30, 'G' },
229 };
230 const size_t num_suffixes = sizeof(suffixes) /
231 sizeof(struct size_suffix_shift);
232 size_t logsize;
233 char *suffix;
234 size_t i;
235
236 if (!size_str)
237 return -1;
238
239 logsize = strtoul(size_str, &suffix, 0);
240 if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str)
241 return -1;
242
243 /* Ignore spaces between number and suffix */
244 while (*suffix && isspace(*suffix))
245 suffix++;
246
247 for (i = 0; i < num_suffixes; i++) {
248 if (*suffix == suffixes[i].unit) {
249 /*
250 * If logsize overflows, probably something was wrong.
251 * Return instead of clamping to an arbitrary value.
252 */
253 if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth))
254 return -1;
255
256 logsize <<= suffixes[i].shiftwidth;
257 suffix++;
258 break;
259 }
260 }
261
262 /* Allow suffix like 'kB' */
263 while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix)))
264 suffix++;
265
266 if (*suffix) {
267 warn("Invalid suffix!");
268 return -1;
269 }
270
271 *size = logsize;
272 return 0;
273}
274
Jeremy Kerr6c8d7812016-03-17 15:05:45 +0800275#ifdef CONFIG_TEST
276int main(void)
277{
278 struct config_item *item;
279 struct config *config;
280
281 config = config_init_fd(STDIN_FILENO, "<stdin>");
282 if (!config)
283 return EXIT_FAILURE;
284
285 for (item = config->items; item; item = item->next)
286 printf("%s: %s\n", item->name, item->value);
287
288 config_fini(config);
289
290 return EXIT_SUCCESS;
291
292}
293#endif