chiark / gitweb /
gpt-auto-generator: print debug messages when we ignore a block device
[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_ARCHITECTURE:
171                 return condition_test_architecture(c);
172
173         case CONDITION_NULL:
174                 return !c->negate;
175
176         default:
177                 assert_not_reached("Invalid condition type.");
178         }
179 }
180
181 bool condition_test_list(const char *unit, Condition *first) {
182         Condition *c;
183         int triggered = -1;
184
185         /* If the condition list is empty, then it is true */
186         if (!first)
187                 return true;
188
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) {
193                 bool b;
194
195                 b = condition_test(c);
196                 if (unit)
197                         log_debug_unit(unit,
198                                        "%s=%s%s%s %s for %s.",
199                                        condition_type_to_string(c->type),
200                                        c->trigger ? "|" : "",
201                                        c->negate ? "!" : "",
202                                        c->parameter,
203                                        b ? "succeeded" : "failed",
204                                        unit);
205                 c->state = b ? 1 : -1;
206
207                 if (!c->trigger && !b)
208                         return false;
209
210                 if (c->trigger && triggered <= 0)
211                         triggered = b;
212         }
213
214         return triggered != 0;
215 }