-
Notifications
You must be signed in to change notification settings - Fork 177
/
default-config-backend.cpp
151 lines (123 loc) · 4.25 KB
/
default-config-backend.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
#include <vector>
#include "wayfire/debug.hpp"
#include "wayfire/signal-definitions.hpp"
#include <string>
#include <wayfire/config/file.hpp>
#include <wayfire/config-backend.hpp>
#include <wayfire/plugin.hpp>
#include <wayfire/core.hpp>
#include <cstring>
#include <sys/inotify.h>
#include <filesystem>
#include <unistd.h>
#define INOT_BUF_SIZE (sizeof(inotify_event) + NAME_MAX + 1)
static std::string config_dir, config_file;
wf::config::config_manager_t *cfg_manager;
static int wd_cfg_dir, wd_cfg_file;
static void add_watch(int fd)
{
wd_cfg_dir = inotify_add_watch(fd, config_dir.c_str(), IN_CREATE | IN_MOVED_TO);
wd_cfg_file = inotify_add_watch(fd, config_file.c_str(), IN_CLOSE_WRITE);
}
static void reload_config(int fd)
{
wf::config::load_configuration_options_from_file(*cfg_manager, config_file);
}
static int handle_config_updated(int fd, uint32_t mask, void *data)
{
if ((mask & WL_EVENT_READABLE) == 0)
{
return 0;
}
char buf[INOT_BUF_SIZE] __attribute__((aligned(alignof(inotify_event))));
bool should_reload = false;
inotify_event *event;
// Reading from the inotify FD is guaranteed to not read partial events.
// From inotify(7):
// Each successful read(2) returns a buffer containing
// one or more [..] structures
auto len = read(fd, buf, INOT_BUF_SIZE);
if (len < 0)
{
return 0;
}
const auto cfg_file_basename = std::filesystem::path(config_file).filename().string();
for (char *ptr = buf;
ptr < (buf + len);
ptr += sizeof(inotify_event) + event->len)
{
event = reinterpret_cast<inotify_event*>(ptr);
// We reload in two cases:
//
// 1. The config file itself was modified, or...
should_reload |= event->wd == wd_cfg_file;
// 2. The config file was moved nto or created inside the parent directory.
if (event->len > 0)
{
// This is UB unless event->len > 0.
auto name_matches = cfg_file_basename == event->name;
if (name_matches)
{
inotify_rm_watch(fd, wd_cfg_file);
wd_cfg_file =
inotify_add_watch(fd, (config_dir + "/" + cfg_file_basename).c_str(), IN_CLOSE_WRITE);
}
should_reload |= name_matches;
}
}
if (should_reload)
{
LOGD("Reloading configuration file");
reload_config(fd);
wf::reload_config_signal ev;
wf::get_core().emit(&ev);
}
return 0;
}
static const char *CONFIG_FILE_ENV = "WAYFIRE_CONFIG_FILE";
namespace wf
{
class dynamic_ini_config_t : public wf::config_backend_t
{
public:
void init(wl_display *display, config::config_manager_t& config,
const std::string& cfg_file) override
{
cfg_manager = &config;
config_file = choose_cfg_file(cfg_file);
std::filesystem::path path = std::filesystem::absolute(config_file);
config_dir = path.parent_path();
LOGI("Using config file: ", config_file.c_str());
setenv(CONFIG_FILE_ENV, config_file.c_str(), 1);
config = wf::config::build_configuration(
get_xml_dirs(), SYSCONFDIR "/wayfire/defaults.ini", config_file);
int inotify_fd = inotify_init1(IN_CLOEXEC);
reload_config(inotify_fd);
add_watch(inotify_fd);
wl_event_loop_add_fd(wl_display_get_event_loop(display),
inotify_fd, WL_EVENT_READABLE, handle_config_updated, NULL);
}
std::string choose_cfg_file(const std::string& cmdline_cfg_file)
{
std::string env_cfg_file = nonull(getenv(CONFIG_FILE_ENV));
if (!cmdline_cfg_file.empty())
{
if ((env_cfg_file != nonull(NULL)) &&
(cmdline_cfg_file != env_cfg_file))
{
LOGW("Wayfire config file specified in the environment is ",
"overridden by the command line arguments!");
}
return cmdline_cfg_file;
}
if (env_cfg_file != nonull(NULL))
{
return env_cfg_file;
}
return (getenv("XDG_CONFIG_HOME") ?:
(std::string(nonull(getenv("HOME"))) + "/.config")) +
"/wayfire.ini";
}
};
}
DECLARE_WAYFIRE_CONFIG_BACKEND(wf::dynamic_ini_config_t);