diff --git a/src/usb_moded-systemd.c b/src/usb_moded-systemd.c index c5c7371..5b62ea1 100644 --- a/src/usb_moded-systemd.c +++ b/src/usb_moded-systemd.c @@ -35,69 +35,129 @@ #include "usb_moded-log.h" #include "usb_moded-systemd.h" -static DBusConnection * get_systemd_dbus_connection(void) -{ - DBusError error; - DBusConnection *conn = 0; - - dbus_error_init(&error); - - conn = dbus_connection_open_private("unix:path=/run/systemd/private", &error); - if (!conn) - { - if (dbus_error_is_set(&error)) - log_err("Cannot connect to systemd: %s", error.message); - else - log_err("Cannot connect to systemd"); - dbus_error_free(&error); - return 0; - } - - return conn; -} +#define SYSTEMD_DBUS_SERVICE "org.freedesktop.systemd1" +#define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1" +#define SYSTEMD_DBUS_INTERFACE "org.freedesktop.systemd1.Manager" + + +/* SystemBus connection ref used for systemd control ipc */ +static DBusConnection *systemd_con = NULL; + +// QDBusObjectPath org.freedesktop.systemd1.Manager.StartUnit(QString name, QString mode) +// QDBusObjectPath org.freedesktop.systemd1.Manager.StopUnit(QString name, QString mode) + // mode = replace // method = StartUnit or StopUnit gboolean systemd_control_service(const char *name, const char *method) { + DBusMessage *req = NULL; + DBusMessage *rsp = NULL; + DBusError err = DBUS_ERROR_INIT; + const char *arg = "replace"; + const char *res = 0; + + + log_debug("%s(%s) ...", method, name); + + if( !systemd_con ) { + log_err("not connected to system bus; skip systemd unit control"); + goto EXIT; + } + + req = dbus_message_new_method_call(SYSTEMD_DBUS_SERVICE, + SYSTEMD_DBUS_PATH, + SYSTEMD_DBUS_INTERFACE, + method); + if( !req ) { + log_err("failed to construct %s.%s request", + SYSTEMD_DBUS_INTERFACE, + method); + goto EXIT; + } + + if( !dbus_message_append_args(req, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_STRING, &arg, + DBUS_TYPE_INVALID)) + { + log_debug("error appending arguments"); + goto EXIT; + } + + + rsp = dbus_connection_send_with_reply_and_block(systemd_con, req, -1, &err); + if( !rsp ) { + log_err("no reply to %s.%s request: %s: %s", + SYSTEMD_DBUS_INTERFACE, + method, + err.name, err.message); + goto EXIT; + } + + if( dbus_set_error_from_message(&err, rsp) ) { + log_err("got error reply to %s.%s request: %s: %s", + SYSTEMD_DBUS_INTERFACE, + method, + err.name, err.message); + goto EXIT; + } + + if( !dbus_message_get_args(rsp, &err, + DBUS_TYPE_OBJECT_PATH, &res, + DBUS_TYPE_INVALID) ) { + log_err("failed to parse reply to %s.%s request: %s: %s", + SYSTEMD_DBUS_INTERFACE, + method, + err.name, err.message); + goto EXIT; + } + +EXIT: + + dbus_error_free(&err); + + if( rsp ) dbus_message_unref(rsp); + if( req ) dbus_message_unref(req); + + log_debug("%s(%s) -> %s", method, name, res ?: "N/A"); + + return res != 0; +} + +/* ========================================================================= * + * start/stop systemd control availability + * ========================================================================= */ + +gboolean +systemd_control_start(void) +{ + gboolean ack = FALSE; + + log_debug("starting systemd control"); + + /* Get connection ref */ + if( (systemd_con = usb_moded_dbus_get_connection()) == 0 ) + { + log_err("Could not connect to dbus for systemd control\n"); + goto cleanup; + } + ack = TRUE; - DBusConnection *bus; - DBusError error; - DBusMessage *msg = NULL, *reply = NULL; - gboolean ret = FALSE; - const char * replace = "replace"; - - dbus_error_init(&error); - - log_debug("Handling %s, with systemd, method %s\n", name, method); - - bus = get_systemd_dbus_connection(); - if(!bus) - return(ret); - - msg = dbus_message_new_method_call("org.freedesktop.systemd1", - "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", method); - if(msg) - { - if(!dbus_message_append_args (msg, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &replace, DBUS_TYPE_INVALID)) - { - log_debug("error appending arguments\n"); - dbus_message_unref(msg); - goto quit; - } - reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &error); - if(reply) - { - dbus_message_unref(reply); - ret = TRUE; - } - dbus_message_unref(msg); - } - -quit: - dbus_connection_close(bus); - dbus_connection_unref(bus); - dbus_error_free(&error); - - return(ret); +cleanup: + + return ack; +} + +void +systemd_control_stop(void) +{ + log_debug("stopping systemd control"); + + if(systemd_con) + { + /* Let go of connection ref */ + dbus_connection_unref(systemd_con), + systemd_con = 0; + } } diff --git a/src/usb_moded-systemd.h b/src/usb_moded-systemd.h index d7475a3..05f9452 100644 --- a/src/usb_moded-systemd.h +++ b/src/usb_moded-systemd.h @@ -24,3 +24,5 @@ #define SYSTEMD_START "StartUnit" gboolean systemd_control_service(const char *name, const char *method); +gboolean systemd_control_start(void); +void systemd_control_stop(void); diff --git a/src/usb_moded.c b/src/usb_moded.c index 467f4ed..0ad7413 100644 --- a/src/usb_moded.c +++ b/src/usb_moded.c @@ -54,6 +54,7 @@ #include "usb_moded-network.h" #include "usb_moded-mac.h" #include "usb_moded-android.h" +#include "usb_moded-systemd.h" #ifdef MEEGOLOCK #include "usb_moded-dsme.h" #endif @@ -1197,6 +1198,11 @@ int main(int argc, char* argv[]) goto EXIT; } + if( !systemd_control_start() ) { + log_crit("systemd control could not be started"); + goto EXIT; + } + /* init daemon into a clean state first, then dbus and hw_abstraction last */ usb_moded_init(); @@ -1252,6 +1258,7 @@ int main(int argc, char* argv[]) EXIT: dsme_listener_stop(); handle_exit(); + systemd_control_stop(); allow_suspend(); return result;