blob: 1edfd60c591b718c7efa499e31cd39f0456bb924 [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"
Kristian Høgsbergf73f3162013-05-26 20:50:53 -040044
Kristian Høgsberg73274712013-04-01 12:41:23 -040045struct weston_config_entry {
46 char *key;
47 char *value;
48 struct wl_list link;
49};
50
51struct weston_config_section {
52 char *name;
53 struct wl_list entry_list;
54 struct wl_list link;
55};
56
57struct weston_config {
58 struct wl_list section_list;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070059 char path[PATH_MAX];
Kristian Høgsberg73274712013-04-01 12:41:23 -040060};
61
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070062static int
63open_config_file(struct weston_config *c, const char *name)
64{
65 const char *config_dir = getenv("XDG_CONFIG_HOME");
66 const char *home_dir = getenv("HOME");
67 const char *config_dirs = getenv("XDG_CONFIG_DIRS");
68 const char *p, *next;
69 int fd;
70
71 if (name[0] == '/') {
72 snprintf(c->path, sizeof c->path, "%s", name);
73 return open(name, O_RDONLY | O_CLOEXEC);
74 }
75
76 /* Precedence is given to config files in the home directory,
77 * and then to directories listed in XDG_CONFIG_DIRS and
78 * finally to the current working directory. */
79
80 /* $XDG_CONFIG_HOME */
81 if (config_dir) {
82 snprintf(c->path, sizeof c->path, "%s/%s", config_dir, name);
83 fd = open(c->path, O_RDONLY | O_CLOEXEC);
84 if (fd >= 0)
85 return fd;
86 }
87
88 /* $HOME/.config */
89 if (home_dir) {
90 snprintf(c->path, sizeof c->path,
91 "%s/.config/%s", home_dir, name);
92 fd = open(c->path, O_RDONLY | O_CLOEXEC);
93 if (fd >= 0)
94 return fd;
95 }
96
97 /* For each $XDG_CONFIG_DIRS: weston/<config_file> */
98 if (!config_dirs)
99 config_dirs = "/etc/xdg"; /* See XDG base dir spec. */
100
101 for (p = config_dirs; *p != '\0'; p = next) {
102 next = strchrnul(p, ':');
103 snprintf(c->path, sizeof c->path,
104 "%.*s/weston/%s", (int)(next - p), p, name);
105 fd = open(c->path, O_RDONLY | O_CLOEXEC);
106 if (fd >= 0)
107 return fd;
108
109 if (*next == ':')
110 next++;
111 }
112
113 /* Current working directory. */
114 snprintf(c->path, sizeof c->path, "./%s", name);
115
116 return open(c->path, O_RDONLY | O_CLOEXEC);
117}
118
Kristian Høgsberg73274712013-04-01 12:41:23 -0400119static struct weston_config_entry *
120config_section_get_entry(struct weston_config_section *section,
121 const char *key)
122{
123 struct weston_config_entry *e;
124
125 if (section == NULL)
126 return NULL;
127 wl_list_for_each(e, &section->entry_list, link)
128 if (strcmp(e->key, key) == 0)
129 return e;
130
131 return NULL;
132}
133
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200134WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400135struct weston_config_section *
136weston_config_get_section(struct weston_config *config, const char *section,
137 const char *key, const char *value)
138{
139 struct weston_config_section *s;
140 struct weston_config_entry *e;
141
Mun Gwan-gyeong72a3ab72013-05-25 02:09:13 +0900142 if (config == NULL)
143 return NULL;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400144 wl_list_for_each(s, &config->section_list, link) {
145 if (strcmp(s->name, section) != 0)
146 continue;
147 if (key == NULL)
148 return s;
149 e = config_section_get_entry(s, key);
150 if (e && strcmp(e->value, value) == 0)
151 return s;
152 }
153
154 return NULL;
155}
156
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200157WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400158int
159weston_config_section_get_int(struct weston_config_section *section,
160 const char *key,
161 int32_t *value, int32_t default_value)
162{
163 struct weston_config_entry *entry;
164 char *end;
165
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 Harringtoncbc05372016-07-07 14:08:28 -0700173 errno = 0;
Bryce Harrington375759e2016-07-12 16:51:27 -0700174 *value = strtol(entry->value, &end, 10);
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700175 if (errno != 0 || end == entry->value || *end != '\0') {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400176 *value = default_value;
177 errno = EINVAL;
178 return -1;
179 }
180
181 return 0;
182}
183
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200184WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400185int
186weston_config_section_get_uint(struct weston_config_section *section,
187 const char *key,
188 uint32_t *value, uint32_t default_value)
189{
Bryce Harringtond0716f42016-07-14 18:28:04 -0700190 long int ret;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400191 struct weston_config_entry *entry;
192 char *end;
193
194 entry = config_section_get_entry(section, key);
195 if (entry == NULL) {
196 *value = default_value;
197 errno = ENOENT;
198 return -1;
199 }
200
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700201 errno = 0;
Bryce Harringtond0716f42016-07-14 18:28:04 -0700202 ret = strtol(entry->value, &end, 0);
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700203 if (errno != 0 || end == entry->value || *end != '\0') {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400204 *value = default_value;
205 errno = EINVAL;
206 return -1;
207 }
208
Bryce Harringtond0716f42016-07-14 18:28:04 -0700209 /* check range */
210 if (ret < 0 || ret > INT_MAX) {
211 *value = default_value;
212 errno = ERANGE;
213 return -1;
214 }
215
216 *value = ret;
217
Kristian Høgsberg73274712013-04-01 12:41:23 -0400218 return 0;
219}
220
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200221WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400222int
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700223weston_config_section_get_color(struct weston_config_section *section,
224 const char *key,
225 uint32_t *color, uint32_t default_color)
226{
227 struct weston_config_entry *entry;
228 int len;
229 char *end;
230
231 entry = config_section_get_entry(section, key);
232 if (entry == NULL) {
233 *color = default_color;
234 errno = ENOENT;
235 return -1;
236 }
237
238 len = strlen(entry->value);
239 if (len == 1 && entry->value[0] == '0') {
240 *color = 0;
241 return 0;
242 } else if (len != 8 && len != 10) {
243 fprintf(stderr, "string '%s' is length %d\n", entry->value, len);
244 *color = default_color;
245 errno = EINVAL;
246 return -1;
247 }
248
249 errno = 0;
250 *color = strtoul(entry->value, &end, 16);
251 if (errno != 0 || end == entry->value || *end != '\0') {
252 *color = default_color;
253 errno = EINVAL;
254 return -1;
255 }
256
257 return 0;
258}
259
260WL_EXPORT
261int
Armin Kb502f902013-07-31 01:41:03 +0200262weston_config_section_get_double(struct weston_config_section *section,
263 const char *key,
264 double *value, double default_value)
265{
266 struct weston_config_entry *entry;
267 char *end;
268
269 entry = config_section_get_entry(section, key);
270 if (entry == NULL) {
271 *value = default_value;
272 errno = ENOENT;
273 return -1;
274 }
275
276 *value = strtod(entry->value, &end);
277 if (*end != '\0') {
278 *value = default_value;
279 errno = EINVAL;
280 return -1;
281 }
282
283 return 0;
284}
285
286WL_EXPORT
287int
Kristian Høgsberg73274712013-04-01 12:41:23 -0400288weston_config_section_get_string(struct weston_config_section *section,
289 const char *key,
290 char **value, const char *default_value)
291{
292 struct weston_config_entry *entry;
293
294 entry = config_section_get_entry(section, key);
295 if (entry == NULL) {
296 if (default_value)
297 *value = strdup(default_value);
298 else
299 *value = NULL;
300 errno = ENOENT;
301 return -1;
302 }
303
304 *value = strdup(entry->value);
305
306 return 0;
307}
308
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200309WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400310int
311weston_config_section_get_bool(struct weston_config_section *section,
312 const char *key,
313 int *value, int default_value)
314{
315 struct weston_config_entry *entry;
316
317 entry = config_section_get_entry(section, key);
318 if (entry == NULL) {
319 *value = default_value;
320 errno = ENOENT;
321 return -1;
322 }
323
324 if (strcmp(entry->value, "false") == 0)
325 *value = 0;
326 else if (strcmp(entry->value, "true") == 0)
327 *value = 1;
328 else {
329 *value = default_value;
330 errno = EINVAL;
331 return -1;
332 }
333
334 return 0;
335}
336
Derek Foremanc7210432014-08-21 11:32:38 -0500337WL_EXPORT
338const char *
339weston_config_get_libexec_dir(void)
340{
341 const char *path = getenv("WESTON_BUILD_DIR");
342
343 if (path)
344 return path;
345
346 return LIBEXECDIR;
347}
348
Pekka Paalanen6c71aae2015-03-24 15:56:19 +0200349const char *
350weston_config_get_name_from_env(void)
351{
352 const char *name;
353
354 name = getenv(WESTON_CONFIG_FILE_ENV_VAR);
355 if (name)
356 return name;
357
358 return "weston.ini";
359}
360
Kristian Høgsberg73274712013-04-01 12:41:23 -0400361static struct weston_config_section *
362config_add_section(struct weston_config *config, const char *name)
363{
364 struct weston_config_section *section;
365
366 section = malloc(sizeof *section);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800367 if (section == NULL)
368 return NULL;
369
Kristian Høgsberg73274712013-04-01 12:41:23 -0400370 section->name = strdup(name);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800371 if (section->name == NULL) {
372 free(section);
373 return NULL;
374 }
375
Kristian Høgsberg73274712013-04-01 12:41:23 -0400376 wl_list_init(&section->entry_list);
377 wl_list_insert(config->section_list.prev, &section->link);
378
379 return section;
380}
381
382static struct weston_config_entry *
383section_add_entry(struct weston_config_section *section,
384 const char *key, const char *value)
385{
386 struct weston_config_entry *entry;
387
388 entry = malloc(sizeof *entry);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800389 if (entry == NULL)
390 return NULL;
391
Kristian Høgsberg73274712013-04-01 12:41:23 -0400392 entry->key = strdup(key);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800393 if (entry->key == NULL) {
394 free(entry);
395 return NULL;
396 }
397
Kristian Høgsberg73274712013-04-01 12:41:23 -0400398 entry->value = strdup(value);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800399 if (entry->value == NULL) {
400 free(entry->key);
401 free(entry);
402 return NULL;
403 }
404
Kristian Høgsberg73274712013-04-01 12:41:23 -0400405 wl_list_insert(section->entry_list.prev, &entry->link);
406
407 return entry;
408}
409
410struct weston_config *
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700411weston_config_parse(const char *name)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400412{
413 FILE *fp;
414 char line[512], *p;
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200415 struct stat filestat;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400416 struct weston_config *config;
417 struct weston_config_section *section = NULL;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700418 int i, fd;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400419
420 config = malloc(sizeof *config);
421 if (config == NULL)
422 return NULL;
423
424 wl_list_init(&config->section_list);
425
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700426 fd = open_config_file(config, name);
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700427 if (fd == -1) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400428 free(config);
429 return NULL;
430 }
431
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200432 if (fstat(fd, &filestat) < 0 ||
433 !S_ISREG(filestat.st_mode)) {
434 close(fd);
435 free(config);
436 return NULL;
437 }
438
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700439 fp = fdopen(fd, "r");
440 if (fp == NULL) {
441 free(config);
442 return NULL;
443 }
Kristian Høgsberg73274712013-04-01 12:41:23 -0400444
445 while (fgets(line, sizeof line, fp)) {
446 switch (line[0]) {
447 case '#':
448 case '\n':
449 continue;
450 case '[':
451 p = strchr(&line[1], ']');
452 if (!p || p[1] != '\n') {
453 fprintf(stderr, "malformed "
454 "section header: %s\n", line);
455 fclose(fp);
456 weston_config_destroy(config);
457 return NULL;
458 }
459 p[0] = '\0';
460 section = config_add_section(config, &line[1]);
461 continue;
462 default:
463 p = strchr(line, '=');
464 if (!p || p == line || !section) {
465 fprintf(stderr, "malformed "
466 "config line: %s\n", line);
467 fclose(fp);
468 weston_config_destroy(config);
469 return NULL;
470 }
471
472 p[0] = '\0';
473 p++;
474 while (isspace(*p))
475 p++;
476 i = strlen(p);
477 while (i > 0 && isspace(p[i - 1])) {
478 p[i - 1] = '\0';
479 i--;
480 }
481 section_add_entry(section, line, p);
482 continue;
483 }
484 }
485
486 fclose(fp);
487
488 return config;
489}
490
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700491const char *
492weston_config_get_full_path(struct weston_config *config)
493{
Alexandru DAMIAN5f429302013-09-26 10:27:16 +0100494 return config == NULL ? NULL : config->path;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700495}
496
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400497int
498weston_config_next_section(struct weston_config *config,
499 struct weston_config_section **section,
500 const char **name)
501{
Mun Gwan-gyeong151a5282013-05-28 00:04:26 +0900502 if (config == NULL)
503 return 0;
504
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400505 if (*section == NULL)
506 *section = container_of(config->section_list.next,
507 struct weston_config_section, link);
508 else
509 *section = container_of((*section)->link.next,
510 struct weston_config_section, link);
511
512 if (&(*section)->link == &config->section_list)
513 return 0;
514
515 *name = (*section)->name;
516
517 return 1;
518}
519
Kristian Høgsberg73274712013-04-01 12:41:23 -0400520void
521weston_config_destroy(struct weston_config *config)
522{
523 struct weston_config_section *s, *next_s;
524 struct weston_config_entry *e, *next_e;
525
Mun Gwan-gyeong77325402013-05-28 00:20:04 +0900526 if (config == NULL)
527 return;
528
Kristian Høgsberg73274712013-04-01 12:41:23 -0400529 wl_list_for_each_safe(s, next_s, &config->section_list, link) {
530 wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
531 free(e->key);
532 free(e->value);
533 free(e);
534 }
535 free(s->name);
536 free(s);
537 }
538
539 free(config);
540}