1 /**
2 * @file conf.c Configuration utils
3 *
4 * Copyright (C) 2010 Creytiv.com
5 */
6 #define _DEFAULT_SOURCE 1
7 #define _BSD_SOURCE 1
8 #include <fcntl.h>
9 #ifdef HAVE_UNISTD_H
10 #include <unistd.h>
11 #endif
12 #include <stdio.h>
13 #include <sys/stat.h>
14 #ifdef HAVE_IO_H
15 #include <io.h>
16 #endif
17 #include <re.h>
18 #include <rem.h>
19 #include <baresip.h>
20 #include "core.h"
21
22
23 #define DEBUG_MODULE ""
24 #define DEBUG_LEVEL 0
25 #include <re_dbg.h>
26
27
28 #ifdef WIN32
29 #define open _open
30 #define read _read
31 #define close _close
32 #endif
33
34
35 #if defined (WIN32)
36 #define DIR_SEP "\\"
37 #else
38 #define DIR_SEP "/"
39 #endif
40
41
42 static const char *conf_path = NULL;
43 static struct conf *conf_obj;
44
45
46 /**
47 * Check if a file exists
48 *
49 * @param path Filename
50 *
51 * @return True if exist, False if not
52 */
conf_fileexist(const char * path)53 bool conf_fileexist(const char *path)
54 {
55 struct stat st;
56
57 if (!path)
58 return false;
59
60 if (stat(path, &st) < 0)
61 return false;
62
63 if ((st.st_mode & S_IFMT) != S_IFREG)
64 return false;
65
66 return st.st_size > 0;
67 }
68
69
print_populated(const char * what,uint32_t n)70 static void print_populated(const char *what, uint32_t n)
71 {
72 info("Populated %u %s%s\n", n, what, 1==n ? "" : "s");
73 }
74
75
76 /**
77 * Parse a config file, calling handler for each line
78 *
79 * @param filename Config file
80 * @param ch Line handler
81 * @param arg Handler argument
82 *
83 * @return 0 if success, otherwise errorcode
84 */
conf_parse(const char * filename,confline_h * ch,void * arg)85 int conf_parse(const char *filename, confline_h *ch, void *arg)
86 {
87 struct pl pl, val;
88 struct mbuf *mb;
89 int err = 0, fd = open(filename, O_RDONLY);
90 if (fd < 0)
91 return errno;
92
93 mb = mbuf_alloc(1024);
94 if (!mb) {
95 err = ENOMEM;
96 goto out;
97 }
98
99 for (;;) {
100 uint8_t buf[1024];
101
102 const ssize_t n = read(fd, (void *)buf, sizeof(buf));
103 if (n < 0) {
104 err = errno;
105 break;
106 }
107 else if (n == 0)
108 break;
109
110 err |= mbuf_write_mem(mb, buf, n);
111 }
112
113 pl.p = (const char *)mb->buf;
114 pl.l = mb->end;
115
116 while (pl.p < ((const char *)mb->buf + mb->end) && !err) {
117 const char *lb = pl_strchr(&pl, '\n');
118
119 val.p = pl.p;
120 val.l = lb ? (uint32_t)(lb - pl.p) : pl.l;
121 pl_advance(&pl, val.l + 1);
122
123 if (!val.l || val.p[0] == '#')
124 continue;
125
126 err = ch(&val, arg);
127 }
128
129 out:
130 mem_deref(mb);
131 (void)close(fd);
132
133 return err;
134 }
135
136
137 /**
138 * Set the path to configuration files
139 *
140 * @param path Configuration path
141 */
conf_path_set(const char * path)142 void conf_path_set(const char *path)
143 {
144 conf_path = path;
145 }
146
147
148 /**
149 * Get the path to configuration files
150 *
151 * @param path Buffer to write path
152 * @param sz Size of path buffer
153 *
154 * @return 0 if success, otherwise errorcode
155 */
conf_path_get(char * path,size_t sz)156 int conf_path_get(char *path, size_t sz)
157 {
158 char buf[FS_PATH_MAX];
159 int err;
160
161 /* Use explicit conf path */
162 if (conf_path) {
163 if (re_snprintf(path, sz, "%s", conf_path) < 0)
164 return ENOMEM;
165 return 0;
166 }
167
168 #ifdef CONFIG_PATH
169 str_ncpy(buf, CONFIG_PATH, sizeof(buf));
170 (void)err;
171 #else
172 err = fs_gethome(buf, sizeof(buf));
173 if (err)
174 return err;
175 #endif
176
177 if (re_snprintf(path, sz, "%s" DIR_SEP ".baresip", buf) < 0)
178 return ENOMEM;
179
180 return 0;
181 }
182
183
conf_get_range(const struct conf * conf,const char * name,struct range * rng)184 int conf_get_range(const struct conf *conf, const char *name,
185 struct range *rng)
186 {
187 struct pl r, min, max;
188 uint32_t v;
189 int err;
190
191 err = conf_get(conf, name, &r);
192 if (err)
193 return err;
194
195 err = re_regex(r.p, r.l, "[0-9]+-[0-9]+", &min, &max);
196 if (err) {
197 /* fallback to non-range numeric value */
198 err = conf_get_u32(conf, name, &v);
199 if (err) {
200 warning("conf: %s: could not parse range: (%r)\n",
201 name, &r);
202 return err;
203 }
204
205 rng->min = rng->max = v;
206
207 return err;
208 }
209
210 rng->min = pl_u32(&min);
211 rng->max = pl_u32(&max);
212
213 if (rng->min > rng->max) {
214 warning("conf: %s: invalid range (%u - %u)\n",
215 name, rng->min, rng->max);
216 return EINVAL;
217 }
218
219 return 0;
220 }
221
222
conf_get_csv(const struct conf * conf,const char * name,char * str1,size_t sz1,char * str2,size_t sz2)223 int conf_get_csv(const struct conf *conf, const char *name,
224 char *str1, size_t sz1, char *str2, size_t sz2)
225 {
226 struct pl r, pl1, pl2 = pl_null;
227 int err;
228
229 err = conf_get(conf, name, &r);
230 if (err)
231 return err;
232
233 /* note: second value may be quoted */
234 err = re_regex(r.p, r.l, "[^,]+,[~]*", &pl1, &pl2);
235 if (err)
236 return err;
237
238 (void)pl_strcpy(&pl1, str1, sz1);
239 if (pl_isset(&pl2))
240 (void)pl_strcpy(&pl2, str2, sz2);
241
242 return 0;
243 }
244
245
conf_get_vidsz(const struct conf * conf,const char * name,struct vidsz * sz)246 int conf_get_vidsz(const struct conf *conf, const char *name, struct vidsz *sz)
247 {
248 struct pl r, w, h;
249 int err;
250
251 err = conf_get(conf, name, &r);
252 if (err)
253 return err;
254
255 w.l = h.l = 0;
256 err = re_regex(r.p, r.l, "[0-9]+x[0-9]+", &w, &h);
257 if (err)
258 return err;
259
260 if (pl_isset(&w) && pl_isset(&h)) {
261 sz->w = pl_u32(&w);
262 sz->h = pl_u32(&h);
263 }
264
265 /* check resolution */
266 if (sz->w & 0x1 || sz->h & 0x1) {
267 warning("conf: %s: should be multiple of 2 (%u x %u)\n",
268 name, sz->w, sz->h);
269 return EINVAL;
270 }
271
272 return 0;
273 }
274
275
conf_get_sa(const struct conf * conf,const char * name,struct sa * sa)276 int conf_get_sa(const struct conf *conf, const char *name, struct sa *sa)
277 {
278 struct pl opt;
279 int err;
280
281 if (!conf || !name || !sa)
282 return EINVAL;
283
284 err = conf_get(conf, name, &opt);
285 if (err)
286 return err;
287
288 return sa_decode(sa, opt.p, opt.l);
289 }
290
291
292 /**
293 * Configure the system with default settings
294 *
295 * @return 0 if success, otherwise errorcode
296 */
conf_configure(void)297 int conf_configure(void)
298 {
299 char path[FS_PATH_MAX], file[FS_PATH_MAX];
300 int err;
301
302 #if defined (WIN32)
303 dbg_init(DBG_INFO, DBG_NONE);
304 #endif
305
306 err = conf_path_get(path, sizeof(path));
307 if (err) {
308 warning("conf: could not get config path: %m\n", err);
309 return err;
310 }
311
312 if (re_snprintf(file, sizeof(file), "%s/config", path) < 0)
313 return ENOMEM;
314
315 if (!conf_fileexist(file)) {
316
317 (void)fs_mkdir(path, 0700);
318
319 err = config_write_template(file, conf_config());
320 if (err)
321 goto out;
322 }
323
324 conf_obj = mem_deref(conf_obj);
325 err = conf_alloc(&conf_obj, file);
326 if (err)
327 goto out;
328
329 err = config_parse_conf(conf_config(), conf_obj);
330 if (err)
331 goto out;
332
333 out:
334 return err;
335 }
336
337
338 /**
339 * Load all modules from config file
340 *
341 * @return 0 if success, otherwise errorcode
342 *
343 * @note conf_configure must be called first
344 */
conf_modules(void)345 int conf_modules(void)
346 {
347 int err;
348
349 err = module_init(conf_obj);
350 if (err) {
351 warning("conf: configure module parse error (%m)\n", err);
352 goto out;
353 }
354
355 print_populated("audio codec", list_count(baresip_aucodecl()));
356 print_populated("audio filter", list_count(baresip_aufiltl()));
357 #ifdef USE_VIDEO
358 print_populated("video codec", list_count(baresip_vidcodecl()));
359 print_populated("video filter", list_count(baresip_vidfiltl()));
360 #endif
361
362 out:
363 return err;
364 }
365
366
367 /**
368 * Get the current configuration object
369 *
370 * @return Config object
371 *
372 * @note It is only available after init and before conf_close()
373 */
conf_cur(void)374 struct conf *conf_cur(void)
375 {
376 if (!conf_obj) {
377 warning("conf: no config object\n");
378 }
379 return conf_obj;
380 }
381
382
conf_close(void)383 void conf_close(void)
384 {
385 conf_obj = mem_deref(conf_obj);
386 }
387