chiark / gitweb /
condition: split out most of condition handling into libsystemd-shard
[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
37 Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
38         Condition *c;
39
40         assert(type < _CONDITION_TYPE_MAX);
41
42         c = new0(Condition, 1);
43         if (!c)
44                 return NULL;
45
46         c->type = type;
47         c->trigger = trigger;
48         c->negate = negate;
49
50         if (parameter) {
51                 c->parameter = strdup(parameter);
52                 if (!c->parameter) {
53                         free(c);
54                         return NULL;
55                 }
56         }
57
58         return c;
59 }
60
61 void condition_free(Condition *c) {
62         assert(c);
63
64         free(c->parameter);
65         free(c);
66 }
67
68 void condition_free_list(Condition *first) {
69         Condition *c, *n;
70
71         LIST_FOREACH_SAFE(conditions, c, n, first)
72                 condition_free(c);
73 }
74
75 bool condition_test_kernel_command_line(Condition *c) {
76         char *line, *w, *state, *word = NULL;
77         bool equal;
78         int r;
79         size_t l, pl;
80         bool found = false;
81
82         assert(c);
83         assert(c->parameter);
84         assert(c->type == CONDITION_KERNEL_COMMAND_LINE);
85
86         r = proc_cmdline(&line);
87         if (r < 0)
88                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
89         if (r <= 0)
90                 return c->negate;
91
92         equal = !!strchr(c->parameter, '=');
93         pl = strlen(c->parameter);
94
95         FOREACH_WORD_QUOTED(w, l, line, state) {
96
97                 free(word);
98                 word = strndup(w, l);
99                 if (!word)
100                         break;
101
102                 if (equal) {
103                         if (streq(word, c->parameter)) {
104                                 found = true;
105                                 break;
106                         }
107                 } else {
108                         if (startswith(word, c->parameter) && (word[pl] == '=' || word[pl] == 0)) {
109                                 found = true;
110                                 break;
111                         }
112                 }
113
114         }
115
116         free(word);
117         free(line);
118
119         return found == !c->negate;
120 }
121
122 bool condition_test_virtualization(Condition *c) {
123         int b;
124         Virtualization 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_host(Condition *c) {
158         sd_id128_t x, y;
159         char *h;
160         int r;
161         bool b;
162
163         assert(c);
164         assert(c->parameter);
165         assert(c->type == CONDITION_HOST);
166
167         if (sd_id128_from_string(c->parameter, &x) >= 0) {
168
169                 r = sd_id128_get_machine(&y);
170                 if (r < 0)
171                         return c->negate;
172
173                 return sd_id128_equal(x, y);
174         }
175
176         h = gethostname_malloc();
177         if (!h)
178                 return c->negate;
179
180         b = fnmatch(c->parameter, h, FNM_CASEFOLD) == 0;
181         free(h);
182
183         return b == !c->negate;
184 }
185
186 bool condition_test_ac_power(Condition *c) {
187         int r;
188
189         assert(c);
190         assert(c->parameter);
191         assert(c->type == CONDITION_AC_POWER);
192
193         r = parse_boolean(c->parameter);
194         if (r < 0)
195                 return !c->negate;
196
197         return ((on_ac_power() != 0) == !!r) == !c->negate;
198 }
199
200 void condition_dump(Condition *c, FILE *f, const char *prefix) {
201         assert(c);
202         assert(f);
203
204         if (!prefix)
205                 prefix = "";
206
207         fprintf(f,
208                 "%s\t%s: %s%s%s %s\n",
209                 prefix,
210                 condition_type_to_string(c->type),
211                 c->trigger ? "|" : "",
212                 c->negate ? "!" : "",
213                 c->parameter,
214                 c->state < 0 ? "failed" : c->state > 0 ? "succeeded" : "untested");
215 }
216
217 void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
218         Condition *c;
219
220         LIST_FOREACH(conditions, c, first)
221                 condition_dump(c, f, prefix);
222 }
223
224 static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
225         [CONDITION_PATH_EXISTS] = "ConditionPathExists",
226         [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
227         [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
228         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
229         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
230         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
231         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
232         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
233         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
234         [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
235         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
236         [CONDITION_SECURITY] = "ConditionSecurity",
237         [CONDITION_CAPABILITY] = "ConditionCapability",
238         [CONDITION_HOST] = "ConditionHost",
239         [CONDITION_AC_POWER] = "ConditionACPower",
240         [CONDITION_NULL] = "ConditionNull"
241 };
242
243 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);