davemds pushed a commit to branch master. http://git.enlightenment.org/enlightenment/modules/places.git/commit/?id=182b9bbd82ed09441c1bdf7dc7b815cec3055c1c
commit 182b9bbd82ed09441c1bdf7dc7b815cec3055c1c Author: Dave Andreoli <d...@gurumeditation.it> Date: Thu Apr 22 07:58:40 2021 +0200 Add a new EXPERIMENTAL systemd backend --- meson.build | 15 +- meson_options.txt | 20 ++- src/e_mod_places.c | 13 +- src/e_mod_systemd.c | 510 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/e_mod_systemd.h | 7 + src/meson.build | 1 + 6 files changed, 557 insertions(+), 9 deletions(-) diff --git a/meson.build b/meson.build index 0687036..300ec9b 100644 --- a/meson.build +++ b/meson.build @@ -49,13 +49,20 @@ if get_option('mount') == true endif -#### Experimental eeze support #### +#### EXPERIMENTAL eeze support #### if get_option('eeze') == true dependency('eeze', required: true) config_h.set('PLACES_HAVE_EEZE', 1) endif +#### EXPERIMENTAL systemd support #### +if get_option('systemd') == true + dependency('systemd', required: true,) + config_h.set('PLACES_HAVE_SYSTEMD', 1) +endif + + #### i18n #### dep_intl = [] if get_option('nls') @@ -100,6 +107,8 @@ if meson.version().version_compare('>=0.53') summary({'udisks2': get_option('udisks2'), 'udisks1': get_option('udisks'), 'mount': get_option('mount'), - 'eeze': get_option('eeze'), - }, section: 'Backends', bool_yn: true) + }, section: 'Backends', bool_yn: true) + summary({'eeze': get_option('eeze'), + 'systemd': get_option('systemd'), + }, section: 'Experimental Backends', bool_yn: true) endif \ No newline at end of file diff --git a/meson_options.txt b/meson_options.txt index d26365e..a260a35 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -1,3 +1,5 @@ + +# Backends option('udisks2', type: 'boolean', value: true, @@ -5,16 +7,24 @@ option('udisks2', option('udisks', type: 'boolean', value: false, - description: 'enable udisks1 support (default=false)') + description: 'enable deprecated udisks1 support (default=false)') option('mount', type: 'boolean', value: true, description: 'enable fstab/mtab support (default=true)') -option('eeze', - type: 'boolean', - value: false, - description: 'enable experimental eeze support (default=false)') + +# Localization option('nls', type: 'boolean', value: true, description: 'enable localization (default=true)') + +# Experimental (NOT FULLY WORKING) backends +option('eeze', + type: 'boolean', + value: false, + description: 'enable EXPERIMENTAL eeze support (default=false)') +option('systemd', + type: 'boolean', + value: false, + description: 'enable EXPERIMENTAL systemd support (default=false)') \ No newline at end of file diff --git a/src/e_mod_places.c b/src/e_mod_places.c index 263183f..cf615b6 100644 --- a/src/e_mod_places.c +++ b/src/e_mod_places.c @@ -4,6 +4,11 @@ #include "e_mod_main.h" #include "e_mod_places.h" + +#ifdef PLACES_HAVE_SYSTEMD +# include "e_mod_systemd.h" +#endif + #ifdef PLACES_HAVE_EEZE # include "e_mod_eeze.h" #endif @@ -65,6 +70,9 @@ places_init(void) printf("PLACES: Init\n"); +#ifdef PLACES_HAVE_SYSTEMD + places_systemd_init(); +#endif #ifdef PLACES_HAVE_EEZE places_eeze_init(); #endif @@ -119,6 +127,9 @@ places_shutdown(void) while (volumes) places_volume_del((Volume*)volumes->data); +#ifdef PLACES_HAVE_SYSTEMD + places_systemd_shutdown(); +#endif #ifdef PLACES_HAVE_EEZE places_eeze_shutdown(); #endif @@ -276,7 +287,7 @@ places_volume_update(Volume *vol) Evas_Object *obj; Eina_List *l; - if (eina_streq(vol->fstype, "nfs") || + if (eina_str_has_prefix(vol->fstype, "nfs") || // nfs, nfs3, nfs4, etc.. eina_streq(vol->fstype, "cifs")) vol->remote = EINA_TRUE; else diff --git a/src/e_mod_systemd.c b/src/e_mod_systemd.c new file mode 100644 index 0000000..cc3784d --- /dev/null +++ b/src/e_mod_systemd.c @@ -0,0 +1,510 @@ + +#include "places_config.h" + + +#ifdef PLACES_HAVE_SYSTEMD + +#include <e.h> +#include <Eldbus.h> +#include "e_mod_main.h" +#include "e_mod_places.h" + +/* + +NOTE + +- I remoti li vede solo con opzione "auto" in fstab !!!! + +*/ + +/* Systemd defines */ +#define SYSTEMD_BUS "org.freedesktop.systemd1" +#define SYSTEMD_PATH "/org/freedesktop/systemd1" +#define SYSTEMD_MANAGER_IFACE "org.freedesktop.systemd1.Manager" +#define SYSTEMD_UNIT_IFACE "org.freedesktop.systemd1.Unit" +#define SYSTEMD_MOUNT_IFACE "org.freedesktop.systemd1.Mount" + + + +/* Local backend data */ +typedef struct Places_Systemd_Backend_Data +{ + Eldbus_Object *unit_obj; +} Places_Systemd_Backend_Data; + + +/* Local Function Prototypes */ +static void _places_sd_name_start(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending); + +static void _places_sd_list_units_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending); +static void _places_sd_unit_new_cb(void *data, const Eldbus_Message *msg); +static void _places_sd_unit_removed_cb(void *data, const Eldbus_Message *msg); + +static void _places_sd_mount_props_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending); +static void _places_sd_unit_props_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending); +static void _places_sd_mount_props_changed_cb(void *data, const Eldbus_Message *msg); +static void _places_sd_read_unit_properties(Volume *vol, const char *iface, Eldbus_Message_Iter *props); + +static Volume* _places_sd_volume_add(const char *obj_path, Eina_Bool first_time); +static void _places_sd_volume_finalize(Volume *vol); +static void _places_sd_mount_func(Volume *vol, Eina_List *opts); +static void _places_sd_unmount_func(Volume *vol, Eina_List *opts); +static void _places_sd_eject_func(Volume *vol, Eina_List *opts); +static void _places_sd_volume_free_func(Volume *vol); + + +/* Local Variables */ +static Eldbus_Connection *_places_sd_conn = NULL; +static Eldbus_Object *_places_sd_manager = NULL; + + +Eina_Bool +places_systemd_init(void) +{ + printf("PLACES: systemd: init()\n"); + + EINA_SAFETY_ON_FALSE_RETURN_VAL(eldbus_init(), EINA_FALSE); + + _places_sd_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SYSTEM); + // _places_sd_conn = eldbus_connection_get(ELDBUS_CONNECTION_TYPE_SESSION); + if (!_places_sd_conn) + { + printf("PLACES: systemd: Error connecting to system bus.\n"); + return EINA_FALSE; + } + + eldbus_name_start(_places_sd_conn, SYSTEMD_BUS, 0, + _places_sd_name_start, NULL); + return EINA_TRUE; +} + + +void +places_systemd_shutdown(void) +{ + printf("PLACES: systemd: shutdown()\n"); + E_FREE_FUNC(_places_sd_manager, eldbus_object_unref); + E_FREE_FUNC(_places_sd_conn, eldbus_connection_unref); + eldbus_shutdown(); +} + + +/* The service is up and running, setup the Manager object */ +static void +_places_sd_name_start(void *data, const Eldbus_Message *msg, + Eldbus_Pending *pending) +{ + Eldbus_Proxy *proxy; + Eldbus_Message *meth; + Eldbus_Message_Iter *iter, *array; + + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + + printf("PLACES: systemd Up and running\n"); + + // get the systemd Manager object + _places_sd_manager = eldbus_object_get(_places_sd_conn, SYSTEMD_BUS, SYSTEMD_PATH); + proxy = eldbus_proxy_get(_places_sd_manager, SYSTEMD_MANAGER_IFACE); + // NOTE: proxy will be automatically deleted on obj deletion + + // call the ListUnitsByPatterns(as states, as patterns) on the Manager object + meth = eldbus_proxy_method_call_new(proxy, "ListUnitsByPatterns"); + iter = eldbus_message_iter_get(meth); + eldbus_message_iter_arguments_append(iter, "as", &array); + eldbus_message_iter_container_close(iter, array); + eldbus_message_iter_arguments_append(iter, "as", &array); + eldbus_message_iter_basic_append(array, 's', "*.mount"); + // eldbus_message_iter_basic_append(array, 's', "*.device"); + eldbus_message_iter_container_close(iter, array); + eldbus_proxy_send(proxy, meth, _places_sd_list_units_cb, NULL, -1); + + + // connect the Manager UnitNew / UnitRemoved signal handlers + eldbus_proxy_signal_handler_add(proxy, "UnitNew", + _places_sd_unit_new_cb, NULL); + eldbus_proxy_signal_handler_add(proxy, "UnitRemoved", + _places_sd_unit_removed_cb, NULL); +} + + +/* Callback for the Manager method: ListUnitsByPatterns() */ +static void +_places_sd_list_units_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + Eldbus_Message_Iter *units, *unit; + const char *name, *label; + const char *load_state, *active_state, *sub_state; + const char *followed, *obj_path; + const char *job_type, *job_obj_path; + unsigned int job_id; + + + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + + EINA_SAFETY_ON_FALSE_RETURN( + eldbus_message_arguments_get(msg, "a(ssssssouso)", &units) + ); + + printf("PLACES: ListUnits\n"); + + while (eldbus_message_iter_get_and_next(units, 'r', &unit)) + { + if (eldbus_message_iter_arguments_get(unit, "ssssssouso", + &name, &label, + &load_state, &active_state, &sub_state, + &followed, + &obj_path, + &job_id,&job_type, &job_obj_path)) + { + printf("******* %s\n", obj_path); + printf(" name: %s\n", name); + printf(" label: %s\n", label); + printf(" load_state: %s\n", load_state); + printf(" active_state: %s\n", active_state); + printf(" sub_state: %s\n", sub_state); + printf(" followed: %s\n", followed); + printf(" job_id: %d\n", job_id); + printf(" job_type: %s\n", job_type); + printf(" job_obj_path: %s\n", job_obj_path); + + _places_sd_volume_add(obj_path, EINA_TRUE); + } + } +} + + +/* Callback for the Manager signal 'UnitNew' */ +static void +_places_sd_unit_new_cb(void *data, const Eldbus_Message *msg) +{ + const char *id, *obj_path; + + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_arguments_get(msg, "so", &id, &obj_path)); + + // printf("PLACES: UnitNew(%s, %s)\n", id, obj_path); + + if (eina_str_has_suffix(id, ".mount") || + eina_str_has_suffix(id, ".device")) + { + printf("PLACES: UnitNew(%s, %s)\n", id, obj_path); + if (eina_str_has_suffix(id, ".mount")) + { + _places_sd_volume_add(obj_path, EINA_FALSE); + } + } +} + + +/* Callback for the Manager signal 'UnitRemoved' */ +static void +_places_sd_unit_removed_cb(void *data, const Eldbus_Message *msg) +{ + const char *id, *obj_path; + + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + EINA_SAFETY_ON_FALSE_RETURN(eldbus_message_arguments_get(msg, "so", &id, &obj_path)); + + // printf("PLACES: UnitRemoved(%s, %s)\n", id, obj_path); + + if (eina_str_has_suffix(id, ".mount") || + eina_str_has_suffix(id, ".device")) + printf("PLACES: UnitRemoved(%s, %s)\n", id, obj_path); + // TODO +} + + +static Volume* +_places_sd_volume_add(const char *obj_path, Eina_Bool first_time) +{ + Places_Systemd_Backend_Data *bdata; + Volume *vol; + + // return a previously created Volume + vol = places_volume_by_id_get(obj_path); + if (vol) return vol; + + // create the backend data struct + bdata = E_NEW(Places_Systemd_Backend_Data, 1); + if (!bdata) return NULL; + + // create the Eldbus object for this unit + bdata->unit_obj = eldbus_object_get(_places_sd_conn, SYSTEMD_BUS, obj_path); + if (!bdata->unit_obj) return NULL; + + // create the places Volume + vol = places_volume_add(obj_path, first_time); + if (!vol) return NULL; + vol->backend_data = bdata; + vol->mount_func = _places_sd_mount_func; + vol->unmount_func = _places_sd_unmount_func; + vol->eject_func = _places_sd_eject_func; + vol->free_func = _places_sd_volume_free_func; + + // request all the properties for the Mount & Unit ifaces + Eldbus_Proxy *proxy; + proxy = eldbus_proxy_get(bdata->unit_obj, SYSTEMD_MOUNT_IFACE); + eldbus_proxy_property_get_all(proxy, _places_sd_mount_props_all_cb, vol); + proxy = eldbus_proxy_get(bdata->unit_obj, SYSTEMD_UNIT_IFACE); + eldbus_proxy_property_get_all(proxy, _places_sd_unit_props_all_cb, vol); + + // Get notifications on object properties change + eldbus_object_signal_handler_add(bdata->unit_obj, + ELDBUS_FDO_INTERFACE_PROPERTIES, + "PropertiesChanged", + _places_sd_mount_props_changed_cb, vol); + + return vol; +} + + +static void +_places_sd_volume_free_func(Volume *vol) +{ + Places_Systemd_Backend_Data *bdata = vol->backend_data; + if (bdata) + { + E_FREE_FUNC(bdata->unit_obj, eldbus_object_unref); + E_FREE(vol->backend_data); + } +} + + +/* Callback for ALL properties of the Mount iface */ +static void +_places_sd_mount_props_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + Volume *vol = data; + Eldbus_Message_Iter *props; + + EINA_SAFETY_ON_NULL_RETURN(vol); + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + + if (eldbus_message_arguments_get(msg, "a{sv}", &props)) + { + printf("PLACES: ALL Mount props for: %s\n", vol->id); + _places_sd_read_unit_properties(vol, SYSTEMD_MOUNT_IFACE, props); + } +} + + +/* Callback for ALL properties of the Unit iface */ +static void +_places_sd_unit_props_all_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + Volume *vol = data; + Eldbus_Message_Iter *props; + + EINA_SAFETY_ON_NULL_RETURN(vol); + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + + if (eldbus_message_arguments_get(msg, "a{sv}", &props)) + { + printf("PLACES: ALL Unit props for: %s\n", vol->id); + _places_sd_read_unit_properties(vol, SYSTEMD_UNIT_IFACE, props); + } +} + + +/* Callback for DBUS signal "PropertiesChanged" on the unit objects */ +static void +_places_sd_mount_props_changed_cb(void *data, const Eldbus_Message *msg) +{ + Volume *vol = data; + Eldbus_Message_Iter *changed_props, *invalidated_props; + const char *iface; + + EINA_SAFETY_ON_NULL_RETURN(vol); + EINA_SAFETY_ON_TRUE_RETURN(eldbus_message_error_get(msg, NULL, NULL)); + + if (eldbus_message_arguments_get(msg, "sa{sv}as", &iface, + &changed_props, &invalidated_props)) + { + printf("PLACES: PropertiesChanged obj:%s - iface:%s\n", vol->id, iface); + _places_sd_read_unit_properties(vol, iface, changed_props); + } +} + + +/* Read the properties for a .mount object (Mount & Unit ifaces)*/ +static void +_places_sd_read_unit_properties(Volume *vol, const char *iface, Eldbus_Message_Iter *props) +{ + Eldbus_Message_Iter *entry, *var; + const char *key, *str_val; + unsigned int changed = 0; + Eina_Bool is_mount_iface = eina_streq(iface, SYSTEMD_MOUNT_IFACE); + Eina_Bool is_unit_iface = eina_streq(iface, SYSTEMD_UNIT_IFACE); + + // NOTE props must be a{sv} + EINA_SAFETY_ON_NULL_RETURN(vol); + EINA_SAFETY_ON_NULL_RETURN(props); + + printf("PLACES: Properties obj:%s - iface:%s\n", vol->id, iface); + + // collect usefull props iterating over the dict + while (eldbus_message_iter_get_and_next(props, 'e', &entry)) + { + if (!eldbus_message_iter_arguments_get(entry, "sv", &key, &var)) + continue; + + // printf(" prop: %s\n", key); + if (is_mount_iface) + { + if (eina_streq(key, "Where")) + { + eldbus_message_iter_arguments_get(var, "s", &str_val); + if (eina_stringshare_replace(&vol->mount_point, str_val)) + changed++; + } + else if (eina_streq(key, "What")) + { + eldbus_message_iter_arguments_get(var, "s", &str_val); + if (eina_stringshare_replace(&vol->device, str_val)) + changed++; + } + else if (eina_streq(key, "Type")) + { + eldbus_message_iter_arguments_get(var, "s", &str_val); + if (eina_stringshare_replace(&vol->fstype, str_val)) + changed++; + } + // Mount.ExecMount + // Mount.ExecRemount + // Mount.ExecUnmount + } + + else if (is_unit_iface) + { + if (eina_streq(key, "SubState")) + { + eldbus_message_iter_arguments_get(var, "s", &str_val); + if (eina_streq(str_val, "mounted")) + { + if (!vol->mounted) + { + vol->mounted = EINA_TRUE; + changed++; + } + } + else + { + if (vol->mounted) + { + vol->mounted = EINA_FALSE; + changed++; + } + } + } + // Unit.CanStart bool + // Unit.CanStop bool + } + + } + + if (changed) + _places_sd_volume_finalize(vol); + +} + + +/* Called after all properties has been readed */ +static void +_places_sd_volume_finalize(Volume *vol) +{ + Eina_Bool is_valid = EINA_FALSE; + printf("PLACES: Validating %s\n", vol->id); + + // TODO array of know types + if (eina_streq(vol->fstype, "ext4") || + eina_streq(vol->fstype, "vfat") || + eina_streq(vol->fstype, "nfs") || + eina_streq(vol->fstype, "nfs3") || + eina_streq(vol->fstype, "nfs4") || + eina_streq(vol->fstype, "ntfs") || + eina_streq(vol->fstype, "cifs")) + is_valid = EINA_TRUE; + else + is_valid = EINA_FALSE; + + // choose a label + if (vol->mount_point && vol->mount_point[0]) + eina_stringshare_replace(&vol->label, vol->mount_point); + else if (vol->device && vol->device[0]) + eina_stringshare_replace(&vol->label, vol->device); + + // the update is always needed to trigger auto_mount/auto_open + places_volume_update(vol); + + if (is_valid != vol->valid) + { + // trigger a full redraw, is the only way to show/hide a new device + vol->valid = is_valid; + places_update_all_gadgets(); + } + + places_print_volume(vol); // TODO REMOVE ME +} + + +/* Callback for mount(), umont() and eject() calls */ +static void +_places_sd_task_cb(void *data, const Eldbus_Message *msg, Eldbus_Pending *pending) +{ + const char *str; + Eina_Bool ret; + + if (eldbus_message_error_get(msg, NULL, NULL)) + { + ret = eldbus_message_arguments_get(msg, "s", &str); + e_util_dialog_internal(D_("Operation failed"), + ret ? str : D_("Unknown error")); + } +} + + +static void +_places_sd_mount_func(Volume *vol, Eina_List *opts) +{ + Places_Systemd_Backend_Data *bdata = vol->backend_data; + Eldbus_Message *msg; + + EINA_SAFETY_ON_FALSE_RETURN((bdata && bdata->unit_obj)); + + printf("PLACES: systemd Mount %s\n", vol->id); + + // Call the Start(s mode) method on the Unit iface + msg = eldbus_object_method_call_new(bdata->unit_obj, + SYSTEMD_UNIT_IFACE, "Start"); + eldbus_message_arguments_append(msg, "s", "replace"); + eldbus_object_send(bdata->unit_obj, msg, _places_sd_task_cb, vol, -1); +} + + +static void +_places_sd_unmount_func(Volume *vol, Eina_List *opts) +{ + Places_Systemd_Backend_Data *bdata = vol->backend_data; + Eldbus_Message *msg; + + EINA_SAFETY_ON_FALSE_RETURN((bdata && bdata->unit_obj)); + + printf("PLACES: systemd Unmount %s\n", vol->id); + + // Call the Stop(s mode) method on the Unit iface + msg = eldbus_object_method_call_new(bdata->unit_obj, + SYSTEMD_UNIT_IFACE, "Stop"); + eldbus_message_arguments_append(msg, "s", "replace"); + eldbus_object_send(bdata->unit_obj, msg, _places_sd_task_cb, vol, -1); +} + + +static void +_places_sd_eject_func(Volume *vol, Eina_List *opts) +{ + // Places_Systemd_Backend_Data *bdata = vol->backend_data; + printf("PLACES: TODO systemd Eject %s\n", vol->id); +} + + +#endif diff --git a/src/e_mod_systemd.h b/src/e_mod_systemd.h new file mode 100644 index 0000000..b5e527e --- /dev/null +++ b/src/e_mod_systemd.h @@ -0,0 +1,7 @@ +#ifndef E_MOD_PLACES_SYSTEMD_H +#define E_MOD_PLACES_SYSTEMD_H + +void places_systemd_init(void); +void places_systemd_shutdown(void); + +#endif diff --git a/src/meson.build b/src/meson.build index 4c8798d..3d78656 100644 --- a/src/meson.build +++ b/src/meson.build @@ -9,6 +9,7 @@ module = shared_module( 'e_mod_udisks_eldbus.c', 'e_mod_mount.c', 'e_mod_eeze.c', + 'e_mod_systemd.c', dependencies : [dep_e, dep_intl], install_dir: lib_install_dir, --