summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2010-11-11 21:28:33 +0100
committerLennart Poettering <lennart@poettering.net>2010-11-12 00:40:26 +0100
commit5a1e99375d03bc88795d68c66bf3933dd04c1015 (patch)
tree896d67db2106f26846b44c919873bd67eb190b8a
parent91901329245f070b621a24577393fb8f4ce9bffc (diff)
manager: hookup generators
-rw-r--r--Makefile.am10
-rw-r--r--src/manager.c161
-rw-r--r--src/manager.h4
3 files changed, 173 insertions, 2 deletions
diff --git a/Makefile.am b/Makefile.am
index 6357936d5c..ab8146d085 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,12 +26,13 @@ udevrulesdir=@udevrulesdir@
pamlibdir=@pamlibdir@
pkgconfigdatadir=$(datadir)/pkgconfig
polkitpolicydir=$(datadir)/polkit-1/actions
-bashcompletiondir=${sysconfdir}/bash_completion.d
+bashcompletiondir=$(sysconfdir)/bash_completion.d
# Our own, non-special dirs
pkgsysconfdir=$(sysconfdir)/systemd
sessionunitdir=$(pkgdatadir)/session
tmpfilesdir=$(sysconfdir)/tmpfiles.d
+sessiongeneratordir=$(pkglibexecdir)/session-generators
# And these are the special ones for /
rootdir=@rootdir@
@@ -39,6 +40,7 @@ rootbindir=$(rootdir)/bin
rootsbindir=$(rootdir)/sbin
rootlibexecdir=$(rootdir)/lib/systemd
systemunitdir=$(rootdir)/lib/systemd/system
+systemgeneratordir=$(rootdir)/lib/systemd/system-generators
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
@@ -58,6 +60,8 @@ AM_CPPFLAGS = \
-DRUNTIME_DIR=\"$(localstatedir)/run\" \
-DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \
-DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \
+ -DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \
+ -DSESSION_GENERATOR_PATH=\"$(sessiongeneratordir)\" \
-I $(top_srcdir)/src
if TARGET_GENTOO
@@ -115,10 +119,12 @@ rootlibexec_PROGRAMS = \
systemd-fsck \
systemd-quotacheck \
systemd-cryptsetup \
- systemd-cryptsetup-generator \
systemd-timestamp \
systemd-ac-power
+systemgenerator_PROGRAMS = \
+ systemd-cryptsetup-generator
+
noinst_PROGRAMS = \
test-engine \
test-job-type \
diff --git a/src/manager.c b/src/manager.c
index d690a0f16b..d2dc8b9ef8 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -433,6 +433,8 @@ void manager_free(Manager *m) {
* around */
manager_shutdown_cgroup(m, m->exit_code != MANAGER_REEXECUTE);
+ manager_undo_generators(m);
+
bus_done(m);
hashmap_free(m->units);
@@ -567,6 +569,8 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
assert(m);
+ manager_run_generators(m);
+
manager_build_unit_path_cache(m);
/* If we will deserialize make sure that during enumeration
@@ -2626,12 +2630,17 @@ int manager_reload(Manager *m) {
/* From here on there is no way back. */
manager_clear_jobs_and_units(m);
+ manager_undo_generators(m);
/* Find new unit paths */
lookup_paths_free(&m->lookup_paths);
if ((q = lookup_paths_init(&m->lookup_paths, m->running_as)) < 0)
r = q;
+ manager_run_generators(m);
+
+ manager_build_unit_path_cache(m);
+
m->n_deserializing ++;
/* First, enumerate what we can from all config files */
@@ -2756,6 +2765,158 @@ void manager_check_finished(Manager *m) {
}
+void manager_run_generators(Manager *m) {
+ DIR *d = NULL;
+ struct dirent *de;
+ Hashmap *pids = NULL;
+ const char *generator_path;
+
+ assert(m);
+
+ generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : SESSION_GENERATOR_PATH;
+ if (!(d = opendir(generator_path))) {
+
+ if (errno == ENOENT)
+ return;
+
+ log_error("Failed to enumerate generator directory: %m");
+ return;
+ }
+
+ if (!m->generator_unit_path) {
+ char *p;
+ char system_path[] = "/dev/.systemd/generator-XXXXXX",
+ session_path[] = "/tmp/systemd-generator-XXXXXX";
+
+ if (!(p = mkdtemp(m->running_as == MANAGER_SYSTEM ? system_path : session_path))) {
+ log_error("Failed to generate generator directory: %m");
+ goto finish;
+ }
+
+ if (!(m->generator_unit_path = strdup(p))) {
+ log_error("Failed to allocate generator unit path.");
+ goto finish;
+ }
+ }
+
+ if (!(pids = hashmap_new(trivial_hash_func, trivial_compare_func))) {
+ log_error("Failed to allocate set.");
+ goto finish;
+ }
+
+ while ((de = readdir(d))) {
+ char *path;
+ pid_t pid;
+ int k;
+
+ if (ignore_file(de->d_name))
+ continue;
+
+ if (de->d_type != DT_REG &&
+ de->d_type != DT_LNK &&
+ de->d_type != DT_UNKNOWN)
+ continue;
+
+ if (asprintf(&path, "%s/%s", generator_path, de->d_name) < 0) {
+ log_error("Out of memory");
+ continue;
+ }
+
+ if ((pid = fork()) < 0) {
+ log_error("Failed to fork: %m");
+ free(path);
+ continue;
+ }
+
+ if (pid == 0) {
+ const char *arguments[5];
+ /* Child */
+
+ arguments[0] = path;
+ arguments[1] = m->generator_unit_path;
+ arguments[2] = NULL;
+
+ execv(path, (char **) arguments);
+
+ log_error("Failed to execute %s: %m", path);
+ _exit(EXIT_FAILURE);
+ }
+
+ if ((k = hashmap_put(pids, UINT_TO_PTR(pid), path)) < 0) {
+ log_error("Failed to add PID to set: %s", strerror(-k));
+ free(path);
+ }
+ }
+
+ while (!hashmap_isempty(pids)) {
+ siginfo_t si;
+ char *path;
+
+ zero(si);
+ if (waitid(P_ALL, 0, &si, WEXITED) < 0) {
+
+ if (errno == EINTR)
+ continue;
+
+ log_error("waitid() failed: %m");
+ goto finish;
+ }
+
+ if ((path = hashmap_remove(pids, UINT_TO_PTR(si.si_pid)))) {
+ if (!is_clean_exit(si.si_code, si.si_status)) {
+ if (si.si_code == CLD_EXITED)
+ log_error("%s exited with exit status %i.", path, si.si_status);
+ else
+ log_error("%s terminated by signal %s.", path, signal_to_string(si.si_status));
+ }
+
+ free(path);
+ }
+ }
+
+ if (rmdir(m->generator_unit_path) >= 0) {
+ /* Uh? we were able to remove this dir? I guess that
+ * means the directory was empty, hence let's shortcut
+ * this */
+
+ free(m->generator_unit_path);
+ m->generator_unit_path = NULL;
+ goto finish;
+ }
+
+ if (!strv_find(m->lookup_paths.unit_path, m->generator_unit_path)) {
+ char **l;
+
+ if (!(l = strv_append(m->lookup_paths.unit_path, m->generator_unit_path))) {
+ log_error("Failed to add generator directory to unit search path: %m");
+ goto finish;
+ }
+
+ strv_free(m->lookup_paths.unit_path);
+ m->lookup_paths.unit_path = l;
+ }
+
+finish:
+ if (d)
+ closedir(d);
+
+ if (pids)
+ hashmap_free_free(pids);
+}
+
+void manager_undo_generators(Manager *m) {
+ assert(m);
+
+ if (!m->generator_unit_path)
+ return;
+
+ strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
+ rm_rf(m->generator_unit_path, false, true);
+
+ free(m->generator_unit_path);
+ m->generator_unit_path = NULL;
+}
+
static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_SYSTEM] = "system",
[MANAGER_SESSION] = "session"
diff --git a/src/manager.h b/src/manager.h
index ab7f26368c..e61194ad41 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -148,6 +148,7 @@ struct Manager {
dual_timestamp finish_timestamp;
char *console;
+ char *generator_unit_path;
/* Data specific to the device subsystem */
struct udev* udev;
@@ -279,6 +280,9 @@ bool manager_unit_pending_inactive(Manager *m, const char *name);
void manager_check_finished(Manager *m);
+void manager_run_generators(Manager *m);
+void manager_undo_generators(Manager *m);
+
const char *manager_running_as_to_string(ManagerRunningAs i);
ManagerRunningAs manager_running_as_from_string(const char *s);