Branch data 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 : : }
|