]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/condition.c
relicense to LGPLv2.1 (with exceptions)
[thirdparty/systemd.git] / src / core / condition.c
CommitLineData
52661efd
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
f23c09b0 6 Copyright 2010 Lennart Poettering
52661efd
LP
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
52661efd
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
52661efd 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
52661efd
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <stdlib.h>
23#include <errno.h>
24#include <string.h>
25#include <unistd.h>
62590f23 26#include <sys/capability.h>
52661efd 27
07e833bc
MS
28#ifdef HAVE_SELINUX
29#include <selinux/selinux.h>
30#endif
31
52661efd
LP
32#include "util.h"
33#include "condition.h"
8095200d 34#include "virt.h"
52661efd 35
267632f0 36Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
52661efd
LP
37 Condition *c;
38
8092a428
LP
39 assert(type < _CONDITION_TYPE_MAX);
40
ab7f148f
LP
41 c = new0(Condition, 1);
42 if (!c)
da19d5c1
LP
43 return NULL;
44
52661efd 45 c->type = type;
267632f0 46 c->trigger = trigger;
52661efd
LP
47 c->negate = negate;
48
ab7f148f
LP
49 if (parameter) {
50 c->parameter = strdup(parameter);
51 if (!c->parameter) {
d257ddef
LP
52 free(c);
53 return NULL;
54 }
ab7f148f 55 }
52661efd
LP
56
57 return c;
58}
59
60void condition_free(Condition *c) {
61 assert(c);
62
63 free(c->parameter);
64 free(c);
65}
66
67void condition_free_list(Condition *first) {
68 Condition *c, *n;
69
70 LIST_FOREACH_SAFE(conditions, c, n, first)
71 condition_free(c);
72}
73
74static bool test_kernel_command_line(const char *parameter) {
75 char *line, *w, *state, *word = NULL;
76 bool equal;
77 int r;
78 size_t l, pl;
79 bool found = false;
80
039655a4
LP
81 assert(parameter);
82
a373b0e7 83 if (detect_container(NULL) > 0)
2fc97846
LP
84 return false;
85
ab7f148f
LP
86 r = read_one_line_file("/proc/cmdline", &line);
87 if (r < 0) {
52661efd
LP
88 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
89 return false;
90 }
91
92 equal = !!strchr(parameter, '=');
93 pl = strlen(parameter);
94
95 FOREACH_WORD_QUOTED(w, l, line, state) {
96
97 free(word);
ab7f148f
LP
98 word = strndup(w, l);
99 if (!word)
52661efd
LP
100 break;
101
102 if (equal) {
103 if (streq(word, parameter)) {
104 found = true;
105 break;
106 }
107 } else {
108 if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) {
109 found = true;
110 break;
111 }
112 }
113
114 }
115
116 free(word);
117 free(line);
118
119 return found;
120}
121
039655a4 122static bool test_virtualization(const char *parameter) {
8095200d
LP
123 int b;
124 Virtualization v;
039655a4
LP
125 const char *id;
126
127 assert(parameter);
128
8095200d
LP
129 v = detect_virtualization(&id);
130 if (v < 0) {
131 log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
039655a4
LP
132 return false;
133 }
134
8095200d 135 /* First, compare with yes/no */
039655a4
LP
136 b = parse_boolean(parameter);
137
8095200d
LP
138 if (v > 0 && b > 0)
139 return true;
140
141 if (v == 0 && b == 0)
142 return true;
143
144 /* Then, compare categorization */
145 if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
039655a4
LP
146 return true;
147
8095200d 148 if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
039655a4
LP
149 return true;
150
8095200d 151 /* Finally compare id */
e5396fed 152 return v > 0 && streq(parameter, id);
039655a4
LP
153}
154
07e833bc
MS
155static bool test_security(const char *parameter) {
156#ifdef HAVE_SELINUX
d24e1b48 157 if (streq(parameter, "selinux"))
07e833bc
MS
158 return is_selinux_enabled() > 0;
159#endif
160 return false;
161}
162
62590f23
LP
163static bool test_capability(const char *parameter) {
164 cap_value_t value;
165 FILE *f;
166 char line[LINE_MAX];
167 unsigned long long capabilities = (unsigned long long) -1;
168
169 /* If it's an invalid capability, we don't have it */
170
171 if (cap_from_name(parameter, &value) < 0)
172 return false;
173
174 /* If it's a valid capability we default to assume
175 * that we have it */
176
177 f = fopen("/proc/self/status", "re");
178 if (!f)
179 return true;
180
181 while (fgets(line, sizeof(line), f)) {
182 truncate_nl(line);
183
184 if (startswith(line, "CapBnd:")) {
185 (void) sscanf(line+7, "%llx", &capabilities);
186 break;
187 }
188 }
189
7670e5a2
TJ
190 fclose(f);
191
62590f23
LP
192 return !!(capabilities & (1ULL << value));
193}
194
52661efd
LP
195bool condition_test(Condition *c) {
196 assert(c);
197
198 switch(c->type) {
199
200 case CONDITION_PATH_EXISTS:
201 return (access(c->parameter, F_OK) >= 0) == !c->negate;
202
8092a428
LP
203 case CONDITION_PATH_EXISTS_GLOB:
204 return (glob_exists(c->parameter) > 0) == !c->negate;
205
2b583ce6
KS
206 case CONDITION_PATH_IS_DIRECTORY: {
207 struct stat st;
208
8571962c 209 if (stat(c->parameter, &st) < 0)
1f8fef5a 210 return c->negate;
2b583ce6
KS
211 return S_ISDIR(st.st_mode) == !c->negate;
212 }
213
0d60602c
MS
214 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
215 struct stat st;
216
217 if (lstat(c->parameter, &st) < 0)
1f8fef5a 218 return c->negate;
0d60602c
MS
219 return S_ISLNK(st.st_mode) == !c->negate;
220 }
221
ab7f148f
LP
222 case CONDITION_PATH_IS_MOUNT_POINT:
223 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
224
36af55d9
LP
225 case CONDITION_DIRECTORY_NOT_EMPTY: {
226 int k;
227
228 k = dir_is_empty(c->parameter);
229 return !(k == -ENOENT || k > 0) == !c->negate;
230 }
231
82e487c5
LP
232 case CONDITION_FILE_IS_EXECUTABLE: {
233 struct stat st;
234
34a2dc4b 235 if (stat(c->parameter, &st) < 0)
1f8fef5a 236 return c->negate;
82e487c5
LP
237
238 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
239 }
240
52661efd 241 case CONDITION_KERNEL_COMMAND_LINE:
cb40c15e 242 return test_kernel_command_line(c->parameter) == !c->negate;
52661efd 243
039655a4 244 case CONDITION_VIRTUALIZATION:
cb40c15e 245 return test_virtualization(c->parameter) == !c->negate;
039655a4 246
07e833bc
MS
247 case CONDITION_SECURITY:
248 return test_security(c->parameter) == !c->negate;
249
62590f23
LP
250 case CONDITION_CAPABILITY:
251 return test_capability(c->parameter) == !c->negate;
252
d257ddef
LP
253 case CONDITION_NULL:
254 return !c->negate;
255
52661efd
LP
256 default:
257 assert_not_reached("Invalid condition type.");
258 }
259}
260
261bool condition_test_list(Condition *first) {
262 Condition *c;
267632f0 263 int triggered = -1;
52661efd
LP
264
265 /* If the condition list is empty, then it is true */
266 if (!first)
267 return true;
268
267632f0
LP
269 /* Otherwise, if all of the non-trigger conditions apply and
270 * if any of the trigger conditions apply (unless there are
271 * none) we return true */
272 LIST_FOREACH(conditions, c, first) {
273 bool b;
274
275 b = condition_test(c);
276
277 if (!c->trigger && !b)
278 return false;
279
280 if (c->trigger && triggered <= 0)
281 triggered = b;
282 }
52661efd 283
267632f0 284 return triggered != 0;
52661efd
LP
285}
286
287void condition_dump(Condition *c, FILE *f, const char *prefix) {
288 assert(c);
289 assert(f);
290
291 if (!prefix)
292 prefix = "";
293
294 fprintf(f,
8fb81fa7 295 "%s\t%s: %s%s%s\n",
52661efd
LP
296 prefix,
297 condition_type_to_string(c->type),
267632f0 298 c->trigger ? "|" : "",
52661efd
LP
299 c->negate ? "!" : "",
300 c->parameter);
301}
302
303void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
304 Condition *c;
305
306 LIST_FOREACH(conditions, c, first)
307 condition_dump(c, f, prefix);
308}
309
310static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
d257ddef 311 [CONDITION_PATH_EXISTS] = "ConditionPathExists",
8092a428 312 [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
8fb81fa7 313 [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
0d60602c 314 [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
ab7f148f 315 [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
8fb81fa7
MS
316 [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
317 [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
318 [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
07e833bc 319 [CONDITION_SECURITY] = "ConditionSecurity",
d257ddef 320 [CONDITION_NULL] = "ConditionNull"
52661efd
LP
321};
322
323DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);