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"
42 static bool condition_test_security(Condition *c) {
45 assert(c->type == CONDITION_SECURITY);
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;
59 static bool condition_test_capability(Condition *c) {
60 _cleanup_fclose_ FILE *f = NULL;
63 unsigned long long capabilities = -1;
67 assert(c->type == CONDITION_CAPABILITY);
69 /* If it's an invalid capability, we don't have it */
71 if (cap_from_name(c->parameter, &value) < 0)
74 /* If it's a valid capability we default to assume
77 f = fopen("/proc/self/status", "re");
81 while (fgets(line, sizeof(line), f)) {
84 if (startswith(line, "CapBnd:")) {
85 (void) sscanf(line+7, "%llx", &capabilities);
90 return !!(capabilities & (1ULL << value)) == !c->negate;
93 static bool condition_test_needs_update(Condition *c) {
95 struct stat usr, other;
99 assert(c->type == CONDITION_NEEDS_UPDATE);
101 /* If the file system is read-only we shouldn't suggest an update */
102 if (path_is_read_only_fs(c->parameter) > 0)
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
109 if (!path_is_absolute(c->parameter))
112 p = strappenda(c->parameter, "/.updated");
113 if (lstat(p, &other) < 0)
116 if (lstat("/usr/", &usr) < 0)
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;
123 static bool condition_test(Condition *c) {
128 case CONDITION_PATH_EXISTS:
129 return (access(c->parameter, F_OK) >= 0) == !c->negate;
131 case CONDITION_PATH_EXISTS_GLOB:
132 return (glob_exists(c->parameter) > 0) == !c->negate;
134 case CONDITION_PATH_IS_DIRECTORY: {
137 if (stat(c->parameter, &st) < 0)
139 return S_ISDIR(st.st_mode) == !c->negate;
142 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
145 if (lstat(c->parameter, &st) < 0)
147 return S_ISLNK(st.st_mode) == !c->negate;
150 case CONDITION_PATH_IS_MOUNT_POINT:
151 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
153 case CONDITION_PATH_IS_READ_WRITE:
154 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
156 case CONDITION_DIRECTORY_NOT_EMPTY: {
159 k = dir_is_empty(c->parameter);
160 return !(k == -ENOENT || k > 0) == !c->negate;
163 case CONDITION_FILE_NOT_EMPTY: {
166 if (stat(c->parameter, &st) < 0)
169 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
172 case CONDITION_FILE_IS_EXECUTABLE: {
175 if (stat(c->parameter, &st) < 0)
178 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
181 case CONDITION_KERNEL_COMMAND_LINE:
182 return condition_test_kernel_command_line(c);
184 case CONDITION_VIRTUALIZATION:
185 return condition_test_virtualization(c);
187 case CONDITION_SECURITY:
188 return condition_test_security(c);
190 case CONDITION_CAPABILITY:
191 return condition_test_capability(c);
194 return condition_test_host(c);
196 case CONDITION_AC_POWER:
197 return condition_test_ac_power(c);
199 case CONDITION_ARCHITECTURE:
200 return condition_test_architecture(c);
202 case CONDITION_NEEDS_UPDATE:
203 return condition_test_needs_update(c);
209 assert_not_reached("Invalid condition type.");
213 bool condition_test_list(const char *unit, Condition *first) {
217 /* If the condition list is empty, then it is true */
221 /* Otherwise, if all of the non-trigger conditions apply and
222 * if any of the trigger conditions apply (unless there are
223 * none) we return true */
224 LIST_FOREACH(conditions, c, first) {
227 b = condition_test(c);
230 "%s=%s%s%s %s for %s.",
231 condition_type_to_string(c->type),
232 c->trigger ? "|" : "",
233 c->negate ? "!" : "",
235 b ? "succeeded" : "failed",
237 c->state = b ? 1 : -1;
239 if (!c->trigger && !b)
242 if (c->trigger && triggered <= 0)
246 return triggered != 0;