chiark / gitweb /
update TODO
[elogind.git] / src / shared / condition-util.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/statvfs.h>
27 #include <fnmatch.h>
28
29 #include <systemd/sd-id128.h>
30 #include "util.h"
31 #include "condition-util.h"
32 #include "virt.h"
33 #include "path-util.h"
34 #include "fileio.h"
35 #include "unit.h"
36 #include "architecture.h"
37
38 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
39         Condition *c;
40
41         assert(type < _CONDITION_TYPE_MAX);
42
43         c = new0(Condition, 1);
44         if (!c)
45                 return NULL;
46
47         c->type = type;
48         c->trigger = trigger;
49         c->negate = negate;
50
51         if (parameter) {
52                 c->parameter = strdup(parameter);
53                 if (!c->parameter) {
54                         free(c);
55                         return NULL;
56                 }
57         }
58
59         return c;
60 }
61
62 void condition_free(Condition *c) {
63         assert(c);
64
65         free(c->parameter);
66         free(c);
67 }
68
69 void condition_free_list(Condition *first) {
70         Condition *c, *n;
71
72         LIST_FOREACH_SAFE(conditions, c, n, first)
73                 condition_free(c);
74 }
75
76 bool condition_test_kernel_command_line(Condition *c) {
77         char *line, *w, *state, *word = NULL;
78         bool equal;
79         int r;
80         size_t l, pl;
81         bool found = false;
82
83         assert(c);
84         assert(c->parameter);
85         assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
86
87         r = proc_cmdline(&line);
88         if (r < 0)
89                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
90         if (r <= 0)
91                 return c->negate;
92
93         equal = !!strchr(c->parameter, '=');
94         pl = strlen(c->parameter);
95
96         FOREACH_WORD_QUOTED(w, l, line, state) {
97
98                 free(word);
99                 word = strndup(w, l);
100                 if (!word)
101                         break;
102
103                 if (equal) {
104                         if (streq(word, c->parameter)) {
105                                 found = true;
106                                 break;
107                         }
108                 } else {
109                         if (startswith(word, c->parameter) && (word[pl] == '=' || word[pl] == 0)) {
110                                 found = true;
111                                 break;
112                         }
113                 }
114
115         }
116
117         free(word);
118         free(line);
119
120         return found == !c->negate;
121 }
122
123 bool condition_test_virtualization(Condition *c) {
124         int b;
125         Virtualization v;
126         const char *id;
127
128         assert(c);
129         assert(c->parameter);
130         assert(c->type == CONDITION_VIRTUALIZATION);
131
132         v = detect_virtualization(&id);
133         if (v < 0) {
134                 log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
135                 return c->negate;
136         }
137
138         /* First, compare with yes/no */
139         b = parse_boolean(c->parameter);
140
141         if (v > 0 && b > 0)
142                 return !c->negate;
143
144         if (v == 0 && b == 0)
145                 return !c->negate;
146
147         /* Then, compare categorization */
148         if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm"))
149                 return !c->negate;
150
151         if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container"))
152                 return !c->negate;
153
154         /* Finally compare id */
155         return (v > 0 && streq(c->parameter, id)) == !c->negate;
156 }
157
158 bool condition_test_architecture(Condition *c) {
159         Architecture a, b;
160
161         assert(c);
162         assert(c->parameter);
163         assert(c->type == CONDITION_ARCHITECTURE);
164
165         a = uname_architecture();
166         if (a < 0)
167                 return c->negate;
168
169         if (streq(c->parameter, "native"))
170                 b = native_architecture();
171         else
172                 b = architecture_from_string(c->parameter);
173
174         if (b < 0)
175                 return c->negate;
176
177         return (a == b) == !c->negate;
178 }
179
180 bool condition_test_host(Condition *c) {
181         sd_id128_t x, y;
182         char *h;
183         int r;
184         bool b;
185
186         assert(c);
187         assert(c->parameter);
188         assert(c->type == CONDITION_HOST);
189
190         if (sd_id128_from_string(c->parameter, &x) >= 0) {
191
192                 r = sd_id128_get_machine(&y);
193                 if (r < 0)
194                         return c->negate;
195
196                 return sd_id128_equal(x, y) == !c->negate;
197         }
198
199         h = gethostname_malloc();
200         if (!h)
201                 return c->negate;
202
203         b = fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
204         free(h);
205
206         return b == !c->negate;
207 }
208
209 bool condition_test_ac_power(Condition *c) {
210         int r;
211
212         assert(c);
213         assert(c->parameter);
214         assert(c->type == CONDITION_AC_POWER);
215
216         r = parse_boolean(c->parameter);
217         if (r < 0)
218                 return !c->negate;
219
220         return ((on_ac_power() != 0) == !!r) == !c->negate;
221 }
222
223 void condition_dump(Condition *c, FILE *f, const char *prefix) {
224         assert(c);
225         assert(f);
226
227         if (!prefix)
228                 prefix = "";
229
230         fprintf(f,
231                 "%s\t%s: %s%s%s %s\n",
232                 prefix,
233                 condition_type_to_string(c->type),
234                 c->trigger ? "|" : "",
235                 c->negate ? "!" : "",
236                 c->parameter,
237                 c->state < 0 ? "failed" : c->state > 0 ? "succeeded" : "untested");
238 }
239
240 void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
241         Condition *c;
242
243         LIST_FOREACH(conditions, c, first)
244                 condition_dump(c, f, prefix);
245 }
246
247 static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
248         [CONDITION_PATH_EXISTS] = "ConditionPathExists",
249         [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
250         [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
251         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
252         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
253         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
254         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
255         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
256         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
257         [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
258         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
259         [CONDITION_SECURITY] = "ConditionSecurity",
260         [CONDITION_CAPABILITY] = "ConditionCapability",
261         [CONDITION_HOST] = "ConditionHost",
262         [CONDITION_AC_POWER] = "ConditionACPower",
263         [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
264         [CONDITION_NULL] = "ConditionNull"
265 };
266
267 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);