#include <sys/epoll.h>
#include <sys/timerfd.h>
#include <sys/poll.h>
+#include <stdlib.h>
+#include <unistd.h>
#include "set.h"
#include "unit.h"
"0123456789" \
"abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
- "-_"
+ "-_.\\"
bool unit_name_is_valid(const char *n) {
UnitType t;
if (!(e = strrchr(n, '.')))
return false;
+ if (e == n)
+ return false;
+
for (i = n; i < e; i++)
if (!strchr(VALID_CHARS, *i))
return false;
bidi_set_free(u, u->meta.dependencies[d]);
free(u->meta.description);
+ free(u->meta.load_path);
while ((t = set_steal_first(u->meta.names)))
free(t);
return 0;
}
-/* FIXME: Does not rollback on failure! */
+/* FIXME: Does not rollback on failure! Needs to fix special unit
+ * pointers. Needs to merge names and dependencies properly.*/
int unit_merge(Unit *u, Unit *other) {
int r;
UnitDependency d;
prefix, load_state_table[u->meta.load_state],
prefix, active_state_table[unit_active_state(u)]);
+ if (u->meta.load_path)
+ fprintf(f, "%s\tLoad Path: %s\n", prefix, u->meta.load_path);
+
SET_FOREACH(t, u->meta.names, i)
fprintf(f, "%s\tName: %s\n", prefix, t);
/* Common implementation for multiple backends */
int unit_load_fragment_and_dropin(Unit *u) {
- int r;
+ int r, ret;
assert(u);
if ((r = unit_load_fragment(u)) < 0)
return r;
+ ret = r > 0;
+
/* Load drop-in directory data */
if ((r = unit_load_dropin(u)) < 0)
return r;
- return 0;
+ return ret;
}
int unit_load(Unit *u) {
retroactively_stop_dependencies(u);
}
-int unit_watch_fd(Unit *u, int fd, uint32_t events) {
+int unit_watch_fd(Unit *u, int fd, uint32_t events, Watch *w) {
struct epoll_event ev;
assert(u);
assert(fd >= 0);
+ assert(w);
+ assert(w->type == WATCH_INVALID || (w->type == WATCH_FD && w->fd == fd && w->unit == u));
zero(ev);
- ev.data.fd = fd;
- ev.data.ptr = u;
- ev.data.u32 = MANAGER_FD;
+ ev.data.ptr = w;
ev.events = events;
- if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) >= 0)
- return 0;
+ if (epoll_ctl(u->meta.manager->epoll_fd,
+ w->type == WATCH_INVALID ? EPOLL_CTL_ADD : EPOLL_CTL_MOD,
+ fd,
+ &ev) < 0)
+ return -errno;
- if (errno == EEXIST)
- if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_MOD, fd, &ev) >= 0)
- return 0;
+ w->fd = fd;
+ w->type = WATCH_FD;
+ w->unit = u;
- return -errno;
+ return 0;
}
-void unit_unwatch_fd(Unit *u, int fd) {
+void unit_unwatch_fd(Unit *u, Watch *w) {
assert(u);
- assert(fd >= 0);
+ assert(w);
+
+ if (w->type == WATCH_INVALID)
+ return;
+
+ assert(w->type == WATCH_FD && w->unit == u);
+ assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
- assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, fd, NULL) >= 0 || errno == ENOENT);
+ w->fd = -1;
+ w->type = WATCH_INVALID;
+ w->unit = NULL;
}
int unit_watch_pid(Unit *u, pid_t pid) {
hashmap_remove(u->meta.manager->watch_pids, UINT32_TO_PTR(pid));
}
-int unit_watch_timer(Unit *u, usec_t delay, int *id) {
- struct epoll_event ev;
- int fd;
+int unit_watch_timer(Unit *u, usec_t delay, Watch *w) {
struct itimerspec its;
- int flags;
+ int flags, fd;
bool ours;
assert(u);
- assert(id);
+ assert(w);
+ assert(w->type == WATCH_INVALID || (w->type == WATCH_TIMER && w->unit == u));
/* This will try to reuse the old timer if there is one */
- if (*id >= 0) {
+ if (w->type == WATCH_TIMER) {
ours = false;
- fd = *id;
-
+ fd = w->fd;
} else {
ours = true;
-
if ((fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
return -errno;
}
if (timerfd_settime(fd, flags, &its, NULL) < 0)
goto fail;
- zero(ev);
- ev.data.fd = fd;
- ev.data.ptr = u;
- ev.data.u32 = MANAGER_TIMER;
- ev.events = POLLIN;
+ if (w->type == WATCH_INVALID) {
+ struct epoll_event ev;
- if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
- goto fail;
+ zero(ev);
+ ev.data.ptr = w;
+ ev.events = POLLIN;
+
+ if (epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_ADD, fd, &ev) < 0)
+ goto fail;
+ }
+
+ w->fd = fd;
+ w->type = WATCH_TIMER;
+ w->unit = u;
- *id = fd;
return 0;
fail:
return -errno;
}
-void unit_unwatch_timer(Unit *u, int *id) {
+void unit_unwatch_timer(Unit *u, Watch *w) {
assert(u);
- assert(id);
+ assert(w);
- if (*id < 0)
+ if (w->type == WATCH_INVALID)
return;
- assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, *id, NULL) >= 0);
- assert_se(close_nointr(*id) == 0);
- *id = -1;
+ assert(w->type == WATCH_TIMER && w->unit == u);
+
+ assert_se(epoll_ctl(u->meta.manager->epoll_fd, EPOLL_CTL_DEL, w->fd, NULL) >= 0);
+ assert_se(close_nointr(w->fd) == 0);
+
+ w->fd = -1;
+ w->type = WATCH_INVALID;
+ w->unit = NULL;
}
bool unit_job_is_applicable(Unit *u, JobType j) {
return 0;
}
+
+int unit_add_dependency_by_name(Unit *u, UnitDependency d, const char *name) {
+ Unit *other;
+ int r;
+
+ if ((r = manager_load_unit(u->meta.manager, name, &other)) < 0)
+ return r;
+
+ if ((r = unit_add_dependency(u, d, other)) < 0)
+ return r;
+
+ return 0;
+}
+
+const char *unit_path(void) {
+ char *e;
+
+ if ((e = getenv("UNIT_PATH")))
+ if (path_is_absolute(e))
+ return e;
+
+ return UNIT_PATH;
+}
+
+int set_unit_path(const char *p) {
+ char *cwd, *c;
+ int r;
+
+ /* This is mostly for debug purposes */
+
+ if (path_is_absolute(p)) {
+ if (!(c = strdup(p)))
+ return -ENOMEM;
+ } else {
+ if (!(cwd = get_current_dir_name()))
+ return -errno;
+
+ r = asprintf(&c, "%s/%s", cwd, p);
+ free(cwd);
+
+ if (r < 0)
+ return -ENOMEM;
+ }
+
+ if (setenv("UNIT_PATH", c, 0) < 0) {
+ r = -errno;
+ free(c);
+ return r;
+ }
+
+ return 0;
+}