chiark / gitweb /
condition: split out most of condition handling into libsystemd-shard
[elogind.git] / src / core / condition.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 Lennart Poettering
7
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.
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
16   Lesser General Public License for more details.
17
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/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/capability.h>
27 #include <sys/statvfs.h>
28 #include <fnmatch.h>
29
30 #include <systemd/sd-id128.h>
31 #include "util.h"
32 #include "condition.h"
33 #include "virt.h"
34 #include "path-util.h"
35 #include "fileio.h"
36 #include "unit.h"
37 #include "smack-util.h"
38 #include "apparmor-util.h"
39 #include "ima-util.h"
40 #include "selinux-util.h"
41
42 static 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;
55         return c->negate;
56 }
57
58 static bool condition_test_capability(Condition *c) {
59         cap_value_t value;
60         FILE *f;
61         char line[LINE_MAX];
62         unsigned long long capabilities = (unsigned long long) -1;
63
64         assert(c);
65         assert(c->parameter);
66         assert(c->type == CONDITION_CAPABILITY);
67
68         /* If it's an invalid capability, we don't have it */
69
70         if (cap_from_name(c->parameter, &value) < 0)
71                 return c->negate;
72
73         /* If it's a valid capability we default to assume
74          * that we have it */
75
76         f = fopen("/proc/self/status", "re");
77         if (!f)
78                 return !c->negate;
79
80         while (fgets(line, sizeof(line), f)) {
81                 truncate_nl(line);
82
83                 if (startswith(line, "CapBnd:")) {
84                         (void) sscanf(line+7, "%llx", &capabilities);
85                         break;
86                 }
87         }
88
89         fclose(f);
90
91         return !!(capabilities & (1ULL << value)) == !c->negate;
92 }
93
94 static bool condition_test(Condition *c) {
95         assert(c);
96
97         switch(c->type) {
98
99         case CONDITION_PATH_EXISTS:
100                 return (access(c->parameter, F_OK) >= 0) == !c->negate;
101
102         case CONDITION_PATH_EXISTS_GLOB:
103                 return (glob_exists(c->parameter) > 0) == !c->negate;
104
105         case CONDITION_PATH_IS_DIRECTORY: {
106                 struct stat st;
107
108                 if (stat(c->parameter, &st) < 0)
109                         return c->negate;
110                 return S_ISDIR(st.st_mode) == !c->negate;
111         }
112
113         case CONDITION_PATH_IS_SYMBOLIC_LINK: {
114                 struct stat st;
115
116                 if (lstat(c->parameter, &st) < 0)
117                         return c->negate;
118                 return S_ISLNK(st.st_mode) == !c->negate;
119         }
120
121         case CONDITION_PATH_IS_MOUNT_POINT:
122                 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
123
124         case CONDITION_PATH_IS_READ_WRITE:
125                 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
126
127         case CONDITION_DIRECTORY_NOT_EMPTY: {
128                 int k;
129
130                 k = dir_is_empty(c->parameter);
131                 return !(k == -ENOENT || k > 0) == !c->negate;
132         }
133
134         case CONDITION_FILE_NOT_EMPTY: {
135                 struct stat st;
136
137                 if (stat(c->parameter, &st) < 0)
138                         return c->negate;
139
140                 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
141         }
142
143         case CONDITION_FILE_IS_EXECUTABLE: {
144                 struct stat st;
145
146                 if (stat(c->parameter, &st) < 0)
147                         return c->negate;
148
149                 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
150         }
151
152         case CONDITION_KERNEL_COMMAND_LINE:
153                 return condition_test_kernel_command_line(c);
154
155         case CONDITION_VIRTUALIZATION:
156                 return condition_test_virtualization(c);
157
158         case CONDITION_SECURITY:
159                 return condition_test_security(c);
160
161         case CONDITION_CAPABILITY:
162                 return condition_test_capability(c);
163
164         case CONDITION_HOST:
165                 return condition_test_host(c);
166
167         case CONDITION_AC_POWER:
168                 return condition_test_ac_power(c);
169
170         case CONDITION_NULL:
171                 return !c->negate;
172
173         default:
174                 assert_not_reached("Invalid condition type.");
175         }
176 }
177
178 bool condition_test_list(const char *unit, Condition *first) {
179         Condition *c;
180         int triggered = -1;
181
182         /* If the condition list is empty, then it is true */
183         if (!first)
184                 return true;
185
186         /* Otherwise, if all of the non-trigger conditions apply and
187          * if any of the trigger conditions apply (unless there are
188          * none) we return true */
189         LIST_FOREACH(conditions, c, first) {
190                 bool b;
191
192                 b = condition_test(c);
193                 if (unit)
194                         log_debug_unit(unit,
195                                        "%s=%s%s%s %s for %s.",
196                                        condition_type_to_string(c->type),
197                                        c->trigger ? "|" : "",
198                                        c->negate ? "!" : "",
199                                        c->parameter,
200                                        b ? "succeeded" : "failed",
201                                        unit);
202                 c->state = b ? 1 : -1;
203
204                 if (!c->trigger && !b)
205                         return false;
206
207                 if (c->trigger && triggered <= 0)
208                         triggered = b;
209         }
210
211         return triggered != 0;
212 }