From: sanghyeok.oh Date: Thu, 10 Jan 2019 12:48:35 +0000 (+0900) Subject: libgdbus: add api to start or stop systemd unit X-Git-Tag: submit/tizen/20190208.064159^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1d185d66e7b0f5ff6230285cd71f2bb1fe3d839c;p=platform%2Fcore%2Fsystem%2Flibsyscommon.git libgdbus: add api to start or stop systemd unit Change-Id: Iaa17cc32cff1b763c5ed89ddc69582f9b70e535a Signed-off-by: sanghyeok.oh --- diff --git a/packaging/libsyscommon.spec b/packaging/libsyscommon.spec index 3dc79ff..fb7114f 100644 --- a/packaging/libsyscommon.spec +++ b/packaging/libsyscommon.spec @@ -77,4 +77,5 @@ touch debugsources.list %license LICENSE.Apache-2.0 %{_libdir}/libgdbus.so %{_includedir}/libgdbus/dbus-system.h +%{_includedir}/libgdbus/dbus-systemd.h %{_libdir}/pkgconfig/libgdbus.pc diff --git a/src/Makefile.am b/src/Makefile.am deleted file mode 100644 index bbee945..0000000 --- a/src/Makefile.am +++ /dev/null @@ -1,92 +0,0 @@ -AUTOMAKE_OPTIONS = color-tests parallel-tests - -pkgconfiglibdir=$(libdir)/pkgconfig - -CLEANFILES = -EXTRA_DIST = - -lib_LTLIBRARIES = -noinst_LTLIBRARIES = -noinst_DATA = -pkgconfiglib_DATA = - -check_PROGRAMS = -check_DATA = -tests= -#noinst_PROGRAMS = $(tests) -#check_PROGRAMS += $(tests) -#TESTS = $(tests) - -DEFAULT_CFLAGS = \ - $(OUR_CFLAGS) - -DEFAULT_LDFLAGS = \ - $(OUR_LDFLAGS) - -AM_CPPFLAGS = \ - -include $(top_builddir)/config.h \ - $(DEFAULT_CFLAGS) - -AM_CFLAGS = $(DEFAULT_CFLAGS) -AM_LDFLAGS = $(DEFAULT_LDFLAGS) - -INSTALL_EXEC_HOOKS = -UNINSTALL_EXEC_HOOKS = - -# ------------------------------------------------------------------------------ -pkgconfiglib_DATA += \ - libgdbus/libgdbus.pc - -EXTRA_DIST += \ - libgdbus/libgdbus.pc.in - -CLEANFILES += \ - libgdbus/libgdbus.pc - -libgdbus_pkgincludedir=$(includedir)/libgdbus -libgdbus_pkginclude_HEADERS = - -libgdbus_pkginclude_HEADERS += \ - libgdbus/dbus-system.h - -lib_LTLIBRARIES += \ - libgdbus.la - -libgdbus_la_SOURCES = \ - libgdbus/dbus-system.c - -libgdbus_la_CFLAGS = \ - $(AM_CFLAGS) \ - $(GLIB_CFLAGS) \ - $(GIO_UNIX_CFLAGS) \ - $(GIO_CFLAGS) - -libgdbus_la_LIBADD = \ - -lrt \ - $(GIO_LIBS) \ - $(GIO_UNIX_LIBS) - -# ------------------------------------------------------------------------------ -substitutions = \ - '|PACKAGE_VERSION=$(PACKAGE_VERSION)|' \ - '|PACKAGE_NAME=$(PACKAGE_NAME)|' \ - '|PACKAGE_URL=$(PACKAGE_URL)|' \ - '|LIBGDBUS_PC_REQUIRES=$(LIBGDBUS_PC_REQUIRES)|' \ - '|LIBGDBUS_PC_CFLAGS=$(LIBGDBUS_PC_CFLAGS)|' \ - '|LIBGDBUS_PC_LIBS=$(LIBGDBUS_PC_LIBS)|' \ - '|includedir=$(includedir)|' \ - '|VERSION=$(VERSION)|' - -SED_PROCESS = \ - $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \ - $(SED) $(subst '|,-e 's|@,$(subst =,\@|,$(subst |',|g',$(substitutions)))) \ - < $< > $@ - -%.pc: %.pc.in - $(SED_PROCESS) - -%.c: %.gperf - $(AM_V_at)$(MKDIR_P) $(dir $@) - $(AM_V_GPERF)$(GPERF) < $< > $@ - -install-exec-hook: $(INSTALL_EXEC_HOOKS) diff --git a/src/libgdbus/CMakeLists.txt b/src/libgdbus/CMakeLists.txt index 327ea2b..06f1bc2 100644 --- a/src/libgdbus/CMakeLists.txt +++ b/src/libgdbus/CMakeLists.txt @@ -9,9 +9,11 @@ SET(VERSION 4.1) SET(libgdbus_SRCS dbus-system.c + dbus-systemd.c ) SET(HEADERS dbus-system.h + dbus-systemd.h ) # CHECK PKG diff --git a/src/libgdbus/dbus-system.c b/src/libgdbus/dbus-system.c index 42f061b..e59da08 100644 --- a/src/libgdbus/dbus-system.c +++ b/src/libgdbus/dbus-system.c @@ -697,21 +697,20 @@ static int _check_brace(const char * expr) return -1; if (expr[i] == ')') { - if (ch == '(') { + if (ch == '(') --qucnt; - } else + else return -1; } else if (expr[i] == '}') { - if (ch == '{') { + if (ch == '{') --qucnt; - } else + else return -1; } else return -1; - if (qucnt == 0) { + if (qucnt == 0) return i + 1; - } } } @@ -1231,9 +1230,9 @@ int dbus_handle_unregister_dbus_object(dbus_handle_h handle, const char *obj_pat dbus_object_handle_s *oh = NULL; int ret = 0; - if (!obj_path) { + if (!obj_path) return -1; - } + if (!dh) { dh = _dbus_handle_get_default_connection(); if (!dh) { @@ -1507,6 +1506,195 @@ void unsubscribe_dbus_signal(dbus_handle_h handle, guint id) g_dbus_connection_signal_unsubscribe(dh->conn, id); } +static void _signal_reply_sync_cb(GDBusConnection *conn, + const gchar *sender, + const gchar *path, + const gchar *iface, + const gchar *name, + GVariant *param, + gpointer data) +{ + sig_ctx *ctx = data; + if (!ctx) { + _E("user data is null"); + assert(0); + } + + ctx->param = g_variant_ref(param); + ctx->quit_reason = CTX_QUIT_NORMAL; + + if (ctx->timeout_src) { + g_source_destroy(ctx->timeout_src); + ctx->timeout_src = NULL; + } + g_main_loop_quit(ctx->loop); +} + +sig_ctx *dbus_handle_new_signal_ctx(void) +{ + sig_ctx *ctx; + + ctx = (sig_ctx *)malloc(sizeof(sig_ctx)); + if (!ctx) { + _E("failed to alloc mem"); + return NULL; + } + + ctx->sig_id = 0; + + ctx->context = g_main_context_new(); + if (!ctx->context) { + _E("failed to alloc context"); + free(ctx); + return NULL; + } + ctx->loop = g_main_loop_new(ctx->context, FALSE); + if (!ctx->loop) { + _E("failed to alloc main loop"); + g_main_context_unref(ctx->context); + free(ctx); + return NULL; + } + ctx->timeout_src = NULL; + ctx->param = NULL; + ctx->quit_reason = 0; + ctx->user_data = NULL; + + return ctx; +} + +void dbus_handle_free_signal_ctx(sig_ctx *ctx) +{ + if (!ctx) + return ; + + if (ctx->param) { + g_variant_unref(ctx->param); + ctx->param = NULL; + } + if (ctx->sig_id) { + unsubscribe_dbus_signal(NULL, ctx->sig_id); + ctx->sig_id = 0; + } + if (ctx->timeout_src) { + g_source_destroy(ctx->timeout_src); + ctx->timeout_src = NULL; + } + if (ctx->context) { + g_main_context_pop_thread_default(ctx->context); + g_main_context_unref(ctx->context); + ctx->context = NULL; + } + if (ctx->loop) { + g_main_loop_unref(ctx->loop); + ctx->loop = NULL; + } + free(ctx); +} + +static gboolean _cb_ctx_timeout(gpointer user_data) +{ + sig_ctx *ctx = user_data; + + if (!ctx) { + _E("user_data is null"); + return FALSE; + } + + ctx->quit_reason = CTX_QUIT_TIMEOUT; + /* if cb return FALSE, source will be destroyed */ + ctx->timeout_src = NULL; + + unsubscribe_dbus_signal(NULL, ctx->sig_id); + ctx->sig_id = 0; + + g_main_loop_quit(ctx->loop); + + return FALSE; +} + +#define CTX_MAX_TIMEOUT 25000 + +int dbus_handle_signal_ctx_add_timeout(sig_ctx *ctx, int timeout_msec) +{ + GSource *src = NULL; + guint id = 0; + + if (!ctx) + return -EINVAL; + if (timeout_msec < -1) + return -EINVAL; + + if (timeout_msec == -1 || timeout_msec >= CTX_MAX_TIMEOUT) + timeout_msec = CTX_MAX_TIMEOUT; + + src = g_timeout_source_new(timeout_msec); + if (!src) + return -ENOMEM; + + g_source_set_callback(src, _cb_ctx_timeout, ctx, NULL); + g_source_attach(src, ctx->context); + + ctx->timeout_src = src; + + return 0; +} + +guint subscribe_dbus_signal_ctx(dbus_handle_h handle, sig_ctx *ctx, + const char *sender, const char *path, + const char *iface, const char *name, + GDBusSignalCallback _cb) +{ + dcl_dbus_handle(); + + if (!ctx) { + _E("wrong param ctx is null"); + return 0; + } + + if (!dh) { + dh = _dbus_handle_get_default_connection(); + if (!dh) { + _E("failed to get default connection, bustype:%d", + (int)dbus_handle_get_default_bus_type()); + return 0; + } + } + + if (!dh->conn) { + _E("connection is null. check bus status"); + return 0; + } + + if (!_cb) + _cb = _signal_reply_sync_cb; + + /* change context before subscribe */ + g_main_context_push_thread_default(ctx->context); + + ctx->sig_id = g_dbus_connection_signal_subscribe(dh->conn, + sender, iface, name, path, NULL, + G_DBUS_SIGNAL_FLAGS_NONE, _cb, + (void*)ctx, NULL); + + if (!ctx->sig_id) + _E("failed to subscribe signal"); + + return ctx->sig_id; +} + +int dbus_handle_signal_ctx_wait(sig_ctx *ctx) +{ + if (!ctx || !ctx->loop) + return -EINVAL; + + g_main_loop_run(ctx->loop); + + _D("quit g_main_loop"); + + return ctx->quit_reason; +} + int _check_type_string_is_container(const char *signature) { if (!signature) @@ -1574,9 +1762,8 @@ static GVariant* _append_variant(const char *signature, const char *param[]) snprintf(container, sizeof(container) - 1, "(%s)", signature); sig = container; } - if (!g_variant_type_is_container(G_VARIANT_TYPE(sig))) { + if (!g_variant_type_is_container(G_VARIANT_TYPE(sig))) _E("signature (%s) is not container type", signature); - } builder = g_variant_builder_new(G_VARIANT_TYPE(sig)); len = strlen(sig); diff --git a/src/libgdbus/dbus-system.h b/src/libgdbus/dbus-system.h index a9df43f..ef5ba75 100644 --- a/src/libgdbus/dbus-system.h +++ b/src/libgdbus/dbus-system.h @@ -481,6 +481,23 @@ int dbus_handle_register_dbus_object_all(dbus_handle_h handle); guint subscribe_dbus_signal(dbus_handle_h handle, const char *path, const char *iface, const char *name, GDBusSignalCallback cb, void *data, destroy_notified free_func); void unsubscribe_dbus_signal(dbus_handle_h handle, guint id); +enum ctx_quit_reason {CTX_QUIT_UNKNOWN, CTX_QUIT_NORMAL, CTX_QUIT_TIMEOUT}; + +typedef struct { + guint sig_id; + GMainContext *context; + GMainLoop *loop; + GSource *timeout_src; + GVariant *param; + enum ctx_quit_reason quit_reason; + void *user_data; +} sig_ctx; + +sig_ctx *dbus_handle_new_signal_ctx(void); +void dbus_handle_free_signal_ctx(sig_ctx *ctx); +guint subscribe_dbus_signal_ctx(dbus_handle_h handle, sig_ctx *ctx, const char *sender, const char *path, const char *iface, const char *name, GDBusSignalCallback cb); +int dbus_handle_signal_ctx_add_timeout(sig_ctx *ctx, int timeout); + GVariant *dbus_handle_make_simple_array(const char *sig, int *param); int dbus_handle_broadcast_dbus_signal(const char *path, const char *iface, const char *name, const char *signature, const char *param[]); diff --git a/src/libgdbus/dbus-systemd.c b/src/libgdbus/dbus-systemd.c new file mode 100644 index 0000000..998468d --- /dev/null +++ b/src/libgdbus/dbus-systemd.c @@ -0,0 +1,481 @@ +/* + * libsyscommon + * + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include + +#include "shared/log.h" + +#define SYSTEMD_DBUS_SERVICE "org.freedesktop.systemd1" +#define SYSTEMD_DBUS_PATH "/org/freedesktop/systemd1" +#define SYSTEMD_DBUS_UNIT_PATH "/org/freedesktop/systemd1/unit/" + +#define SYSTEMD_DBUS_MANAGER_IFACE "org.freedesktop.systemd1.Manager" +#define SYSTEMD_DBUS_UNIT_IFACE "org.freedesktop.systemd1.Unit" +#define SYSTEMD_DBUS_SERVICE_IFACE "org.freedesktop.systemd1.Service" +#define SYSTEMD_DBUS_TARGET_IFACE "org.freedesktop.systemd1.Target" + +#define DBUS_IFACE_DBUS_PROPERTIES "org.freedesktop.DBus.Properties" + +#define SUFFIX_SERVICE ".service" +#define SUFFIX_SOCKET ".socket" +#define SUFFIX_BUSNAME ".busname" +#define SUFFIX_TARGET ".target" +#define SUFFIX_DEVICE ".device" +#define SUFFIX_MOUNT ".mount" +#define SUFFIX_SWAP ".swap" +#define SUFFIX_TIMER ".timer" +#define SUFFIX_PATH ".path" +#define SUFFIX_SLICE ".slice" +#define SUFFIX_SCOPE ".scope" + +#define UNIT_NAME_MAX 256 + +typedef struct { + char *job_id; + char *unit_name; +} unitinfo; + +static void _cb_JobRemoved(GDBusConnection *conn, + const char *sender, + const char *path, + const char *iface, + const char *name, + GVariant *param, + gpointer data) +{ + sig_ctx *ctx = data; + gchar *job_id = NULL; + gchar *unit_name = NULL; + unitinfo *uinfo = NULL; + + if (!ctx) { + _E("User data ctx is null"); + return ; + } + + uinfo = ctx->user_data; + if (!uinfo) { + _E("User_data uinfo is null"); + return ; + } + if (!dh_get_param_from_var(param, "(uoss)", NULL, &job_id, &unit_name, NULL)) { + _E("Failed to get param"); + return ; + } + if (strcmp(uinfo->job_id, job_id) || strcmp(uinfo->unit_name, unit_name)) { + _E("Not matched: job_id:%s, unit_name:%s", job_id, unit_name); + goto err; + } + + /* otherwise, if matched signal, quit loop */ + + ctx->quit_reason = CTX_QUIT_NORMAL; + if (ctx->timeout_src) { + g_source_destroy(ctx->timeout_src); + ctx->timeout_src = NULL; + } + + g_main_loop_quit(ctx->loop); + +err: + g_free(job_id); + g_free(unit_name); +} + +static int _systemd_control_unit_sync(const char *method, const char *name, int timeout_msec) +{ + GVariant *reply = NULL; + gchar *objpath = NULL; + int ret = 0; + sig_ctx *ctx = NULL; + gchar *unit_name = NULL; + unitinfo uinfo; + int quit_reason; + + ctx = dbus_handle_new_signal_ctx(); + if (!ctx) + return -ENOMEM; + + _I("Starting: %s %s", method, name); + + /* synchronous siganl subscriptsion */ + ret = subscribe_dbus_signal_ctx(NULL, ctx, SYSTEMD_DBUS_SERVICE, SYSTEMD_DBUS_PATH, SYSTEMD_DBUS_IFACE_MANAGER, "JobRemoved", _cb_JobRemoved); + if (ret == 0) { + ret = -1; + goto finish; + } + + reply = dbus_handle_method_sync_with_reply_var(SYSTEMD_DBUS_DEST, + SYSTEMD_DBUS_PATH, + SYSTEMD_DBUS_MANAGER_IFACE, + method, + g_variant_new("(ss)", name, "replace")); + if (!reply || !dh_get_param_from_var(reply, "(o)", &objpath)) { + _E("fail (%s): no message", method); + ret = -EBADMSG; + goto finish; + } + + uinfo.job_id = objpath; + uinfo.unit_name = name; + ctx->user_data = &uinfo; + + /* set timeout */ + ret = dbus_handle_signal_ctx_add_timeout(ctx, timeout_msec); + if (ret < 0) { + _E("Failed to set timeout, %d", ret); + goto finish; + } + + /* run loop and wait signal callback */ + quit_reason = dbus_handle_signal_ctx_wait(ctx); + if (quit_reason != CTX_QUIT_NORMAL) { + ret = -1; + _E("Failed to receive JobRemoved signal %d", quit_reason); + goto finish; + } + + _I("Finished: %s %s", method, name); + +finish: + if (unit_name) + g_free(unit_name); + + if (reply) + g_variant_unref(reply); + g_free(objpath); + + dbus_handle_free_signal_ctx(ctx); + + return ret; +} + +static int _systemd_control_unit_async(const char *method, const char *name) +{ + GVariant *reply = NULL; + gchar *objpath = NULL; + int ret = 0; + + _I("Starting: %s %s", method, name); + + reply = dbus_handle_method_sync_with_reply_var(SYSTEMD_DBUS_DEST, + SYSTEMD_DBUS_PATH, + SYSTEMD_DBUS_MANAGER_IFACE, + method, + g_variant_new("(ss)", name, "replace")); + + if (!reply || !dh_get_param_from_var(reply, "(o)", &objpath)) { + _E("fail (%s): no message", method); + ret = -EBADMSG; + goto finish; + } + + _I("Finished: %s %s", method, name); +finish: + if (reply) + g_variant_unref(reply); + g_free(objpath); + + return ret; +} + +static int _has_suffix(const char *service_name, const char *suffix) +{ + int index = 0; + + if (!service_name || !suffix) + return FALSE; + + index = strlen(service_name) - strlen(suffix); + if (index <= 0) + return FALSE; + + if (strcmp(service_name + index, suffix) == 0) + return TRUE; + return FALSE; +} + +static int _change_suffix(const char *name, const char *suffix, char **new_name) +{ + char *buf = NULL; + char *ext = NULL; + unsigned int len = 0; + int ret = 0; + + if (!name || !suffix || !new_name) { + _E("Wrong param name:%s, suffix:%s, new_name:%s", name, suffix, new_name); + return -EINVAL; + } + + ext = strrchr(name, '.'); + if (ext == name) { + _E("Wrong file name %s", name); + return -EINVAL; + } + + /* if ext is same as suffix */ + if (ext && strcmp(ext, suffix) == 0) { + *new_name = strdup(name); + return 0; + } + + /* otherwise, make new unit name */ + if (ext) + len = ext - name; + else + len = strlen(name); + + /* check max len */ + if ((len + strlen(suffix)) >= UNIT_NAME_MAX) { + _E("Name is too long:%d", (len + strlen(suffix))); + return -ENAMETOOLONG; + } + + buf = (char *)malloc(sizeof(char) * (len + strlen(suffix) + 1)); + if (!buf) { + _E("Failed to alloc mem"); + return -ENOMEM; + } + + ret = snprintf(buf, len + 1, "%s", name); + if (ret < 0) { + ret = -errno; + _E("Failed to snprintf %d", ret); + goto err; + } + ret = snprintf(buf + len, strlen(suffix) + 1, "%s", suffix); + if (ret < 0) { + ret = -errno; + _E("Failed to snprintf %d", ret); + goto err; + } + + *new_name = buf; + + return 0; + +err: + free(buf); + return ret; +} + +/* +_systemd_start_unit_internal + +Start or Stop systemd unit. + 1) synchronous + - Send StartUnit/StopUnit Method call(sync) + reply:(o):/org/freedesktop/systemd1/job/[jobid] + - Wait JobRemoved signal from systemd + (uoss):(uint32 [jobid], objectpath '/org/freedesktop/systemd1/job/[jobid]', '[unit name]', '[result]') + 2) asynchronous + - Send StartUnit/StopUnit Method call(sync) + +@param name: unit name +@param suffix: (nullable): change extension of unit name, or %NULL +@param timeout_msec: the timeout in milliseconds, -1 to use the default +@param method: method name, "StartUnit" or "StopUnit" +@param sync: %TRUE +Returns: the exit status +*/ +static int _systemd_start_unit_internal(const char *name, const char *suffix, + int timeout_msec, const char *method, int sync) +{ + unsigned int len = 0; + char *new_name = NULL; + int ret = 0; + + if (!name || !method) { + _E("Wrong param name %s, method %s", name, method); + return -EINVAL; + } + if (timeout_msec < -1) { + _E("wrong timeout. timeout(>=0 or -1)"); + return -EINVAL; + } + + if (suffix) { + ret = _change_suffix(name, suffix, &new_name); + if (ret < 0) + return ret; + name = new_name; + } else { + if (strlen(name) > UNIT_NAME_MAX) { + _E("Invalid name length %d(>%d)", strlen(name), UNIT_NAME_MAX); + return -EINVAL; + } + } + + if (sync) + ret = _systemd_control_unit_sync(method, name, timeout_msec); + else + ret = _systemd_control_unit_async(method, name); + + if (new_name) + free(new_name); + + return ret; +} + +int systemd_start_unit_sync(const char *name, const char *suffix, int timeout_msec) +{ + return _systemd_start_unit_internal(name, suffix, timeout_msec, "StartUnit", TRUE); +} + +int systemd_stop_unit_sync(const char *name, const char *suffix, int timeout_msec) +{ + return _systemd_start_unit_internal(name, suffix, timeout_msec, "StopUnit", TRUE); +} + +int systemd_start_unit_async(const char *name, const char *suffix) +{ + return _systemd_start_unit_internal(name, suffix, -1, "StartUnit", FALSE); +} + +int systemd_stop_unit_async(const char *name, const char *suffix) +{ + return _systemd_start_unit_internal(name, suffix, -1, "StopUnit", FALSE); +} + +#define SYSTEMD_UNIT_ESCAPE_CHAR ".-" + +static char *systemd_get_unit_dbus_path(const char *unit) +{ + char *path = NULL; + int i; + size_t p, k, prefix_len, unit_len; + size_t path_len, len, escape; + + if (!unit) + return NULL; + unit_len = strlen(unit); + + for (escape = 0, p = 0; p < unit_len; escape++) { + k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR); + if (p + k >= unit_len) + break; + p += k+1; + } + + prefix_len = strlen(SYSTEMD_DBUS_UNIT_PATH); + /* assume we try to get object path of foo-bar.service then + * the object path will be + * "/org/freedesktop/systemd1/unit/foo_2dbar_2eservice\n". In + * this case we can find two escape characters, one of escape + * char('-') is changed to three of char("_2d"). So the total + * length will be: */ + /* (PREFIX) + (unit - escape + 3*escape) + NULL */ + path_len = prefix_len + (unit_len - escape) + + (escape * 3 * sizeof(char)) + 1; + path = (char *)calloc(path_len, sizeof(char)); + if (!path) + return NULL; + + strncpy(path, SYSTEMD_DBUS_UNIT_PATH, prefix_len); + for (i = 0, p = 0; i <= escape; i++) { + k = strcspn(unit + p, SYSTEMD_UNIT_ESCAPE_CHAR); + strncpy(path + prefix_len, unit + p, k); + if (k < strlen(unit + p)) { + len = path_len - (prefix_len + k); + snprintf(path + prefix_len + k, len, + "_%x", *(unit + p + k) & 0xff); + prefix_len += k + 3; + p += k+1; + } + } + + return path; +} + +GVariant *systemd_get_manager_property(const char *property) +{ + GVariant *reply = NULL; + GVariant *val = NULL; + + if (!property) + return NULL; + + reply = dbus_handle_method_sync_with_reply_var(SYSTEMD_DBUS_DEST, + SYSTEMD_DBUS_PATH, + DBUS_IFACE_DBUS_PROPERTIES, + "Get", + g_variant_new("(ss)", SYSTEMD_DBUS_MANAGER_IFACE, property)); + if (!reply || !dh_get_param_from_var(reply, "(v)", &val)) + _E("Failed to get variant"); + if (reply) + g_variant_unref(reply); + + return val; +} + +GVariant *systemd_get_unit_property(const char *unit, + const char *property) +{ + char *escaped; + GVariant *reply = NULL; + GVariant *val = NULL; + + if (!unit || !property) + return NULL; + + escaped = systemd_get_unit_dbus_path(unit); + + reply = dbus_handle_method_sync_with_reply_var(SYSTEMD_DBUS_DEST, + escaped, + DBUS_IFACE_DBUS_PROPERTIES, + "Get", + g_variant_new("(ss)", SYSTEMD_DBUS_UNIT_IFACE, property)); + + if (!reply || !dh_get_param_from_var(reply, "(v)", &val)) + _E("Failed to get variant"); + if (reply) + g_variant_unref(reply); + free(escaped); + + return val; +} + +GVariant *systemd_get_service_property(const char *unit, + const char *property) +{ + char *escaped; + GVariant *reply = NULL; + GVariant *val = NULL; + + if (!unit || !property) + return NULL; + + escaped = systemd_get_unit_dbus_path(unit); + + reply = dbus_handle_method_sync_with_reply_var(SYSTEMD_DBUS_DEST, + escaped, + DBUS_IFACE_DBUS_PROPERTIES, + "Get", + g_variant_new("(ss)", SYSTEMD_DBUS_SERVICE_IFACE, property)); + if (!reply || !dh_get_param_from_var(reply, "(v)", &val)) + _E("Failed to get variant"); + if (reply) + g_variant_unref(reply); + free(escaped); + return val; +} diff --git a/src/libgdbus/dbus-systemd.h b/src/libgdbus/dbus-systemd.h new file mode 100644 index 0000000..121bbf1 --- /dev/null +++ b/src/libgdbus/dbus-systemd.h @@ -0,0 +1,46 @@ +/* + * libsyscommon + * + * Copyright (c) 2019 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the License); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#ifndef __DBUS_SYSTEMD_H__ +#define __DBUS_SYSTEMD_H__ + +#include "dbus-system.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int systemd_start_unit_sync(const char *name, const char *suffix, int timeout_msec); +int systemd_stop_unit_sync(const char *name, const char *suffix, int timeout_msec); + +int systemd_start_unit_async(const char *name, const char *suffix); +int systemd_stop_unit_async(const char *name, const char *suffix); + +GVariant *systemd_get_manager_property(const char *property); +GVariant *systemd_get_unit_property(const char *unit, + const char *property); +GVariant *systemd_get_service_property(const char *unit, + const char *property); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DBUS_SYSTEMD_H__ */ +