diff options
-rw-r--r-- | src/utils-systemd.c | 133 | ||||
-rw-r--r-- | src/utils-systemd.h | 4 |
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); + |