xref: /openbmc/obmc-console/config.c (revision e3f1aa1e)
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 <errno.h>
20 #include <fcntl.h>
21 #include <limits.h>
22 #include <stdint.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <strings.h>
27 #include <termios.h> /* for speed_t */
28 #include <unistd.h>
29 
30 #include <sys/mman.h>
31 #include <sys/stat.h>
32 
33 #include <iniparser/iniparser.h>
34 
35 #include "config.h"
36 #include "config-internal.h"
37 #include "util.h"
38 
39 static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
40 
41 const char *config_get_value(struct config *config, const char *name)
42 {
43 	char buf[CONFIG_MAX_KEY_LENGTH];
44 	int rc;
45 
46 	if (!config->dict) {
47 		return NULL;
48 	}
49 
50 	rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name);
51 	if (rc < 0) {
52 		return NULL;
53 	}
54 
55 	if ((size_t)rc >= sizeof(buf)) {
56 		return NULL;
57 	}
58 
59 	const char *value = iniparser_getstring(config->dict, buf, NULL);
60 	if (value && strlen(value) == 0) {
61 		return NULL;
62 	}
63 
64 	return value;
65 }
66 
67 struct config *config_init(const char *filename)
68 {
69 	struct config *config;
70 	dictionary *dict;
71 
72 	if (!filename) {
73 		filename = config_default_filename;
74 	}
75 
76 	if (access(filename, R_OK) == 0) {
77 		dict = iniparser_load(filename);
78 		if (!dict) {
79 			/* Assume this is a parse failure */
80 			return NULL;
81 		}
82 	} else {
83 		/* If a config file was explicitly specified, then lack of access is always an error */
84 		if (filename != config_default_filename) {
85 			warn("Failed to open configuration file at '%s'",
86 			     filename);
87 			return NULL;
88 		}
89 
90 		/* For the default config path, any result other than not-present is an error */
91 		if (errno != ENOENT && errno != ENOTDIR) {
92 			warn("Failed to open configuration file at '%s'",
93 			     filename);
94 			return NULL;
95 		}
96 
97 		/* Config not present at default path, pretend its empty */
98 		dict = NULL;
99 	}
100 
101 	config = malloc(sizeof(*config));
102 	if (!config) {
103 		iniparser_freedict(dict);
104 		return NULL;
105 	}
106 
107 	config->dict = dict;
108 
109 	return config;
110 }
111 
112 void config_fini(struct config *config)
113 {
114 	if (!config) {
115 		return;
116 	}
117 
118 	if (config->dict) {
119 		iniparser_freedict(config->dict);
120 	}
121 
122 	free(config);
123 }
124 
125 struct terminal_speed_name {
126 	speed_t speed;
127 	uint32_t baud;
128 	const char *name;
129 };
130 
131 #define TERM_SPEED(x)                                                          \
132 	{                                                                      \
133 		B##x, x, #x                                                    \
134 	}
135 
136 // clang-format off
137 static const struct terminal_speed_name terminal_speeds[] = {
138 	TERM_SPEED(50),
139 	TERM_SPEED(75),
140 	TERM_SPEED(110),
141 	TERM_SPEED(134),
142 	TERM_SPEED(150),
143 	TERM_SPEED(200),
144 	TERM_SPEED(300),
145 	TERM_SPEED(600),
146 	TERM_SPEED(1200),
147 	TERM_SPEED(1800),
148 	TERM_SPEED(2400),
149 	TERM_SPEED(4800),
150 	TERM_SPEED(9600),
151 	TERM_SPEED(19200),
152 	TERM_SPEED(38400),
153 	TERM_SPEED(57600),
154 	TERM_SPEED(115200),
155 	TERM_SPEED(230400),
156 	TERM_SPEED(460800),
157 	TERM_SPEED(500000),
158 	TERM_SPEED(576000),
159 	TERM_SPEED(921600),
160 	TERM_SPEED(1000000),
161 	TERM_SPEED(1152000),
162 	TERM_SPEED(1500000),
163 	TERM_SPEED(2000000),
164 	TERM_SPEED(2500000),
165 	TERM_SPEED(3000000),
166 	TERM_SPEED(3500000),
167 	TERM_SPEED(4000000),
168 };
169 // clang-format on
170 
171 int config_parse_baud(speed_t *speed, const char *baud_string)
172 {
173 	size_t i;
174 
175 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
176 		if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
177 			*speed = terminal_speeds[i].speed;
178 			return 0;
179 		}
180 	}
181 	return -1;
182 }
183 
184 uint32_t parse_baud_to_int(speed_t speed)
185 {
186 	size_t i;
187 
188 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
189 		if (terminal_speeds[i].speed == speed) {
190 			return terminal_speeds[i].baud;
191 		}
192 	}
193 	return 0;
194 }
195 
196 speed_t parse_int_to_baud(uint32_t baud)
197 {
198 	size_t i;
199 
200 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
201 		if (terminal_speeds[i].baud == baud) {
202 			return terminal_speeds[i].speed;
203 		}
204 	}
205 	return 0;
206 }
207 
208 int config_parse_bytesize(const char *size_str, size_t *size)
209 {
210 	struct size_suffix_shift {
211 		/* Left shiftwidth corresponding to the suffix. */
212 		size_t shiftwidth;
213 		int unit;
214 	};
215 
216 	const struct size_suffix_shift suffixes[] = {
217 		{ 10, 'k' },
218 		{ 20, 'M' },
219 		{ 30, 'G' },
220 	};
221 	const size_t num_suffixes =
222 		sizeof(suffixes) / sizeof(struct size_suffix_shift);
223 	size_t logsize;
224 	char *suffix;
225 	size_t i;
226 
227 	if (!size_str) {
228 		return -1;
229 	}
230 
231 	logsize = strtoul(size_str, &suffix, 0);
232 	if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
233 		return -1;
234 	}
235 
236 	/* Ignore spaces between number and suffix */
237 	while (*suffix && isspace(*suffix)) {
238 		suffix++;
239 	}
240 
241 	for (i = 0; i < num_suffixes; i++) {
242 		if (*suffix == suffixes[i].unit) {
243 			/*
244 			 * If logsize overflows, probably something was wrong.
245 			 * Return instead of clamping to an arbitrary value.
246 			 */
247 			if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
248 				return -1;
249 			}
250 
251 			logsize <<= suffixes[i].shiftwidth;
252 			suffix++;
253 			break;
254 		}
255 	}
256 
257 	/* Allow suffix like 'kB' */
258 	while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
259 		suffix++;
260 	}
261 
262 	if (*suffix) {
263 		warn("Invalid suffix!");
264 		return -1;
265 	}
266 
267 	*size = logsize;
268 	return 0;
269 }
270 
271 /* Default console id if not specified on command line or in config */
272 #define DEFAULT_CONSOLE_ID "default"
273 
274 /* Get the console id */
275 const char *config_resolve_console_id(struct config *config, const char *id_arg)
276 {
277 	const char *configured;
278 
279 	if (id_arg) {
280 		return id_arg;
281 	}
282 
283 	if ((configured = config_get_value(config, "console-id"))) {
284 		return configured;
285 	}
286 
287 	return DEFAULT_CONSOLE_ID;
288 }
289