xref: /openbmc/obmc-console/config.c (revision 4ec26bb16e3a8ef10b4c00a50605c70e2a5c228b)
19326d779SJeremy Kerr /**
29326d779SJeremy Kerr  * Copyright © 2016 IBM Corporation
39326d779SJeremy Kerr  *
49326d779SJeremy Kerr  * Licensed under the Apache License, Version 2.0 (the "License");
59326d779SJeremy Kerr  * you may not use this file except in compliance with the License.
69326d779SJeremy Kerr  * You may obtain a copy of the License at
79326d779SJeremy Kerr  *
89326d779SJeremy Kerr  *     http://www.apache.org/licenses/LICENSE-2.0
99326d779SJeremy Kerr  *
109326d779SJeremy Kerr  * Unless required by applicable law or agreed to in writing, software
119326d779SJeremy Kerr  * distributed under the License is distributed on an "AS IS" BASIS,
129326d779SJeremy Kerr  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139326d779SJeremy Kerr  * See the License for the specific language governing permissions and
149326d779SJeremy Kerr  * limitations under the License.
159326d779SJeremy Kerr  */
16d66195c1SJeremy Kerr 
176424cc3bSKun Yi #include <ctype.h>
18d66195c1SJeremy Kerr #include <err.h>
19d30d7573SAndrew Jeffery #include <errno.h>
20d66195c1SJeremy Kerr #include <fcntl.h>
216424cc3bSKun Yi #include <limits.h>
22d66195c1SJeremy Kerr #include <stdint.h>
23d66195c1SJeremy Kerr #include <stdio.h>
24d66195c1SJeremy Kerr #include <stdlib.h>
25d66195c1SJeremy Kerr #include <string.h>
26d66195c1SJeremy Kerr #include <strings.h>
27fcbdea9cSBenjamin Fair #include <termios.h> /* for speed_t */
28d66195c1SJeremy Kerr #include <unistd.h>
29d66195c1SJeremy Kerr 
30d66195c1SJeremy Kerr #include <sys/mman.h>
31d66195c1SJeremy Kerr #include <sys/stat.h>
321e04f449SAlexander Hansen 
331e04f449SAlexander Hansen #include <iniparser/iniparser.h>
341e04f449SAlexander Hansen 
351e04f449SAlexander Hansen #include "config-internal.h"
36e3a083ebSAlexander Hansen #include "config.h"
37e3f1aa1eSAlexander Hansen #include "util.h"
38d66195c1SJeremy Kerr 
39e440a407SJeremy Kerr static const char *config_default_filename = SYSCONFDIR "/obmc-console.conf";
40d66195c1SJeremy Kerr 
config_get_value(struct config * config,const char * name)41d66195c1SJeremy Kerr const char *config_get_value(struct config *config, const char *name)
42d66195c1SJeremy Kerr {
431e04f449SAlexander Hansen 	char buf[CONFIG_MAX_KEY_LENGTH];
44d659cfcdSAndrew Jeffery 	int rc;
45d66195c1SJeremy Kerr 
46*4ec26bb1SIgor Kononenko 	if (!config || !config->dict) {
47d659cfcdSAndrew Jeffery 		return NULL;
48d659cfcdSAndrew Jeffery 	}
49d659cfcdSAndrew Jeffery 
50d659cfcdSAndrew Jeffery 	rc = snprintf(buf, CONFIG_MAX_KEY_LENGTH, ":%s", name);
51d66195c1SJeremy Kerr 	if (rc < 0) {
521e04f449SAlexander Hansen 		return NULL;
53d66195c1SJeremy Kerr 	}
541e04f449SAlexander Hansen 
551e04f449SAlexander Hansen 	if ((size_t)rc >= sizeof(buf)) {
561e04f449SAlexander Hansen 		return NULL;
572eb56f55SJeremy Kerr 	}
581e04f449SAlexander Hansen 
591e04f449SAlexander Hansen 	const char *value = iniparser_getstring(config->dict, buf, NULL);
601e04f449SAlexander Hansen 	if (value && strlen(value) == 0) {
611e04f449SAlexander Hansen 		return NULL;
62d66195c1SJeremy Kerr 	}
63d66195c1SJeremy Kerr 
641e04f449SAlexander Hansen 	return value;
656c8d781cSJeremy Kerr }
666c8d781cSJeremy Kerr 
config_init(const char * filename)676c8d781cSJeremy Kerr struct config *config_init(const char *filename)
686c8d781cSJeremy Kerr {
696c8d781cSJeremy Kerr 	struct config *config;
70d659cfcdSAndrew Jeffery 	dictionary *dict;
716c8d781cSJeremy Kerr 
722834c5b1SAndrew Jeffery 	if (!filename) {
736c8d781cSJeremy Kerr 		filename = config_default_filename;
742834c5b1SAndrew Jeffery 	}
756c8d781cSJeremy Kerr 
76d659cfcdSAndrew Jeffery 	if (access(filename, R_OK) == 0) {
77d659cfcdSAndrew Jeffery 		dict = iniparser_load(filename);
78d659cfcdSAndrew Jeffery 		if (!dict) {
79d659cfcdSAndrew Jeffery 			/* Assume this is a parse failure */
806c8d781cSJeremy Kerr 			return NULL;
816c8d781cSJeremy Kerr 		}
82d659cfcdSAndrew Jeffery 	} else {
83d659cfcdSAndrew Jeffery 		/* If a config file was explicitly specified, then lack of access is always an error */
84d659cfcdSAndrew Jeffery 		if (filename != config_default_filename) {
85d659cfcdSAndrew Jeffery 			warn("Failed to open configuration file at '%s'",
86d659cfcdSAndrew Jeffery 			     filename);
871e04f449SAlexander Hansen 			return NULL;
881e04f449SAlexander Hansen 		}
891e04f449SAlexander Hansen 
90d659cfcdSAndrew Jeffery 		/* For the default config path, any result other than not-present is an error */
91d659cfcdSAndrew Jeffery 		if (errno != ENOENT && errno != ENOTDIR) {
92d659cfcdSAndrew Jeffery 			warn("Failed to open configuration file at '%s'",
93d659cfcdSAndrew Jeffery 			     filename);
94d659cfcdSAndrew Jeffery 			return NULL;
95d659cfcdSAndrew Jeffery 		}
96d659cfcdSAndrew Jeffery 
97d659cfcdSAndrew Jeffery 		/* Config not present at default path, pretend its empty */
98d659cfcdSAndrew Jeffery 		dict = NULL;
99d659cfcdSAndrew Jeffery 	}
100d659cfcdSAndrew Jeffery 
1011e04f449SAlexander Hansen 	config = malloc(sizeof(*config));
102d659cfcdSAndrew Jeffery 	if (!config) {
103d659cfcdSAndrew Jeffery 		iniparser_freedict(dict);
104d659cfcdSAndrew Jeffery 		return NULL;
1051e04f449SAlexander Hansen 	}
1061e04f449SAlexander Hansen 
107d659cfcdSAndrew Jeffery 	config->dict = dict;
108d659cfcdSAndrew Jeffery 
109d66195c1SJeremy Kerr 	return config;
110d66195c1SJeremy Kerr }
111d66195c1SJeremy Kerr 
config_get_section_value(struct config * config,const char * secname,const char * name)112e3a083ebSAlexander Hansen const char *config_get_section_value(struct config *config, const char *secname,
113e3a083ebSAlexander Hansen 				     const char *name)
114e3a083ebSAlexander Hansen {
115e3a083ebSAlexander Hansen 	char buf[CONFIG_MAX_KEY_LENGTH];
116e3a083ebSAlexander Hansen 	int rc;
117e3a083ebSAlexander Hansen 
118e3a083ebSAlexander Hansen 	rc = snprintf(buf, sizeof(buf), "%s:%s", secname, name);
119e3a083ebSAlexander Hansen 	if (rc < 0) {
120e3a083ebSAlexander Hansen 		return NULL;
121e3a083ebSAlexander Hansen 	}
122e3a083ebSAlexander Hansen 
123e3a083ebSAlexander Hansen 	if ((size_t)rc >= sizeof(buf)) {
124e3a083ebSAlexander Hansen 		// error / key too long for the buffer
125e3a083ebSAlexander Hansen 		warnx("config: section:key too long for buffer: '%s':'%s'",
126e3a083ebSAlexander Hansen 		      secname, name);
127e3a083ebSAlexander Hansen 		return NULL;
128e3a083ebSAlexander Hansen 	}
129e3a083ebSAlexander Hansen 
130e3a083ebSAlexander Hansen 	return iniparser_getstring(config->dict, buf, NULL);
131e3a083ebSAlexander Hansen }
132e3a083ebSAlexander Hansen 
config_fini(struct config * config)133d66195c1SJeremy Kerr void config_fini(struct config *config)
134d66195c1SJeremy Kerr {
135ba2af969SAndrew Jeffery 	if (!config) {
136ba2af969SAndrew Jeffery 		return;
137ba2af969SAndrew Jeffery 	}
138ba2af969SAndrew Jeffery 
1391e04f449SAlexander Hansen 	if (config->dict) {
1401e04f449SAlexander Hansen 		iniparser_freedict(config->dict);
141d66195c1SJeremy Kerr 	}
142d66195c1SJeremy Kerr 
143d66195c1SJeremy Kerr 	free(config);
144d66195c1SJeremy Kerr }
1456c8d781cSJeremy Kerr 
146fcbdea9cSBenjamin Fair struct terminal_speed_name {
147fcbdea9cSBenjamin Fair 	speed_t speed;
148f9c8f6caSCheng C Yang 	uint32_t baud;
149fcbdea9cSBenjamin Fair 	const char *name;
150fcbdea9cSBenjamin Fair };
151fcbdea9cSBenjamin Fair 
152b965c220SPatrick Williams #define TERM_SPEED(x) { B##x, x, #x }
153f9c8f6caSCheng C Yang 
154a72711afSAndrew Jeffery // clang-format off
155f9c8f6caSCheng C Yang static const struct terminal_speed_name terminal_speeds[] = {
156f9c8f6caSCheng C Yang 	TERM_SPEED(50),
157f9c8f6caSCheng C Yang 	TERM_SPEED(75),
158f9c8f6caSCheng C Yang 	TERM_SPEED(110),
159f9c8f6caSCheng C Yang 	TERM_SPEED(134),
160f9c8f6caSCheng C Yang 	TERM_SPEED(150),
161f9c8f6caSCheng C Yang 	TERM_SPEED(200),
162f9c8f6caSCheng C Yang 	TERM_SPEED(300),
163f9c8f6caSCheng C Yang 	TERM_SPEED(600),
164f9c8f6caSCheng C Yang 	TERM_SPEED(1200),
165f9c8f6caSCheng C Yang 	TERM_SPEED(1800),
166f9c8f6caSCheng C Yang 	TERM_SPEED(2400),
167f9c8f6caSCheng C Yang 	TERM_SPEED(4800),
168f9c8f6caSCheng C Yang 	TERM_SPEED(9600),
169f9c8f6caSCheng C Yang 	TERM_SPEED(19200),
170f9c8f6caSCheng C Yang 	TERM_SPEED(38400),
171f9c8f6caSCheng C Yang 	TERM_SPEED(57600),
172f9c8f6caSCheng C Yang 	TERM_SPEED(115200),
173f9c8f6caSCheng C Yang 	TERM_SPEED(230400),
174f9c8f6caSCheng C Yang 	TERM_SPEED(460800),
175f9c8f6caSCheng C Yang 	TERM_SPEED(500000),
176f9c8f6caSCheng C Yang 	TERM_SPEED(576000),
177f9c8f6caSCheng C Yang 	TERM_SPEED(921600),
178f9c8f6caSCheng C Yang 	TERM_SPEED(1000000),
179f9c8f6caSCheng C Yang 	TERM_SPEED(1152000),
180f9c8f6caSCheng C Yang 	TERM_SPEED(1500000),
181f9c8f6caSCheng C Yang 	TERM_SPEED(2000000),
182f9c8f6caSCheng C Yang 	TERM_SPEED(2500000),
183f9c8f6caSCheng C Yang 	TERM_SPEED(3000000),
184f9c8f6caSCheng C Yang 	TERM_SPEED(3500000),
185f9c8f6caSCheng C Yang 	TERM_SPEED(4000000),
186fcbdea9cSBenjamin Fair };
187a72711afSAndrew Jeffery // clang-format on
188f9c8f6caSCheng C Yang 
config_parse_baud(speed_t * speed,const char * baud_string)189f9c8f6caSCheng C Yang int config_parse_baud(speed_t *speed, const char *baud_string)
190f9c8f6caSCheng C Yang {
191fcbdea9cSBenjamin Fair 	size_t i;
192fcbdea9cSBenjamin Fair 
193f9c8f6caSCheng C Yang 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
194fcbdea9cSBenjamin Fair 		if (strcmp(baud_string, terminal_speeds[i].name) == 0) {
195fcbdea9cSBenjamin Fair 			*speed = terminal_speeds[i].speed;
196fcbdea9cSBenjamin Fair 			return 0;
197fcbdea9cSBenjamin Fair 		}
198fcbdea9cSBenjamin Fair 	}
199fcbdea9cSBenjamin Fair 	return -1;
200fcbdea9cSBenjamin Fair }
201fcbdea9cSBenjamin Fair 
parse_baud_to_int(speed_t speed)202f9c8f6caSCheng C Yang uint32_t parse_baud_to_int(speed_t speed)
203f9c8f6caSCheng C Yang {
204f9c8f6caSCheng C Yang 	size_t i;
205f9c8f6caSCheng C Yang 
206f9c8f6caSCheng C Yang 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
207f9c8f6caSCheng C Yang 		if (terminal_speeds[i].speed == speed) {
208f9c8f6caSCheng C Yang 			return terminal_speeds[i].baud;
209f9c8f6caSCheng C Yang 		}
210f9c8f6caSCheng C Yang 	}
211f9c8f6caSCheng C Yang 	return 0;
212f9c8f6caSCheng C Yang }
213f9c8f6caSCheng C Yang 
parse_int_to_baud(uint32_t baud)214f9c8f6caSCheng C Yang speed_t parse_int_to_baud(uint32_t baud)
215f9c8f6caSCheng C Yang {
216f9c8f6caSCheng C Yang 	size_t i;
217f9c8f6caSCheng C Yang 
218f9c8f6caSCheng C Yang 	for (i = 0; i < ARRAY_SIZE(terminal_speeds); i++) {
219f9c8f6caSCheng C Yang 		if (terminal_speeds[i].baud == baud) {
220f9c8f6caSCheng C Yang 			return terminal_speeds[i].speed;
221f9c8f6caSCheng C Yang 		}
222f9c8f6caSCheng C Yang 	}
223f9c8f6caSCheng C Yang 	return 0;
224f9c8f6caSCheng C Yang }
225f9c8f6caSCheng C Yang 
config_parse_bytesize(const char * size_str,size_t * size)226d6e8b64aSMedicine Yeh int config_parse_bytesize(const char *size_str, size_t *size)
2276424cc3bSKun Yi {
2286424cc3bSKun Yi 	struct size_suffix_shift {
2296424cc3bSKun Yi 		/* Left shiftwidth corresponding to the suffix. */
2306424cc3bSKun Yi 		size_t shiftwidth;
2316424cc3bSKun Yi 		int unit;
2326424cc3bSKun Yi 	};
2336424cc3bSKun Yi 
2346424cc3bSKun Yi 	const struct size_suffix_shift suffixes[] = {
2356424cc3bSKun Yi 		{ 10, 'k' },
2366424cc3bSKun Yi 		{ 20, 'M' },
2376424cc3bSKun Yi 		{ 30, 'G' },
2386424cc3bSKun Yi 	};
239a72711afSAndrew Jeffery 	const size_t num_suffixes =
240a72711afSAndrew Jeffery 		sizeof(suffixes) / sizeof(struct size_suffix_shift);
2416424cc3bSKun Yi 	size_t logsize;
2426424cc3bSKun Yi 	char *suffix;
2436424cc3bSKun Yi 	size_t i;
2446424cc3bSKun Yi 
2452834c5b1SAndrew Jeffery 	if (!size_str) {
2466424cc3bSKun Yi 		return -1;
2472834c5b1SAndrew Jeffery 	}
2486424cc3bSKun Yi 
2496424cc3bSKun Yi 	logsize = strtoul(size_str, &suffix, 0);
2502834c5b1SAndrew Jeffery 	if (logsize == 0 || logsize >= UINT32_MAX || suffix == size_str) {
2516424cc3bSKun Yi 		return -1;
2522834c5b1SAndrew Jeffery 	}
2536424cc3bSKun Yi 
2546424cc3bSKun Yi 	/* Ignore spaces between number and suffix */
2552834c5b1SAndrew Jeffery 	while (*suffix && isspace(*suffix)) {
2566424cc3bSKun Yi 		suffix++;
2572834c5b1SAndrew Jeffery 	}
2586424cc3bSKun Yi 
2596424cc3bSKun Yi 	for (i = 0; i < num_suffixes; i++) {
2606424cc3bSKun Yi 		if (*suffix == suffixes[i].unit) {
2616424cc3bSKun Yi 			/*
2626424cc3bSKun Yi 			 * If logsize overflows, probably something was wrong.
2636424cc3bSKun Yi 			 * Return instead of clamping to an arbitrary value.
2646424cc3bSKun Yi 			 */
2652834c5b1SAndrew Jeffery 			if (logsize > (UINT32_MAX >> suffixes[i].shiftwidth)) {
2666424cc3bSKun Yi 				return -1;
2672834c5b1SAndrew Jeffery 			}
2686424cc3bSKun Yi 
2696424cc3bSKun Yi 			logsize <<= suffixes[i].shiftwidth;
2706424cc3bSKun Yi 			suffix++;
2716424cc3bSKun Yi 			break;
2726424cc3bSKun Yi 		}
2736424cc3bSKun Yi 	}
2746424cc3bSKun Yi 
2756424cc3bSKun Yi 	/* Allow suffix like 'kB' */
2762834c5b1SAndrew Jeffery 	while (*suffix && (tolower(*suffix) == 'b' || isspace(*suffix))) {
2776424cc3bSKun Yi 		suffix++;
2782834c5b1SAndrew Jeffery 	}
2796424cc3bSKun Yi 
2806424cc3bSKun Yi 	if (*suffix) {
2816424cc3bSKun Yi 		warn("Invalid suffix!");
2826424cc3bSKun Yi 		return -1;
2836424cc3bSKun Yi 	}
2846424cc3bSKun Yi 
2856424cc3bSKun Yi 	*size = logsize;
2866424cc3bSKun Yi 	return 0;
2876424cc3bSKun Yi }
2886424cc3bSKun Yi 
2895ba20b5bSNinad Palsule /* Default console id if not specified on command line or in config */
2905ba20b5bSNinad Palsule #define DEFAULT_CONSOLE_ID "default"
2915ba20b5bSNinad Palsule 
2925ba20b5bSNinad Palsule /* Get the console id */
config_resolve_console_id(struct config * config,const char * id_arg)2935ba20b5bSNinad Palsule const char *config_resolve_console_id(struct config *config, const char *id_arg)
2945ba20b5bSNinad Palsule {
2955ba20b5bSNinad Palsule 	const char *configured;
2965ba20b5bSNinad Palsule 
2975ba20b5bSNinad Palsule 	if (id_arg) {
2985ba20b5bSNinad Palsule 		return id_arg;
2995ba20b5bSNinad Palsule 	}
3005ba20b5bSNinad Palsule 
3015ba20b5bSNinad Palsule 	if ((configured = config_get_value(config, "console-id"))) {
3025ba20b5bSNinad Palsule 		return configured;
3035ba20b5bSNinad Palsule 	}
3045ba20b5bSNinad Palsule 
3055ba20b5bSNinad Palsule 	return DEFAULT_CONSOLE_ID;
3065ba20b5bSNinad Palsule }
307e3a083ebSAlexander Hansen 
config_count_sections(struct config * config)308e3a083ebSAlexander Hansen int config_count_sections(struct config *config)
309e3a083ebSAlexander Hansen {
310e3a083ebSAlexander Hansen 	return iniparser_getnsec(config->dict);
311e3a083ebSAlexander Hansen }
312e3a083ebSAlexander Hansen 
config_get_section_name(struct config * config,int i)313e3a083ebSAlexander Hansen const char *config_get_section_name(struct config *config, int i)
314e3a083ebSAlexander Hansen {
315e3a083ebSAlexander Hansen 	return iniparser_getsecname(config->dict, i);
316e3a083ebSAlexander Hansen }
317