/* SPDX-License-Identifier: LGPL-2.1-or-later */ #include #include "analyze.h" #include "analyze-condition.h" #include "analyze-verify-util.h" #include "condition.h" #include "conf-parser.h" #include "load-fragment.h" #include "service.h" static int parse_condition(Unit *u, const char *line) { assert(u); assert(line); for (ConditionType t = 0; t < _CONDITION_TYPE_MAX; t++) { ConfigParserCallback callback; Condition **target; const char *p, *name; name = condition_type_to_string(t); p = startswith(line, name); if (p) target = &u->conditions; else { name = assert_type_to_string(t); p = startswith(line, name); if (!p) continue; target = &u->asserts; } p += strspn(p, WHITESPACE); if (*p != '=') continue; p++; p += strspn(p, WHITESPACE); if (condition_takes_path(t)) callback = config_parse_unit_condition_path; else callback = config_parse_unit_condition_string; return callback(NULL, "(cmdline)", 0, NULL, 0, name, t, p, target, u); } return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line); } _printf_(7, 8) static int log_helper(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) { Unit *u = ASSERT_PTR(userdata); va_list ap; int r; /* "upgrade" debug messages */ level = MIN(LOG_INFO, level); va_start(ap, format); r = log_object_internalv(level, error, file, line, func, NULL, u->id, NULL, NULL, format, ap); va_end(ap); return r; } static int verify_conditions(char **lines, LookupScope scope, const char *unit, const char *root) { _cleanup_(manager_freep) Manager *m = NULL; Unit *u; int r, q = 1; if (unit) { _cleanup_strv_free_ char **filenames = NULL; _cleanup_free_ char *var = NULL; filenames = strv_new(unit); if (!filenames) return log_oom(); 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, MANAGER_TEST_RUN_MINIMAL, &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; if (unit) { _cleanup_free_ char *prepared = NULL; r = verify_prepare_filename(unit, &prepared); if (r < 0) return log_error_errno(r, "Failed to prepare filename %s: %m", unit); r = manager_load_startable_unit_or_warn(m, NULL, prepared, &u); if (r < 0) return r; } else { r = unit_new_for_name(m, sizeof(Service), "test.service", &u); if (r < 0) return log_error_errno(r, "Failed to create test.service: %m"); STRV_FOREACH(line, lines) { r = parse_condition(u, *line); if (r < 0) return r; } } r = condition_test_list(u->asserts, environ, assert_type_to_string, log_helper, u); if (u->asserts) log_notice("Asserts %s.", r > 0 ? "succeeded" : "failed"); q = condition_test_list(u->conditions, environ, condition_type_to_string, log_helper, u); if (u->conditions) log_notice("Conditions %s.", q > 0 ? "succeeded" : "failed"); return r > 0 && q > 0 ? 0 : -EIO; } int verb_condition(int argc, char *argv[], void *userdata) { int r; r = verify_conditions(strv_skip(argv, 1), arg_scope, arg_unit, arg_root); if (r < 0) return r; return EXIT_SUCCESS; }