]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
analyze: split out "verify" verb into own .c/.h file
authorLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2022 13:39:16 +0000 (14:39 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 21 Feb 2022 16:22:23 +0000 (17:22 +0100)
This renames the old analyze-verify.[ch] pair →
analyze-verify-util.[ch], because it's used by the test logic as well,
and by keeping it separate from the verify verb logic we don't have to
import the arg_xyz variables.

src/analyze/analyze-condition.c
src/analyze/analyze-verify-util.c [new file with mode: 0644]
src/analyze/analyze-verify-util.h [new file with mode: 0644]
src/analyze/analyze-verify.c
src/analyze/analyze-verify.h
src/analyze/analyze.c
src/analyze/analyze.h
src/analyze/meson.build
src/analyze/test-verify.c

index f57bb27b9a8192679a392ec73f92a378e5f47766..e8b0fa978bc8d40a3fdd6fc4303ef77e2562be30 100644 (file)
@@ -3,7 +3,7 @@
 #include <stdlib.h>
 
 #include "analyze-condition.h"
-#include "analyze-verify.h"
+#include "analyze-verify-util.h"
 #include "condition.h"
 #include "conf-parser.h"
 #include "load-fragment.h"
diff --git a/src/analyze/analyze-verify-util.c b/src/analyze/analyze-verify-util.c
new file mode 100644 (file)
index 0000000..6c28cc0
--- /dev/null
@@ -0,0 +1,351 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include <stdlib.h>
+
+#include "all-units.h"
+#include "alloc-util.h"
+#include "analyze-verify-util.h"
+#include "bus-error.h"
+#include "bus-util.h"
+#include "log.h"
+#include "manager.h"
+#include "pager.h"
+#include "path-util.h"
+#include "string-table.h"
+#include "strv.h"
+#include "unit-name.h"
+#include "unit-serialize.h"
+
+static void log_syntax_callback(const char *unit, int level, void *userdata) {
+        Set **s = userdata;
+        int r;
+
+        assert(userdata);
+        assert(unit);
+
+        if (level > LOG_WARNING)
+                return;
+
+        if (*s == POINTER_MAX)
+                return;
+
+        r = set_put_strdup(s, unit);
+        if (r < 0) {
+                set_free_free(*s);
+                *s = POINTER_MAX;
+        }
+}
+
+int verify_prepare_filename(const char *filename, char **ret) {
+        int r;
+        const char *name;
+        _cleanup_free_ char *abspath = NULL;
+        _cleanup_free_ char *dir = NULL;
+        _cleanup_free_ char *with_instance = NULL;
+        char *c;
+
+        assert(filename);
+        assert(ret);
+
+        r = path_make_absolute_cwd(filename, &abspath);
+        if (r < 0)
+                return r;
+
+        name = basename(abspath);
+        if (!unit_name_is_valid(name, UNIT_NAME_ANY))
+                return -EINVAL;
+
+        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
+                r = unit_name_replace_instance(name, "i", &with_instance);
+                if (r < 0)
+                        return r;
+        }
+
+        dir = dirname_malloc(abspath);
+        if (!dir)
+                return -ENOMEM;
+
+        c = path_join(dir, with_instance ?: name);
+        if (!c)
+                return -ENOMEM;
+
+        *ret = c;
+        return 0;
+}
+
+int verify_generate_path(char **var, char **filenames) {
+        const char *old;
+        char **filename;
+
+        _cleanup_strv_free_ char **ans = NULL;
+        int r;
+
+        STRV_FOREACH(filename, filenames) {
+                char *t;
+
+                t = dirname_malloc(*filename);
+                if (!t)
+                        return -ENOMEM;
+
+                r = strv_consume(&ans, t);
+                if (r < 0)
+                        return r;
+        }
+
+        assert_se(strv_uniq(ans));
+
+        /* First, prepend our directories. Second, if some path was specified, use that, and
+         * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
+         * Treat explicit empty path to mean that nothing should be appended.
+         */
+        old = getenv("SYSTEMD_UNIT_PATH");
+        if (!streq_ptr(old, "")) {
+                if (!old)
+                        old = ":";
+
+                r = strv_extend(&ans, old);
+                if (r < 0)
+                        return r;
+        }
+
+        *var = strv_join(ans, ":");
+        if (!*var)
+                return -ENOMEM;
+
+        return 0;
+}
+
+static int verify_socket(Unit *u) {
+        Unit *service;
+        int r;
+
+        assert(u);
+
+        if (u->type != UNIT_SOCKET)
+                return 0;
+
+        r = socket_load_service_unit(SOCKET(u), -1, &service);
+        if (r < 0)
+                return log_unit_error_errno(u, r, "service unit for the socket cannot be loaded: %m");
+
+        if (service->load_state != UNIT_LOADED)
+                return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT),
+                                            "service %s not loaded, socket cannot be started.", service->id);
+
+        log_unit_debug(u, "using service unit %s.", service->id);
+        return 0;
+}
+
+int verify_executable(Unit *u, const ExecCommand *exec, const char *root) {
+        int r;
+
+        if (!exec)
+                return 0;
+
+        if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
+                return 0;
+
+        r = find_executable_full(exec->path, root, NULL, false, NULL, NULL);
+        if (r < 0)
+                return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
+
+        return 0;
+}
+
+static int verify_executables(Unit *u, const char *root) {
+        ExecCommand *exec;
+        int r = 0, k;
+        unsigned i;
+
+        assert(u);
+
+        exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
+                u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
+                u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
+        k = verify_executable(u, exec, root);
+        if (k < 0 && r == 0)
+                r = k;
+
+        if (u->type == UNIT_SERVICE)
+                for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
+                        k = verify_executable(u, SERVICE(u)->exec_command[i], root);
+                        if (k < 0 && r == 0)
+                                r = k;
+                }
+
+        if (u->type == UNIT_SOCKET)
+                for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
+                        k = verify_executable(u, SOCKET(u)->exec_command[i], root);
+                        if (k < 0 && r == 0)
+                                r = k;
+                }
+
+        return r;
+}
+
+static int verify_documentation(Unit *u, bool check_man) {
+        char **p;
+        int r = 0, k;
+
+        STRV_FOREACH(p, u->documentation) {
+                log_unit_debug(u, "Found documentation item: %s", *p);
+
+                if (check_man && startswith(*p, "man:")) {
+                        k = show_man_page(*p + 4, true);
+                        if (k != 0) {
+                                if (k < 0)
+                                        log_unit_error_errno(u, k, "Can't show %s: %m", *p + 4);
+                                else {
+                                        log_unit_error(u, "Command 'man %s' failed with code %d", *p + 4, k);
+                                        k = -ENOEXEC;
+                                }
+                                if (r == 0)
+                                        r = k;
+                        }
+                }
+        }
+
+        /* Check remote URLs? */
+
+        return r;
+}
+
+static int verify_unit(Unit *u, bool check_man, const char *root) {
+        _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
+        int r, k;
+
+        assert(u);
+
+        if (DEBUG_LOGGING)
+                unit_dump(u, stdout, "\t");
+
+        log_unit_debug(u, "Creating %s/start job", u->id);
+        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
+        if (r < 0)
+                log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
+
+        k = verify_socket(u);
+        if (k < 0 && r == 0)
+                r = k;
+
+        k = verify_executables(u, root);
+        if (k < 0 && r == 0)
+                r = k;
+
+        k = verify_documentation(u, check_man);
+        if (k < 0 && r == 0)
+                r = k;
+
+        return r;
+}
+
+static void set_destroy_ignore_pointer_max(Set** s) {
+        if (*s == POINTER_MAX)
+                return;
+        set_free_free(*s);
+}
+
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
+        const ManagerTestRunFlags flags =
+                MANAGER_TEST_RUN_MINIMAL |
+                MANAGER_TEST_RUN_ENV_GENERATORS |
+                (recursive_errors == RECURSIVE_ERRORS_NO) * MANAGER_TEST_RUN_IGNORE_DEPENDENCIES |
+                run_generators * MANAGER_TEST_RUN_GENERATORS;
+
+        _cleanup_(manager_freep) Manager *m = NULL;
+        _cleanup_(set_destroy_ignore_pointer_max) Set *s = NULL;
+        _unused_ _cleanup_(clear_log_syntax_callback) dummy_t dummy;
+        Unit *units[strv_length(filenames)];
+        _cleanup_free_ char *var = NULL;
+        int r, k, i, count = 0;
+        char **filename;
+
+        if (strv_isempty(filenames))
+                return 0;
+
+        /* Allow systemd-analyze to hook in a callback function so that it can get
+         * all the required log data from the function itself without having to rely
+         * on a global set variable for the same */
+        set_log_syntax_callback(log_syntax_callback, &s);
+
+        /* set the path */
+        r = verify_generate_path(&var, filenames);
+        if (r < 0)
+                return log_error_errno(r, "Failed to generate unit load path: %m");
+
+        assert_se(set_unit_path(var) >= 0);
+
+        r = manager_new(scope, flags, &m);
+        if (r < 0)
+                return log_error_errno(r, "Failed to initialize manager: %m");
+
+        log_debug("Starting manager...");
+
+        r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, root);
+        if (r < 0)
+                return r;
+
+        manager_clear_jobs(m);
+
+        log_debug("Loading remaining units from the command line...");
+
+        STRV_FOREACH(filename, filenames) {
+                _cleanup_free_ char *prepared = NULL;
+
+                log_debug("Handling %s...", *filename);
+
+                k = verify_prepare_filename(*filename, &prepared);
+                if (k < 0) {
+                        log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
+                        if (r == 0)
+                                r = k;
+                        continue;
+                }
+
+                k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
+                if (k < 0) {
+                        if (r == 0)
+                                r = k;
+                        continue;
+                }
+
+                count++;
+        }
+
+        for (i = 0; i < count; i++) {
+                k = verify_unit(units[i], check_man, root);
+                if (k < 0 && r == 0)
+                        r = k;
+        }
+
+        if (s == POINTER_MAX)
+                return log_oom();
+
+        if (set_isempty(s) || r != 0)
+                return r;
+
+        /* If all previous verifications succeeded, then either the recursive parsing of all the
+         * associated dependencies with RECURSIVE_ERRORS_YES or the parsing of the specified unit file
+         * with RECURSIVE_ERRORS_NO must have yielded a syntax warning and hence, a non-empty set. */
+        if (IN_SET(recursive_errors, RECURSIVE_ERRORS_YES, RECURSIVE_ERRORS_NO))
+                return -ENOTRECOVERABLE;
+
+        /* If all previous verifications succeeded, then the non-empty set could have resulted from
+         * a syntax warning encountered during the recursive parsing of the specified unit file and
+         * its direct dependencies. Hence, search for any of the filenames in the set and if found,
+         * return a non-zero process exit status. */
+        if (recursive_errors == RECURSIVE_ERRORS_ONE)
+                STRV_FOREACH(filename, filenames)
+                        if (set_contains(s, basename(*filename)))
+                                return -ENOTRECOVERABLE;
+
+        return 0;
+}
+
+static const char* const recursive_errors_table[_RECURSIVE_ERRORS_MAX] = {
+        [RECURSIVE_ERRORS_NO]  = "no",
+        [RECURSIVE_ERRORS_YES] = "yes",
+        [RECURSIVE_ERRORS_ONE] = "one",
+};
+
+DEFINE_STRING_TABLE_LOOKUP(recursive_errors, RecursiveErrors);
diff --git a/src/analyze/analyze-verify-util.h b/src/analyze/analyze-verify-util.h
new file mode 100644 (file)
index 0000000..47b78a8
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+#pragma once
+
+#include <stdbool.h>
+
+#include "execute.h"
+#include "path-lookup.h"
+
+typedef enum RecursiveErrors {
+        RECURSIVE_ERRORS_YES,               /* Look for errors in all associated units */
+        RECURSIVE_ERRORS_NO,                /* Don't look for errors in any but the selected unit */
+        RECURSIVE_ERRORS_ONE,               /* Look for errors in the selected unit and its direct dependencies */
+        _RECURSIVE_ERRORS_MAX,
+        _RECURSIVE_ERRORS_INVALID = -EINVAL,
+} RecursiveErrors;
+
+int verify_generate_path(char **var, char **filenames);
+int verify_prepare_filename(const char *filename, char **ret);
+int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
+int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
+
+const char* recursive_errors_to_string(RecursiveErrors i) _const_;
+RecursiveErrors recursive_errors_from_string(const char *s) _pure_;
index 943a1f27de9cd1798e7555f1fa4eb2951012b1bd..05fd8a6336f3024f74788ee9152f33a8d4c8f15e 100644 (file)
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 
-#include <stdlib.h>
-
-#include "alloc-util.h"
-#include "all-units.h"
+#include "analyze.h"
 #include "analyze-verify.h"
-#include "bus-error.h"
-#include "bus-util.h"
-#include "log.h"
-#include "manager.h"
-#include "pager.h"
-#include "path-util.h"
-#include "string-table.h"
-#include "strv.h"
-#include "unit-name.h"
-#include "unit-serialize.h"
-
-static void log_syntax_callback(const char *unit, int level, void *userdata) {
-        Set **s = userdata;
-        int r;
-
-        assert(userdata);
-        assert(unit);
+#include "analyze-verify-util.h"
+#include "copy.h"
+#include "rm-rf.h"
+#include "tmpfile-util.h"
 
-        if (level > LOG_WARNING)
-                return;
-
-        if (*s == POINTER_MAX)
-                return;
-
-        r = set_put_strdup(s, unit);
-        if (r < 0) {
-                set_free_free(*s);
-                *s = POINTER_MAX;
-        }
-}
-
-int verify_prepare_filename(const char *filename, char **ret) {
+static int process_aliases(char *argv[], char *tempdir, char ***ret) {
+        _cleanup_strv_free_ char **filenames = NULL;
+        char **filename;
         int r;
-        const char *name;
-        _cleanup_free_ char *abspath = NULL;
-        _cleanup_free_ char *dir = NULL;
-        _cleanup_free_ char *with_instance = NULL;
-        char *c;
 
-        assert(filename);
+        assert(argv);
+        assert(tempdir);
         assert(ret);
 
-        r = path_make_absolute_cwd(filename, &abspath);
-        if (r < 0)
-                return r;
-
-        name = basename(abspath);
-        if (!unit_name_is_valid(name, UNIT_NAME_ANY))
-                return -EINVAL;
+        STRV_FOREACH(filename, strv_skip(argv, 1)) {
+                _cleanup_free_ char *src = NULL, *dst = NULL, *base = NULL;
+                const char *parse_arg;
 
-        if (unit_name_is_valid(name, UNIT_NAME_TEMPLATE)) {
-                r = unit_name_replace_instance(name, "i", &with_instance);
+                parse_arg = *filename;
+                r = extract_first_word(&parse_arg, &src, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_RETAIN_ESCAPE);
                 if (r < 0)
                         return r;
-        }
 
-        dir = dirname_malloc(abspath);
-        if (!dir)
-                return -ENOMEM;
+                if (!parse_arg) {
+                        r = strv_consume(&filenames, TAKE_PTR(src));
+                        if (r < 0)
+                                return r;
 
-        c = path_join(dir, with_instance ?: name);
-        if (!c)
-                return -ENOMEM;
-
-        *ret = c;
-        return 0;
-}
-
-int verify_generate_path(char **var, char **filenames) {
-        const char *old;
-        char **filename;
-
-        _cleanup_strv_free_ char **ans = NULL;
-        int r;
+                        continue;
+                }
 
-        STRV_FOREACH(filename, filenames) {
-                char *t;
+                r = path_extract_filename(parse_arg, &base);
+                if (r < 0)
+                        return r;
 
-                t = dirname_malloc(*filename);
-                if (!t)
+                dst = path_join(tempdir, base);
+                if (!dst)
                         return -ENOMEM;
 
-                r = strv_consume(&ans, t);
+                r = copy_file(src, dst, 0, 0644, 0, 0, COPY_REFLINK);
                 if (r < 0)
                         return r;
-        }
-
-        assert_se(strv_uniq(ans));
 
-        /* First, prepend our directories. Second, if some path was specified, use that, and
-         * otherwise use the defaults. Any duplicates will be filtered out in path-lookup.c.
-         * Treat explicit empty path to mean that nothing should be appended.
-         */
-        old = getenv("SYSTEMD_UNIT_PATH");
-        if (!streq_ptr(old, "")) {
-                if (!old)
-                        old = ":";
-
-                r = strv_extend(&ans, old);
+                r = strv_consume(&filenames, TAKE_PTR(dst));
                 if (r < 0)
                         return r;
         }
 
-        *var = strv_join(ans, ":");
-        if (!*var)
-                return -ENOMEM;
-
+        *ret = TAKE_PTR(filenames);
         return 0;
 }
 
-static int verify_socket(Unit *u) {
-        Unit *service;
+int do_verify(int argc, char *argv[], void *userdata) {
+        _cleanup_strv_free_ char **filenames = NULL;
+        _cleanup_(rm_rf_physical_and_freep) char *tempdir = NULL;
         int r;
 
-        assert(u);
-
-        if (u->type != UNIT_SOCKET)
-                return 0;
-
-        r = socket_load_service_unit(SOCKET(u), -1, &service);
-        if (r < 0)
-                return log_unit_error_errno(u, r, "service unit for the socket cannot be loaded: %m");
-
-        if (service->load_state != UNIT_LOADED)
-                return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT),
-                                            "service %s not loaded, socket cannot be started.", service->id);
-
-        log_unit_debug(u, "using service unit %s.", service->id);
-        return 0;
-}
-
-int verify_executable(Unit *u, const ExecCommand *exec, const char *root) {
-        int r;
-
-        if (!exec)
-                return 0;
-
-        if (exec->flags & EXEC_COMMAND_IGNORE_FAILURE)
-                return 0;
-
-        r = find_executable_full(exec->path, root, NULL, false, NULL, NULL);
-        if (r < 0)
-                return log_unit_error_errno(u, r, "Command %s is not executable: %m", exec->path);
-
-        return 0;
-}
-
-static int verify_executables(Unit *u, const char *root) {
-        ExecCommand *exec;
-        int r = 0, k;
-        unsigned i;
-
-        assert(u);
-
-        exec =  u->type == UNIT_SOCKET ? SOCKET(u)->control_command :
-                u->type == UNIT_MOUNT ? MOUNT(u)->control_command :
-                u->type == UNIT_SWAP ? SWAP(u)->control_command : NULL;
-        k = verify_executable(u, exec, root);
-        if (k < 0 && r == 0)
-                r = k;
-
-        if (u->type == UNIT_SERVICE)
-                for (i = 0; i < ELEMENTSOF(SERVICE(u)->exec_command); i++) {
-                        k = verify_executable(u, SERVICE(u)->exec_command[i], root);
-                        if (k < 0 && r == 0)
-                                r = k;
-                }
-
-        if (u->type == UNIT_SOCKET)
-                for (i = 0; i < ELEMENTSOF(SOCKET(u)->exec_command); i++) {
-                        k = verify_executable(u, SOCKET(u)->exec_command[i], root);
-                        if (k < 0 && r == 0)
-                                r = k;
-                }
-
-        return r;
-}
-
-static int verify_documentation(Unit *u, bool check_man) {
-        char **p;
-        int r = 0, k;
-
-        STRV_FOREACH(p, u->documentation) {
-                log_unit_debug(u, "Found documentation item: %s", *p);
-
-                if (check_man && startswith(*p, "man:")) {
-                        k = show_man_page(*p + 4, true);
-                        if (k != 0) {
-                                if (k < 0)
-                                        log_unit_error_errno(u, k, "Can't show %s: %m", *p + 4);
-                                else {
-                                        log_unit_error(u, "Command 'man %s' failed with code %d", *p + 4, k);
-                                        k = -ENOEXEC;
-                                }
-                                if (r == 0)
-                                        r = k;
-                        }
-                }
-        }
-
-        /* Check remote URLs? */
-
-        return r;
-}
-
-static int verify_unit(Unit *u, bool check_man, const char *root) {
-        _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL;
-        int r, k;
-
-        assert(u);
-
-        if (DEBUG_LOGGING)
-                unit_dump(u, stdout, "\t");
-
-        log_unit_debug(u, "Creating %s/start job", u->id);
-        r = manager_add_job(u->manager, JOB_START, u, JOB_REPLACE, NULL, &err, NULL);
-        if (r < 0)
-                log_unit_error_errno(u, r, "Failed to create %s/start: %s", u->id, bus_error_message(&err, r));
-
-        k = verify_socket(u);
-        if (k < 0 && r == 0)
-                r = k;
-
-        k = verify_executables(u, root);
-        if (k < 0 && r == 0)
-                r = k;
-
-        k = verify_documentation(u, check_man);
-        if (k < 0 && r == 0)
-                r = k;
-
-        return r;
-}
-
-static void set_destroy_ignore_pointer_max(Set** s) {
-        if (*s == POINTER_MAX)
-                return;
-        set_free_free(*s);
-}
-
-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root) {
-        const ManagerTestRunFlags flags =
-                MANAGER_TEST_RUN_MINIMAL |
-                MANAGER_TEST_RUN_ENV_GENERATORS |
-                (recursive_errors == RECURSIVE_ERRORS_NO) * MANAGER_TEST_RUN_IGNORE_DEPENDENCIES |
-                run_generators * MANAGER_TEST_RUN_GENERATORS;
-
-        _cleanup_(manager_freep) Manager *m = NULL;
-        _cleanup_(set_destroy_ignore_pointer_max) Set *s = NULL;
-        _unused_ _cleanup_(clear_log_syntax_callback) dummy_t dummy;
-        Unit *units[strv_length(filenames)];
-        _cleanup_free_ char *var = NULL;
-        int r, k, i, count = 0;
-        char **filename;
-
-        if (strv_isempty(filenames))
-                return 0;
-
-        /* Allow systemd-analyze to hook in a callback function so that it can get
-         * all the required log data from the function itself without having to rely
-         * on a global set variable for the same */
-        set_log_syntax_callback(log_syntax_callback, &s);
-
-        /* set the path */
-        r = verify_generate_path(&var, filenames);
+        r = mkdtemp_malloc("/tmp/systemd-analyze-XXXXXX", &tempdir);
         if (r < 0)
-                return log_error_errno(r, "Failed to generate unit load path: %m");
-
-        assert_se(set_unit_path(var) >= 0);
+                return log_error_errno(r, "Failed to setup working directory: %m");
 
-        r = manager_new(scope, flags, &m);
+        r = process_aliases(argv, tempdir, &filenames);
         if (r < 0)
-                return log_error_errno(r, "Failed to initialize manager: %m");
-
-        log_debug("Starting manager...");
-
-        r = manager_startup(m, /* serialization= */ NULL, /* fds= */ NULL, root);
-        if (r < 0)
-                return r;
-
-        manager_clear_jobs(m);
-
-        log_debug("Loading remaining units from the command line...");
-
-        STRV_FOREACH(filename, filenames) {
-                _cleanup_free_ char *prepared = NULL;
-
-                log_debug("Handling %s...", *filename);
-
-                k = verify_prepare_filename(*filename, &prepared);
-                if (k < 0) {
-                        log_error_errno(k, "Failed to prepare filename %s: %m", *filename);
-                        if (r == 0)
-                                r = k;
-                        continue;
-                }
-
-                k = manager_load_startable_unit_or_warn(m, NULL, prepared, &units[count]);
-                if (k < 0) {
-                        if (r == 0)
-                                r = k;
-                        continue;
-                }
-
-                count++;
-        }
-
-        for (i = 0; i < count; i++) {
-                k = verify_unit(units[i], check_man, root);
-                if (k < 0 && r == 0)
-                        r = k;
-        }
-
-        if (s == POINTER_MAX)
-                return log_oom();
+                return log_error_errno(r, "Couldn't process aliases: %m");
 
-        if (set_isempty(s) || r != 0)
-                return r;
-
-        /* If all previous verifications succeeded, then either the recursive parsing of all the
-         * associated dependencies with RECURSIVE_ERRORS_YES or the parsing of the specified unit file
-         * with RECURSIVE_ERRORS_NO must have yielded a syntax warning and hence, a non-empty set. */
-        if (IN_SET(recursive_errors, RECURSIVE_ERRORS_YES, RECURSIVE_ERRORS_NO))
-                return -ENOTRECOVERABLE;
-
-        /* If all previous verifications succeeded, then the non-empty set could have resulted from
-         * a syntax warning encountered during the recursive parsing of the specified unit file and
-         * its direct dependencies. Hence, search for any of the filenames in the set and if found,
-         * return a non-zero process exit status. */
-        if (recursive_errors == RECURSIVE_ERRORS_ONE)
-                STRV_FOREACH(filename, filenames)
-                        if (set_contains(s, basename(*filename)))
-                                return -ENOTRECOVERABLE;
-
-        return 0;
+        return verify_units(filenames, arg_scope, arg_man, arg_generators, arg_recursive_errors, arg_root);
 }
-
-static const char* const recursive_errors_table[_RECURSIVE_ERRORS_MAX] = {
-        [RECURSIVE_ERRORS_NO]  = "no",
-        [RECURSIVE_ERRORS_YES] = "yes",
-        [RECURSIVE_ERRORS_ONE] = "one",
-};
-
-DEFINE_STRING_TABLE_LOOKUP(recursive_errors, RecursiveErrors);
index 47b78a8158963f75cd441b70cdba4cad7aa85479..1193a0e38c3f0fe2994ba86357d985ccd7079115 100644 (file)
@@ -1,23 +1,4 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
 #pragma once
 
-#include <stdbool.h>
-
-#include "execute.h"
-#include "path-lookup.h"
-
-typedef enum RecursiveErrors {
-        RECURSIVE_ERRORS_YES,               /* Look for errors in all associated units */
-        RECURSIVE_ERRORS_NO,                /* Don't look for errors in any but the selected unit */
-        RECURSIVE_ERRORS_ONE,               /* Look for errors in the selected unit and its direct dependencies */
-        _RECURSIVE_ERRORS_MAX,
-        _RECURSIVE_ERRORS_INVALID = -EINVAL,
-} RecursiveErrors;
-
-int verify_generate_path(char **var, char **filenames);
-int verify_prepare_filename(const char *filename, char **ret);
-int verify_executable(Unit *u, const ExecCommand *exec, const char *root);
-int verify_units(char **filenames, UnitFileScope scope, bool check_man, bool run_generators, RecursiveErrors recursive_errors, const char *root);
-
-const char* recursive_errors_to_string(RecursiveErrors i) _const_;
-RecursiveErrors recursive_errors_from_string(const char *s) _pure_;
+int do_verify(int argc, char *argv[], void *userdata);
index 68cda2b5ea7822d482a662bead18c378071df1ac..cb4d8c7ca474c88a4fe1a4dd389a7378150e321e 100644 (file)
@@ -90,7 +90,7 @@ PagerFlags arg_pager_flags = 0;
 BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
 const char *arg_host = NULL;
 UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
-static RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES;
+RecursiveErrors arg_recursive_errors = RECURSIVE_ERRORS_YES;
 bool arg_man = true;
 bool arg_generators = false;
 char *arg_root = NULL;
@@ -151,53 +151,6 @@ int bus_get_unit_property_strv(sd_bus *bus, const char *path, const char *proper
         return 0;
 }
 
-static int process_aliases(char *argv[], char *tempdir, char ***ret) {
-        _cleanup_strv_free_ char **filenames = NULL;
-        char **filename;
-        int r;
-
-        assert(argv);
-        assert(tempdir);
-        assert(ret);
-
-        STRV_FOREACH(filename, strv_skip(argv, 1)) {
-                _cleanup_free_ char *src = NULL, *dst = NULL, *base = NULL;
-                const char *parse_arg;
-
-                parse_arg = *filename;
-                r = extract_first_word(&parse_arg, &src, ":", EXTRACT_DONT_COALESCE_SEPARATORS|EXTRACT_RETAIN_ESCAPE);
-                if (r < 0)
-                        return r;
-
-                if (!parse_arg) {
-                        r = strv_consume(&filenames, TAKE_PTR(src));
-                        if (r < 0)
-                                return r;
-
-                        continue;
-                }
-
-                r = path_extract_filename(parse_arg, &base);
-                if (r < 0)
-                        return r;
-
-                dst = path_join(tempdir, base);
-                if (!dst)
-                        return -ENOMEM;
-
-                r = copy_file(src, dst, 0, 0644, 0, 0, COPY_REFLINK);
-                if (r < 0)
-                        return r;
-
-                r = strv_consume(&filenames, TAKE_PTR(dst));
-                if (r < 0)
-                        return r;
-        }
-
-        *ret = TAKE_PTR(filenames);
-        return 0;
-}
-
 void time_parsing_hint(const char *p, bool calendar, bool timestamp, bool timespan) {
         if (calendar && calendar_spec_from_string(p, NULL) >= 0)
                 log_notice("Hint: this expression is a valid calendar specification. "
@@ -214,22 +167,6 @@ static int do_condition(int argc, char *argv[], void *userdata) {
         return verify_conditions(strv_skip(argv, 1), arg_scope, arg_unit, arg_root);
 }
 
-static int do_verify(int argc, char *argv[], void *userdata) {
-        _cleanup_strv_free_ char **filenames = NULL;
-        _cleanup_(rm_rf_physical_and_freep) char *tempdir = NULL;
-        int r;
-
-        r = mkdtemp_malloc("/tmp/systemd-analyze-XXXXXX", &tempdir);
-        if (r < 0)
-                return log_error_errno(r, "Failed to setup working directory: %m");
-
-        r = process_aliases(argv, tempdir, &filenames);
-        if (r < 0)
-                return log_error_errno(r, "Couldn't process aliases: %m");
-
-        return verify_units(filenames, arg_scope, arg_man, arg_generators, arg_recursive_errors, arg_root);
-}
-
 static int help(int argc, char *argv[], void *userdata) {
         _cleanup_free_ char *link = NULL, *dot_link = NULL;
         int r;
index 94eec410621a486c66042280db92ef1ce658d544..9755f9df36da7aab470e90c7909aefb9e7c5d712 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <stdbool.h>
 
+#include "analyze-verify-util.h"
 #include "bus-util.h"
 #include "json.h"
 #include "pager.h"
@@ -22,6 +23,7 @@ extern PagerFlags arg_pager_flags;
 extern BusTransport arg_transport;
 extern const char *arg_host;
 extern UnitFileScope arg_scope;
+extern RecursiveErrors arg_recursive_errors;
 extern bool arg_man;
 extern bool arg_generators;
 extern char *arg_root;
index 83b244c80c2e04cc67b274e422e3bc469156bd27..619f878e546f0e478cf287ba296b3c1adb8764b3 100644 (file)
@@ -47,13 +47,15 @@ systemd_analyze_sources = files('''
         analyze-unit-paths.h
         analyze-verify.c
         analyze-verify.h
+        analyze-verify-util.c
+        analyze-verify-util.h
         analyze.c
 '''.split())
 
 tests += [
         [files('test-verify.c',
-               'analyze-verify.c',
-               'analyze-verify.h'),
+               'analyze-verify-util.c',
+               'analyze-verify-util.h'),
          [libcore,
           libshared],
          [],
index eaf5e0b39b41d15c16b39bd8228cbaf1a16a1012..f8c0bd9786925de4eeba55889ed40bba087e4e5e 100644 (file)
@@ -1,5 +1,6 @@
 /* SPDX-License-Identifier: LGPL-2.1-or-later */
-#include "analyze-verify.h"
+
+#include "analyze-verify-util.h"
 #include "tests.h"
 
 static void test_verify_nonexistent(void) {