aboutsummaryrefslogtreecommitdiffstats
path: root/src/utils-systemd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/utils-systemd.c')
-rw-r--r--src/utils-systemd.c356
1 files changed, 341 insertions, 15 deletions
diff --git a/src/utils-systemd.c b/src/utils-systemd.c
index d804144..830fec6 100644
--- a/src/utils-systemd.c
+++ b/src/utils-systemd.c
@@ -32,9 +32,16 @@
# include <systemd/sd-bus-protocol.h>
#else
struct sd_bus;
-# define sd_bus_default_user(p) ((*(p)=NULL),(-ENOTSUP))
-# define sd_bus_default_system(p) ((*(p)=NULL),(-ENOTSUP))
-# define sd_bus_call_method(...) (-ENOTSUP)
+ struct sd_bus_message;
+ typedef struct { const char *name; const char *message; } sd_bus_error;
+# define sd_bus_default_user(p) ((*(p)=NULL),(-ENOTSUP))
+# define sd_bus_default_system(p) ((*(p)=NULL),(-ENOTSUP))
+# define sd_bus_call_method(...) (-ENOTSUP)
+# define SD_BUS_ERROR_NULL {NULL,NULL}
+# define sd_bus_message_read_basic(...) (-ENOTSUP)
+# define sd_bus_message_unref(...) (NULL)
+# define sd_bus_get_property_string(...) (-ENOTSUP)
+# define sd_bus_get_property_trivial(...) (-ENOTSUP)
#endif
#include "utils-systemd.h"
@@ -46,7 +53,25 @@
static const char sdb_path[] = "/org/freedesktop/systemd1";
static const char sdb_destination[] = "org.freedesktop.systemd1";
static const char sdbi_manager[] = "org.freedesktop.systemd1.Manager";
+static const char sdbi_unit[] = "org.freedesktop.systemd1.Unit";
+static const char sdbi_service[] = "org.freedesktop.systemd1.Service";
static const char sdbm_reload[] = "Reload";
+static const char sdbm_start_unit[] = "StartUnit";
+static const char sdbm_stop_unit[] = "StopUnit";
+static const char sdbm_start[] = "Start";
+static const char sdbm_stop[] = "Stop";
+static const char sdbm_get_unit[] = "GetUnit";
+static const char sdbm_get_unit_by_pid[] = "GetUnitByPID";
+static const char sdbm_load_unit[] = "LoadUnit";
+static const char sdbp_active_state[] = "ActiveState";
+static const char sdbp_exec_main_pid[] = "ExecMainPID";
+
+const char SysD_State_Inactive[] = "inactive";
+const char SysD_State_Activating[] = "activating";
+const char SysD_State_Active[] = "active";
+const char SysD_State_Deactivating[] = "deactivating";
+const char SysD_State_Reloading[] = "reloading";
+const char SysD_State_Failed[] = "failed";
static struct sd_bus *sysbus;
static struct sd_bus *usrbus;
@@ -80,20 +105,227 @@ static int get_bus(int isuser, struct sd_bus **ret)
struct sd_bus *bus;
bus = isuser ? usrbus : sysbus;
- if (bus) {
+ if (bus)
*ret = bus;
- rc = 0;
- } else if (isuser) {
+ else if (isuser) {
rc = sd_bus_default_user(ret);
- if (!rc)
- usrbus = *ret;
+ if (rc < 0)
+ goto error;
+ usrbus = *ret;
} else {
rc = sd_bus_default_system(ret);
- if (!rc)
- sysbus = *ret;
+ if (rc < 0)
+ goto error;
+ sysbus = *ret;
}
+ return 0;
+error:
return sderr2errno(rc);
}
+
+#if 0
+/********************************************************************
+ * routines for escaping unit names to compute dbus path of units
+ *******************************************************************/
+/*
+ * Should the char 'c' be escaped?
+ */
+static inline int should_escape_for_path(char c)
+{
+ if (c >= 'A') {
+ return c <= (c >= 'a' ? 'z' : 'Z');
+ } else {
+ return c >= '0' && c <= '9';
+ }
+}
+
+/*
+ * ascii char for the hexadecimal digit 'x'
+ */
+static inline char d2h(int x)
+{
+ return (char)(x + (x > 9 ? ('a' - 10) : '0'));
+}
+
+/*
+ * escapes in 'path' of 'pathlen' the 'unit'
+ * returns 0 in case of success or -1 in case of error
+ */
+static int unit_escape_for_path(char *path, size_t pathlen, const char *unit)
+{
+ size_t r, w;
+ char c;
+
+ c = unit[r = w = 0];
+ while (c) {
+ if (should_escape_for_path(c)) {
+ if (w + 2 >= pathlen)
+ goto toolong;
+ path[w++] = '_';
+ path[w++] = d2h((c >> 4) & 15);;
+ path[w++] = d2h(c & 15);
+ } else {
+ if (w >= pathlen)
+ goto toolong;
+ path[w++] = c;
+ }
+ c = unit[++r];
+ }
+ if (w >= pathlen)
+ goto toolong;
+ path[w] = 0;
+ return 0;
+toolong:
+ return seterrno(ENAMETOOLONG);
+}
+#endif
+
+/********************************************************************
+ * Routines for getting paths
+ *******************************************************************/
+
+static char *get_dpath(struct sd_bus_message *msg)
+{
+ int rc;
+ const char *reply;
+ char *result;
+
+ rc = sd_bus_message_read_basic(msg, 'o', &reply);
+ rc = sderr2errno(rc);
+ if (rc < 0)
+ result = NULL;
+ else {
+ result = strdup(reply);
+ if (!result)
+ errno = ENOMEM;
+ }
+ sd_bus_message_unref(msg);
+ return result;
+}
+
+static char *get_unit_dpath(struct sd_bus *bus, const char *unit, int load)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, load ? sdbm_load_unit : sdbm_get_unit, &err, &ret, "s", unit);
+ if (rc < 0)
+ goto error;
+
+ return get_dpath(ret);
+error:
+ sd_bus_message_unref(ret);
+ return NULL;
+}
+
+static char *get_unit_dpath_by_pid(struct sd_bus *bus, unsigned pid)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_get_unit_by_pid, &err, &ret, "u", pid);
+ if (rc < 0)
+ goto error;
+
+ return get_dpath(ret);
+error:
+ sd_bus_message_unref(ret);
+ return NULL;
+}
+
+static int unit_pid(struct sd_bus *bus, const char *dpath)
+{
+ int rc;
+ unsigned u = 0;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_get_property_trivial(bus, sdb_destination, dpath, sdbi_service, sdbp_exec_main_pid, &err, 'u', &u);
+ return rc < 0 ? rc : (int)u;
+}
+
+static const char *unit_state(struct sd_bus *bus, const char *dpath)
+{
+ int rc;
+ char *st;
+ const char *resu;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_get_property_string(bus, sdb_destination, dpath, sdbi_unit, sdbp_active_state, &err, &st);
+ if (rc < 0) {
+ errno = -rc;
+ resu = NULL;
+ } else {
+ if (!strcmp(st, SysD_State_Active))
+ resu = SysD_State_Active;
+ else if (!strcmp(st, SysD_State_Reloading))
+ resu = SysD_State_Reloading;
+ else if (!strcmp(st, SysD_State_Inactive))
+ resu = SysD_State_Inactive;
+ else if (!strcmp(st, SysD_State_Failed))
+ resu = SysD_State_Failed;
+ else if (!strcmp(st, SysD_State_Activating))
+ resu = SysD_State_Activating;
+ else if (!strcmp(st, SysD_State_Deactivating))
+ resu = SysD_State_Deactivating;
+ else {
+ errno = EBADMSG;
+ resu = NULL;
+ }
+ free(st);
+ }
+ return resu;
+}
+
+static int unit_start(struct sd_bus *bus, const char *dpath)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_start, &err, &ret, "s", "replace");
+ sd_bus_message_unref(ret);
+ return rc;
+}
+
+static int unit_stop(struct sd_bus *bus, const char *dpath)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_stop, &err, &ret, "s", "replace");
+ sd_bus_message_unref(ret);
+ return rc;
+}
+
+static int unit_start_name(struct sd_bus *bus, const char *name)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_start_unit, &err, &ret, "ss", name, "replace");
+ sd_bus_message_unref(ret);
+ return rc;
+}
+
+static int unit_stop_name(struct sd_bus *bus, const char *name)
+{
+ int rc;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+
+ rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_stop_unit, &err, &ret, "ss", name, "replace");
+ sd_bus_message_unref(ret);
+ return rc;
+}
+
+/********************************************************************
+ *
+ *******************************************************************/
+
static int check_snprintf_result(int rc, size_t buflen)
{
return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
@@ -101,7 +333,7 @@ static int check_snprintf_result(int rc, size_t buflen)
int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
{
- int rc = snprintf(path, pathlen, "%s/%s",
+ int rc = snprintf(path, pathlen, "%s/%s",
SYSTEMD_UNITS_ROOT,
isuser ? "user" : "system");
@@ -110,7 +342,7 @@ int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
{
- int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
+ int rc = snprintf(path, pathlen, "%s/%s/%s.%s",
SYSTEMD_UNITS_ROOT,
isuser ? "user" : "system",
unit,
@@ -121,7 +353,7 @@ int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *un
int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
{
- int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
+ int rc = snprintf(path, pathlen, "%s/%s/%s.wants/%s.%s",
SYSTEMD_UNITS_ROOT,
isuser ? "user" : "system",
wanter,
@@ -142,12 +374,15 @@ int systemd_daemon_reload(int isuser)
{
int rc;
struct sd_bus *bus;
+ struct sd_bus_message *ret = NULL;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
rc = get_bus(isuser, &bus);
- if (!rc) {
+ if (rc >= 0) {
/* TODO: asynchronous bind... */
/* TODO: more diagnostic... */
- rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, NULL, NULL, NULL);
+ rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, &err, &ret, NULL);
+ sd_bus_message_unref(ret);
}
return rc;
}
@@ -220,3 +455,94 @@ int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const
return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
}
+char *systemd_unit_dpath_by_name(int isuser, const char *name, int load)
+{
+ struct sd_bus *bus;
+
+ return get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
+}
+
+char *systemd_unit_dpath_by_pid(int isuser, unsigned pid)
+{
+ struct sd_bus *bus;
+
+ return get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath_by_pid(bus, pid);
+}
+
+int systemd_unit_start_dpath(int isuser, const char *dpath)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ return rc < 0 ? rc : unit_start(bus, dpath);
+}
+
+int systemd_unit_stop_dpath(int isuser, const char *dpath)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ return rc < 0 ? rc : unit_stop(bus, dpath);
+}
+
+int systemd_unit_start_name(int isuser, const char *name)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ if (rc >= 0)
+ rc = unit_start_name(bus, name);
+ return rc;
+}
+
+int systemd_unit_stop_name(int isuser, const char *name)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ if (rc >= 0)
+ rc = unit_stop_name(bus, name);
+ return rc;
+}
+
+int systemd_unit_stop_pid(int isuser, unsigned pid)
+{
+ int rc;
+ struct sd_bus *bus;
+ char *dpath;
+
+ rc = get_bus(isuser, &bus);
+ if (rc >= 0) {
+ dpath = get_unit_dpath_by_pid(bus, pid);
+ if (!dpath)
+ rc = -1;
+ else {
+ rc = unit_stop(bus, dpath);
+ free(dpath);
+ }
+ }
+ return rc;
+}
+
+int systemd_unit_pid_of_dpath(int isuser, const char *dpath)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ return rc < 0 ? rc : unit_pid(bus, dpath);
+}
+
+const char *systemd_unit_state_of_dpath(int isuser, const char *dpath)
+{
+ int rc;
+ struct sd_bus *bus;
+
+ rc = get_bus(isuser, &bus);
+ return rc < 0 ? NULL : unit_state(bus, dpath);
+}
+