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>
30 #include <systemd/sd-id128.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;
58 static bool condition_test_capability(Condition *c) {
62 unsigned long long capabilities = (unsigned long long) -1;
66 assert(c->type == CONDITION_CAPABILITY);
68 /* If it's an invalid capability, we don't have it */
70 if (cap_from_name(c->parameter, &value) < 0)
73 /* If it's a valid capability we default to assume
76 f = fopen("/proc/self/status", "re");
80 while (fgets(line, sizeof(line), f)) {
83 if (startswith(line, "CapBnd:")) {
84 (void) sscanf(line+7, "%llx", &capabilities);
91 return !!(capabilities & (1ULL << value)) == !c->negate;
94 static bool condition_test(Condition *c) {
99 case CONDITION_PATH_EXISTS:
100 return (access(c->parameter, F_OK) >= 0) == !c->negate;
102 case CONDITION_PATH_EXISTS_GLOB:
103 return (glob_exists(c->parameter) > 0) == !c->negate;
105 case CONDITION_PATH_IS_DIRECTORY: {
108 if (stat(c->parameter, &st) < 0)
110 return S_ISDIR(st.st_mode) == !c->negate;
113 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
116 if (lstat(c->parameter, &st) < 0)
118 return S_ISLNK(st.st_mode) == !c->negate;
121 case CONDITION_PATH_IS_MOUNT_POINT:
122 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
124 case CONDITION_PATH_IS_READ_WRITE:
125 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
127 case CONDITION_DIRECTORY_NOT_EMPTY: {
130 k = dir_is_empty(c->parameter);
131 return !(k == -ENOENT || k > 0) == !c->negate;
134 case CONDITION_FILE_NOT_EMPTY: {
137 if (stat(c->parameter, &st) < 0)
140 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
143 case CONDITION_FILE_IS_EXECUTABLE: {
146 if (stat(c->parameter, &st) < 0)
149 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
152 case CONDITION_KERNEL_COMMAND_LINE:
153 return condition_test_kernel_command_line(c);
155 case CONDITION_VIRTUALIZATION:
156 return condition_test_virtualization(c);
158 case CONDITION_SECURITY:
159 return condition_test_security(c);
161 case CONDITION_CAPABILITY:
162 return condition_test_capability(c);
165 return condition_test_host(c);
167 case CONDITION_AC_POWER:
168 return condition_test_ac_power(c);
170 case CONDITION_ARCHITECTURE:
171 return condition_test_architecture(c);
177 assert_not_reached("Invalid condition type.");
181 bool condition_test_list(const char *unit, Condition *first) {
185 /* If the condition list is empty, then it is true */
189 /* Otherwise, if all of the non-trigger conditions apply and
190 * if any of the trigger conditions apply (unless there are
191 * none) we return true */
192 LIST_FOREACH(conditions, c, first) {
195 b = condition_test(c);
198 "%s=%s%s%s %s for %s.",
199 condition_type_to_string(c->type),
200 c->trigger ? "|" : "",
201 c->negate ? "!" : "",
203 b ? "succeeded" : "failed",
205 c->state = b ? 1 : -1;
207 if (!c->trigger && !b)
210 if (c->trigger && triggered <= 0)
214 return triggered != 0;