]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/condition.c
journalctl: always show monotonic timestamp even if it's from an old boot
[thirdparty/systemd.git] / src / 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
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
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
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
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);