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