blob: 2a595b1f63ee32d1bb1e6f9a54bfc7269ad209c6 [file] [log] [blame]
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -05001/*
2 * Copyright © 2011 Intel Corporation
3 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050011 *
Bryce Harrington6c6164c2015-06-11 14:20:17 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050024 */
25
Daniel Stonec228e232013-05-22 18:03:19 +030026#include "config.h"
27
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050028#include <string.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030029#include <stdint.h>
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050030#include <stdio.h>
31#include <stdlib.h>
32#include <assert.h>
Kristian Høgsberg3d890492012-08-03 21:56:41 -040033#include <ctype.h>
Ossama Othmana50e6e42013-05-14 09:48:26 -070034#include <limits.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <fcntl.h>
38#include <unistd.h>
Kristian Høgsberg73274712013-04-01 12:41:23 -040039#include <errno.h>
Kristian Høgsbergac3a59a2011-11-14 22:43:37 -050040
Kristian Høgsberg73274712013-04-01 12:41:23 -040041#include <wayland-util.h>
Kristian Høgsberg9b935c82011-12-08 12:44:27 -050042#include "config-parser.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070043#include "helpers.h"
Bryce Harrington25a2bdd2016-08-03 17:40:52 -070044#include "string-helpers.h"
Kristian Høgsbergf73f3162013-05-26 20:50:53 -040045
Kristian Høgsberg73274712013-04-01 12:41:23 -040046struct weston_config_entry {
47 char *key;
48 char *value;
49 struct wl_list link;
50};
51
52struct weston_config_section {
53 char *name;
54 struct wl_list entry_list;
55 struct wl_list link;
56};
57
58struct weston_config {
59 struct wl_list section_list;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070060 char path[PATH_MAX];
Kristian Høgsberg73274712013-04-01 12:41:23 -040061};
62
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070063static int
64open_config_file(struct weston_config *c, const char *name)
65{
66 const char *config_dir = getenv("XDG_CONFIG_HOME");
67 const char *home_dir = getenv("HOME");
68 const char *config_dirs = getenv("XDG_CONFIG_DIRS");
69 const char *p, *next;
70 int fd;
71
72 if (name[0] == '/') {
73 snprintf(c->path, sizeof c->path, "%s", name);
74 return open(name, O_RDONLY | O_CLOEXEC);
75 }
76
77 /* Precedence is given to config files in the home directory,
78 * and then to directories listed in XDG_CONFIG_DIRS and
79 * finally to the current working directory. */
80
81 /* $XDG_CONFIG_HOME */
82 if (config_dir) {
83 snprintf(c->path, sizeof c->path, "%s/%s", config_dir, name);
84 fd = open(c->path, O_RDONLY | O_CLOEXEC);
85 if (fd >= 0)
86 return fd;
87 }
88
89 /* $HOME/.config */
90 if (home_dir) {
91 snprintf(c->path, sizeof c->path,
92 "%s/.config/%s", home_dir, name);
93 fd = open(c->path, O_RDONLY | O_CLOEXEC);
94 if (fd >= 0)
95 return fd;
96 }
97
98 /* For each $XDG_CONFIG_DIRS: weston/<config_file> */
99 if (!config_dirs)
100 config_dirs = "/etc/xdg"; /* See XDG base dir spec. */
101
102 for (p = config_dirs; *p != '\0'; p = next) {
103 next = strchrnul(p, ':');
104 snprintf(c->path, sizeof c->path,
105 "%.*s/weston/%s", (int)(next - p), p, name);
106 fd = open(c->path, O_RDONLY | O_CLOEXEC);
107 if (fd >= 0)
108 return fd;
109
110 if (*next == ':')
111 next++;
112 }
113
114 /* Current working directory. */
115 snprintf(c->path, sizeof c->path, "./%s", name);
116
117 return open(c->path, O_RDONLY | O_CLOEXEC);
118}
119
Kristian Høgsberg73274712013-04-01 12:41:23 -0400120static struct weston_config_entry *
121config_section_get_entry(struct weston_config_section *section,
122 const char *key)
123{
124 struct weston_config_entry *e;
125
126 if (section == NULL)
127 return NULL;
128 wl_list_for_each(e, &section->entry_list, link)
129 if (strcmp(e->key, key) == 0)
130 return e;
131
132 return NULL;
133}
134
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200135WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400136struct weston_config_section *
137weston_config_get_section(struct weston_config *config, const char *section,
138 const char *key, const char *value)
139{
140 struct weston_config_section *s;
141 struct weston_config_entry *e;
142
Mun Gwan-gyeong72a3ab72013-05-25 02:09:13 +0900143 if (config == NULL)
144 return NULL;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400145 wl_list_for_each(s, &config->section_list, link) {
146 if (strcmp(s->name, section) != 0)
147 continue;
148 if (key == NULL)
149 return s;
150 e = config_section_get_entry(s, key);
151 if (e && strcmp(e->value, value) == 0)
152 return s;
153 }
154
155 return NULL;
156}
157
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200158WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400159int
160weston_config_section_get_int(struct weston_config_section *section,
161 const char *key,
162 int32_t *value, int32_t default_value)
163{
164 struct weston_config_entry *entry;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400165
166 entry = config_section_get_entry(section, key);
167 if (entry == NULL) {
168 *value = default_value;
169 errno = ENOENT;
170 return -1;
171 }
172
Bryce Harrington25a2bdd2016-08-03 17:40:52 -0700173 if (!safe_strtoint(entry->value, value)) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400174 *value = default_value;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400175 return -1;
176 }
177
178 return 0;
179}
180
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200181WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400182int
183weston_config_section_get_uint(struct weston_config_section *section,
184 const char *key,
185 uint32_t *value, uint32_t default_value)
186{
Bryce Harringtond0716f42016-07-14 18:28:04 -0700187 long int ret;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400188 struct weston_config_entry *entry;
189 char *end;
190
191 entry = config_section_get_entry(section, key);
192 if (entry == NULL) {
193 *value = default_value;
194 errno = ENOENT;
195 return -1;
196 }
197
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700198 errno = 0;
Bryce Harringtond0716f42016-07-14 18:28:04 -0700199 ret = strtol(entry->value, &end, 0);
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700200 if (errno != 0 || end == entry->value || *end != '\0') {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400201 *value = default_value;
202 errno = EINVAL;
203 return -1;
204 }
205
Bryce Harringtond0716f42016-07-14 18:28:04 -0700206 /* check range */
207 if (ret < 0 || ret > INT_MAX) {
208 *value = default_value;
209 errno = ERANGE;
210 return -1;
211 }
212
213 *value = ret;
214
Kristian Høgsberg73274712013-04-01 12:41:23 -0400215 return 0;
216}
217
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200218WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400219int
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700220weston_config_section_get_color(struct weston_config_section *section,
221 const char *key,
222 uint32_t *color, uint32_t default_color)
223{
224 struct weston_config_entry *entry;
225 int len;
226 char *end;
227
228 entry = config_section_get_entry(section, key);
229 if (entry == NULL) {
230 *color = default_color;
231 errno = ENOENT;
232 return -1;
233 }
234
235 len = strlen(entry->value);
236 if (len == 1 && entry->value[0] == '0') {
237 *color = 0;
238 return 0;
239 } else if (len != 8 && len != 10) {
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700240 *color = default_color;
241 errno = EINVAL;
242 return -1;
243 }
244
245 errno = 0;
246 *color = strtoul(entry->value, &end, 16);
247 if (errno != 0 || end == entry->value || *end != '\0') {
248 *color = default_color;
249 errno = EINVAL;
250 return -1;
251 }
252
253 return 0;
254}
255
256WL_EXPORT
257int
Armin Kb502f902013-07-31 01:41:03 +0200258weston_config_section_get_double(struct weston_config_section *section,
259 const char *key,
260 double *value, double default_value)
261{
262 struct weston_config_entry *entry;
263 char *end;
264
265 entry = config_section_get_entry(section, key);
266 if (entry == NULL) {
267 *value = default_value;
268 errno = ENOENT;
269 return -1;
270 }
271
272 *value = strtod(entry->value, &end);
273 if (*end != '\0') {
274 *value = default_value;
275 errno = EINVAL;
276 return -1;
277 }
278
279 return 0;
280}
281
282WL_EXPORT
283int
Kristian Høgsberg73274712013-04-01 12:41:23 -0400284weston_config_section_get_string(struct weston_config_section *section,
285 const char *key,
286 char **value, const char *default_value)
287{
288 struct weston_config_entry *entry;
289
290 entry = config_section_get_entry(section, key);
291 if (entry == NULL) {
292 if (default_value)
293 *value = strdup(default_value);
294 else
295 *value = NULL;
296 errno = ENOENT;
297 return -1;
298 }
299
300 *value = strdup(entry->value);
301
302 return 0;
303}
304
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200305WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400306int
307weston_config_section_get_bool(struct weston_config_section *section,
308 const char *key,
309 int *value, int default_value)
310{
311 struct weston_config_entry *entry;
312
313 entry = config_section_get_entry(section, key);
314 if (entry == NULL) {
315 *value = default_value;
316 errno = ENOENT;
317 return -1;
318 }
319
320 if (strcmp(entry->value, "false") == 0)
321 *value = 0;
322 else if (strcmp(entry->value, "true") == 0)
323 *value = 1;
324 else {
325 *value = default_value;
326 errno = EINVAL;
327 return -1;
328 }
329
330 return 0;
331}
332
Derek Foremanc7210432014-08-21 11:32:38 -0500333WL_EXPORT
334const char *
335weston_config_get_libexec_dir(void)
336{
337 const char *path = getenv("WESTON_BUILD_DIR");
338
339 if (path)
340 return path;
341
342 return LIBEXECDIR;
343}
344
Pekka Paalanen6c71aae2015-03-24 15:56:19 +0200345const char *
346weston_config_get_name_from_env(void)
347{
348 const char *name;
349
350 name = getenv(WESTON_CONFIG_FILE_ENV_VAR);
351 if (name)
352 return name;
353
354 return "weston.ini";
355}
356
Kristian Høgsberg73274712013-04-01 12:41:23 -0400357static struct weston_config_section *
358config_add_section(struct weston_config *config, const char *name)
359{
360 struct weston_config_section *section;
361
362 section = malloc(sizeof *section);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800363 if (section == NULL)
364 return NULL;
365
Kristian Høgsberg73274712013-04-01 12:41:23 -0400366 section->name = strdup(name);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800367 if (section->name == NULL) {
368 free(section);
369 return NULL;
370 }
371
Kristian Høgsberg73274712013-04-01 12:41:23 -0400372 wl_list_init(&section->entry_list);
373 wl_list_insert(config->section_list.prev, &section->link);
374
375 return section;
376}
377
378static struct weston_config_entry *
379section_add_entry(struct weston_config_section *section,
380 const char *key, const char *value)
381{
382 struct weston_config_entry *entry;
383
384 entry = malloc(sizeof *entry);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800385 if (entry == NULL)
386 return NULL;
387
Kristian Høgsberg73274712013-04-01 12:41:23 -0400388 entry->key = strdup(key);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800389 if (entry->key == NULL) {
390 free(entry);
391 return NULL;
392 }
393
Kristian Høgsberg73274712013-04-01 12:41:23 -0400394 entry->value = strdup(value);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800395 if (entry->value == NULL) {
396 free(entry->key);
397 free(entry);
398 return NULL;
399 }
400
Kristian Høgsberg73274712013-04-01 12:41:23 -0400401 wl_list_insert(section->entry_list.prev, &entry->link);
402
403 return entry;
404}
405
406struct weston_config *
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700407weston_config_parse(const char *name)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400408{
409 FILE *fp;
410 char line[512], *p;
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200411 struct stat filestat;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400412 struct weston_config *config;
413 struct weston_config_section *section = NULL;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700414 int i, fd;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400415
416 config = malloc(sizeof *config);
417 if (config == NULL)
418 return NULL;
419
420 wl_list_init(&config->section_list);
421
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700422 fd = open_config_file(config, name);
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700423 if (fd == -1) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400424 free(config);
425 return NULL;
426 }
427
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200428 if (fstat(fd, &filestat) < 0 ||
429 !S_ISREG(filestat.st_mode)) {
430 close(fd);
431 free(config);
432 return NULL;
433 }
434
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700435 fp = fdopen(fd, "r");
436 if (fp == NULL) {
437 free(config);
438 return NULL;
439 }
Kristian Høgsberg73274712013-04-01 12:41:23 -0400440
441 while (fgets(line, sizeof line, fp)) {
442 switch (line[0]) {
443 case '#':
444 case '\n':
445 continue;
446 case '[':
447 p = strchr(&line[1], ']');
448 if (!p || p[1] != '\n') {
449 fprintf(stderr, "malformed "
450 "section header: %s\n", line);
451 fclose(fp);
452 weston_config_destroy(config);
453 return NULL;
454 }
455 p[0] = '\0';
456 section = config_add_section(config, &line[1]);
457 continue;
458 default:
459 p = strchr(line, '=');
460 if (!p || p == line || !section) {
461 fprintf(stderr, "malformed "
462 "config line: %s\n", line);
463 fclose(fp);
464 weston_config_destroy(config);
465 return NULL;
466 }
467
468 p[0] = '\0';
469 p++;
470 while (isspace(*p))
471 p++;
472 i = strlen(p);
473 while (i > 0 && isspace(p[i - 1])) {
474 p[i - 1] = '\0';
475 i--;
476 }
477 section_add_entry(section, line, p);
478 continue;
479 }
480 }
481
482 fclose(fp);
483
484 return config;
485}
486
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700487const char *
488weston_config_get_full_path(struct weston_config *config)
489{
Alexandru DAMIAN5f429302013-09-26 10:27:16 +0100490 return config == NULL ? NULL : config->path;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700491}
492
Emmanuel Gil Peyrota1d214b2017-02-21 11:58:20 +0000493WL_EXPORT
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400494int
495weston_config_next_section(struct weston_config *config,
496 struct weston_config_section **section,
497 const char **name)
498{
Mun Gwan-gyeong151a5282013-05-28 00:04:26 +0900499 if (config == NULL)
500 return 0;
501
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400502 if (*section == NULL)
503 *section = container_of(config->section_list.next,
504 struct weston_config_section, link);
505 else
506 *section = container_of((*section)->link.next,
507 struct weston_config_section, link);
508
509 if (&(*section)->link == &config->section_list)
510 return 0;
511
512 *name = (*section)->name;
513
514 return 1;
515}
516
Kristian Høgsberg73274712013-04-01 12:41:23 -0400517void
518weston_config_destroy(struct weston_config *config)
519{
520 struct weston_config_section *s, *next_s;
521 struct weston_config_entry *e, *next_e;
522
Mun Gwan-gyeong77325402013-05-28 00:20:04 +0900523 if (config == NULL)
524 return;
525
Kristian Høgsberg73274712013-04-01 12:41:23 -0400526 wl_list_for_each_safe(s, next_s, &config->section_list, link) {
527 wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
528 free(e->key);
529 free(e->value);
530 free(e);
531 }
532 free(s->name);
533 free(s);
534 }
535
536 free(config);
537}