2011-11-15 03:43:37 +00:00
|
|
|
/*
|
|
|
|
* Copyright © 2011 Intel Corporation
|
|
|
|
*
|
2015-06-11 21:20:17 +00:00
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
* the following conditions:
|
2011-11-15 03:43:37 +00:00
|
|
|
*
|
2015-06-11 21:20:17 +00:00
|
|
|
* The above copyright notice and this permission notice (including the
|
|
|
|
* next paragraph) shall be included in all copies or substantial
|
|
|
|
* portions of the Software.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
|
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
* SOFTWARE.
|
2011-11-15 03:43:37 +00:00
|
|
|
*/
|
|
|
|
|
2013-05-22 15:03:19 +00:00
|
|
|
#include "config.h"
|
|
|
|
|
2011-11-15 03:43:37 +00:00
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <assert.h>
|
2012-08-04 01:56:41 +00:00
|
|
|
#include <ctype.h>
|
2013-05-14 16:48:26 +00:00
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
2013-04-01 16:41:23 +00:00
|
|
|
#include <errno.h>
|
2011-11-15 03:43:37 +00:00
|
|
|
|
2013-04-01 16:41:23 +00:00
|
|
|
#include <wayland-util.h>
|
2011-12-08 17:44:27 +00:00
|
|
|
#include "config-parser.h"
|
2011-11-15 03:43:37 +00:00
|
|
|
|
2013-05-27 00:50:53 +00:00
|
|
|
#define container_of(ptr, type, member) ({ \
|
|
|
|
const __typeof__( ((type *)0)->member ) *__mptr = (ptr); \
|
|
|
|
(type *)( (char *)__mptr - offsetof(type,member) );})
|
|
|
|
|
2013-09-22 06:17:35 +00:00
|
|
|
struct weston_config_entry {
|
|
|
|
char *key;
|
|
|
|
char *value;
|
|
|
|
struct wl_list link;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct weston_config_section {
|
|
|
|
char *name;
|
|
|
|
struct wl_list entry_list;
|
|
|
|
struct wl_list link;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct weston_config {
|
|
|
|
struct wl_list section_list;
|
|
|
|
char path[PATH_MAX];
|
|
|
|
};
|
|
|
|
|
2013-09-22 06:02:31 +00:00
|
|
|
static int
|
2013-09-22 06:17:35 +00:00
|
|
|
open_config_file(struct weston_config *c, const char *name)
|
2011-11-15 09:45:40 +00:00
|
|
|
{
|
2013-05-14 16:48:26 +00:00
|
|
|
const char *config_dir = getenv("XDG_CONFIG_HOME");
|
|
|
|
const char *home_dir = getenv("HOME");
|
|
|
|
const char *config_dirs = getenv("XDG_CONFIG_DIRS");
|
|
|
|
const char *p, *next;
|
|
|
|
int fd;
|
|
|
|
|
2013-09-22 06:17:35 +00:00
|
|
|
if (name[0] == '/') {
|
|
|
|
snprintf(c->path, sizeof c->path, "%s", name);
|
2013-09-22 06:02:31 +00:00
|
|
|
return open(name, O_RDONLY | O_CLOEXEC);
|
2013-09-22 06:17:35 +00:00
|
|
|
}
|
2013-09-22 06:02:31 +00:00
|
|
|
|
2013-05-14 16:48:26 +00:00
|
|
|
/* Precedence is given to config files in the home directory,
|
|
|
|
* and then to directories listed in XDG_CONFIG_DIRS and
|
|
|
|
* finally to the current working directory. */
|
|
|
|
|
|
|
|
/* $XDG_CONFIG_HOME */
|
|
|
|
if (config_dir) {
|
2013-09-22 06:17:35 +00:00
|
|
|
snprintf(c->path, sizeof c->path, "%s/%s", config_dir, name);
|
|
|
|
fd = open(c->path, O_RDONLY | O_CLOEXEC);
|
2013-05-14 16:48:26 +00:00
|
|
|
if (fd >= 0)
|
|
|
|
return fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* $HOME/.config */
|
|
|
|
if (home_dir) {
|
2013-09-22 06:17:35 +00:00
|
|
|
snprintf(c->path, sizeof c->path,
|
|
|
|
"%s/.config/%s", home_dir, name);
|
|
|
|
fd = open(c->path, O_RDONLY | O_CLOEXEC);
|
2013-05-14 16:48:26 +00:00
|
|
|
if (fd >= 0)
|
|
|
|
return fd;
|
|
|
|
}
|
2011-11-15 09:45:40 +00:00
|
|
|
|
2013-05-14 16:48:26 +00:00
|
|
|
/* For each $XDG_CONFIG_DIRS: weston/<config_file> */
|
|
|
|
if (!config_dirs)
|
|
|
|
config_dirs = "/etc/xdg"; /* See XDG base dir spec. */
|
2011-11-15 09:45:40 +00:00
|
|
|
|
2013-05-14 16:48:26 +00:00
|
|
|
for (p = config_dirs; *p != '\0'; p = next) {
|
|
|
|
next = strchrnul(p, ':');
|
2013-09-22 06:17:35 +00:00
|
|
|
snprintf(c->path, sizeof c->path,
|
2013-05-14 16:48:26 +00:00
|
|
|
"%.*s/weston/%s", (int)(next - p), p, name);
|
2013-09-22 06:17:35 +00:00
|
|
|
fd = open(c->path, O_RDONLY | O_CLOEXEC);
|
2013-05-14 16:48:26 +00:00
|
|
|
if (fd >= 0)
|
|
|
|
return fd;
|
|
|
|
|
|
|
|
if (*next == ':')
|
|
|
|
next++;
|
2011-11-15 09:45:40 +00:00
|
|
|
}
|
|
|
|
|
2013-05-14 16:48:26 +00:00
|
|
|
/* Current working directory. */
|
2013-09-22 06:17:35 +00:00
|
|
|
snprintf(c->path, sizeof c->path, "./%s", name);
|
2011-11-15 09:45:40 +00:00
|
|
|
|
2013-09-22 06:17:35 +00:00
|
|
|
return open(c->path, O_RDONLY | O_CLOEXEC);
|
2011-11-15 09:45:40 +00:00
|
|
|
}
|
2013-04-01 16:41:23 +00:00
|
|
|
|
|
|
|
static struct weston_config_entry *
|
|
|
|
config_section_get_entry(struct weston_config_section *section,
|
|
|
|
const char *key)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *e;
|
|
|
|
|
|
|
|
if (section == NULL)
|
|
|
|
return NULL;
|
|
|
|
wl_list_for_each(e, §ion->entry_list, link)
|
|
|
|
if (strcmp(e->key, key) == 0)
|
|
|
|
return e;
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-01 15:03:08 +00:00
|
|
|
WL_EXPORT
|
2013-04-01 16:41:23 +00:00
|
|
|
struct weston_config_section *
|
|
|
|
weston_config_get_section(struct weston_config *config, const char *section,
|
|
|
|
const char *key, const char *value)
|
|
|
|
{
|
|
|
|
struct weston_config_section *s;
|
|
|
|
struct weston_config_entry *e;
|
|
|
|
|
config-parser: Avoid null dereference when handling config-parser
backtrace:
(gdb) bt
#0 weston_config_get_section (config=0x0, section=0x8062f31 "keyboard", key=0x0, value=0x0)
at config-parser.c:265
#1 0x080535a1 in weston_compositor_init (ec=0x905b690, display=0x9056490, argc=0xbf8bd2f0,
argv=0xbf8bd384, config_fd=-1) at compositor.c:2819
#2 0xb75d72bb in x11_compositor_create (config_fd=-1, argv=0xbf8bd384, argc=<optimized out>,
use_pixman=0, no_input=0, fullscreen=0, display=0x9056490) at compositor-x11.c:1527
#3 backend_init (display=0x9056490, argc=0xbf8bd2f0, argv=0xbf8bd384, config_fd=-1)
at compositor-x11.c:1746
2013-05-24 17:09:13 +00:00
|
|
|
if (config == NULL)
|
|
|
|
return NULL;
|
2013-04-01 16:41:23 +00:00
|
|
|
wl_list_for_each(s, &config->section_list, link) {
|
|
|
|
if (strcmp(s->name, section) != 0)
|
|
|
|
continue;
|
|
|
|
if (key == NULL)
|
|
|
|
return s;
|
|
|
|
e = config_section_get_entry(s, key);
|
|
|
|
if (e && strcmp(e->value, value) == 0)
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-01 15:03:08 +00:00
|
|
|
WL_EXPORT
|
2013-04-01 16:41:23 +00:00
|
|
|
int
|
|
|
|
weston_config_section_get_int(struct weston_config_section *section,
|
|
|
|
const char *key,
|
|
|
|
int32_t *value, int32_t default_value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
entry = config_section_get_entry(section, key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
*value = default_value;
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = strtol(entry->value, &end, 0);
|
|
|
|
if (*end != '\0') {
|
|
|
|
*value = default_value;
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-01 15:03:08 +00:00
|
|
|
WL_EXPORT
|
2013-04-01 16:41:23 +00:00
|
|
|
int
|
|
|
|
weston_config_section_get_uint(struct weston_config_section *section,
|
|
|
|
const char *key,
|
|
|
|
uint32_t *value, uint32_t default_value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
entry = config_section_get_entry(section, key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
*value = default_value;
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = strtoul(entry->value, &end, 0);
|
|
|
|
if (*end != '\0') {
|
|
|
|
*value = default_value;
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-30 23:41:03 +00:00
|
|
|
WL_EXPORT
|
|
|
|
int
|
|
|
|
weston_config_section_get_double(struct weston_config_section *section,
|
|
|
|
const char *key,
|
|
|
|
double *value, double default_value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
char *end;
|
|
|
|
|
|
|
|
entry = config_section_get_entry(section, key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
*value = default_value;
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = strtod(entry->value, &end);
|
|
|
|
if (*end != '\0') {
|
|
|
|
*value = default_value;
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-01 15:03:08 +00:00
|
|
|
WL_EXPORT
|
2013-04-01 16:41:23 +00:00
|
|
|
int
|
|
|
|
weston_config_section_get_string(struct weston_config_section *section,
|
|
|
|
const char *key,
|
|
|
|
char **value, const char *default_value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
|
|
|
|
entry = config_section_get_entry(section, key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
if (default_value)
|
|
|
|
*value = strdup(default_value);
|
|
|
|
else
|
|
|
|
*value = NULL;
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*value = strdup(entry->value);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-01 15:03:08 +00:00
|
|
|
WL_EXPORT
|
2013-04-01 16:41:23 +00:00
|
|
|
int
|
|
|
|
weston_config_section_get_bool(struct weston_config_section *section,
|
|
|
|
const char *key,
|
|
|
|
int *value, int default_value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
|
|
|
|
entry = config_section_get_entry(section, key);
|
|
|
|
if (entry == NULL) {
|
|
|
|
*value = default_value;
|
|
|
|
errno = ENOENT;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp(entry->value, "false") == 0)
|
|
|
|
*value = 0;
|
|
|
|
else if (strcmp(entry->value, "true") == 0)
|
|
|
|
*value = 1;
|
|
|
|
else {
|
|
|
|
*value = default_value;
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-08-21 16:32:38 +00:00
|
|
|
WL_EXPORT
|
|
|
|
const char *
|
|
|
|
weston_config_get_libexec_dir(void)
|
|
|
|
{
|
|
|
|
const char *path = getenv("WESTON_BUILD_DIR");
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
return path;
|
|
|
|
|
|
|
|
return LIBEXECDIR;
|
|
|
|
}
|
|
|
|
|
2015-03-24 13:56:19 +00:00
|
|
|
const char *
|
|
|
|
weston_config_get_name_from_env(void)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
|
|
|
|
name = getenv(WESTON_CONFIG_FILE_ENV_VAR);
|
|
|
|
if (name)
|
|
|
|
return name;
|
|
|
|
|
|
|
|
return "weston.ini";
|
|
|
|
}
|
|
|
|
|
2013-04-01 16:41:23 +00:00
|
|
|
static struct weston_config_section *
|
|
|
|
config_add_section(struct weston_config *config, const char *name)
|
|
|
|
{
|
|
|
|
struct weston_config_section *section;
|
|
|
|
|
|
|
|
section = malloc(sizeof *section);
|
|
|
|
section->name = strdup(name);
|
|
|
|
wl_list_init(§ion->entry_list);
|
|
|
|
wl_list_insert(config->section_list.prev, §ion->link);
|
|
|
|
|
|
|
|
return section;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct weston_config_entry *
|
|
|
|
section_add_entry(struct weston_config_section *section,
|
|
|
|
const char *key, const char *value)
|
|
|
|
{
|
|
|
|
struct weston_config_entry *entry;
|
|
|
|
|
|
|
|
entry = malloc(sizeof *entry);
|
|
|
|
entry->key = strdup(key);
|
|
|
|
entry->value = strdup(value);
|
|
|
|
wl_list_insert(section->entry_list.prev, &entry->link);
|
|
|
|
|
|
|
|
return entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct weston_config *
|
2013-09-22 06:02:31 +00:00
|
|
|
weston_config_parse(const char *name)
|
2013-04-01 16:41:23 +00:00
|
|
|
{
|
|
|
|
FILE *fp;
|
|
|
|
char line[512], *p;
|
2015-03-24 13:56:17 +00:00
|
|
|
struct stat filestat;
|
2013-04-01 16:41:23 +00:00
|
|
|
struct weston_config *config;
|
|
|
|
struct weston_config_section *section = NULL;
|
2013-09-22 06:02:31 +00:00
|
|
|
int i, fd;
|
2013-04-01 16:41:23 +00:00
|
|
|
|
|
|
|
config = malloc(sizeof *config);
|
|
|
|
if (config == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
wl_list_init(&config->section_list);
|
|
|
|
|
2013-09-22 06:17:35 +00:00
|
|
|
fd = open_config_file(config, name);
|
2013-09-22 06:02:31 +00:00
|
|
|
if (fd == -1) {
|
2013-04-01 16:41:23 +00:00
|
|
|
free(config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-24 13:56:17 +00:00
|
|
|
if (fstat(fd, &filestat) < 0 ||
|
|
|
|
!S_ISREG(filestat.st_mode)) {
|
|
|
|
close(fd);
|
|
|
|
free(config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-09-22 06:02:31 +00:00
|
|
|
fp = fdopen(fd, "r");
|
|
|
|
if (fp == NULL) {
|
|
|
|
free(config);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-04-01 16:41:23 +00:00
|
|
|
|
|
|
|
while (fgets(line, sizeof line, fp)) {
|
|
|
|
switch (line[0]) {
|
|
|
|
case '#':
|
|
|
|
case '\n':
|
|
|
|
continue;
|
|
|
|
case '[':
|
|
|
|
p = strchr(&line[1], ']');
|
|
|
|
if (!p || p[1] != '\n') {
|
|
|
|
fprintf(stderr, "malformed "
|
|
|
|
"section header: %s\n", line);
|
|
|
|
fclose(fp);
|
|
|
|
weston_config_destroy(config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
p[0] = '\0';
|
|
|
|
section = config_add_section(config, &line[1]);
|
|
|
|
continue;
|
|
|
|
default:
|
|
|
|
p = strchr(line, '=');
|
|
|
|
if (!p || p == line || !section) {
|
|
|
|
fprintf(stderr, "malformed "
|
|
|
|
"config line: %s\n", line);
|
|
|
|
fclose(fp);
|
|
|
|
weston_config_destroy(config);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
p[0] = '\0';
|
|
|
|
p++;
|
|
|
|
while (isspace(*p))
|
|
|
|
p++;
|
|
|
|
i = strlen(p);
|
|
|
|
while (i > 0 && isspace(p[i - 1])) {
|
|
|
|
p[i - 1] = '\0';
|
|
|
|
i--;
|
|
|
|
}
|
|
|
|
section_add_entry(section, line, p);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(fp);
|
|
|
|
|
|
|
|
return config;
|
|
|
|
}
|
|
|
|
|
2013-09-22 06:17:35 +00:00
|
|
|
const char *
|
|
|
|
weston_config_get_full_path(struct weston_config *config)
|
|
|
|
{
|
2013-09-26 09:27:16 +00:00
|
|
|
return config == NULL ? NULL : config->path;
|
2013-09-22 06:17:35 +00:00
|
|
|
}
|
|
|
|
|
2013-05-27 00:50:53 +00:00
|
|
|
int
|
|
|
|
weston_config_next_section(struct weston_config *config,
|
|
|
|
struct weston_config_section **section,
|
|
|
|
const char **name)
|
|
|
|
{
|
config-parser: Avoid null dereference when handling config-parser ( when weston starts without config file. )
backtrace:
(gdb) bt
#0 weston_config_next_section (config=0x0, section=0xbfb2b608, name=0xbfb2b618) at config-parser.c:485
#1 0xb75b1371 in x11_compositor_create (config=0x1, argv=0xbfb2ba44, argc=<optimized out>, use_pixman=0, no_input=0, fullscreen=0, display=0xb75b55f9)
at compositor-x11.c:1582
#2 backend_init (display=0x8354490, argc=0xbfb2b9b0, argv=0xbfb2ba44, config=0x0) at compositor-x11.c:1674
#3 0x0804df7b in main (argc=1, argv=0xbfb2ba44) at compositor.c:3289
2013-05-27 15:04:26 +00:00
|
|
|
if (config == NULL)
|
|
|
|
return 0;
|
|
|
|
|
2013-05-27 00:50:53 +00:00
|
|
|
if (*section == NULL)
|
|
|
|
*section = container_of(config->section_list.next,
|
|
|
|
struct weston_config_section, link);
|
|
|
|
else
|
|
|
|
*section = container_of((*section)->link.next,
|
|
|
|
struct weston_config_section, link);
|
|
|
|
|
|
|
|
if (&(*section)->link == &config->section_list)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
*name = (*section)->name;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2013-04-01 16:41:23 +00:00
|
|
|
void
|
|
|
|
weston_config_destroy(struct weston_config *config)
|
|
|
|
{
|
|
|
|
struct weston_config_section *s, *next_s;
|
|
|
|
struct weston_config_entry *e, *next_e;
|
|
|
|
|
2013-05-27 15:20:04 +00:00
|
|
|
if (config == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-04-01 16:41:23 +00:00
|
|
|
wl_list_for_each_safe(s, next_s, &config->section_list, link) {
|
|
|
|
wl_list_for_each_safe(e, next_e, &s->entry_list, link) {
|
|
|
|
free(e->key);
|
|
|
|
free(e->value);
|
|
|
|
free(e);
|
|
|
|
}
|
|
|
|
free(s->name);
|
|
|
|
free(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(config);
|
|
|
|
}
|