ladishd: dump params of loaded apps after xml load
[ladish.git] / conf.c
blobed42117398013bc5a5b2ea58a0c3877526a41956
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2010 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the settings storage
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
29 #include <unistd.h>
30 #include <signal.h>
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 #include <fcntl.h>
34 #include <errno.h>
36 #include "dbus/helpers.h"
37 #include "dbus/error.h"
38 #include "dbus_constants.h"
39 #include "common/catdup.h"
40 #include "common/dirhelpers.h"
42 #define STORAGE_BASE_DIR "/.ladish/conf/"
44 extern const struct dbus_interface_descriptor g_interface;
46 static const char * g_dbus_unique_name;
47 static dbus_object_path g_object;
48 static bool g_quit;
50 struct pair
52 struct list_head siblings;
53 uint64_t version;
54 char * key;
55 char * value;
56 bool stored;
59 struct list_head g_pairs;
61 static bool connect_dbus(void)
63 int ret;
65 dbus_error_init(&g_dbus_error);
67 g_dbus_connection = dbus_bus_get(DBUS_BUS_SESSION, &g_dbus_error);
68 if (dbus_error_is_set(&g_dbus_error))
70 log_error("Failed to get bus: %s", g_dbus_error.message);
71 dbus_error_free(&g_dbus_error);
72 goto fail;
75 g_dbus_unique_name = dbus_bus_get_unique_name(g_dbus_connection);
76 if (g_dbus_unique_name == NULL)
78 log_error("Failed to read unique bus name");
79 goto unref_connection;
82 log_info("Connected to local session bus, unique name is \"%s\"", g_dbus_unique_name);
84 ret = dbus_bus_request_name(g_dbus_connection, CONF_SERVICE_NAME, DBUS_NAME_FLAG_DO_NOT_QUEUE, &g_dbus_error);
85 if (ret == -1)
87 log_error("Failed to acquire bus name: %s", g_dbus_error.message);
88 dbus_error_free(&g_dbus_error);
89 goto unref_connection;
92 if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
94 log_error("Requested connection name already exists");
95 goto unref_connection;
98 g_object = dbus_object_path_new(CONF_OBJECT_PATH, &g_interface, NULL, NULL);
99 if (g_object == NULL)
101 goto unref_connection;
104 if (!dbus_object_path_register(g_dbus_connection, g_object))
106 goto destroy_control_object;
109 return true;
111 destroy_control_object:
112 dbus_object_path_destroy(g_dbus_connection, g_object);
113 unref_connection:
114 dbus_connection_unref(g_dbus_connection);
116 fail:
117 return false;
120 static void disconnect_dbus(void)
122 dbus_object_path_destroy(g_dbus_connection, g_object);
123 dbus_connection_unref(g_dbus_connection);
126 void term_signal_handler(int signum)
128 log_info("Caught signal %d (%s), terminating", signum, strsignal(signum));
129 g_quit = true;
132 bool install_term_signal_handler(int signum, bool ignore_if_already_ignored)
134 sig_t sigh;
136 sigh = signal(signum, term_signal_handler);
137 if (sigh == SIG_ERR)
139 log_error("signal() failed to install handler function for signal %d.", signum);
140 return false;
143 if (sigh == SIG_IGN && ignore_if_already_ignored)
145 signal(SIGTERM, SIG_IGN);
148 return true;
151 int main(int argc, char ** argv)
153 int ret;
155 if (getenv("HOME") == NULL)
157 log_error("Environment variable HOME not set");
158 return 1;
161 INIT_LIST_HEAD(&g_pairs);
163 install_term_signal_handler(SIGTERM, false);
164 install_term_signal_handler(SIGINT, true);
166 if (!connect_dbus())
168 log_error("Failed to connect to D-Bus");
169 return 1;
172 while (!g_quit)
174 dbus_connection_read_write_dispatch(g_dbus_connection, 50);
177 ret = 0;
179 disconnect_dbus();
180 return 0;
183 static struct pair * create_pair(const char * key, const char * value)
185 struct pair * pair_ptr;
187 pair_ptr = malloc(sizeof(struct pair));
188 if (pair_ptr == NULL)
190 log_error("malloc() failed to allocate memory for pair struct");
191 return NULL;
194 pair_ptr->key = strdup(key);
195 if (pair_ptr->key == NULL)
197 log_error("strdup(\"%s\") failed for key", key);
198 free(pair_ptr);
199 return NULL;
202 if (value != NULL)
204 pair_ptr->value = strdup(value);
205 if (pair_ptr->value == NULL)
207 log_error("strdup(\"%s\") failed for value", value);
208 free(pair_ptr->key);
209 free(pair_ptr);
210 return NULL;
213 else
215 /* Caller will fill this shortly */
216 pair_ptr->value = NULL;
219 pair_ptr->version = 1;
220 pair_ptr->stored = false;
222 list_add_tail(&pair_ptr->siblings, &g_pairs);
224 return pair_ptr;
227 static bool store_pair(struct pair * pair_ptr)
229 char * dirpath;
230 char * filepath;
231 int fd;
232 size_t len;
233 ssize_t written;
235 dirpath = catdupv(getenv("HOME"), STORAGE_BASE_DIR, pair_ptr->key, NULL);
236 if (dirpath == NULL)
238 return false;
241 if (!ensure_dir_exist(dirpath, 0700))
243 free(dirpath);
244 return false;
247 filepath = catdup(dirpath, "/value");
248 free(dirpath);
249 if (filepath == NULL)
251 return false;
254 fd = creat(filepath, 0700);
255 if (fd == -1)
257 log_error("Failed to create \"%s\": %d (%s)", filepath, errno, strerror(errno));
258 free(filepath);
259 return false;
262 len = strlen(pair_ptr->value);
264 written = write(fd, pair_ptr->value, len);
265 if (written < 0)
267 log_error("Failed to write() to \"%s\": %d (%s)", filepath, errno, strerror(errno));
268 free(filepath);
269 return false;
272 if ((size_t)written != len)
274 log_error("write() to \"%s\" returned %zd instead of %zu", filepath, written, len);
275 free(filepath);
276 return false;
279 close(fd);
280 free(filepath);
282 pair_ptr->stored = true;
284 return true;
287 static struct pair * load_pair(const char * key)
289 struct pair * pair_ptr;
290 char * path;
291 struct stat st;
292 int fd;
293 char * buffer;
294 ssize_t bytes_read;
296 path = catdupv(getenv("HOME"), STORAGE_BASE_DIR, key, "/value", NULL);
297 if (path == NULL)
299 return false;
302 if (stat(path, &st) != 0)
304 log_error("Failed to stat \"%s\": %d (%s)", path, errno, strerror(errno));
305 free(path);
306 return false;
309 if (!S_ISREG(st.st_mode))
311 log_error("\"%s\" is not a regular file.", path);
312 free(path);
313 return false;
316 fd = open(path, O_RDONLY);
317 if (fd == -1)
319 log_error("Failed to open \"%s\": %d (%s)", path, errno, strerror(errno));
320 free(path);
321 return false;
324 buffer = malloc((size_t)st.st_size + 1);
325 if (buffer == NULL)
327 log_error("malloc() failed to allocate %zu bytes of memory for value", (size_t)st.st_size + 1);
328 close(fd);
329 free(path);
330 return false;
333 bytes_read = read(fd, buffer, st.st_size);
334 if (bytes_read < 0)
336 log_error("Failed to read() from \"%s\": %d (%s)", path, errno, strerror(errno));
337 free(buffer);
338 close(fd);
339 free(path);
340 return false;
343 if (bytes_read != st.st_size)
345 log_error("read() from \"%s\" returned %zd instead of %llu", path, bytes_read, (unsigned long long)st.st_size);
346 free(buffer);
347 close(fd);
348 free(path);
349 return false;
352 buffer[st.st_size] = 0;
354 pair_ptr = create_pair(key, NULL);
355 if (pair_ptr == NULL)
357 free(buffer);
358 close(fd);
359 free(path);
360 return false;
363 pair_ptr->value = buffer;
365 close(fd);
366 free(path);
368 return pair_ptr;
371 static struct pair * find_pair(const char * key)
373 struct list_head * node_ptr;
374 struct pair * pair_ptr;
376 list_for_each(node_ptr, &g_pairs)
378 pair_ptr = list_entry(node_ptr, struct pair, siblings);
379 if (strcmp(pair_ptr->key, key) == 0)
381 return pair_ptr;
385 return NULL;
388 static void emit_changed(struct pair * pair_ptr)
390 dbus_signal_emit(
391 g_dbus_connection,
392 CONF_OBJECT_PATH,
393 CONF_IFACE,
394 "changed",
395 "sst",
396 &pair_ptr->key,
397 &pair_ptr->value,
398 &pair_ptr->version);
401 /***************************************************************************/
402 /* D-Bus interface implementation */
404 static void conf_set(struct dbus_method_call * call_ptr)
406 const char * key;
407 const char * value;
408 struct pair * pair_ptr;
409 char * buffer;
410 bool store;
412 if (!dbus_message_get_args(
413 call_ptr->message,
414 &g_dbus_error,
415 DBUS_TYPE_STRING, &key,
416 DBUS_TYPE_STRING, &value,
417 DBUS_TYPE_INVALID))
419 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
420 dbus_error_free(&g_dbus_error);
421 return;
424 log_info("set '%s' <- '%s'", key, value);
426 pair_ptr = find_pair(key);
427 if (pair_ptr == NULL)
429 pair_ptr = create_pair(key, value);
430 if (pair_ptr == NULL)
432 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Memory allocation failed");
433 return;
436 emit_changed(pair_ptr);
438 store = true;
440 else
442 store = strcmp(pair_ptr->value, value) != 0;
443 if (store)
445 buffer = strdup(value);
446 if (buffer == NULL)
448 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Memory allocation failed. strdup(\"%s\") failed for value", value);
449 return;
451 free(pair_ptr->value);
452 pair_ptr->value = buffer;
453 pair_ptr->version++;
454 pair_ptr->stored = false; /* mark that new value was not stored on disk yet */
456 emit_changed(pair_ptr);
458 else if (!pair_ptr->stored) /* if store to disk failed last time, retry */
460 store = true;
464 if (store)
466 if (!store_pair(pair_ptr))
468 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "Storing the value of key '%s' to disk failed", pair_ptr->key);
469 return;
473 method_return_new_single(call_ptr, DBUS_TYPE_UINT64, &pair_ptr->version);
476 static void conf_get(struct dbus_method_call * call_ptr)
478 const char * key;
479 struct pair * pair_ptr;
481 if (!dbus_message_get_args(
482 call_ptr->message,
483 &g_dbus_error,
484 DBUS_TYPE_STRING, &key,
485 DBUS_TYPE_INVALID))
487 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_INVALID_ARGS, "Invalid arguments to method \"%s\": %s", call_ptr->method_name, g_dbus_error.message);
488 dbus_error_free(&g_dbus_error);
489 return;
492 pair_ptr = find_pair(key);
493 if (pair_ptr == NULL)
495 pair_ptr = load_pair(key);
496 if (pair_ptr == NULL)
498 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_KEY_NOT_FOUND, "Key '%s' not found", key);
499 return;
503 log_info("get '%s' -> '%s'", key, pair_ptr->value);
505 method_return_new_valist(
506 call_ptr,
507 DBUS_TYPE_STRING, &pair_ptr->value,
508 DBUS_TYPE_UINT64, &pair_ptr->version,
509 DBUS_TYPE_INVALID);
512 static void conf_exit(struct dbus_method_call * call_ptr)
514 log_info("Exit command received through D-Bus");
515 g_quit = true;
516 method_return_new_void(call_ptr);
519 METHOD_ARGS_BEGIN(set, "Set conf value")
520 METHOD_ARG_DESCRIBE_IN("key", DBUS_TYPE_STRING_AS_STRING, "")
521 METHOD_ARG_DESCRIBE_IN("value", DBUS_TYPE_STRING_AS_STRING, "")
522 METHOD_ARG_DESCRIBE_OUT("version", DBUS_TYPE_UINT64_AS_STRING, "")
523 METHOD_ARGS_END
525 METHOD_ARGS_BEGIN(get, "Get conf value")
526 METHOD_ARG_DESCRIBE_IN("key", DBUS_TYPE_STRING_AS_STRING, "")
527 METHOD_ARG_DESCRIBE_OUT("value", DBUS_TYPE_STRING_AS_STRING, "")
528 METHOD_ARG_DESCRIBE_OUT("version", DBUS_TYPE_UINT64_AS_STRING, "")
529 METHOD_ARGS_END
531 METHOD_ARGS_BEGIN(exit, "Tell conf D-Bus service to exit")
532 METHOD_ARGS_END
534 METHODS_BEGIN
535 METHOD_DESCRIBE(set, conf_set)
536 METHOD_DESCRIBE(get, conf_get)
537 METHOD_DESCRIBE(exit, conf_exit)
538 METHODS_END
540 SIGNAL_ARGS_BEGIN(changed, "")
541 SIGNAL_ARG_DESCRIBE("key", DBUS_TYPE_STRING_AS_STRING, "")
542 SIGNAL_ARG_DESCRIBE("value", DBUS_TYPE_STRING_AS_STRING, "")
543 SIGNAL_ARG_DESCRIBE("version", DBUS_TYPE_UINT64_AS_STRING, "")
544 SIGNAL_ARGS_END
546 SIGNALS_BEGIN
547 SIGNAL_DESCRIBE(changed)
548 SIGNALS_END
550 INTERFACE_BEGIN(g_interface, CONF_IFACE)
551 INTERFACE_DEFAULT_HANDLER
552 INTERFACE_EXPOSE_METHODS
553 INTERFACE_EXPOSE_SIGNALS
554 INTERFACE_END