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