chiark / gitweb /
manager: hookup generators
authorLennart Poettering <lennart@poettering.net>
Thu, 11 Nov 2010 20:28:33 +0000 (21:28 +0100)
committerLennart Poettering <lennart@poettering.net>
Thu, 11 Nov 2010 23:40:26 +0000 (00:40 +0100)
Makefile.am
src/manager.c
src/manager.h

index 6357936..ab8146d 100644 (file)
@@ -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 \
index d690a0f..d2dc8b9 100644 (file)
@@ -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"
index ab7f263..e61194a 100644 (file)
@@ -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);