]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/analyze/analyze-condition.c
Merge pull request #14109 from poettering/varlink-tweaks
[thirdparty/systemd.git] / src / analyze / analyze-condition.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <stdlib.h>
4
5 #include "analyze-condition.h"
6 #include "condition.h"
7 #include "conf-parser.h"
8 #include "load-fragment.h"
9 #include "service.h"
10
11 typedef struct condition_definition {
12 const char *name;
13 ConfigParserCallback parser;
14 ConditionType type;
15 } condition_definition;
16
17 static const condition_definition condition_definitions[] = {
18 { "ConditionPathExists", config_parse_unit_condition_path, CONDITION_PATH_EXISTS },
19 { "ConditionPathExistsGlob", config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB },
20 { "ConditionPathIsDirectory", config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY },
21 { "ConditionPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
22 { "ConditionPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
23 { "ConditionPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
24 { "ConditionDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
25 { "ConditionFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
26 { "ConditionFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
27 { "ConditionNeedsUpdate", config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE },
28 { "ConditionFirstBoot", config_parse_unit_condition_string, CONDITION_FIRST_BOOT },
29 { "ConditionKernelCommandLine", config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE },
30 { "ConditionKernelVersion", config_parse_unit_condition_string, CONDITION_KERNEL_VERSION },
31 { "ConditionArchitecture", config_parse_unit_condition_string, CONDITION_ARCHITECTURE },
32 { "ConditionVirtualization", config_parse_unit_condition_string, CONDITION_VIRTUALIZATION },
33 { "ConditionSecurity", config_parse_unit_condition_string, CONDITION_SECURITY },
34 { "ConditionCapability", config_parse_unit_condition_string, CONDITION_CAPABILITY },
35 { "ConditionHost", config_parse_unit_condition_string, CONDITION_HOST },
36 { "ConditionACPower", config_parse_unit_condition_string, CONDITION_AC_POWER },
37 { "ConditionUser", config_parse_unit_condition_string, CONDITION_USER },
38 { "ConditionGroup", config_parse_unit_condition_string, CONDITION_GROUP },
39 { "ConditionControlGroupController", config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER },
40
41 { "AssertPathExists", config_parse_unit_condition_path, CONDITION_PATH_EXISTS },
42 { "AssertPathExistsGlob", config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB },
43 { "AssertPathIsDirectory", config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY },
44 { "AssertPathIsSymbolicLink", config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK },
45 { "AssertPathIsMountPoint", config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT },
46 { "AssertPathIsReadWrite", config_parse_unit_condition_path, CONDITION_PATH_IS_READ_WRITE },
47 { "AssertDirectoryNotEmpty", config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY },
48 { "AssertFileNotEmpty", config_parse_unit_condition_path, CONDITION_FILE_NOT_EMPTY },
49 { "AssertFileIsExecutable", config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE },
50 { "AssertNeedsUpdate", config_parse_unit_condition_path, CONDITION_NEEDS_UPDATE },
51 { "AssertFirstBoot", config_parse_unit_condition_string, CONDITION_FIRST_BOOT },
52 { "AssertKernelCommandLine", config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE },
53 { "AssertKernelVersion", config_parse_unit_condition_string, CONDITION_KERNEL_VERSION },
54 { "AssertArchitecture", config_parse_unit_condition_string, CONDITION_ARCHITECTURE },
55 { "AssertVirtualization", config_parse_unit_condition_string, CONDITION_VIRTUALIZATION },
56 { "AssertSecurity", config_parse_unit_condition_string, CONDITION_SECURITY },
57 { "AssertCapability", config_parse_unit_condition_string, CONDITION_CAPABILITY },
58 { "AssertHost", config_parse_unit_condition_string, CONDITION_HOST },
59 { "AssertACPower", config_parse_unit_condition_string, CONDITION_AC_POWER },
60 { "AssertUser", config_parse_unit_condition_string, CONDITION_USER },
61 { "AssertGroup", config_parse_unit_condition_string, CONDITION_GROUP },
62 { "AssertControlGroupController", config_parse_unit_condition_string, CONDITION_CONTROL_GROUP_CONTROLLER },
63
64 /* deprecated, but we should still parse them */
65 { "ConditionNull", config_parse_unit_condition_null, 0 },
66 { "AssertNull", config_parse_unit_condition_null, 0 },
67 };
68
69 static int parse_condition(Unit *u, const char *line) {
70 const char *p;
71 Condition **target;
72
73 if ((p = startswith(line, "Condition")))
74 target = &u->conditions;
75 else if ((p = startswith(line, "Assert")))
76 target = &u->asserts;
77 else
78 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
79
80 for (size_t i = 0; i < ELEMENTSOF(condition_definitions); i++) {
81 const condition_definition *c = &condition_definitions[i];
82
83 p = startswith(line, c->name);
84 if (!p)
85 continue;
86 p += strspn(p, WHITESPACE);
87 if (*p != '=')
88 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected \"=\" in \"%s\".", line);
89
90 p += 1 + strspn(p + 1, WHITESPACE);
91
92 return c->parser(NULL, "(stdin)", 0, NULL, 0, c->name, c->type, p, target, u);
93 }
94
95 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
96 }
97
98 _printf_(7, 8)
99 static int log_helper(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) {
100 Unit *u = userdata;
101 va_list ap;
102 int r;
103
104 assert(u);
105
106 /* "upgrade" debug messages */
107 level = MIN(LOG_INFO, level);
108
109 va_start(ap, format);
110 r = log_object_internalv(level, error, file, line, func,
111 NULL,
112 u->id,
113 NULL,
114 NULL,
115 format, ap);
116 va_end(ap);
117
118 return r;
119 }
120
121 int verify_conditions(char **lines, UnitFileScope scope) {
122 _cleanup_(manager_freep) Manager *m = NULL;
123 Unit *u;
124 char **line;
125 int r, q = 1;
126
127 r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m);
128 if (r < 0)
129 return log_error_errno(r, "Failed to initialize manager: %m");
130
131 log_debug("Starting manager...");
132 r = manager_startup(m, NULL, NULL);
133 if (r < 0)
134 return r;
135
136 r = unit_new_for_name(m, sizeof(Service), "test.service", &u);
137 if (r < 0)
138 return log_error_errno(r, "Failed to create test.service: %m");
139
140 STRV_FOREACH(line, lines) {
141 r = parse_condition(u, *line);
142 if (r < 0)
143 return r;
144 }
145
146 r = condition_test_list(u->asserts, assert_type_to_string, log_helper, u);
147 if (u->asserts)
148 log_notice("Asserts %s.", r > 0 ? "succeeded" : "failed");
149
150 q = condition_test_list(u->conditions, condition_type_to_string, log_helper, u);
151 if (u->conditions)
152 log_notice("Conditions %s.", q > 0 ? "succeeded" : "failed");
153
154 return r > 0 && q > 0 ? 0 : -EIO;
155 }