chiark / gitweb /
core: add new ConditionNeedsUpdate= unit condition
[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, v;
125         const char *id;
126
127         assert(c);
128         assert(c->parameter);
129         assert(c->type == CONDITION_VIRTUALIZATION);
130
131         v = detect_virtualization(&id);
132         if (v < 0) {
133                 log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v));
134                 return c->negate;
135         }
136
137         /* First, compare with yes/no */
138         b = parse_boolean(c->parameter);
139
140         if (v > 0 && b > 0)
141                 return !c->negate;
142
143         if (v == 0 && b == 0)
144                 return !c->negate;
145
146         /* Then, compare categorization */
147         if (v == VIRTUALIZATION_VM && streq(c->parameter, "vm"))
148                 return !c->negate;
149
150         if (v == VIRTUALIZATION_CONTAINER && streq(c->parameter, "container"))
151                 return !c->negate;
152
153         /* Finally compare id */
154         return (v > 0 && streq(c->parameter, id)) == !c->negate;
155 }
156
157 bool condition_test_architecture(Condition *c) {
158         Architecture a, b;
159
160         assert(c);
161         assert(c->parameter);
162         assert(c->type == CONDITION_ARCHITECTURE);
163
164         a = uname_architecture();
165         if (a < 0)
166                 return c->negate;
167
168         if (streq(c->parameter, "native"))
169                 b = native_architecture();
170         else
171                 b = architecture_from_string(c->parameter);
172
173         if (b < 0)
174                 return c->negate;
175
176         return (a == b) == !c->negate;
177 }
178
179 bool condition_test_host(Condition *c) {
180         _cleanup_free_ char *h = NULL;
181         sd_id128_t x, y;
182         int r;
183
184         assert(c);
185         assert(c->parameter);
186         assert(c->type == CONDITION_HOST);
187
188         if (sd_id128_from_string(c->parameter, &x) >= 0) {
189
190                 r = sd_id128_get_machine(&y);
191                 if (r < 0)
192                         return c->negate;
193
194                 return sd_id128_equal(x, y) == !c->negate;
195         }
196
197         h = gethostname_malloc();
198         if (!h)
199                 return c->negate;
200
201         return (fnmatch(c->parameter, h, FNM_CASEFOLD) == 0) == !c->negate;
202 }
203
204 bool condition_test_ac_power(Condition *c) {
205         int r;
206
207         assert(c);
208         assert(c->parameter);
209         assert(c->type == CONDITION_AC_POWER);
210
211         r = parse_boolean(c->parameter);
212         if (r < 0)
213                 return !c->negate;
214
215         return ((on_ac_power() != 0) == !!r) == !c->negate;
216 }
217
218 void condition_dump(Condition *c, FILE *f, const char *prefix) {
219         assert(c);
220         assert(f);
221
222         if (!prefix)
223                 prefix = "";
224
225         fprintf(f,
226                 "%s\t%s: %s%s%s %s\n",
227                 prefix,
228                 condition_type_to_string(c->type),
229                 c->trigger ? "|" : "",
230                 c->negate ? "!" : "",
231                 c->parameter,
232                 c->state < 0 ? "failed" : c->state > 0 ? "succeeded" : "untested");
233 }
234
235 void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
236         Condition *c;
237
238         LIST_FOREACH(conditions, c, first)
239                 condition_dump(c, f, prefix);
240 }
241
242 static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
243         [CONDITION_PATH_EXISTS] = "ConditionPathExists",
244         [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
245         [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
246         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
247         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
248         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
249         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
250         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
251         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
252         [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
253         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
254         [CONDITION_SECURITY] = "ConditionSecurity",
255         [CONDITION_CAPABILITY] = "ConditionCapability",
256         [CONDITION_HOST] = "ConditionHost",
257         [CONDITION_AC_POWER] = "ConditionACPower",
258         [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
259         [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
260         [CONDITION_NULL] = "ConditionNull"
261 };
262
263 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);