blob: ed120d5022060139332539145bdcfb3ed6021282 [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>
Pekka Paalanen49399802020-11-27 14:36:08 +020042#include <libweston/zalloc.h>
Pekka Paalanen91b10102019-04-04 14:27:31 +030043#include <libweston/config-parser.h>
Jon Cruz867d50e2015-06-15 15:37:10 -070044#include "helpers.h"
Bryce Harrington25a2bdd2016-08-03 17:40:52 -070045#include "string-helpers.h"
Kristian Høgsbergf73f3162013-05-26 20:50:53 -040046
Kristian Høgsberg73274712013-04-01 12:41:23 -040047struct weston_config_entry {
48 char *key;
49 char *value;
50 struct wl_list link;
51};
52
53struct weston_config_section {
54 char *name;
55 struct wl_list entry_list;
56 struct wl_list link;
57};
58
59struct weston_config {
60 struct wl_list section_list;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070061 char path[PATH_MAX];
Kristian Høgsberg73274712013-04-01 12:41:23 -040062};
63
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070064static int
65open_config_file(struct weston_config *c, const char *name)
66{
67 const char *config_dir = getenv("XDG_CONFIG_HOME");
68 const char *home_dir = getenv("HOME");
69 const char *config_dirs = getenv("XDG_CONFIG_DIRS");
70 const char *p, *next;
71 int fd;
72
73 if (name[0] == '/') {
74 snprintf(c->path, sizeof c->path, "%s", name);
75 return open(name, O_RDONLY | O_CLOEXEC);
76 }
77
78 /* Precedence is given to config files in the home directory,
Dima Ryazanovad0d83b2018-11-14 22:55:22 -080079 * then to directories listed in XDG_CONFIG_DIRS. */
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -070080
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
Dima Ryazanovad0d83b2018-11-14 22:55:22 -0800114 return -1;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700115}
116
Kristian Høgsberg73274712013-04-01 12:41:23 -0400117static struct weston_config_entry *
118config_section_get_entry(struct weston_config_section *section,
119 const char *key)
120{
121 struct weston_config_entry *e;
122
123 if (section == NULL)
124 return NULL;
125 wl_list_for_each(e, &section->entry_list, link)
126 if (strcmp(e->key, key) == 0)
127 return e;
128
129 return NULL;
130}
131
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200132WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400133struct weston_config_section *
134weston_config_get_section(struct weston_config *config, const char *section,
135 const char *key, const char *value)
136{
137 struct weston_config_section *s;
138 struct weston_config_entry *e;
139
Mun Gwan-gyeong72a3ab72013-05-25 02:09:13 +0900140 if (config == NULL)
141 return NULL;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400142 wl_list_for_each(s, &config->section_list, link) {
143 if (strcmp(s->name, section) != 0)
144 continue;
145 if (key == NULL)
146 return s;
147 e = config_section_get_entry(s, key);
148 if (e && strcmp(e->value, value) == 0)
149 return s;
150 }
151
152 return NULL;
153}
154
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200155WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400156int
157weston_config_section_get_int(struct weston_config_section *section,
158 const char *key,
159 int32_t *value, int32_t default_value)
160{
161 struct weston_config_entry *entry;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400162
163 entry = config_section_get_entry(section, key);
164 if (entry == NULL) {
165 *value = default_value;
166 errno = ENOENT;
167 return -1;
168 }
169
Bryce Harrington25a2bdd2016-08-03 17:40:52 -0700170 if (!safe_strtoint(entry->value, value)) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400171 *value = default_value;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400172 return -1;
173 }
174
175 return 0;
176}
177
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200178WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400179int
180weston_config_section_get_uint(struct weston_config_section *section,
181 const char *key,
182 uint32_t *value, uint32_t default_value)
183{
Bryce Harringtond0716f42016-07-14 18:28:04 -0700184 long int ret;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400185 struct weston_config_entry *entry;
186 char *end;
187
188 entry = config_section_get_entry(section, key);
189 if (entry == NULL) {
190 *value = default_value;
191 errno = ENOENT;
192 return -1;
193 }
194
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700195 errno = 0;
Bryce Harringtond0716f42016-07-14 18:28:04 -0700196 ret = strtol(entry->value, &end, 0);
Bryce Harringtoncbc05372016-07-07 14:08:28 -0700197 if (errno != 0 || end == entry->value || *end != '\0') {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400198 *value = default_value;
199 errno = EINVAL;
200 return -1;
201 }
202
Bryce Harringtond0716f42016-07-14 18:28:04 -0700203 /* check range */
204 if (ret < 0 || ret > INT_MAX) {
205 *value = default_value;
206 errno = ERANGE;
207 return -1;
208 }
209
210 *value = ret;
211
Kristian Høgsberg73274712013-04-01 12:41:23 -0400212 return 0;
213}
214
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200215WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400216int
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700217weston_config_section_get_color(struct weston_config_section *section,
218 const char *key,
219 uint32_t *color, uint32_t default_color)
220{
221 struct weston_config_entry *entry;
222 int len;
223 char *end;
224
225 entry = config_section_get_entry(section, key);
226 if (entry == NULL) {
227 *color = default_color;
228 errno = ENOENT;
229 return -1;
230 }
231
232 len = strlen(entry->value);
233 if (len == 1 && entry->value[0] == '0') {
234 *color = 0;
235 return 0;
236 } else if (len != 8 && len != 10) {
Bryce Harringtone776f2a2016-07-14 18:28:03 -0700237 *color = default_color;
238 errno = EINVAL;
239 return -1;
240 }
241
242 errno = 0;
243 *color = strtoul(entry->value, &end, 16);
244 if (errno != 0 || end == entry->value || *end != '\0') {
245 *color = default_color;
246 errno = EINVAL;
247 return -1;
248 }
249
250 return 0;
251}
252
253WL_EXPORT
254int
Armin Kb502f902013-07-31 01:41:03 +0200255weston_config_section_get_double(struct weston_config_section *section,
256 const char *key,
257 double *value, double default_value)
258{
259 struct weston_config_entry *entry;
260 char *end;
261
262 entry = config_section_get_entry(section, key);
263 if (entry == NULL) {
264 *value = default_value;
265 errno = ENOENT;
266 return -1;
267 }
268
269 *value = strtod(entry->value, &end);
270 if (*end != '\0') {
271 *value = default_value;
272 errno = EINVAL;
273 return -1;
274 }
275
276 return 0;
277}
278
279WL_EXPORT
280int
Kristian Høgsberg73274712013-04-01 12:41:23 -0400281weston_config_section_get_string(struct weston_config_section *section,
282 const char *key,
283 char **value, const char *default_value)
284{
285 struct weston_config_entry *entry;
286
287 entry = config_section_get_entry(section, key);
288 if (entry == NULL) {
289 if (default_value)
290 *value = strdup(default_value);
291 else
292 *value = NULL;
293 errno = ENOENT;
294 return -1;
295 }
296
297 *value = strdup(entry->value);
298
299 return 0;
300}
301
Quentin Glidic6e2c1242013-07-01 17:03:08 +0200302WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400303int
304weston_config_section_get_bool(struct weston_config_section *section,
305 const char *key,
Daniel Stone51d995a2019-11-26 00:14:24 +0000306 bool *value, bool default_value)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400307{
308 struct weston_config_entry *entry;
309
310 entry = config_section_get_entry(section, key);
311 if (entry == NULL) {
312 *value = default_value;
313 errno = ENOENT;
314 return -1;
315 }
316
317 if (strcmp(entry->value, "false") == 0)
Daniel Stone51d995a2019-11-26 00:14:24 +0000318 *value = false;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400319 else if (strcmp(entry->value, "true") == 0)
Daniel Stone51d995a2019-11-26 00:14:24 +0000320 *value = true;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400321 else {
322 *value = default_value;
323 errno = EINVAL;
324 return -1;
325 }
326
327 return 0;
328}
329
Michael Olbrich4c347b82018-10-08 16:04:44 +0200330WL_EXPORT
Pekka Paalanen6c71aae2015-03-24 15:56:19 +0200331const char *
332weston_config_get_name_from_env(void)
333{
334 const char *name;
335
336 name = getenv(WESTON_CONFIG_FILE_ENV_VAR);
337 if (name)
338 return name;
339
340 return "weston.ini";
341}
342
Kristian Høgsberg73274712013-04-01 12:41:23 -0400343static struct weston_config_section *
344config_add_section(struct weston_config *config, const char *name)
345{
346 struct weston_config_section *section;
347
Pekka Paalanen49399802020-11-27 14:36:08 +0200348 section = zalloc(sizeof *section);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800349 if (section == NULL)
350 return NULL;
351
Kristian Høgsberg73274712013-04-01 12:41:23 -0400352 section->name = strdup(name);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800353 if (section->name == NULL) {
354 free(section);
355 return NULL;
356 }
357
Kristian Høgsberg73274712013-04-01 12:41:23 -0400358 wl_list_init(&section->entry_list);
359 wl_list_insert(config->section_list.prev, &section->link);
360
361 return section;
362}
363
364static struct weston_config_entry *
365section_add_entry(struct weston_config_section *section,
366 const char *key, const char *value)
367{
368 struct weston_config_entry *entry;
369
Pekka Paalanen49399802020-11-27 14:36:08 +0200370 entry = zalloc(sizeof *entry);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800371 if (entry == NULL)
372 return NULL;
373
Kristian Høgsberg73274712013-04-01 12:41:23 -0400374 entry->key = strdup(key);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800375 if (entry->key == NULL) {
376 free(entry);
377 return NULL;
378 }
379
Kristian Høgsberg73274712013-04-01 12:41:23 -0400380 entry->value = strdup(value);
Bryce Harrington3f2062c2016-02-17 20:46:01 -0800381 if (entry->value == NULL) {
382 free(entry->key);
383 free(entry);
384 return NULL;
385 }
386
Kristian Høgsberg73274712013-04-01 12:41:23 -0400387 wl_list_insert(section->entry_list.prev, &entry->link);
388
389 return entry;
390}
391
Michael Olbrich4c347b82018-10-08 16:04:44 +0200392WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400393struct weston_config *
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700394weston_config_parse(const char *name)
Kristian Høgsberg73274712013-04-01 12:41:23 -0400395{
396 FILE *fp;
397 char line[512], *p;
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200398 struct stat filestat;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400399 struct weston_config *config;
400 struct weston_config_section *section = NULL;
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700401 int i, fd;
Kristian Høgsberg73274712013-04-01 12:41:23 -0400402
Pekka Paalanen49399802020-11-27 14:36:08 +0200403 config = zalloc(sizeof *config);
Kristian Høgsberg73274712013-04-01 12:41:23 -0400404 if (config == NULL)
405 return NULL;
406
407 wl_list_init(&config->section_list);
408
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700409 fd = open_config_file(config, name);
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700410 if (fd == -1) {
Kristian Høgsberg73274712013-04-01 12:41:23 -0400411 free(config);
412 return NULL;
413 }
414
Pekka Paalanen49f6d622015-03-24 15:56:17 +0200415 if (fstat(fd, &filestat) < 0 ||
416 !S_ISREG(filestat.st_mode)) {
417 close(fd);
418 free(config);
419 return NULL;
420 }
421
Kristian Høgsberg1abe0482013-09-21 23:02:31 -0700422 fp = fdopen(fd, "r");
423 if (fp == NULL) {
424 free(config);
425 return NULL;
426 }
Kristian Høgsberg73274712013-04-01 12:41:23 -0400427
428 while (fgets(line, sizeof line, fp)) {
429 switch (line[0]) {
430 case '#':
431 case '\n':
432 continue;
433 case '[':
434 p = strchr(&line[1], ']');
435 if (!p || p[1] != '\n') {
436 fprintf(stderr, "malformed "
437 "section header: %s\n", line);
438 fclose(fp);
439 weston_config_destroy(config);
440 return NULL;
441 }
442 p[0] = '\0';
443 section = config_add_section(config, &line[1]);
444 continue;
445 default:
446 p = strchr(line, '=');
447 if (!p || p == line || !section) {
448 fprintf(stderr, "malformed "
449 "config line: %s\n", line);
450 fclose(fp);
451 weston_config_destroy(config);
452 return NULL;
453 }
454
455 p[0] = '\0';
456 p++;
457 while (isspace(*p))
458 p++;
459 i = strlen(p);
460 while (i > 0 && isspace(p[i - 1])) {
461 p[i - 1] = '\0';
462 i--;
463 }
464 section_add_entry(section, line, p);
465 continue;
466 }
467 }
468
469 fclose(fp);
470
471 return config;
472}
473
Daniel Stone3ef098f2019-11-25 10:30:11 +0000474WL_EXPORT
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700475const char *
476weston_config_get_full_path(struct weston_config *config)
477{
Alexandru DAMIAN5f429302013-09-26 10:27:16 +0100478 return config == NULL ? NULL : config->path;
Kristian Høgsbergeeefc9e2013-09-21 23:17:35 -0700479}
480
Emmanuel Gil Peyrota1d214b2017-02-21 11:58:20 +0000481WL_EXPORT
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400482int
483weston_config_next_section(struct weston_config *config,
484 struct weston_config_section **section,
485 const char **name)
486{
Mun Gwan-gyeong151a5282013-05-28 00:04:26 +0900487 if (config == NULL)
488 return 0;
489
Kristian Høgsbergf73f3162013-05-26 20:50:53 -0400490 if (*section == NULL)
491 *section = container_of(config->section_list.next,
492 struct weston_config_section, link);
493 else
494 *section = container_of((*section)->link.next,
495 struct weston_config_section, link);
496
497 if (&(*section)->link == &config->section_list)
498 return 0;
499
500 *name = (*section)->name;
501
502 return 1;
503}
504
Daniel Stone3ef098f2019-11-25 10:30:11 +0000505WL_EXPORT
Kristian Høgsberg73274712013-04-01 12:41:23 -0400506void
507weston_config_destroy(struct weston_config *config)
508{
509 struct weston_config_section *s, *next_s;
510 struct weston_config_entry *e, *next_e;
511
Mun Gwan-gyeong77325402013-05-28 00:20:04 +0900512 if (config == NULL)
513 return;
514
Kristian Høgsberg73274712013-04-01 12:41:23 -0400515 wl_list_for_each_safe(s, next_s, &config->section_list, link) {
516 wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
517 free(e->key);
518 free(e->value);
519 free(e);
520 }
521 free(s->name);
522 free(s);
523 }
524
525 free(config);
526}