/*
- Copyright 2017 IoT.bzh
+ Copyright (C) 2015-2020 IoT.bzh
author: José Bollo <jose.bollo@iot.bzh>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
+#include <time.h>
#ifndef NO_LIBSYSTEMD
# include <systemd/sd-bus.h>
struct sd_bus;
struct sd_bus_message;
typedef struct { const char *name; const char *message; } sd_bus_error;
+# define sd_bus_unref(...) ((void)0)
# define sd_bus_default_user(p) ((*(p)=NULL),(-ENOTSUP))
# define sd_bus_default_system(p) ((*(p)=NULL),(-ENOTSUP))
# define sd_bus_call_method(...) (-ENOTSUP)
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 sdbi_job[] = "org.freedesktop.systemd1.Job";
+static const char sdbj_state[] = "State";
static const char sdbm_reload[] = "Reload";
static const char sdbm_start_unit[] = "StartUnit";
static const char sdbm_restart_unit[] = "RestartUnit";
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 const char *sds_state_names[] = {
+ NULL,
+ "inactive",
+ "activating",
+ "active",
+ "deactivating",
+ "reloading",
+ "failed"
+};
+
+static const char *sds_job_state_names[] = {
+ NULL,
+ "waiting",
+ "running"
+};
static struct sd_bus *sysbus;
static struct sd_bus *usrbus;
return rc < 0 ? -errno : rc;
}
-/* Returns in 'ret' either the system bus (if isuser==0)
+/*
+ * Returns in 'ret' either the system bus (if isuser==0)
* or the user bus (if isuser!=0).
* Returns 0 in case of success or -1 in case of error
*/
-static int get_bus(int isuser, struct sd_bus **ret)
+int systemd_get_bus(int isuser, struct sd_bus **ret)
{
int rc;
struct sd_bus *bus;
return sderr2errno(rc);
}
+void systemd_set_bus(int isuser, struct sd_bus *bus)
+{
+ struct sd_bus **target = isuser ? &usrbus : &sysbus;
+ if (*target)
+ sd_bus_unref(*target);
+ *target = bus;
+}
+
#if 0
/********************************************************************
* routines for escaping unit names to compute dbus path of units
return rc < 0 ? rc : (int)u;
}
-static const char *unit_state(struct sd_bus *bus, const char *dpath)
+static enum SysD_State unit_state(struct sd_bus *bus, const char *dpath)
{
int rc;
char *st;
- const char *resu;
+ enum SysD_State resu;
sd_bus_error err = SD_BUS_ERROR_NULL;
+ resu = SysD_State_INVALID;
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;
+ switch (st[0]) {
+ case 'a':
+ if (!strcmp(st, sds_state_names[SysD_State_Active]))
+ resu = SysD_State_Active;
+ else if (!strcmp(st, sds_state_names[SysD_State_Activating]))
+ resu = SysD_State_Activating;
+ break;
+ case 'd':
+ if (!strcmp(st, sds_state_names[SysD_State_Deactivating]))
+ resu = SysD_State_Deactivating;
+ break;
+ case 'f':
+ if (!strcmp(st, sds_state_names[SysD_State_Failed]))
+ resu = SysD_State_Failed;
+ break;
+ case 'i':
+ if (!strcmp(st, sds_state_names[SysD_State_Inactive]))
+ resu = SysD_State_Inactive;
+ break;
+ case 'r':
+ if (!strcmp(st, sds_state_names[SysD_State_Reloading]))
+ resu = SysD_State_Reloading;
+ break;
+ default:
+ break;
}
+ if (resu == NULL)
+ errno = EBADMSG;
free(st);
}
return resu;
}
+static int job_wait(struct sd_bus *bus, struct sd_bus_message *job)
+{
+ int rc;
+ sd_bus_error err = SD_BUS_ERROR_NULL;
+ const char *jpath = NULL;
+ char *jstate;
+ struct timespec tispec;
+ const int period_ms = 10;
+ const int trial_s = 10;
+ const int trial_count = (trial_s * 1000) / period_ms;
+ const int period_ns = period_ms * 1000000;
+ int trial;
+
+ /* Get job path */
+ rc = sd_bus_message_read_basic(job, 'o', &jpath);
+ if (rc < 0)
+ return rc;
+
+ /* Wait for job to enter "running" state */
+ rc = 0;
+ for (trial = 1 ; trial <= trial_count ; trial++) {
+ jstate = NULL;
+ if(sd_bus_get_property_string(bus, sdb_destination, jpath, sdbi_job, sdbj_state, &err, &jstate) >= 0) {
+ if(jstate && strcmp(jstate, sds_job_state_names[SysD_Job_State_Running]) == 0) {
+ free(jstate);
+ break;
+ } else {
+ tispec.tv_sec = 0;
+ tispec.tv_nsec = period_ns;
+ nanosleep(&tispec, NULL);
+ }
+ free(jstate);
+ }
+ }
+ if(trial > trial_count)
+ rc = -1;
+
+ return rc;
+}
+
static int unit_start(struct sd_bus *bus, const char *dpath)
{
int rc;
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");
+ if(ret) {
+ rc = job_wait(bus, ret);
+ }
sd_bus_message_unref(ret);
return rc;
}
sd_bus_error err = SD_BUS_ERROR_NULL;
rc = sd_bus_call_method(bus, sdb_destination, dpath, sdbi_unit, sdbm_restart, &err, &ret, "s", "replace");
+ if(ret) {
+ rc = job_wait(bus, ret);
+ }
sd_bus_message_unref(ret);
return rc;
}
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");
+ if(ret) {
+ rc = job_wait(bus, ret);
+ }
sd_bus_message_unref(ret);
return rc;
}
sd_bus_error err = SD_BUS_ERROR_NULL;
rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_restart_unit, &err, &ret, "ss", name, "replace");
+ if(ret) {
+ rc = job_wait(bus, ret);
+ }
sd_bus_message_unref(ret);
return rc;
}
struct sd_bus_message *ret = NULL;
sd_bus_error err = SD_BUS_ERROR_NULL;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
if (rc >= 0) {
/* TODO: asynchronous bind... */
/* TODO: more diagnostic... */
{
struct sd_bus *bus;
- return get_bus(isuser, &bus) < 0 ? NULL : get_unit_dpath(bus, name, load);
+ return systemd_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);
+ return systemd_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);
+ rc = systemd_get_bus(isuser, &bus);
return rc < 0 ? rc : unit_start(bus, dpath);
}
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
return rc < 0 ? rc : unit_restart(bus, dpath);
}
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
return rc < 0 ? rc : unit_stop(bus, dpath);
}
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
if (rc >= 0)
rc = unit_start_name(bus, name);
return rc;
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
if (rc >= 0)
rc = unit_restart_name(bus, name);
return rc;
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
if (rc >= 0)
rc = unit_stop_name(bus, name);
return rc;
struct sd_bus *bus;
char *dpath;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
if (rc >= 0) {
dpath = get_unit_dpath_by_pid(bus, pid);
if (!dpath)
int rc;
struct sd_bus *bus;
- rc = get_bus(isuser, &bus);
+ rc = systemd_get_bus(isuser, &bus);
return rc < 0 ? rc : unit_pid(bus, dpath);
}
-const char *systemd_unit_state_of_dpath(int isuser, const char *dpath)
+enum SysD_State 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);
+ rc = systemd_get_bus(isuser, &bus);
+ return rc < 0 ? SysD_State_INVALID : unit_state(bus, dpath);
}
+const char *systemd_state_name(enum SysD_State state)
+{
+ return sds_state_names[state];
+}