1 /* SPDX-License-Identifier: LGPL-2.1+ */
5 #include "analyze-condition.h"
7 #include "conf-parser.h"
8 #include "load-fragment.h"
11 typedef struct condition_definition
{
13 ConfigParserCallback parser
;
15 } condition_definition
;
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
},
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
},
66 /* deprecated, but we should still parse them */
67 { "ConditionNull", config_parse_unit_condition_null
, 0 },
68 { "AssertNull", config_parse_unit_condition_null
, 0 },
71 static int parse_condition(Unit
*u
, const char *line
) {
75 if ((p
= startswith(line
, "Condition")))
76 target
= &u
->conditions
;
77 else if ((p
= startswith(line
, "Assert")))
80 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Cannot parse \"%s\".", line
);
82 for (size_t i
= 0; i
< ELEMENTSOF(condition_definitions
); i
++) {
83 const condition_definition
*c
= &condition_definitions
[i
];
85 p
= startswith(line
, c
->name
);
88 p
+= strspn(p
, WHITESPACE
);
90 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Expected \"=\" in \"%s\".", line
);
92 p
+= 1 + strspn(p
+ 1, WHITESPACE
);
94 return c
->parser(NULL
, "(stdin)", 0, NULL
, 0, c
->name
, c
->type
, p
, target
, u
);
97 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Cannot parse \"%s\".", line
);
101 static int log_helper(void *userdata
, int level
, int error
, const char *file
, int line
, const char *func
, const char *format
, ...) {
108 /* "upgrade" debug messages */
109 level
= MIN(LOG_INFO
, level
);
111 va_start(ap
, format
);
112 r
= log_object_internalv(level
, error
, file
, line
, func
,
123 int verify_conditions(char **lines
, UnitFileScope scope
) {
124 _cleanup_(manager_freep
) Manager
*m
= NULL
;
129 r
= manager_new(scope
, MANAGER_TEST_RUN_MINIMAL
, &m
);
131 return log_error_errno(r
, "Failed to initialize manager: %m");
133 log_debug("Starting manager...");
134 r
= manager_startup(m
, NULL
, NULL
);
138 r
= unit_new_for_name(m
, sizeof(Service
), "test.service", &u
);
140 return log_error_errno(r
, "Failed to create test.service: %m");
142 STRV_FOREACH(line
, lines
) {
143 r
= parse_condition(u
, *line
);
148 r
= condition_test_list(u
->asserts
, environ
, assert_type_to_string
, log_helper
, u
);
150 log_notice("Asserts %s.", r
> 0 ? "succeeded" : "failed");
152 q
= condition_test_list(u
->conditions
, environ
, condition_type_to_string
, log_helper
, u
);
154 log_notice("Conditions %s.", q
> 0 ? "succeeded" : "failed");
156 return r
> 0 && q
> 0 ? 0 : -EIO
;