Line data Source code
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 0 : static int parse_condition(Unit *u, const char *line) {
70 : const char *p;
71 : Condition **target;
72 :
73 0 : if ((p = startswith(line, "Condition")))
74 0 : target = &u->conditions;
75 0 : else if ((p = startswith(line, "Assert")))
76 0 : target = &u->asserts;
77 : else
78 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
79 :
80 0 : for (size_t i = 0; i < ELEMENTSOF(condition_definitions); i++) {
81 0 : const condition_definition *c = &condition_definitions[i];
82 :
83 0 : p = startswith(line, c->name);
84 0 : if (!p)
85 0 : continue;
86 0 : p += strspn(p, WHITESPACE);
87 0 : if (*p != '=')
88 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Expected \"=\" in \"%s\".", line);
89 :
90 0 : p += 1 + strspn(p + 1, WHITESPACE);
91 :
92 0 : return c->parser(NULL, "(stdin)", 0, NULL, 0, c->name, c->type, p, target, u);
93 : }
94 :
95 0 : return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Cannot parse \"%s\".", line);
96 : }
97 :
98 : _printf_(7, 8)
99 0 : static int log_helper(void *userdata, int level, int error, const char *file, int line, const char *func, const char *format, ...) {
100 0 : Unit *u = userdata;
101 : va_list ap;
102 : int r;
103 :
104 0 : assert(u);
105 :
106 : /* "upgrade" debug messages */
107 0 : level = MIN(LOG_INFO, level);
108 :
109 0 : va_start(ap, format);
110 0 : r = log_object_internalv(level, error, file, line, func,
111 : NULL,
112 0 : u->id,
113 : NULL,
114 : NULL,
115 : format, ap);
116 0 : va_end(ap);
117 :
118 0 : return r;
119 : }
120 :
121 0 : int verify_conditions(char **lines, UnitFileScope scope) {
122 0 : _cleanup_(manager_freep) Manager *m = NULL;
123 : Unit *u;
124 : char **line;
125 0 : int r, q = 1;
126 :
127 0 : r = manager_new(scope, MANAGER_TEST_RUN_MINIMAL, &m);
128 0 : if (r < 0)
129 0 : return log_error_errno(r, "Failed to initialize manager: %m");
130 :
131 0 : log_debug("Starting manager...");
132 0 : r = manager_startup(m, NULL, NULL);
133 0 : if (r < 0)
134 0 : return r;
135 :
136 0 : r = unit_new_for_name(m, sizeof(Service), "test.service", &u);
137 0 : if (r < 0)
138 0 : return log_error_errno(r, "Failed to create test.service: %m");
139 :
140 0 : STRV_FOREACH(line, lines) {
141 0 : r = parse_condition(u, *line);
142 0 : if (r < 0)
143 0 : return r;
144 : }
145 :
146 0 : r = condition_test_list(u->asserts, assert_type_to_string, log_helper, u);
147 0 : if (u->asserts)
148 0 : log_notice("Asserts %s.", r > 0 ? "succeeded" : "failed");
149 :
150 0 : q = condition_test_list(u->conditions, condition_type_to_string, log_helper, u);
151 0 : if (u->conditions)
152 0 : log_notice("Conditions %s.", q > 0 ? "succeeded" : "failed");
153 :
154 0 : return r > 0 && q > 0 ? 0 : -EIO;
155 : }
|