chiark / gitweb /
manager: rework generator logic
authorLennart Poettering <lennart@poettering.net>
Wed, 23 May 2012 01:43:29 +0000 (03:43 +0200)
committerLennart Poettering <lennart@poettering.net>
Wed, 23 May 2012 01:43:29 +0000 (03:43 +0200)
Previously generated units were always placed at the end of the search
path. With this change there will be three unit dirs instead of one, to
place generated entries at the beginning, in the middle and at the end
of the search path:

beginning: for units that need to override all configuration, regardless
of user or vendor. Example use: system-update-generator uses this to
temporarily redirect default.target.

middle: for units that need to override vendor configuration, but not
vendor configuration. Example use: /etc/fstab should override vendor
supplied configuration (think /tmp), but should not override native user
configuration.

end: does not override anything but is available as well. Possible usage
might be to convert D-Bus bus service files to native units but allowing
vendor supplied native units to win.

13 files changed:
src/core/manager.c
src/core/manager.h
src/cryptsetup/cryptsetup-generator.c
src/fstab-generator/fstab-generator.c
src/getty-generator/getty-generator.c
src/rc-local-generator/rc-local-generator.c
src/shared/install.c
src/shared/path-lookup.c
src/shared/path-lookup.h
src/shared/strv.c
src/shared/strv.h
src/system-update-generator/system-update-generator.c
src/systemctl/systemctl.c

index 30437425c4ac955cb8b75e74b950ee4f8f97cf0f..5c6d63668d7491f821281af736f555901184887a 100644 (file)
@@ -299,9 +299,6 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
         if ((m->epoll_fd = epoll_create1(EPOLL_CLOEXEC)) < 0)
                 goto fail;
 
-        if ((r = lookup_paths_init(&m->lookup_paths, m->running_as, true)) < 0)
-                goto fail;
-
         if ((r = manager_setup_signals(m)) < 0)
                 goto fail;
 
@@ -637,6 +634,14 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
 
         manager_run_generators(m);
 
+        r = lookup_paths_init(
+                        &m->lookup_paths, m->running_as, true,
+                        m->generator_unit_path,
+                        m->generator_unit_path_early,
+                        m->generator_unit_path_late);
+        if (r < 0)
+                return r;
+
         manager_build_unit_path_cache(m);
 
         /* If we will deserialize make sure that during enumeration
@@ -649,12 +654,15 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
         r = manager_enumerate(m);
 
         /* Second, deserialize if there is something to deserialize */
-        if (serialization)
-                if ((q = manager_deserialize(m, serialization, fds)) < 0)
+        if (serialization) {
+                q = manager_deserialize(m, serialization, fds);
+                if (q < 0)
                         r = q;
+        }
 
         /* Third, fire things up! */
-        if ((q = manager_coldplug(m)) < 0)
+        q = manager_coldplug(m);
+        if (q < 0)
                 r = q;
 
         if (serialization) {
@@ -1871,18 +1879,21 @@ int manager_reload(Manager *m) {
 
         assert(m);
 
-        if ((r = manager_open_serialization(m, &f)) < 0)
+        r = manager_open_serialization(m, &f);
+        if (r < 0)
                 return r;
 
         m->n_reloading ++;
 
-        if (!(fds = fdset_new())) {
+        fds = fdset_new();
+        if (!fds) {
                 m->n_reloading --;
                 r = -ENOMEM;
                 goto finish;
         }
 
-        if ((r = manager_serialize(m, f, fds)) < 0) {
+        r = manager_serialize(m, f, fds);
+        if (r < 0) {
                 m->n_reloading --;
                 goto finish;
         }
@@ -1896,29 +1907,37 @@ 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, true)) < 0)
-                r = q;
 
+        /* Find new unit paths */
         manager_run_generators(m);
 
+        q = lookup_paths_init(
+                        &m->lookup_paths, m->running_as, true,
+                        m->generator_unit_path,
+                        m->generator_unit_path_early,
+                        m->generator_unit_path_late);
+        if (q < 0)
+                r = q;
+
         manager_build_unit_path_cache(m);
 
         /* First, enumerate what we can from all config files */
-        if ((q = manager_enumerate(m)) < 0)
+        q = manager_enumerate(m);
+        if (q < 0)
                 r = q;
 
         /* Second, deserialize our stored data */
-        if ((q = manager_deserialize(m, f, fds)) < 0)
+        q = manager_deserialize(m, f, fds);
+        if (q < 0)
                 r = q;
 
         fclose(f);
         f = NULL;
 
         /* Third, fire things up! */
-        if ((q = manager_coldplug(m)) < 0)
+        q = manager_coldplug(m);
+        if (q < 0)
                 r = q;
 
         assert(m->n_reloading > 0);
@@ -2030,17 +2049,76 @@ void manager_check_finished(Manager *m) {
                    format_timespan(sum, sizeof(sum), total_usec));
 }
 
+static int create_generator_dir(Manager *m, char **generator, const char *name) {
+        char *p;
+        int r;
+
+        assert(m);
+        assert(generator);
+        assert(name);
+
+        if (*generator)
+                return 0;
+
+        if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
+
+                p = strappend("/run/systemd/", name);
+                if (!p) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+
+                r = mkdir_p(p, 0755);
+                if (r < 0) {
+                        log_error("Failed to create generator directory: %s", strerror(-r));
+                        free(p);
+                        return r;
+                }
+        } else {
+                p = join("/tmp/systemd-", name, ".XXXXXX", NULL);
+                if (!p) {
+                        log_error("Out of memory");
+                        return -ENOMEM;
+                }
+
+                if (!mkdtemp(p)) {
+                        free(p);
+                        log_error("Failed to create generator directory: %m");
+                        return -errno;
+                }
+        }
+
+        *generator = p;
+        return 0;
+}
+
+static void trim_generator_dir(Manager *m, char **generator) {
+        assert(m);
+        assert(generator);
+
+        if (!*generator)
+                return;
+
+        if (rmdir(*generator) >= 0) {
+                free(*generator);
+                *generator = NULL;
+        }
+
+        return;
+}
+
 void manager_run_generators(Manager *m) {
         DIR *d = NULL;
         const char *generator_path;
-        const char *argv[3];
+        const char *argv[5];
         mode_t u;
+        int r;
 
         assert(m);
 
         generator_path = m->running_as == MANAGER_SYSTEM ? SYSTEM_GENERATOR_PATH : USER_GENERATOR_PATH;
-        if (!(d = opendir(generator_path))) {
-
+        d = opendir(generator_path);
+        if (!d) {
                 if (errno == ENOENT)
                         return;
 
@@ -2048,79 +2126,57 @@ void manager_run_generators(Manager *m) {
                 return;
         }
 
-        if (!m->generator_unit_path) {
-                const char *p;
-                char user_path[] = "/tmp/systemd-generator-XXXXXX";
-
-                if (m->running_as == MANAGER_SYSTEM && getpid() == 1) {
-                        p = "/run/systemd/generator";
-
-                        if (mkdir_p(p, 0755) < 0) {
-                                log_error("Failed to create generator directory: %m");
-                                goto finish;
-                        }
+        r = create_generator_dir(m, &m->generator_unit_path, "generator");
+        if (r < 0)
+                goto finish;
 
-                } else {
-                        if (!(p = mkdtemp(user_path))) {
-                                log_error("Failed to create generator directory: %m");
-                                goto finish;
-                        }
-                }
+        r = create_generator_dir(m, &m->generator_unit_path_early, "generator.early");
+        if (r < 0)
+                goto finish;
 
-                if (!(m->generator_unit_path = strdup(p))) {
-                        log_error("Failed to allocate generator unit path.");
-                        goto finish;
-                }
-        }
+        r = create_generator_dir(m, &m->generator_unit_path_late, "generator.late");
+        if (r < 0)
+                goto finish;
 
         argv[0] = NULL; /* Leave this empty, execute_directory() will fill something in */
         argv[1] = m->generator_unit_path;
-        argv[2] = NULL;
+        argv[2] = m->generator_unit_path_early;
+        argv[3] = m->generator_unit_path_late;
+        argv[4] = NULL;
 
         u = umask(0022);
         execute_directory(generator_path, d, (char**) argv);
         umask(u);
 
-        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;
-
-                log_debug("Added generator unit path %s to search path.", m->generator_unit_path);
-        }
+        trim_generator_dir(m, &m->generator_unit_path);
+        trim_generator_dir(m, &m->generator_unit_path_early);
+        trim_generator_dir(m, &m->generator_unit_path_late);
 
 finish:
         if (d)
                 closedir(d);
 }
 
-void manager_undo_generators(Manager *m) {
+static void remove_generator_dir(Manager *m, char **generator) {
         assert(m);
+        assert(generator);
 
-        if (!m->generator_unit_path)
+        if (!*generator)
                 return;
 
-        strv_remove(m->lookup_paths.unit_path, m->generator_unit_path);
-        rm_rf(m->generator_unit_path, false, true, false);
+        strv_remove(m->lookup_paths.unit_path, *generator);
+        rm_rf(*generator, false, true, false);
 
-        free(m->generator_unit_path);
-        m->generator_unit_path = NULL;
+        free(*generator);
+        *generator = NULL;
+}
+
+void manager_undo_generators(Manager *m) {
+        assert(m);
+
+        remove_generator_dir(m, &m->generator_unit_path);
+        remove_generator_dir(m, &m->generator_unit_path_early);
+        remove_generator_dir(m, &m->generator_unit_path_late);
 }
 
 int manager_set_default_controllers(Manager *m, char **controllers) {
@@ -2146,18 +2202,17 @@ int manager_set_default_rlimits(Manager *m, struct rlimit **default_rlimit) {
         assert(m);
 
         for (i = 0; i < RLIMIT_NLIMITS; i++) {
-                if (default_rlimit[i]) {
-                        m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
+                if (!default_rlimit[i])
+                        continue;
 
-                        if (!m->rlimit[i])
-                                return -ENOMEM;
-                }
+                m->rlimit[i] = newdup(struct rlimit, default_rlimit[i], 1);
+                if (!m->rlimit[i])
+                        return -ENOMEM;
         }
 
         return 0;
 }
 
-
 void manager_recheck_journal(Manager *m) {
         Unit *u;
 
index 9b947c9530469b7cf6b816bb21ae860acd1dcd97..b29d0a79353e43af072579bd01b21f6e325b60a5 100644 (file)
@@ -152,6 +152,8 @@ struct Manager {
         dual_timestamp finish_timestamp;
 
         char *generator_unit_path;
+        char *generator_unit_path_early;
+        char *generator_unit_path_late;
 
         /* Data specific to the device subsystem */
         struct udev* udev;
index 51706b7a860766c804fbefe8fbff283cc1f60a96..de64afd7274dc7f4d091c1bfc40f52a1d85e88d4 100644 (file)
@@ -240,8 +240,8 @@ int main(int argc, char *argv[]) {
         int r = EXIT_SUCCESS;
         unsigned n = 0;
 
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
                 return EXIT_FAILURE;
         }
 
index 8a519fcfd90a15597013fea171776c72c79cbfca..8676a20539c5c10596920c023e0914f7a3237030 100644 (file)
@@ -498,8 +498,8 @@ finish:
 int main(int argc, char *argv[]) {
         int r;
 
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
                 return EXIT_FAILURE;
         }
 
@@ -510,8 +510,6 @@ int main(int argc, char *argv[]) {
         log_parse_environment();
         log_open();
 
-        log_set_max_level(LOG_DEBUG);
-
         umask(0022);
 
         r = parse_fstab();
index b2e4f52c3ca88ab55b0f051021c8d87d79632a60..85600263f9cce42a8ce8310bb5488473ad580e7b 100644 (file)
@@ -38,8 +38,8 @@ static int add_symlink(const char *fservice, const char *tservice) {
         assert(fservice);
         assert(tservice);
 
-        asprintf(&from, SYSTEM_DATA_UNIT_PATH "/%s", fservice);
-        asprintf(&to, "%s/getty.target.wants/%s", arg_dest, tservice);
+        from = strappend(SYSTEM_DATA_UNIT_PATH "/", fservice);
+        to = join(arg_dest,"/getty.target.wants/", tservice, NULL);
 
         if (!from || !to) {
                 log_error("Out of memory");
@@ -99,20 +99,20 @@ int main(int argc, char *argv[]) {
         char *active;
         const char *j;
 
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
                 return EXIT_FAILURE;
         }
 
+        if (argc > 1)
+                arg_dest = argv[1];
+
         log_set_target(LOG_TARGET_SAFE);
         log_parse_environment();
         log_open();
 
         umask(0022);
 
-        if (argc > 1)
-            arg_dest = argv[1];
-
         if (detect_container(NULL) > 0) {
                 log_debug("Automatically adding console shell.");
 
index 1464c8e49749876ec1fd309e9588bf60984148fe..38168cc01f74af7b5d82e8b42a31a907d0217915 100644 (file)
@@ -66,7 +66,6 @@ static int add_symlink(const char *service, const char *where) {
         }
 
 finish:
-
         free(from);
         free(to);
 
@@ -83,20 +82,21 @@ static bool file_is_executable(const char *f) {
 }
 
 int main(int argc, char *argv[]) {
-
         int r = EXIT_SUCCESS;
 
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
                 return EXIT_FAILURE;
         }
 
+        if (argc > 1)
+                arg_dest = argv[1];
+
         log_set_target(LOG_TARGET_SAFE);
         log_parse_environment();
         log_open();
 
-        if (argc > 1)
-                arg_dest = argv[1];
+        umask(0022);
 
         if (file_is_executable(SCRIPT_PATH_START)) {
                 log_debug("Automatically adding rc-local.service.");
index d6644e580fbf16cc904bfe92ec4837a7a347d389..7e4f666952a9debc438c36e02eed1ac4b09be35c 100644 (file)
@@ -60,7 +60,8 @@ static int lookup_paths_init_from_scope(LookupPaths *paths, UnitFileScope scope)
 
         return lookup_paths_init(paths,
                                  scope == UNIT_FILE_SYSTEM ? MANAGER_SYSTEM : MANAGER_USER,
-                                 scope == UNIT_FILE_USER);
+                                 scope == UNIT_FILE_USER,
+                                 NULL, NULL, NULL);
 }
 
 static int get_config_path(UnitFileScope scope, bool runtime, const char *root_dir, char **ret) {
index 41ebc7f5b3e38c7eafe96437d262cb6067df2a65..32ddb388656637da8e0653d07910ec0854420c8e 100644 (file)
@@ -34,7 +34,8 @@
 int user_config_home(char **config_home) {
         const char *e;
 
-        if ((e = getenv("XDG_CONFIG_HOME"))) {
+        e = getenv("XDG_CONFIG_HOME");
+        if (e) {
                 if (asprintf(config_home, "%s/systemd/user", e) < 0)
                         return -ENOMEM;
 
@@ -42,7 +43,8 @@ int user_config_home(char **config_home) {
         } else {
                 const char *home;
 
-                if ((home = getenv("HOME"))) {
+                home = getenv("HOME");
+                if (home) {
                         if (asprintf(config_home, "%s/.config/systemd/user", home) < 0)
                                 return -ENOMEM;
 
@@ -53,7 +55,11 @@ int user_config_home(char **config_home) {
         return 0;
 }
 
-static char** user_dirs(void) {
+static char** user_dirs(
+                const char *generator,
+                const char *generator_early,
+                const char *generator_late) {
+
         const char * const config_unit_paths[] = {
                 USER_CONFIG_UNIT_PATH,
                 "/etc/systemd/user",
@@ -89,15 +95,19 @@ static char** user_dirs(void) {
 
         home = getenv("HOME");
 
-        if ((e = getenv("XDG_CONFIG_DIRS")))
-                if (!(config_dirs = strv_split(e, ":")))
+        e = getenv("XDG_CONFIG_DIRS");
+        if (e) {
+                config_dirs = strv_split(e, ":");
+                if (!config_dirs)
                         goto fail;
+        }
 
         /* We don't treat /etc/xdg/systemd here as the spec
          * suggests because we assume that that is a link to
          * /etc/systemd/ anyway. */
 
-        if ((e = getenv("XDG_DATA_HOME"))) {
+        e = getenv("XDG_DATA_HOME");
+        if (e) {
                 if (asprintf(&data_home, "%s/systemd/user", e) < 0)
                         goto fail;
 
@@ -116,57 +126,87 @@ static char** user_dirs(void) {
                 (void) symlink("../../../.config/systemd/user", data_home);
         }
 
-        if ((e = getenv("XDG_DATA_DIRS")))
+        e = getenv("XDG_DATA_DIRS");
+        if (e)
                 data_dirs = strv_split(e, ":");
         else
                 data_dirs = strv_new("/usr/local/share",
                                      "/usr/share",
                                      NULL);
-
         if (!data_dirs)
                 goto fail;
 
         /* Now merge everything we found. */
+        if (generator_early) {
+                t = strv_append(r, generator_early);
+                if (!t)
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
         if (config_home) {
-                if (!(t = strv_append(r, config_home)))
+                t = strv_append(r, config_home);
+                if (!t)
                         goto fail;
                 strv_free(r);
                 r = t;
         }
 
         if (!strv_isempty(config_dirs)) {
-                if (!(t = strv_merge_concat(r, config_dirs, "/systemd/user")))
+                t = strv_merge_concat(r, config_dirs, "/systemd/user");
+                if (!t)
                         goto finish;
                 strv_free(r);
                 r = t;
         }
 
-        if (!(t = strv_merge(r, (char**) config_unit_paths)))
+        t = strv_merge(r, (char**) config_unit_paths);
+        if (!t)
                 goto fail;
         strv_free(r);
         r = t;
 
+        if (generator) {
+                t = strv_append(r, generator);
+                if (!t)
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
         if (data_home) {
-                if (!(t = strv_append(r, data_home)))
+                t = strv_append(r, data_home);
+                if (!t)
                         goto fail;
                 strv_free(r);
                 r = t;
         }
 
         if (!strv_isempty(data_dirs)) {
-                if (!(t = strv_merge_concat(r, data_dirs, "/systemd/user")))
+                t = strv_merge_concat(r, data_dirs, "/systemd/user");
+                if (!t)
                         goto fail;
                 strv_free(r);
                 r = t;
         }
 
-        if (!(t = strv_merge(r, (char**) data_unit_paths)))
+        t = strv_merge(r, (char**) data_unit_paths);
+        if (!t)
                 goto fail;
         strv_free(r);
         r = t;
 
+        if (generator_late) {
+                t = strv_append(r, generator_late);
+                if (!t)
+                        goto fail;
+                strv_free(r);
+                r = t;
+        }
+
         if (!path_strv_make_absolute_cwd(r))
-            goto fail;
+                goto fail;
 
 finish:
         free(config_home);
@@ -182,7 +222,14 @@ fail:
         goto finish;
 }
 
-int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal) {
+int lookup_paths_init(
+                LookupPaths *p,
+                ManagerRunningAs running_as,
+                bool personal,
+                const char *generator,
+                const char *generator_early,
+                const char *generator_late) {
+
         const char *e;
         char *t;
 
@@ -190,64 +237,83 @@ int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal
 
         /* First priority is whatever has been passed to us via env
          * vars */
-        if ((e = getenv("SYSTEMD_UNIT_PATH")))
-                if (!(p->unit_path = path_split_and_make_absolute(e)))
+        e = getenv("SYSTEMD_UNIT_PATH");
+        if (e) {
+                p->unit_path = path_split_and_make_absolute(e);
+                if (!p->unit_path)
                         return -ENOMEM;
+        } else
+                p->unit_path = NULL;
 
         if (strv_isempty(p->unit_path)) {
-
                 /* Nothing is set, so let's figure something out. */
                 strv_free(p->unit_path);
 
+                /* For the user units we include share/ in the search
+                 * path in order to comply with the XDG basedir
+                 * spec. For the system stuff we avoid such
+                 * nonsense. OTOH we include /lib in the search path
+                 * for the system stuff but avoid it for user
+                 * stuff. */
+
                 if (running_as == MANAGER_USER) {
 
                         if (personal)
-                                p->unit_path = user_dirs();
+                                p->unit_path = user_dirs(generator, generator_early, generator_late);
                         else
                                 p->unit_path = strv_new(
                                                 /* If you modify this you also want to modify
                                                  * systemduserunitpath= in systemd.pc.in, and
                                                  * the arrays in user_dirs() above! */
+                                                STRV_IFNOTNULL(generator_early),
                                                 USER_CONFIG_UNIT_PATH,
                                                 "/etc/systemd/user",
                                                 "/run/systemd/user",
+                                                STRV_IFNOTNULL(generator),
                                                 "/usr/local/lib/systemd/user",
                                                 "/usr/local/share/systemd/user",
                                                 USER_DATA_UNIT_PATH,
                                                 "/usr/lib/systemd/user",
                                                 "/usr/share/systemd/user",
+                                                STRV_IFNOTNULL(generator_late),
                                                 NULL);
 
                         if (!p->unit_path)
                                 return -ENOMEM;
 
-                } else
-                        if (!(p->unit_path = strv_new(
-                                              /* If you modify this you also want to modify
-                                               * systemdsystemunitpath= in systemd.pc.in! */
-                                              SYSTEM_CONFIG_UNIT_PATH,
-                                              "/etc/systemd/system",
-                                              "/run/systemd/system",
-                                              "/usr/local/lib/systemd/system",
-                                              SYSTEM_DATA_UNIT_PATH,
-                                              "/usr/lib/systemd/system",
+                } else {
+                        p->unit_path = strv_new(
+                                        /* If you modify this you also want to modify
+                                         * systemdsystemunitpath= in systemd.pc.in! */
+                                        STRV_IFNOTNULL(generator_early),
+                                        SYSTEM_CONFIG_UNIT_PATH,
+                                        "/etc/systemd/system",
+                                        "/run/systemd/system",
+                                        STRV_IFNOTNULL(generator),
+                                        "/usr/local/lib/systemd/system",
+                                        SYSTEM_DATA_UNIT_PATH,
+                                        "/usr/lib/systemd/system",
 #ifdef HAVE_SPLIT_USR
-                                              "/lib/systemd/system",
+                                        "/lib/systemd/system",
 #endif
-                                              NULL)))
+                                        STRV_IFNOTNULL(generator_late),
+                                        NULL);
+
+                        if (!p->unit_path)
                                 return -ENOMEM;
+                }
         }
 
-        if (p->unit_path)
-                if (!path_strv_canonicalize(p->unit_path))
-                        return -ENOMEM;
+        if (!path_strv_canonicalize(p->unit_path))
+                return -ENOMEM;
 
         strv_uniq(p->unit_path);
         path_strv_remove_empty(p->unit_path);
 
         if (!strv_isempty(p->unit_path)) {
 
-                if (!(t = strv_join(p->unit_path, "\n\t")))
+                t = strv_join(p->unit_path, "\n\t");
+                if (!t)
                         return -ENOMEM;
                 log_debug("Looking for unit files in:\n\t%s", t);
                 free(t);
@@ -261,51 +327,58 @@ int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal
 #ifdef HAVE_SYSV_COMPAT
                 /* /etc/init.d/ compatibility does not matter to users */
 
-                if ((e = getenv("SYSTEMD_SYSVINIT_PATH")))
-                        if (!(p->sysvinit_path = path_split_and_make_absolute(e)))
+                e = getenv("SYSTEMD_SYSVINIT_PATH");
+                if (e) {
+                        p->sysvinit_path = path_split_and_make_absolute(e);
+                        if (!p->sysvinit_path)
                                 return -ENOMEM;
+                } else
+                        p->sysvinit_path = NULL;
 
                 if (strv_isempty(p->sysvinit_path)) {
                         strv_free(p->sysvinit_path);
 
-                        if (!(p->sysvinit_path = strv_new(
-                                              SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
-                                              NULL)))
+                        p->sysvinit_path = strv_new(
+                                        SYSTEM_SYSVINIT_PATH,     /* /etc/init.d/ */
+                                        NULL);
+                        if (!p->sysvinit_path)
                                 return -ENOMEM;
                 }
 
-                if ((e = getenv("SYSTEMD_SYSVRCND_PATH")))
-                        if (!(p->sysvrcnd_path = path_split_and_make_absolute(e)))
+                e = getenv("SYSTEMD_SYSVRCND_PATH");
+                if (e) {
+                        p->sysvrcnd_path = path_split_and_make_absolute(e);
+                        if (!p->sysvrcnd_path)
                                 return -ENOMEM;
+                } else
+                        p->sysvrcnd_path = NULL;
 
                 if (strv_isempty(p->sysvrcnd_path)) {
                         strv_free(p->sysvrcnd_path);
 
-                        if (!(p->sysvrcnd_path = strv_new(
-                                              SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
-                                              NULL)))
+                        p->sysvrcnd_path = strv_new(
+                                        SYSTEM_SYSVRCND_PATH,     /* /etc/rcN.d/ */
+                                        NULL);
+                        if (!p->sysvrcnd_path)
                                 return -ENOMEM;
                 }
 
-                if (p->sysvinit_path)
-                        if (!path_strv_canonicalize(p->sysvinit_path))
-                                return -ENOMEM;
+                if (!path_strv_canonicalize(p->sysvinit_path))
+                        return -ENOMEM;
 
-                if (p->sysvrcnd_path)
-                        if (!path_strv_canonicalize(p->sysvrcnd_path))
-                                return -ENOMEM;
+                if (!path_strv_canonicalize(p->sysvrcnd_path))
+                        return -ENOMEM;
 
                 strv_uniq(p->sysvinit_path);
                 strv_uniq(p->sysvrcnd_path);
-
                 path_strv_remove_empty(p->sysvinit_path);
                 path_strv_remove_empty(p->sysvrcnd_path);
 
                 if (!strv_isempty(p->sysvinit_path)) {
 
-                        if (!(t = strv_join(p->sysvinit_path, "\n\t")))
+                        t = strv_join(p->sysvinit_path, "\n\t");
+                        if (!t)
                                 return -ENOMEM;
-
                         log_debug("Looking for SysV init scripts in:\n\t%s", t);
                         free(t);
                 } else {
@@ -316,7 +389,8 @@ int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal
 
                 if (!strv_isempty(p->sysvrcnd_path)) {
 
-                        if (!(t = strv_join(p->sysvrcnd_path, "\n\t")))
+                        t = strv_join(p->sysvrcnd_path, "\n\t");
+                        if (!t)
                                 return -ENOMEM;
 
                         log_debug("Looking for SysV rcN.d links in:\n\t%s", t);
index e8a5a77a7b3a3c81e0600fe58e10c4a648472e4d..96c49c2400e523e6d37237da1cdf9a9487b08a72 100644 (file)
@@ -34,7 +34,7 @@ typedef struct LookupPaths {
 
 int user_config_home(char **config_home);
 
-int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal);
+int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as, bool personal, const char *generator, const char *generator_early, const char *generator_late);
 void lookup_paths_free(LookupPaths *p);
 
 #endif
index 18de4f8391f30fd45848141a88c9753b95390d92..c8d856344c18987b7c2dc6360cc4417b0820fd8c 100644 (file)
@@ -106,28 +106,44 @@ char **strv_new_ap(const char *x, va_list ap) {
         unsigned n = 0, i = 0;
         va_list aq;
 
+        /* As a special trick we ignore all listed strings that equal
+         * (const char*) -1. This is supposed to be used with the
+         * STRV_IFNOTNULL() macro to include possibly NULL strings in
+         * the string list. */
+
         if (x) {
-                n = 1;
+                n = x == (const char*) -1 ? 0 : 1;
 
                 va_copy(aq, ap);
-                while (va_arg(aq, const char*))
+                while ((s = va_arg(aq, const char*))) {
+                        if (s == (const char*) -1)
+                                continue;
+
                         n++;
+                }
+
                 va_end(aq);
         }
 
-        if (!(a = new(char*, n+1)))
+        a = new(char*, n+1);
+        if (!a)
                 return NULL;
 
         if (x) {
-                if (!(a[i] = strdup(x))) {
-                        free(a);
-                        return NULL;
+                if (x != (const char*) -1) {
+                        a[i] = strdup(x);
+                        if (!a[i])
+                                goto fail;
+                        i++;
                 }
 
-                i++;
-
                 while ((s = va_arg(ap, const char*))) {
-                        if (!(a[i] = strdup(s)))
+
+                        if (s == (const char*) -1)
+                                continue;
+
+                        a[i] = strdup(s);
+                        if (!a[i])
                                 goto fail;
 
                         i++;
@@ -169,25 +185,27 @@ char **strv_merge(char **a, char **b) {
         if (!b)
                 return strv_copy(a);
 
-        if (!(r = new(char*, strv_length(a)+strv_length(b)+1)))
+        r = new(char*, strv_length(a) + strv_length(b) + 1);
+        if (!r)
                 return NULL;
 
-        for (k = r; *a; k++, a++)
-                if (!(*k = strdup(*a)))
+        for (k = r; *a; k++, a++) {
+                *k = strdup(*a);
+                if (!*k)
                         goto fail;
-        for (; *b; k++, b++)
-                if (!(*k = strdup(*b)))
+        }
+
+        for (; *b; k++, b++) {
+                *k = strdup(*b);
+                if (!*k)
                         goto fail;
+        }
 
         *k = NULL;
         return r;
 
 fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
+        strv_free(r);
         return NULL;
 }
 
@@ -221,11 +239,7 @@ char **strv_merge_concat(char **a, char **b, const char *suffix) {
         return r;
 
 fail:
-        for (k--; k >= r; k--)
-                free(*k);
-
-        free(r);
-
+        strv_free(r);
         return NULL;
 
 }
index afb31f385fffbb4ef68e956de953da43ec136010..635e92b728ed551142fbf0ba45a2cec502b3bd26 100644 (file)
@@ -47,6 +47,10 @@ char **strv_uniq(char **l);
 char **strv_new(const char *x, ...) _sentinel_ _malloc_;
 char **strv_new_ap(const char *x, va_list ap) _malloc_;
 
+static inline const char* STRV_IFNOTNULL(const char *x) {
+        return x ? x : (const char *) -1;
+}
+
 static inline bool strv_isempty(char **l) {
         return !l || !*l;
 }
index f4e8dafebd9bdb3986e76c7f4dccfb3ebff82ead..abda5a0190e836892a2f995c5f2776019d67f4ec 100644 (file)
@@ -66,13 +66,13 @@ static int generate_symlink(void) {
 int main(int argc, char *argv[]) {
         int r;
 
-        if (argc > 2) {
-                log_error("This program takes one or no arguments.");
+        if (argc > 1 && argc != 4) {
+                log_error("This program takes three or no arguments.");
                 return EXIT_FAILURE;
         }
 
         if (argc > 1)
-                arg_dest = argv[1];
+                arg_dest = argv[2];
 
         log_set_target(LOG_TARGET_SAFE);
         log_parse_environment();
index 03c2fd2d62672a61297d43d16cec6c3b232741a6..66f4113eb223c91c7e05848778f56245f3e92ba7 100644 (file)
@@ -3697,12 +3697,11 @@ static int enable_sysv_units(char **args) {
          * afterwards only the native units remain */
 
         zero(paths);
-        r = lookup_paths_init(&paths, MANAGER_SYSTEM, false);
+        r = lookup_paths_init(&paths, MANAGER_SYSTEM, false, NULL, NULL, NULL);
         if (r < 0)
                 return r;
 
         r = 0;
-
         for (f = 1; args[f]; f++) {
                 const char *name;
                 char *p;