]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/condition.c
unit: add new ConditionHost= condition type
[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>
d0516109 27#include <sys/statvfs.h>
c0d6e764 28#include <fnmatch.h>
52661efd 29
07e833bc
MS
30#ifdef HAVE_SELINUX
31#include <selinux/selinux.h>
32#endif
33
c0d6e764 34#include <systemd/sd-id128.h>
52661efd
LP
35#include "util.h"
36#include "condition.h"
8095200d 37#include "virt.h"
9eb977db 38#include "path-util.h"
52661efd 39
267632f0 40Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
52661efd
LP
41 Condition *c;
42
8092a428
LP
43 assert(type < _CONDITION_TYPE_MAX);
44
ab7f148f
LP
45 c = new0(Condition, 1);
46 if (!c)
da19d5c1
LP
47 return NULL;
48
52661efd 49 c->type = type;
267632f0 50 c->trigger = trigger;
52661efd
LP
51 c->negate = negate;
52
ab7f148f
LP
53 if (parameter) {
54 c->parameter = strdup(parameter);
55 if (!c->parameter) {
d257ddef
LP
56 free(c);
57 return NULL;
58 }
ab7f148f 59 }
52661efd
LP
60
61 return c;
62}
63
64void condition_free(Condition *c) {
65 assert(c);
66
67 free(c->parameter);
68 free(c);
69}
70
71void condition_free_list(Condition *first) {
72 Condition *c, *n;
73
74 LIST_FOREACH_SAFE(conditions, c, n, first)
75 condition_free(c);
76}
77
78static bool test_kernel_command_line(const char *parameter) {
79 char *line, *w, *state, *word = NULL;
80 bool equal;
81 int r;
82 size_t l, pl;
83 bool found = false;
84
039655a4
LP
85 assert(parameter);
86
a373b0e7 87 if (detect_container(NULL) > 0)
2fc97846
LP
88 return false;
89
ab7f148f
LP
90 r = read_one_line_file("/proc/cmdline", &line);
91 if (r < 0) {
52661efd
LP
92 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
93 return false;
94 }
95
96 equal = !!strchr(parameter, '=');
97 pl = strlen(parameter);
98
99 FOREACH_WORD_QUOTED(w, l, line, state) {
100
101 free(word);
ab7f148f
LP
102 word = strndup(w, l);
103 if (!word)
52661efd
LP
104 break;
105
106 if (equal) {
107 if (streq(word, parameter)) {
108 found = true;
109 break;
110 }
111 } else {
112 if (startswith(word, parameter) && (word[pl] == '=' || word[pl] == 0)) {
113 found = true;
114 break;
115 }
116 }
117
118 }
119
120 free(word);
121 free(line);
122
123 return found;
124}
125
039655a4 126static bool test_virtualization(const char *parameter) {
8095200d
LP
127 int b;
128 Virtualization v;
039655a4
LP
129 const char *id;
130
131 assert(parameter);
132
8095200d
LP
133 v = detect_virtualization(&id);
134 if (v < 0) {
135 log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
039655a4
LP
136 return false;
137 }
138
8095200d 139 /* First, compare with yes/no */
039655a4
LP
140 b = parse_boolean(parameter);
141
8095200d
LP
142 if (v > 0 && b > 0)
143 return true;
144
145 if (v == 0 && b == 0)
146 return true;
147
148 /* Then, compare categorization */
149 if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
039655a4
LP
150 return true;
151
8095200d 152 if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
039655a4
LP
153 return true;
154
8095200d 155 /* Finally compare id */
e5396fed 156 return v > 0 && streq(parameter, id);
039655a4
LP
157}
158
07e833bc
MS
159static bool test_security(const char *parameter) {
160#ifdef HAVE_SELINUX
d24e1b48 161 if (streq(parameter, "selinux"))
07e833bc
MS
162 return is_selinux_enabled() > 0;
163#endif
164 return false;
165}
166
62590f23
LP
167static bool test_capability(const char *parameter) {
168 cap_value_t value;
169 FILE *f;
170 char line[LINE_MAX];
171 unsigned long long capabilities = (unsigned long long) -1;
172
173 /* If it's an invalid capability, we don't have it */
174
175 if (cap_from_name(parameter, &value) < 0)
176 return false;
177
178 /* If it's a valid capability we default to assume
179 * that we have it */
180
181 f = fopen("/proc/self/status", "re");
182 if (!f)
183 return true;
184
185 while (fgets(line, sizeof(line), f)) {
186 truncate_nl(line);
187
188 if (startswith(line, "CapBnd:")) {
189 (void) sscanf(line+7, "%llx", &capabilities);
190 break;
191 }
192 }
193
7670e5a2
TJ
194 fclose(f);
195
62590f23
LP
196 return !!(capabilities & (1ULL << value));
197}
198
c0d6e764
LP
199static bool test_host(const char *parameter) {
200 sd_id128_t x, y;
201 char *h;
202 int r;
203 bool b;
204
205 if (sd_id128_from_string(parameter, &x) >= 0) {
206
207 r = sd_id128_get_machine(&y);
208 if (r < 0)
209 return false;
210
211 return sd_id128_equal(x, y);
212 }
213
214 h = gethostname_malloc();
215 if (!h)
216 return false;
217
218 b = fnmatch(parameter, h, FNM_CASEFOLD) == 0;
219 free(h);
220
221 return b;
222}
223
52661efd
LP
224bool condition_test(Condition *c) {
225 assert(c);
226
227 switch(c->type) {
228
229 case CONDITION_PATH_EXISTS:
230 return (access(c->parameter, F_OK) >= 0) == !c->negate;
231
8092a428
LP
232 case CONDITION_PATH_EXISTS_GLOB:
233 return (glob_exists(c->parameter) > 0) == !c->negate;
234
2b583ce6
KS
235 case CONDITION_PATH_IS_DIRECTORY: {
236 struct stat st;
237
8571962c 238 if (stat(c->parameter, &st) < 0)
1f8fef5a 239 return c->negate;
2b583ce6
KS
240 return S_ISDIR(st.st_mode) == !c->negate;
241 }
242
0d60602c
MS
243 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
244 struct stat st;
245
246 if (lstat(c->parameter, &st) < 0)
1f8fef5a 247 return c->negate;
0d60602c
MS
248 return S_ISLNK(st.st_mode) == !c->negate;
249 }
250
ab7f148f
LP
251 case CONDITION_PATH_IS_MOUNT_POINT:
252 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
253
3d9a4122
LP
254 case CONDITION_PATH_IS_READ_WRITE:
255 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
d0516109 256
36af55d9
LP
257 case CONDITION_DIRECTORY_NOT_EMPTY: {
258 int k;
259
260 k = dir_is_empty(c->parameter);
261 return !(k == -ENOENT || k > 0) == !c->negate;
262 }
263
82e487c5
LP
264 case CONDITION_FILE_IS_EXECUTABLE: {
265 struct stat st;
266
34a2dc4b 267 if (stat(c->parameter, &st) < 0)
1f8fef5a 268 return c->negate;
82e487c5
LP
269
270 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
271 }
272
52661efd 273 case CONDITION_KERNEL_COMMAND_LINE:
cb40c15e 274 return test_kernel_command_line(c->parameter) == !c->negate;
52661efd 275
039655a4 276 case CONDITION_VIRTUALIZATION:
cb40c15e 277 return test_virtualization(c->parameter) == !c->negate;
039655a4 278
07e833bc
MS
279 case CONDITION_SECURITY:
280 return test_security(c->parameter) == !c->negate;
281
62590f23
LP
282 case CONDITION_CAPABILITY:
283 return test_capability(c->parameter) == !c->negate;
284
c0d6e764
LP
285 case CONDITION_HOST:
286 return test_host(c->parameter) == !c->negate;
287
d257ddef
LP
288 case CONDITION_NULL:
289 return !c->negate;
290
52661efd
LP
291 default:
292 assert_not_reached("Invalid condition type.");
293 }
294}
295
296bool condition_test_list(Condition *first) {
297 Condition *c;
267632f0 298 int triggered = -1;
52661efd
LP
299
300 /* If the condition list is empty, then it is true */
301 if (!first)
302 return true;
303
267632f0
LP
304 /* Otherwise, if all of the non-trigger conditions apply and
305 * if any of the trigger conditions apply (unless there are
306 * none) we return true */
307 LIST_FOREACH(conditions, c, first) {
308 bool b;
309
310 b = condition_test(c);
311
312 if (!c->trigger && !b)
313 return false;
314
315 if (c->trigger && triggered <= 0)
316 triggered = b;
317 }
52661efd 318
267632f0 319 return triggered != 0;
52661efd
LP
320}
321
322void condition_dump(Condition *c, FILE *f, const char *prefix) {
323 assert(c);
324 assert(f);
325
326 if (!prefix)
327 prefix = "";
328
329 fprintf(f,
8fb81fa7 330 "%s\t%s: %s%s%s\n",
52661efd
LP
331 prefix,
332 condition_type_to_string(c->type),
267632f0 333 c->trigger ? "|" : "",
52661efd
LP
334 c->negate ? "!" : "",
335 c->parameter);
336}
337
338void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
339 Condition *c;
340
341 LIST_FOREACH(conditions, c, first)
342 condition_dump(c, f, prefix);
343}
344
345static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
d257ddef 346 [CONDITION_PATH_EXISTS] = "ConditionPathExists",
8092a428 347 [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
8fb81fa7 348 [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
0d60602c 349 [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
ab7f148f 350 [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
d0516109 351 [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
8fb81fa7
MS
352 [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
353 [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
354 [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
07e833bc 355 [CONDITION_SECURITY] = "ConditionSecurity",
c0d6e764 356 [CONDITION_HOST] = "ConditionHost",
d257ddef 357 [CONDITION_NULL] = "ConditionNull"
52661efd
LP
358};
359
360DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);