]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/condition.c
Set $NOTIFY_SOCKET for control procs if NotifyAccess=all
[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
dc92e62c 30#include "sd-id128.h"
52661efd
LP
31#include "util.h"
32#include "condition.h"
8095200d 33#include "virt.h"
9eb977db 34#include "path-util.h"
a5c32cff 35#include "fileio.h"
4b744dfa 36#include "unit.h"
d682b3a7
LP
37#include "smack-util.h"
38#include "apparmor-util.h"
39#include "ima-util.h"
40#include "selinux-util.h"
52661efd 41
afc50ea8
TG
42static bool condition_test_security(Condition *c) {
43 assert(c);
44 assert(c->parameter);
45 assert(c->type == CONDITION_SECURITY);
46
47 if (streq(c->parameter, "selinux"))
48 return use_selinux() == !c->negate;
49 if (streq(c->parameter, "apparmor"))
50 return use_apparmor() == !c->negate;
51 if (streq(c->parameter, "ima"))
52 return use_ima() == !c->negate;
53 if (streq(c->parameter, "smack"))
54 return use_smack() == !c->negate;
dc92e62c 55
afc50ea8 56 return c->negate;
07e833bc
MS
57}
58
afc50ea8 59static bool condition_test_capability(Condition *c) {
dc92e62c 60 _cleanup_fclose_ FILE *f = NULL;
62590f23 61 cap_value_t value;
62590f23 62 char line[LINE_MAX];
de0671ee 63 unsigned long long capabilities = -1;
62590f23 64
afc50ea8
TG
65 assert(c);
66 assert(c->parameter);
67 assert(c->type == CONDITION_CAPABILITY);
68
62590f23
LP
69 /* If it's an invalid capability, we don't have it */
70
afc50ea8
TG
71 if (cap_from_name(c->parameter, &value) < 0)
72 return c->negate;
62590f23
LP
73
74 /* If it's a valid capability we default to assume
75 * that we have it */
76
77 f = fopen("/proc/self/status", "re");
78 if (!f)
afc50ea8 79 return !c->negate;
62590f23
LP
80
81 while (fgets(line, sizeof(line), f)) {
82 truncate_nl(line);
83
84 if (startswith(line, "CapBnd:")) {
85 (void) sscanf(line+7, "%llx", &capabilities);
86 break;
87 }
88 }
89
afc50ea8 90 return !!(capabilities & (1ULL << value)) == !c->negate;
62590f23
LP
91}
92
a55654d5
LP
93static bool condition_test_needs_update(Condition *c) {
94 const char *p;
95 struct stat usr, other;
96
97 assert(c);
98 assert(c->parameter);
99 assert(c->type == CONDITION_NEEDS_UPDATE);
100
101 /* If the file system is read-only we shouldn't suggest an update */
102 if (path_is_read_only_fs(c->parameter) > 0)
103 return c->negate;
104
105 /* Any other failure means we should allow the condition to be true,
106 * so that we rather invoke too many update tools then too
107 * few. */
108
109 if (!path_is_absolute(c->parameter))
110 return !c->negate;
111
112 p = strappenda(c->parameter, "/.updated");
113 if (lstat(p, &other) < 0)
114 return !c->negate;
115
116 if (lstat("/usr/", &usr) < 0)
117 return !c->negate;
118
119 return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
120 (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
121}
122
e2680723
LP
123static bool condition_test_first_boot(Condition *c) {
124 int r;
125
126 assert(c);
127 assert(c->parameter);
128 assert(c->type == CONDITION_FIRST_BOOT);
129
130 r = parse_boolean(c->parameter);
131 if (r < 0)
132 return c->negate;
133
134 return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
135}
136
52990c2e 137static bool condition_test(Condition *c) {
52661efd
LP
138 assert(c);
139
140 switch(c->type) {
141
142 case CONDITION_PATH_EXISTS:
143 return (access(c->parameter, F_OK) >= 0) == !c->negate;
144
8092a428
LP
145 case CONDITION_PATH_EXISTS_GLOB:
146 return (glob_exists(c->parameter) > 0) == !c->negate;
147
2b583ce6
KS
148 case CONDITION_PATH_IS_DIRECTORY: {
149 struct stat st;
150
8571962c 151 if (stat(c->parameter, &st) < 0)
1f8fef5a 152 return c->negate;
2b583ce6
KS
153 return S_ISDIR(st.st_mode) == !c->negate;
154 }
155
0d60602c
MS
156 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
157 struct stat st;
158
159 if (lstat(c->parameter, &st) < 0)
1f8fef5a 160 return c->negate;
0d60602c
MS
161 return S_ISLNK(st.st_mode) == !c->negate;
162 }
163
ab7f148f
LP
164 case CONDITION_PATH_IS_MOUNT_POINT:
165 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
166
3d9a4122
LP
167 case CONDITION_PATH_IS_READ_WRITE:
168 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
d0516109 169
36af55d9
LP
170 case CONDITION_DIRECTORY_NOT_EMPTY: {
171 int k;
172
173 k = dir_is_empty(c->parameter);
174 return !(k == -ENOENT || k > 0) == !c->negate;
175 }
176
742a862b
LP
177 case CONDITION_FILE_NOT_EMPTY: {
178 struct stat st;
179
180 if (stat(c->parameter, &st) < 0)
181 return c->negate;
182
183 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
184 }
185
82e487c5
LP
186 case CONDITION_FILE_IS_EXECUTABLE: {
187 struct stat st;
188
34a2dc4b 189 if (stat(c->parameter, &st) < 0)
1f8fef5a 190 return c->negate;
82e487c5
LP
191
192 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
193 }
194
52661efd 195 case CONDITION_KERNEL_COMMAND_LINE:
afc50ea8 196 return condition_test_kernel_command_line(c);
52661efd 197
039655a4 198 case CONDITION_VIRTUALIZATION:
afc50ea8 199 return condition_test_virtualization(c);
039655a4 200
07e833bc 201 case CONDITION_SECURITY:
afc50ea8 202 return condition_test_security(c);
07e833bc 203
62590f23 204 case CONDITION_CAPABILITY:
afc50ea8 205 return condition_test_capability(c);
62590f23 206
c0d6e764 207 case CONDITION_HOST:
afc50ea8 208 return condition_test_host(c);
c0d6e764 209
240dbaa4 210 case CONDITION_AC_POWER:
afc50ea8 211 return condition_test_ac_power(c);
240dbaa4 212
099524d7
LP
213 case CONDITION_ARCHITECTURE:
214 return condition_test_architecture(c);
215
a55654d5
LP
216 case CONDITION_NEEDS_UPDATE:
217 return condition_test_needs_update(c);
218
e2680723
LP
219 case CONDITION_FIRST_BOOT:
220 return condition_test_first_boot(c);
221
d257ddef
LP
222 case CONDITION_NULL:
223 return !c->negate;
224
52661efd
LP
225 default:
226 assert_not_reached("Invalid condition type.");
227 }
228}
229
4b744dfa 230bool condition_test_list(const char *unit, Condition *first) {
52661efd 231 Condition *c;
267632f0 232 int triggered = -1;
52661efd
LP
233
234 /* If the condition list is empty, then it is true */
235 if (!first)
236 return true;
237
267632f0
LP
238 /* Otherwise, if all of the non-trigger conditions apply and
239 * if any of the trigger conditions apply (unless there are
240 * none) we return true */
241 LIST_FOREACH(conditions, c, first) {
242 bool b;
243
244 b = condition_test(c);
4b744dfa
ZJS
245 if (unit)
246 log_debug_unit(unit,
247 "%s=%s%s%s %s for %s.",
248 condition_type_to_string(c->type),
249 c->trigger ? "|" : "",
250 c->negate ? "!" : "",
251 c->parameter,
252 b ? "succeeded" : "failed",
253 unit);
52990c2e 254 c->state = b ? 1 : -1;
267632f0
LP
255
256 if (!c->trigger && !b)
257 return false;
258
259 if (c->trigger && triggered <= 0)
260 triggered = b;
261 }
52661efd 262
267632f0 263 return triggered != 0;
52661efd 264}