master uint/parados / server / config.c
  1#include <limits.h>
  2#include <stdio.h>
  3#include <stdlib.h>
  4#include <string.h>
  5#include <strings.h>
  6
  7#include "config.h"
  8#include "log.h"
  9#include "users.h"
 10
 11static int load_path(const char* path);
 12static int parse_bool(const char* s, bool* out);
 13static int set_kv(const char* k, const char* v);
 14static char* trim(char* s);
 15
 16/* defaults */
 17char media_dir[4096] = "/mnt/sto/Media/";
 18char server_addr[64] = "127.0.0.1";
 19int  server_port = 8088;
 20bool verbose_log = true;
 21char cors_origin[1024] = "";
 22int http_io_timeout = 5;
 23int max_clients = 64;
 24int auth_delay = 250;
 25
 26/* Load configuration from a file path
 27   Returns 0=Success, -1=Failure */
 28static int load_path(const char* path)
 29{
 30	FILE* f = fopen(path, "r");
 31	if (!f)
 32		return -1;
 33
 34	char* line = NULL;
 35	size_t cap = 0;
 36	ssize_t n;
 37
 38	while ((n = getline(&line, &cap, f)) >= 0) {
 39		(void)n;
 40
 41		char* s = trim(line);
 42		if (s[0] == '\0')
 43			continue;
 44		if (s[0] == '#')
 45			continue;
 46
 47		char* eq = strchr(s, '=');
 48		if (!eq)
 49			continue;
 50
 51		*eq = '\0';
 52		char* k = trim(s);
 53		char* v = trim(eq + 1);
 54
 55		if (k[0] == '\0')
 56			continue;
 57
 58		if (set_kv(k, v) < 0)
 59			LOG_FIELD(true, "CONF", "Config Error", "%s=%s", k, v);
 60	}
 61
 62	free(line);
 63	fclose(f);
 64	return 0;
 65}
 66
 67/* Parse bool string value
 68   Returns 0=Success, -1=Failure */
 69static int parse_bool(const char* s, bool* out)
 70{
 71	if (!s || !out)
 72		return -1;
 73
 74	if (strcmp(s, "1") == 0 || strcasecmp(s, "true") == 0 || strcasecmp(s, "yes") == 0)
 75		*out = true;
 76	else if (strcmp(s, "0") == 0 || strcasecmp(s, "false") == 0 || strcasecmp(s, "no") == 0)
 77		*out = false;
 78	else
 79		return -1;
 80
 81	return 0;
 82}
 83
 84/* Apply a config key/value pair
 85   Returns 0=Success, -1=Failure */
 86static int set_kv(const char* k, const char* v)
 87{
 88	/* regular */
 89	if (strcmp(k, "media_dir") == 0) {
 90		snprintf(media_dir, sizeof(media_dir), "%s", v);
 91		return 0;
 92	}
 93
 94	if (strcmp(k, "server_addr") == 0) {
 95		snprintf(server_addr, sizeof(server_addr), "%s", v);
 96		return 0;
 97	}
 98
 99	if (strcmp(k, "server_port") == 0) {
100		char* end = NULL;
101		long p = strtol(v, &end, 10);
102
103		if (end == v || *end != '\0') {
104			LOG_FIELD(true, "CONF", "Config Error", "%s invalid integer '%s'", k, v);
105			return -1;
106		}
107		if (p < 1 || p > 65535) {
108			LOG_FIELD(true, "CONF", "Config Error", "server_port out of bounds (1..65535)");
109			return -1;
110		}
111
112		server_port = (int)p;
113		return 0;
114	}
115
116	if (strcmp(k, "verbose_log") == 0) {
117		bool b;
118		if (parse_bool(v, &b) < 0){
119			LOG_FIELD(true, "CONF", "Config Error", "verbose_log invalid bool \"%s\"", v);
120			return -1;
121		}
122
123		verbose_log = b;
124		return 0;
125	}
126
127	if (strcmp(k, "cors_origin") == 0) {
128		snprintf(cors_origin, sizeof(cors_origin), "%s", v);
129		return 0;
130	}
131
132	if (strcmp(k, "http_io_timeout") == 0) {
133		char* end = NULL;
134		long t = strtol(v, &end, 10);
135
136		if (end == v || *end != '\0') {
137			LOG_FIELD(true, "CONF", "Config Error", "%s invalid integer '%s'", k, v);
138			return -1;
139		}
140		if (t < 1 || t > 300) {
141			LOG_FIELD(true, "CONF", "Config Error", "http_io_timeout too %s (1..300)", t > 300 ? "high" : "low");
142			return -1;
143		}
144
145		http_io_timeout = (int)t;
146		return 0;
147	}
148
149	if (strcmp(k, "max_clients") == 0) {
150		char* end = NULL;
151		long n = strtol(v, &end, 10);
152
153		if (end == v || *end != '\0') {
154			LOG_FIELD(true, "CONF", "Config Error", "%s invalid integer '%s'", k, v);
155			return -1;
156		}
157		if (n < 1 || n > 1024) {
158			LOG_FIELD(true, "CONF", "Config Error", "max_clients too %s (1..1024)", n > 1024 ? "high" : "low");
159			return -1;
160		}
161
162		max_clients = (int)n;
163		return 0;
164	}
165
166	if (strcmp(k, "auth_delay") == 0) {
167		char* end = NULL;
168		long n = strtol(v, &end, 10);
169
170		if (end == v || *end != '\0') {
171			LOG_FIELD(true, "CONF", "Config Error", "%s invalid integer '%s'", k, v);
172			return -1;
173		}
174		if (n < 0 || n > INT_MAX) {
175			LOG_FIELD(true, "CONF", "Config Error", "auth_delay out of bounds (0..%d)", INT_MAX);
176			return -1;
177		}
178
179		auth_delay = (int)n;
180		return 0;
181	}
182
183	/* auth */
184	if (strcmp(k, "user") == 0) {
185		int r = users_push(v);
186		if (r < 0)
187			LOG_FIELD(true, "CONF", "Config Error", "user invalid '%s'", v);
188		return r;
189	}
190
191	if (strcmp(k, "pass") == 0) {
192		int r = users_set_pass(v);
193		if (r < 0)
194			LOG_FIELD(true, "CONF", "Config Error", "pass invalid '%s'", v);
195		return r;
196	}
197
198	if (strcmp(k, "allow") == 0) {
199		int r = users_add_allow(v);
200		if (r < 0)
201			LOG_FIELD(true, "CONF", "Config Error", "allow invalid '%s'", v);
202		return r;
203	}
204
205	/* unknown key */
206	LOG_FIELD(true, "CONF", "Unknown Key Value", "%s=%s", k, v);
207	return 0;
208}
209
210/* Trim leading and trailing whitespace
211   Returns Ptr to trimmed string */
212static char* trim(char* s)
213{
214	while (*s && (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n'))
215		s++;
216
217	char* e = s + strlen(s);
218	while (e > s) {
219		char c = e[-1];
220		if (c != ' ' && c != '\t' && c != '\r' && c != '\n')
221			break;
222		e--;
223	}
224	*e = '\0';
225	return s;
226}
227
228void config_load(void)
229{
230	const char* e = getenv("PARADOS_CONFIG");
231	const char* path = "";
232	if (e && e[0]) {
233		(void)load_path(e);
234		path = e;
235		goto log;
236	}
237
238	if (load_path("/etc/parados.conf") == 0) {
239		path = "/etc/parados.conf";
240		goto log;
241	}
242
243	if (load_path("./parados.conf") == 0) {
244		path = "./parados.conf";
245		goto log;
246	}
247
248	LOG(true, "CONF", "Unable to load configuration... using defaults");
249	return;
250
251log:
252	(void)0;
253
254	char port[8];
255	char tmo[16];
256	char maxc[16];
257	char adly[16];
258
259	LOG_FIELD(true, "CONF", "Config File", "%s", path);
260	LOG_FIELD(true, "CONF", "Media Directory", "%s", media_dir);
261	LOG_FIELD(true, "CONF", "Server Address", "%s", server_addr);
262	snprintf(port, sizeof(port), "%d", server_port);
263	LOG_FIELD(true, "CONF", "Server Port", "%s", port);
264	LOG_FIELD(true, "CONF", "Verbose Logging", "%s", (verbose_log) ? "true" : "false");
265	LOG_FIELD(true, "CONF", "CORS origins", "%s", cors_origin);
266	snprintf(tmo, sizeof(tmo), "%d", http_io_timeout);
267	LOG_FIELD(true, "CONF", "HTTP IO Timeout", "%s", tmo);
268	snprintf(maxc, sizeof(maxc), "%d", max_clients);
269	LOG_FIELD(true, "CONF", "Max Clients", "%s", maxc);
270	snprintf(adly, sizeof(adly), "%d", auth_delay);
271	LOG_FIELD(true, "CONF", "Auth Delay", "%s (ms)", adly);
272
273	return;
274}
275