summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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);
+