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(Condition *c) {
98 case CONDITION_PATH_EXISTS:
99 return (access(c->parameter, F_OK) >= 0) == !c->negate;
101 case CONDITION_PATH_EXISTS_GLOB:
102 return (glob_exists(c->parameter) > 0) == !c->negate;
104 case CONDITION_PATH_IS_DIRECTORY: {
107 if (stat(c->parameter, &st) < 0)
109 return S_ISDIR(st.st_mode) == !c->negate;
112 case CONDITION_PATH_IS_SYMBOLIC_LINK: {
115 if (lstat(c->parameter, &st) < 0)
117 return S_ISLNK(st.st_mode) == !c->negate;
120 case CONDITION_PATH_IS_MOUNT_POINT:
121 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
123 case CONDITION_PATH_IS_READ_WRITE:
124 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
126 case CONDITION_DIRECTORY_NOT_EMPTY: {
129 k = dir_is_empty(c->parameter);
130 return !(k == -ENOENT || k > 0) == !c->negate;
133 case CONDITION_FILE_NOT_EMPTY: {
136 if (stat(c->parameter, &st) < 0)
139 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
142 case CONDITION_FILE_IS_EXECUTABLE: {
145 if (stat(c->parameter, &st) < 0)
148 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
151 case CONDITION_KERNEL_COMMAND_LINE:
152 return condition_test_kernel_command_line(c);
154 case CONDITION_VIRTUALIZATION:
155 return condition_test_virtualization(c);
157 case CONDITION_SECURITY:
158 return condition_test_security(c);
160 case CONDITION_CAPABILITY:
161 return condition_test_capability(c);
164 return condition_test_host(c);
166 case CONDITION_AC_POWER:
167 return condition_test_ac_power(c);
169 case CONDITION_ARCHITECTURE:
170 return condition_test_architecture(c);
176 assert_not_reached("Invalid condition type.");
180 bool condition_test_list(const char *unit, Condition *first) {
184 /* If the condition list is empty, then it is true */
188 /* Otherwise, if all of the non-trigger conditions apply and
189 * if any of the trigger conditions apply (unless there are
190 * none) we return true */
191 LIST_FOREACH(conditions, c, first) {
194 b = condition_test(c);
197 "%s=%s%s%s %s for %s.",
198 condition_type_to_string(c->type),
199 c->trigger ? "|" : "",
200 c->negate ? "!" : "",
202 b ? "succeeded" : "failed",
204 c->state = b ? 1 : -1;
206 if (!c->trigger && !b)
209 if (c->trigger && triggered <= 0)
213 return triggered != 0;