1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
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
11 (at your option) any later version.
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 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/capability.h>
27 #include <sys/statvfs.h>
32 #include "condition.h"
34 #include "path-util.h"
37 #include "smack-util.h"
38 #include "apparmor-util.h"
40 #include "selinux-util.h"
43 static int condition_test_security(Condition *c) {
46 assert(c->type == CONDITION_SECURITY);
48 if (streq(c->parameter, "selinux"))
49 return mac_selinux_use() == !c->negate;
50 if (streq(c->parameter, "smack"))
51 return mac_smack_use() == !c->negate;
52 if (streq(c->parameter, "apparmor"))
53 return mac_apparmor_use() == !c->negate;
54 if (streq(c->parameter, "audit"))
55 return use_audit() == !c->negate;
56 if (streq(c->parameter, "ima"))
57 return use_ima() == !c->negate;
62 static int condition_test_capability(Condition *c) {
63 _cleanup_fclose_ FILE *f = NULL;
66 unsigned long long capabilities = -1;
70 assert(c->type == CONDITION_CAPABILITY);
72 /* If it's an invalid capability, we don't have it */
74 if (cap_from_name(c->parameter, &value) < 0)
77 /* If it's a valid capability we default to assume
80 f = fopen("/proc/self/status", "re");
84 while (fgets(line, sizeof(line), f)) {
87 if (startswith(line, "CapBnd:")) {
88 (void) sscanf(line+7, "%llx", &capabilities);
93 return !!(capabilities & (1ULL << value)) == !c->negate;
96 static bool condition_test_needs_update(Condition *c) {
98 struct stat usr, other;
101 assert(c->parameter);
102 assert(c->type == CONDITION_NEEDS_UPDATE);
104 /* If the file system is read-only we shouldn't suggest an update */
105 if (path_is_read_only_fs(c->parameter) > 0)
108 /* Any other failure means we should allow the condition to be true,
109 * so that we rather invoke too many update tools then too
112 if (!path_is_absolute(c->parameter))
115 p = strappenda(c->parameter, "/.updated");
116 if (lstat(p, &other) < 0)
119 if (lstat("/usr/", &usr) < 0)
122 return (usr.st_mtim.tv_sec > other.st_mtim.tv_sec ||
123 (usr.st_mtim.tv_sec == other.st_mtim.tv_sec && usr.st_mtim.tv_nsec > other.st_mtim.tv_nsec)) == !c->negate;
126 static bool condition_test_first_boot(Condition *c) {
130 assert(c->parameter);
131 assert(c->type == CONDITION_FIRST_BOOT);
133 r = parse_boolean(c->parameter);
137 return ((access("/run/systemd/first-boot", F_OK) >= 0) == !!r) == !c->negate;
140 static int condition_test(Condition *c) {
145 case CONDITION_PATH_EXISTS:
146 return (access(c->parameter, F_OK) >= 0) == !c->negate;
148 case CONDITION_PATH_EXISTS_GLOB:
149 return (glob_exists(c->parameter) > 0) == !c->negate;
151 case CONDITION_PATH_IS_DIRECTORY: {
154 if (stat(c->parameter, &st) < 0)
156 return S_ISDIR(st.st_mode) == !c->negate;
159 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
162 if (lstat(c->parameter, &st) < 0)
164 return S_ISLNK(st.st_mode) == !c->negate;
167 case CONDITION_PATH_IS_MOUNT_POINT:
168 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
170 case CONDITION_PATH_IS_READ_WRITE:
171 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
173 case CONDITION_DIRECTORY_NOT_EMPTY: {
176 k = dir_is_empty(c->parameter);
177 return !(k == -ENOENT || k > 0) == !c->negate;
180 case CONDITION_FILE_NOT_EMPTY: {
183 if (stat(c->parameter, &st) < 0)
186 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
189 case CONDITION_FILE_IS_EXECUTABLE: {
192 if (stat(c->parameter, &st) < 0)
195 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
198 case CONDITION_KERNEL_COMMAND_LINE:
199 return condition_test_kernel_command_line(c);
201 case CONDITION_VIRTUALIZATION:
202 return condition_test_virtualization(c);
204 case CONDITION_SECURITY:
205 return condition_test_security(c);
207 case CONDITION_CAPABILITY:
208 return condition_test_capability(c);
211 return condition_test_host(c);
213 case CONDITION_AC_POWER:
214 return condition_test_ac_power(c);
216 case CONDITION_ARCHITECTURE:
217 return condition_test_architecture(c);
219 case CONDITION_NEEDS_UPDATE:
220 return condition_test_needs_update(c);
222 case CONDITION_FIRST_BOOT:
223 return condition_test_first_boot(c);
229 assert_not_reached("Invalid condition type.");
233 bool condition_test_list(const char *unit, Condition *first) {
237 /* If the condition list is empty, then it is true */
241 /* Otherwise, if all of the non-trigger conditions apply and
242 * if any of the trigger conditions apply (unless there are
243 * none) we return true */
244 LIST_FOREACH(conditions, c, first) {
247 r = condition_test(c);
249 log_warning_unit(unit,
250 "Couldn't determine result for %s=%s%s%s for %s, assuming failed: %s",
251 condition_type_to_string(c->type),
252 c->trigger ? "|" : "",
253 c->negate ? "!" : "",
259 "%s=%s%s%s %s for %s.",
260 condition_type_to_string(c->type),
261 c->trigger ? "|" : "",
262 c->negate ? "!" : "",
264 r > 0 ? "succeeded" : "failed",
267 c->state = r > 0 ? CONDITION_STATE_SUCCEEDED : CONDITION_STATE_FAILED;
269 if (!c->trigger && r <= 0)
272 if (c->trigger && triggered <= 0)
276 return triggered != 0;