Files
systemd/src/analyze/analyze-condition.c
T
Daan De Meyer 64fd6ba9ca core: Turn manager unit log fields into unit functions
There's no need for these to be fields inside the manager struct,
let's turn them into functions in unit.h instead, again to allow
forward declaring the Manager struct in a later commit.
2025-04-23 09:53:53 +02:00

145 lines
5.0 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <stdlib.h>
#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);
line = skip_leading_chars(line, /* bad = */ NULL);
const char *eq = strchr(line, '=');
if (!eq)
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
_cleanup_free_ char *type_string = strndup(line, eq - line);
if (!type_string)
return log_oom();
delete_trailing_chars(type_string, /* bad = */ NULL);
Condition **target;
ConditionType type;
if (startswith(type_string, "Condition")) {
target = &u->conditions;
type = condition_type_from_string(type_string);
} else {
target = &u->asserts;
type = assert_type_from_string(type_string);
}
if (type < 0)
return log_error_errno(type, "Cannot parse \"%s\".", line);
const char *val = skip_leading_chars(eq + 1, /* bad = */ NULL);
ConfigParserCallback callback;
if (condition_takes_path(type))
callback = config_parse_unit_condition_path;
else
callback = config_parse_unit_condition_string;
return callback(/* unit = */ NULL,
/* filename = */ "(cmdline)",
/* line = */ 0,
/* section = */ NULL,
/* section_line = */ 0,
/* lvalue = */ type_string,
/* ltype = */ type,
/* rvalue = */ val,
/* data = */ target,
/* userdata = */ u);
}
_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,
/* object_field = */ unit_log_field(u),
/* object = */ u->id,
/* extra_field = */ NULL,
/* extra = */ NULL,
format, ap);
va_end(ap);
return r;
}
static int verify_conditions(char **lines, RuntimeScope scope, const char *unit, const char *root) {
_cleanup_(manager_freep) Manager *m = NULL;
Unit *u;
int r, q = 1;
if (unit) {
r = verify_set_unit_path(STRV_MAKE(unit));
if (r < 0)
return log_error_errno(r, "Failed to set unit load path: %m");
}
r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL|MANAGER_TEST_DONT_OPEN_EXECUTOR, &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;
}
}
condition_test_logger_t logger = arg_quiet ? NULL : log_helper;
r = condition_test_list(u->asserts, environ, assert_type_to_string, logger, u);
if (u->asserts)
log_full(arg_quiet ? LOG_DEBUG : LOG_NOTICE, "Asserts %s.", r > 0 ? "succeeded" : "failed");
q = condition_test_list(u->conditions, environ, condition_type_to_string, logger, u);
if (u->conditions)
log_full(arg_quiet ? LOG_DEBUG : 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_runtime_scope, arg_unit, arg_root);
if (r < 0)
return r;
return EXIT_SUCCESS;
}