]>
Commit | Line | Data |
---|---|---|
edfea9fe ZJS |
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 | } |