From c0c5736a4e0d41adc9c97577006c289718c926de Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Thu, 8 Aug 2013 20:32:53 -0300 Subject: [PATCH] ecore: add system modules, implement 'systemd'. Ecore will now load "system modules" on ecore_init(). The "systemd" module will use DBus to monitor localed, hostnamed and timedated and add system events related to those changes. --- configure.ac | 2 + data/Makefile.am | 6 + data/ecore/checkme | 1 + pc/ecore.pc.in | 2 + src/Makefile_Ecore.am | 32 +- src/lib/ecore/ecore.c | 90 +++++ .../system/systemd/ecore_system_systemd.c | 354 ++++++++++++++++++ 7 files changed, 486 insertions(+), 1 deletion(-) create mode 100644 data/ecore/checkme create mode 100644 src/modules/ecore/system/systemd/ecore_system_systemd.c diff --git a/configure.ac b/configure.ac index 0d4f96bbf7..1a01978bb8 100644 --- a/configure.ac +++ b/configure.ac @@ -549,6 +549,8 @@ AC_ARG_ENABLE([systemd], fi ], [want_systemd="no"]) +AM_CONDITIONAL([WANT_SYSTEMD], [test "${want_systemd}" = "yes"]) + #### Platform-dependent DL_LIBS="" diff --git a/data/Makefile.am b/data/Makefile.am index e6926e5a8b..5cd88de865 100644 --- a/data/Makefile.am +++ b/data/Makefile.am @@ -21,6 +21,12 @@ eezefilesdir = $(datadir)/eeze eezefiles_DATA = eeze/checkme EXTRA_DIST += $(eezefiles_DATA) +######################################################################## +# Ecore +ecorefilesdir = $(datadir)/ecore +ecorefiles_DATA = ecore/checkme +EXTRA_DIST += $(ecorefiles_DATA) + ######################################################################## # Ecore_Imf ecoreimffilesdir = $(datadir)/ecore_imf diff --git a/data/ecore/checkme b/data/ecore/checkme new file mode 100644 index 0000000000..1688a66696 --- /dev/null +++ b/data/ecore/checkme @@ -0,0 +1 @@ +This is just a test file used to help ecore determine its prefix location. diff --git a/pc/ecore.pc.in b/pc/ecore.pc.in index 2f0de2a907..ab7004a420 100644 --- a/pc/ecore.pc.in +++ b/pc/ecore.pc.in @@ -2,6 +2,8 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ libdir=@libdir@ includedir=@includedir@ +modules=@libdir@/ecore +module_arch=@MODULE_ARCH@ Name: ecore Description: Ecore event abstraction library diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am index 40329a06c3..5e6515ba56 100644 --- a/src/Makefile_Ecore.am +++ b/src/Makefile_Ecore.am @@ -52,11 +52,41 @@ lib_ecore_libecore_la_SOURCES += lib/ecore/ecore_signal.c lib/ecore/ecore_exe.c endif endif -lib_ecore_libecore_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @ECORE_CFLAGS@ +lib_ecore_libecore_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)/ecore\" \ +-DPACKAGE_BUILD_DIR=\"`pwd`/$(top_builddir)\" \ +@ECORE_CFLAGS@ lib_ecore_libecore_la_LIBADD = @ECORE_LIBS@ lib_ecore_libecore_la_DEPENDENCIES = @ECORE_INTERNAL_LIBS@ lib_ecore_libecore_la_LDFLAGS = @EFL_LTLIBRARY_FLAGS@ + +### Modules + +# systemd + +if WANT_SYSTEMD +ecoresystemdpkgdir = $(libdir)/ecore/system/systemd/$(MODULE_ARCH) +ecoresystemdpkg_LTLIBRARIES = modules/ecore/system/systemd/module.la +modules_ecore_system_systemd_module_la_SOURCES = \ +modules/ecore/system/systemd/ecore_system_systemd.c +modules_ecore_system_systemd_module_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib/efl \ +@ECORE_CFLAGS@ \ +@ELDBUS_CFLAGS@ +modules_ecore_system_systemd_module_la_LIBADD = \ +@USE_ECORE_LIBS@ \ +@USE_ELDBUS_LIBS@ +modules_ecore_system_systemd_module_la_DEPENDENCIES = \ +@USE_ECORE_INTERNAL_LIBS@ \ +@USE_ELDBUS_INTERNAL_LIBS@ +modules_ecore_system_systemd_module_la_LDFLAGS = -module @EFL_LTMODULE_FLAGS@ +modules_ecore_system_systemd_module_la_LIBTOOLFLAGS = --tag=disable-static +endif + + ### Unit tests if EFL_ENABLE_TESTS diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c index 28726a2229..489dc6074d 100644 --- a/src/lib/ecore/ecore.c +++ b/src/lib/ecore/ecore.c @@ -116,6 +116,77 @@ int _ecore_main_lock_count; # define CODESET "INVALID" #endif +static Eina_Prefix *_ecore_pfx = NULL; +static Eina_Array *module_list = NULL; + +static void +ecore_system_modules_load(void) +{ + char buf[PATH_MAX] = ""; + char *path; + + if (getenv("EFL_RUN_IN_TREE")) + { + struct stat st; + snprintf(buf, sizeof(buf), "%s/src/modules/ecore/system", + PACKAGE_BUILD_DIR); + if (stat(buf, &st) == 0) + { + const char *built_modules[] = { +#ifdef HAVE_SYSTEMD + "systemd", +#endif + NULL + }; + const char **itr; + for (itr = built_modules; *itr != NULL; itr++) + { + snprintf(buf, sizeof(buf), + "%s/src/modules/ecore/system/%s/.libs", + PACKAGE_BUILD_DIR, *itr); + module_list = eina_module_list_get(module_list, buf, + EINA_FALSE, NULL, NULL); + } + + if (module_list) + eina_module_list_load(module_list); + return; + } + } + + path = eina_module_environment_path_get("ECORE_MODULES_DIR", + "/ecore/system"); + if (path) + { + module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH); + free(path); + } + + path = eina_module_environment_path_get("HOME", "/.ecore/system"); + if (path) + { + module_list = eina_module_arch_list_get(module_list, path, MODULE_ARCH); + free(path); + } + + snprintf(buf, sizeof(buf), "%s/ecore/system", + eina_prefix_lib_get(_ecore_pfx)); + module_list = eina_module_arch_list_get(module_list, buf, MODULE_ARCH); + + eina_module_list_load(module_list); +} + +static void +ecore_system_modules_unload(void) +{ + if (module_list) + { + eina_module_list_free(module_list); + eina_array_free(module_list); + module_list = NULL; + } +} + /** * @addtogroup Ecore_Init_Group * @@ -170,6 +241,16 @@ ecore_init(void) goto shutdown_log_dom; } + _ecore_pfx = eina_prefix_new(NULL, ecore_init, + "ECORE", "ecore", "checkme", + PACKAGE_BIN_DIR, PACKAGE_LIB_DIR, + PACKAGE_DATA_DIR, PACKAGE_DATA_DIR); + if (!_ecore_pfx) + { + ERR("Could not get ecore installation prefix"); + goto shutdown_log_dom; + } + eo_init(); if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1; @@ -230,6 +311,9 @@ ecore_init(void) EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); + + ecore_system_modules_load(); + return _ecore_init_count; shutdown_mempool: @@ -273,6 +357,8 @@ ecore_shutdown(void) if (--_ecore_init_count != 0) goto unlock; + ecore_system_modules_unload(); + eina_log_timing(_ecore_log_dom, EINA_LOG_STATE_START, EINA_LOG_STATE_SHUTDOWN); @@ -345,6 +431,10 @@ ecore_shutdown(void) ecore_mempool_shutdown(); eina_log_domain_unregister(_ecore_log_dom); _ecore_log_dom = -1; + + eina_prefix_free(_ecore_pfx); + _ecore_pfx = NULL; + eina_shutdown(); #ifdef HAVE_EVIL evil_shutdown(); diff --git a/src/modules/ecore/system/systemd/ecore_system_systemd.c b/src/modules/ecore/system/systemd/ecore_system_systemd.c new file mode 100644 index 0000000000..0943775ead --- /dev/null +++ b/src/modules/ecore/system/systemd/ecore_system_systemd.c @@ -0,0 +1,354 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include + +static int _log_dom = -1; +static Eldbus_Connection *_conn = NULL; + +static Eina_List *_objs = NULL; +static Eina_List *_proxies = NULL; + +#ifdef CRITICAL +#undef CRITICAL +#endif +#define CRITICAL(...) EINA_LOG_DOM_CRIT(_log_dom, __VA_ARGS__) + +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(_log_dom, __VA_ARGS__) + +#ifdef WRN +#undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_log_dom, __VA_ARGS__) + +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(_log_dom, __VA_ARGS__) + + +static void +_props_changed_hostname(void *data EINA_UNUSED, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *changed, *entry, *invalidated; + const char *iface, *prop; + + if (!eldbus_message_arguments_get(msg, "sa{sv}as", + &iface, &changed, &invalidated)) + { + ERR("Error getting data from properties changed signal."); + return; + } + + while (eldbus_message_iter_get_and_next(changed, 'e', &entry)) + { + const void *key; + Eldbus_Message_Iter *var; + if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var)) + continue; + if (strcmp(key, "Hostname") == 0) + goto changed_hostname; + } + + while (eldbus_message_iter_get_and_next(invalidated, 's', &prop)) + { + if (strcmp(prop, "Hostname") == 0) + goto changed_hostname; + } + + return; + + changed_hostname: + ecore_event_add(ECORE_EVENT_HOSTNAME_CHANGED, NULL, NULL, NULL); +} + +static void +_props_changed_timedate(void *data EINA_UNUSED, const Eldbus_Message *msg) +{ + Eldbus_Message_Iter *changed, *entry, *invalidated; + const char *iface, *prop; + + if (!eldbus_message_arguments_get(msg, "sa{sv}as", + &iface, &changed, &invalidated)) + { + ERR("Error getting data from properties changed signal."); + return; + } + + while (eldbus_message_iter_get_and_next(changed, 'e', &entry)) + { + const void *key; + Eldbus_Message_Iter *var; + if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var)) + continue; + if (strcmp(key, "Timezone") == 0) + goto changed_timedate; + } + + while (eldbus_message_iter_get_and_next(invalidated, 's', &prop)) + { + if (strcmp(prop, "Timezone") == 0) + goto changed_timedate; + } + + return; + + changed_timedate: + ecore_event_add(ECORE_EVENT_SYSTEM_TIMEDATE_CHANGED, NULL, NULL, NULL); +} + +struct locale_cat_desc { + int cat; + int namelen; + const char *name; +}; + +static const struct locale_cat_desc locale_cat_desc[] = { +#define CAT(name) {name, sizeof(#name) - 1, #name} + CAT(LC_CTYPE), + CAT(LC_NUMERIC), + CAT(LC_TIME), + CAT(LC_COLLATE), + CAT(LC_MONETARY), + CAT(LC_MESSAGES), + CAT(LC_ALL), + CAT(LC_PAPER), + CAT(LC_NAME), + CAT(LC_ADDRESS), + CAT(LC_TELEPHONE), + CAT(LC_MEASUREMENT), + CAT(LC_IDENTIFICATION), +#undef CAT + {-1, -1, NULL} +}; + +static int _locale_parse(const char *str, int *cat, const char **value) +{ + const struct locale_cat_desc *itr; + const char *p = strchr(str, '='); + int klen; + + if (!p) goto end; + + klen = p - str; + for (itr = locale_cat_desc; itr->name != NULL; itr++) + { + if ((klen == itr->namelen) && (memcmp(str, itr->name, klen) == 0)) + { + *cat = itr->cat; + *value = str + itr->namelen + 1; + return itr - locale_cat_desc; + } + } + + end: + *cat = -1; + *value = NULL; + return -1; +} + +static void _locale_get(void *data EINA_UNUSED, const Eldbus_Message *msg, + Eldbus_Pending *pending EINA_UNUSED) +{ + Eldbus_Message_Iter *variant, *array; + const char *errname, *errmsg, *val; + Eina_Bool setlocs[EINA_C_ARRAY_LENGTH(locale_cat_desc)]; + unsigned int i; + + if (eldbus_message_error_get(msg, &errname, &errmsg)) + { + ERR("Message error %s - %s", errname, errmsg); + goto end; + } + if (!eldbus_message_arguments_get(msg, "v", &variant)) + { + ERR("Error getting arguments."); + goto end; + } + + if (!eldbus_message_iter_get_and_next(variant, 'a', &array)) + { + ERR("Error getting array."); + goto end; + } + + memset(setlocs, 0, sizeof(setlocs)); + while (eldbus_message_iter_get_and_next(array, 's', &val)) + { + int cat, idx; + const char *value; + idx = _locale_parse(val, &cat, &value); + if (idx >= 0) + setlocs[idx] = EINA_TRUE; + setlocale(cat, value); + } + + for (i = 0; i < EINA_C_ARRAY_LENGTH(locale_cat_desc); i++) + { + if ((!setlocs[i]) && (locale_cat_desc[i].cat != LC_ALL)) + setlocale(locale_cat_desc[i].cat, "C"); + } + + end: + ecore_event_add(ECORE_EVENT_LOCALE_CHANGED, NULL, NULL, NULL); +} + +static void +_props_changed_locale(void *data, const Eldbus_Message *msg) +{ + Eldbus_Proxy *proxy = data; + Eldbus_Message_Iter *changed, *entry, *invalidated; + const char *iface, *prop; + + if (!eldbus_message_arguments_get(msg, "sa{sv}as", + &iface, &changed, &invalidated)) + { + ERR("Error getting data from properties changed signal."); + return; + } + + while (eldbus_message_iter_get_and_next(changed, 'e', &entry)) + { + const void *key; + Eldbus_Message_Iter *var; + if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var)) + continue; + if (strcmp(key, "Locale") == 0) + goto changed_locale; + } + + while (eldbus_message_iter_get_and_next(invalidated, 's', &prop)) + { + if (strcmp(prop, "Locale") == 0) + goto changed_locale; + } + + return; + + changed_locale: + eldbus_proxy_property_get(proxy, "Locale", _locale_get, NULL); +} + +static Eina_Bool +_property_change_monitor(const char *name, + const char *path, + const char *iface, + Eldbus_Signal_Cb cb) +{ + Eldbus_Object *o; + Eldbus_Proxy *p; + Eldbus_Signal_Handler *s; + + o = eldbus_object_get(_conn, name, path); + if (!o) + { + ERR("could not get object name=%s, path=%s", name, path); + return EINA_FALSE; + } + + p = eldbus_proxy_get(o, iface); + if (!p) + { + ERR("could not get proxy interface=%s, name=%s, path=%s", + iface, name, path); + eldbus_object_unref(o); + return EINA_FALSE; + } + + s = eldbus_proxy_properties_changed_callback_add(p, cb, p); + if (!s) + { + ERR("could not add signal handler for properties changed for proxy " + "interface=%s, name=%s, path=%s", iface, name, path); + eldbus_proxy_unref(p); + eldbus_object_unref(o); + return EINA_FALSE; + } + + _objs = eina_list_append(_objs, o); + _proxies = eina_list_append(_proxies, p); + return EINA_TRUE; +} + +static void _ecore_system_systemd_shutdown(void); + +static Eina_Bool +_ecore_system_systemd_init(void) +{ + eldbus_init(); + + _log_dom = eina_log_domain_register("ecore_system_systemd", NULL); + if (_log_dom < 0) + { + EINA_LOG_ERR("Could not register log domain: ecore_system_systemd"); + goto error; + } + + _conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); + + if (!_property_change_monitor("org.freedesktop.hostname1", + "/org/freedesktop/hostname1", + "org.freedesktop.hostname1", + _props_changed_hostname)) + goto error; + + if (!_property_change_monitor("org.freedesktop.timedate1", + "/org/freedesktop/timedate1", + "org.freedesktop.timedate1", + _props_changed_timedate)) + goto error; + + if (!_property_change_monitor("org.freedesktop.locale1", + "/org/freedesktop/locale1", + "org.freedesktop.locale1", + _props_changed_locale)) + goto error; + + DBG("ecore system 'systemd' loaded"); + return EINA_TRUE; + + error: + _ecore_system_systemd_shutdown(); + return EINA_FALSE; +} + +static void +_ecore_system_systemd_shutdown(void) +{ + DBG("ecore system 'systemd' unloaded"); + + while (_proxies) + { + eldbus_proxy_unref(_proxies->data); + _proxies = eina_list_remove_list(_proxies, _proxies); + } + + while (_objs) + { + eldbus_object_unref(_objs->data); + _objs = eina_list_remove_list(_objs, _objs); + } + + if (_conn) + { + eldbus_connection_unref(_conn); + _conn = NULL; + } + + if (_log_dom > 0) + { + eina_log_domain_unregister(_log_dom); + _log_dom = -1; + } + + eldbus_shutdown(); +} + +EINA_MODULE_INIT(_ecore_system_systemd_init); +EINA_MODULE_SHUTDOWN(_ecore_system_systemd_shutdown);