aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2017-03-16 09:27:41 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2017-03-17 13:01:40 +0100
commit600a5cde310c62e4c6ed1845cf0234ba04fb6f90 (patch)
tree1fa88eb122eaa6891ba7c11e101aa510fed738cc
parenta1ae7c362b0b7a65cad813a8def6c8eae72f33b2 (diff)
utils-systemd: provide enumeration of units
This enumeration is based on the filesystem, units are listed from the configured directory. This is necessarily because not all units can be loaded by systemd but all can be started. Change-Id: Ic4d1331c8c54f5bbaa747ff8084da2b0c5a65c55 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--src/utils-systemd.c133
-rw-r--r--src/utils-systemd.h4
2 files changed, 119 insertions, 18 deletions
diff --git a/src/utils-systemd.c b/src/utils-systemd.c
index 62930ed..b8c3c0b 100644
--- a/src/utils-systemd.c
+++ b/src/utils-systemd.c
@@ -20,9 +20,12 @@
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <fcntl.h>
#include <string.h>
-#include <poll.h>
-#include <assert.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <systemd/sd-bus.h>
#include <systemd/sd-bus-protocol.h>
@@ -41,6 +44,29 @@ static const char sdbm_reload[] = "Reload";
static struct sd_bus *sysbus;
static struct sd_bus *usrbus;
+/*
+ * Translate systemd errors to errno errors
+ */
+static int seterrno(int value)
+{
+ errno = value;
+ return -1;
+}
+
+static int sderr2errno(int rc)
+{
+ return rc < 0 ? seterrno(-rc) : rc;
+}
+
+static int errno2sderr(int rc)
+{
+ return rc < 0 ? -errno : rc;
+}
+
+/* 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 rc;
@@ -59,7 +85,20 @@ static int get_bus(int isuser, struct sd_bus **ret)
if (!rc)
sysbus = *ret;
}
- return rc;
+ return sderr2errno(rc);
+}
+static int check_snprintf_result(int rc, size_t buflen)
+{
+ return (rc >= 0 && (size_t)rc >= buflen) ? seterrno(ENAMETOOLONG) : rc;
+}
+
+int systemd_get_units_dir(char *path, size_t pathlen, int isuser)
+{
+ int rc = snprintf(path, pathlen, "%s/%s",
+ SYSTEMD_UNITS_ROOT,
+ isuser ? "user" : "system");
+
+ return check_snprintf_result(rc, pathlen);
}
int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext)
@@ -70,11 +109,7 @@ int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *un
unit,
uext);
- if (rc >= 0 && (size_t)rc >= pathlen) {
- errno = ENAMETOOLONG;
- rc = -1;
- }
- return rc;
+ return check_snprintf_result(rc, pathlen);
}
int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext)
@@ -86,22 +121,14 @@ int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *w
unit,
uext);
- if (rc >= 0 && (size_t)rc >= pathlen) {
- errno = ENAMETOOLONG;
- rc = -1;
- }
- return rc;
+ return check_snprintf_result(rc, pathlen);
}
int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext)
{
int rc = snprintf(path, pathlen, "../%s.%s", unit, uext);
- if (rc >= 0 && (size_t)rc >= pathlen) {
- errno = ENAMETOOLONG;
- rc = -1;
- }
- return rc;
+ return check_snprintf_result(rc, pathlen);
}
int systemd_daemon_reload(int isuser)
@@ -111,8 +138,78 @@ int systemd_daemon_reload(int isuser)
rc = get_bus(isuser, &bus);
if (!rc) {
+ /* TODO: asynchronous bind... */
+ /* TODO: more diagnostic... */
rc = sd_bus_call_method(bus, sdb_destination, sdb_path, sdbi_manager, sdbm_reload, NULL, NULL, NULL);
}
return rc;
}
+int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
+{
+ DIR *dir;
+ char path[PATH_MAX + 1];
+ struct dirent *dent;
+ int rc, isfile;
+ size_t offset, len;
+ struct stat st;
+
+ /* get the path */
+ rc = systemd_get_units_dir(path, sizeof path - 1, isuser);
+ if (rc < 0)
+ return rc;
+ offset = (size_t)rc;
+
+ /* open the directory */
+ dir = opendir(path);
+ if (!dir)
+ return -1;
+
+ /* prepare path */
+ path[offset++] = '/';
+
+ /* read the directory */
+ for(;;) {
+ /* get next entry */
+ errno = 0;
+ dent = readdir(dir);
+ if (dent == NULL) {
+ /* end or error */
+ rc = (!errno) - 1;
+ break;
+ }
+
+ /* is a file? */
+ if (dent->d_type == DT_REG)
+ isfile = 1;
+ else if (dent->d_type != DT_UNKNOWN)
+ isfile = 0;
+ else {
+ rc = fstatat(dirfd(dir), dent->d_name, &st, AT_SYMLINK_NOFOLLOW|AT_NO_AUTOMOUNT);
+ if (rc < 0)
+ break;
+ isfile = S_ISREG(st.st_mode);
+ }
+
+ /* calls the callback if is a file */
+ if (isfile) {
+ len = strlen(dent->d_name);
+ if (offset + len >= sizeof path) {
+ rc = seterrno(ENAMETOOLONG);
+ break;
+ }
+ memcpy(&path[offset], dent->d_name, 1 + len);
+ rc = callback(closure, &path[offset], path, isuser);
+ if (rc)
+ break;
+ }
+ }
+ closedir(dir);
+ return rc;
+}
+
+int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure)
+{
+ return systemd_unit_list(1, callback, closure) ? : systemd_unit_list(0, callback, closure);
+}
+
diff --git a/src/utils-systemd.h b/src/utils-systemd.h
index 30f9522..f704d45 100644
--- a/src/utils-systemd.h
+++ b/src/utils-systemd.h
@@ -18,8 +18,12 @@
#pragma once
+extern int systemd_get_units_dir(char *path, size_t pathlen, int isuser);
extern int systemd_get_unit_path(char *path, size_t pathlen, int isuser, const char *unit, const char *uext);
extern int systemd_get_wants_path(char *path, size_t pathlen, int isuser, const char *wanter, const char *unit, const char *uext);
extern int systemd_get_wants_target(char *path, size_t pathlen, const char *unit, const char *uext);
extern int systemd_daemon_reload(int isuser);
+extern int systemd_unit_list(int isuser, int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure);
+extern int systemd_unit_list_all(int (*callback)(void *closure, const char *name, const char *path, int isuser), void *closure);
+