blob: d773cc973872db04e89b83aedb69a33bddce2b17 [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) {
240 fprintf(stderr, "string '%s' is length %d\n", entry->value, len);
241 *color = default_color;
242 errno = EINVAL;
243 return -1;
244 }
245
246 errno = 0;
247 *color = strtoul(entry->value, &end, 16);
248 if (errno != 0 || end == entry->value || *end != '\0') {
249 *color = default_color;
250 errno = EINVAL;
251 return -1;
252 }
253
254 return 0;
255}
256
257WL_EXPORT
258int
Armin Kb502f902013-07-31 01:41:03 +0200259weston_config_section_get_double(struct weston_config_section *section,
260 const char *key,
261 double *value, double default_value)
262{
263 struct weston_config_entry *entry;
264 char *end;
265
266 entry = config_section_get_entry(section, key);
267 if (entry == NULL) {
268 *value = default_value;
269 errno = ENOENT;
270 return -1;
271 }
272
273 *value = strtod(entry->value, &end);
274 if (*end != '\0') {
275 *value = default_value;
276 errno = EINVAL;
277 return -1;
278 }
279
280 return 0;
281}
282
283WL_EXPORT
284int
Kristian Høgsberg73274712013-04-01 12:41:23 -0400285weston_config_section_get_string(struct weston_config_section *section,
286 const char *key,
287 char **value, const char *default_value)
288{
289 struct weston_config_entry *entry;
290
291 entry = config_section_get_entry(section, key);
292 if (entry == NULL) {
293 if (default_value)
294 *value = strdup(default_value);
295 else
296 *value = NULL;
297 errno = ENOENT;
298 return -1;
299 }
300
301 *value = strdup(entry->value);
302
303 return 0;
304}
305
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200306WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400307int
308weston_config_section_get_bool(struct weston_config_section *section,
309 const char *key,
310 int *value, int default_value)
311{
312 struct weston_config_entry *entry;
313
314 entry = config_section_get_entry(section, key);
315 if (entry == NULL) {
316 *value = default_value;
317 errno = ENOENT;
318 return -1;
319 }
320
321 if (strcmp(entry->value, "false") == 0)
322 *value = 0;
323 else if (strcmp(entry->value, "true") == 0)
324 *value = 1;
325 else {
326 *value = default_value;
327 errno = EINVAL;
328 return -1;
329 }
330
331 return 0;
332}
333
Derek Foremanc7210432014-08-21 11:32:38 -0500334WL_EXPORT
335const char *
336weston_config_get_libexec_dir(void)
337{
338 const char *path = getenv("WESTON_BUILD_DIR");
339
340 if (path)
341 return path;
342
343 return LIBEXECDIR;
344}
345
Pekka Paalanen6c71aae2015-03-24 15:56:19 +0200346const char *
347weston_config_get_name_from_env(void)
348{
349 const char *name;
350
351 name = getenv(WESTON_CONFIG_FILE_ENV_VAR);
352 if (name)
353 return name;
354
355 return "weston.ini";
356}
357
Kristian Høgsberg73274712013-04-01 12:41:23 -0400358static struct weston_config_section *
359config_add_section(struct weston_config *config, const char *name)
360{
361 struct weston_config_section *section;
362
363 section = malloc(sizeof *section);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800364 if (section == NULL)
365 return NULL;
366
Kristian Høgsberg73274712013-04-01 12:41:23 -0400367 section->name = strdup(name);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800368 if (section->name == NULL) {
369 free(section);
370 return NULL;
371 }
372
Kristian Høgsberg73274712013-04-01 12:41:23 -0400373 wl_list_init(&section->entry_list);
374 wl_list_insert(config->section_list.prev, &section->link);
375
376 return section;
377}
378
379static struct weston_config_entry *
380section_add_entry(struct weston_config_section *section,
381 const char *key, const char *value)
382{
383 struct weston_config_entry *entry;
384
385 entry = malloc(sizeof *entry);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800386 if (entry == NULL)
387 return NULL;
388
Kristian Høgsberg73274712013-04-01 12:41:23 -0400389 entry->key = strdup(key);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800390 if (entry->key == NULL) {
391 free(entry);
392 return NULL;
393 }
394
Kristian Høgsberg73274712013-04-01 12:41:23 -0400395 entry->value = strdup(value);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800396 if (entry->value == NULL) {
397 free(entry->key);
398 free(entry);
399 return NULL;
400 }
401
Kristian Høgsberg73274712013-04-01 12:41:23 -0400402 wl_list_insert(section->entry_list.prev, &entry->link);
403
404 return entry;
405}
406
407struct weston_config *
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700408weston_config_parse(const char *name)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400409{
410 FILE *fp;
411 char line[512], *p;
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200412 struct stat filestat;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400413 struct weston_config *config;
414 struct weston_config_section *section = NULL;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700415 int i, fd;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400416
417 config = malloc(sizeof *config);
418 if (config == NULL)
419 return NULL;
420
421 wl_list_init(&config->section_list);
422
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700423 fd = open_config_file(config, name);
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700424 if (fd == -1) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400425 free(config);
426 return NULL;
427 }
428
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200429 if (fstat(fd, &filestat) < 0 ||
430 !S_ISREG(filestat.st_mode)) {
431 close(fd);
432 free(config);
433 return NULL;
434 }
435
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700436 fp = fdopen(fd, "r");
437 if (fp == NULL) {
438 free(config);
439 return NULL;
440 }
Kristian Høgsberg73274712013-04-01 12:41:23 -0400441
442 while (fgets(line, sizeof line, fp)) {
443 switch (line[0]) {
444 case '#':
445 case '\n':
446 continue;
447 case '[':
448 p = strchr(&line[1], ']');
449 if (!p || p[1] != '\n') {
450 fprintf(stderr, "malformed "
451 "section header: %s\n", line);
452 fclose(fp);
453 weston_config_destroy(config);
454 return NULL;
455 }
456 p[0] = '\0';
457 section = config_add_section(config, &line[1]);
458 continue;
459 default:
460 p = strchr(line, '=');
461 if (!p || p == line || !section) {
462 fprintf(stderr, "malformed "
463 "config line: %s\n", line);
464 fclose(fp);
465 weston_config_destroy(config);
466 return NULL;
467 }
468
469 p[0] = '\0';
470 p++;
471 while (isspace(*p))
472 p++;
473 i = strlen(p);
474 while (i > 0 && isspace(p[i - 1])) {
475 p[i - 1] = '\0';
476 i--;
477 }
478 section_add_entry(section, line, p);
479 continue;
480 }
481 }
482
483 fclose(fp);
484
485 return config;
486}
487
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700488const char *
489weston_config_get_full_path(struct weston_config *config)
490{
Alexandru DAMIAN5f429302013-09-26 10:27:16 +0100491 return config == NULL ? NULL : config->path;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700492}
493
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}