xref: /openbmc/obmc-console/config.c (revision 9836e2b3)
1 /**
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  */
16 
17 #include <ctype.h>
18 #include <err.h>
19 #include <fcntl.h>
20 #include <limits.h>
21 #include <stdint.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <strings.h>
26 #include <termios.h> /* for speed_t */
27 #include <unistd.h>
28 
29 #include <sys/mman.h>
30 #include <sys/stat.h>
31 #include "console-server.h"
32 
33 static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
34 
35 struct config_item {
36 	char			*name;
37 	char			*value;
38 	struct config_item	*next;
39 };
40 
41 struct config {
42 	struct config_item	*items;
43 };
44 
45 const 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 
56 static 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 
92 static struct config *config_init_fd(int fd, const char *filename)
93 {
94 	struct config *config;
95 	size_t size, len;
96 	char *buf;
97 	int rc;
98 
99 	size = 4096;
100 	len = 0;
101 	buf = malloc(size + 1);
102 	config = NULL;
103 
104 	for (;;) {
105 		rc = read(fd, buf + len, size - len);
106 		if (rc < 0) {
107 			warn("Can't read from configuration file %s", filename);
108 			goto out_free;
109 
110 		} else if (!rc) {
111 			break;
112 		}
113 		len += rc;
114 		if (len == size) {
115 			size <<= 1;
116 			buf = realloc(buf, size + 1);
117 		}
118 
119 	}
120 	buf[len] = '\0';
121 
122 	config = malloc(sizeof(*config));
123 	config->items = NULL;
124 
125 	config_parse(config, buf);
126 
127 out_free:
128 	free(buf);
129 	return config;
130 }
131 
132 struct 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);
149 
150 	return config;
151 }
152 
153 void 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 }
166 
167 struct terminal_speed_name {
168 	speed_t		speed;
169 	uint32_t	baud;
170 	const char	*name;
171 };
172 
173 #define TERM_SPEED(x) { B##x, x, #x}
174 
175 static 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 
208 int config_parse_baud(speed_t *speed, const char *baud_string)
209 {
210 	size_t i;
211 
212 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
213 		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 
221 uint32_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 
233 speed_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 
245 int 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 
303 #ifdef CONFIG_TEST
304 int 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
322