chiark / gitweb /
33752c8f9104ed5a904e83a73e8a1336ccbe2c95
[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 int 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                 return 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 r;
102                 if (r == 0)
103                         return c->negate;
104
105                 if (equal)
106                         found = streq(word, c->parameter);
107                 else {
108                         const char *f;
109
110                         f = startswith(word, c->parameter);
111                         found = f && (*f == '=' || *f == 0);
112                 }
113
114                 if (found)
115                         return !c->negate;
116         }
117
118         return c->negate;
119 }
120
121 int condition_test_virtualization(Condition *c) {
122         int b, v;
123         const char *id;
124
125         assert(c);
126         assert(c->parameter);
127         assert(c->type == CONDITION_VIRTUALIZATION);
128
129         v = detect_virtualization(&id);
130         if (v < 0)
131                 return v;
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 int condition_test_architecture(Condition *c) {
154         int 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 a;
163
164         if (streq(c->parameter, "native"))
165                 b = native_architecture();
166         else
167                 b = architecture_from_string(c->parameter);
168         if (b < 0)
169                 return b;
170
171         return (a == b) == !c->negate;
172 }
173
174 int condition_test_host(Condition *c) {
175         _cleanup_free_ char *h = NULL;
176         sd_id128_t x, y;
177         int r;
178
179         assert(c);
180         assert(c->parameter);
181         assert(c->type == CONDITION_HOST);
182
183         if (sd_id128_from_string(c->parameter, &x) >= 0) {
184
185                 r = sd_id128_get_machine(&y);
186                 if (r < 0)
187                         return r;
188
189                 return sd_id128_equal(x, y) == !c->negate;
190         }
191
192         h = gethostname_malloc();
193         if (!h)
194                 return -ENOMEM;
195
196         return (fnmatch(c->parameter, h, FNM_CASEFOLD) == 0) == !c->negate;
197 }
198
199 int condition_test_ac_power(Condition *c) {
200         int r;
201
202         assert(c);
203         assert(c->parameter);
204         assert(c->type == CONDITION_AC_POWER);
205
206         r = parse_boolean(c->parameter);
207         if (r < 0)
208                 return r;
209
210         return ((on_ac_power() != 0) == !!r) == !c->negate;
211 }
212
213 void condition_dump(Condition *c, FILE *f, const char *prefix) {
214         assert(c);
215         assert(f);
216
217         if (!prefix)
218                 prefix = "";
219
220         fprintf(f,
221                 "%s\t%s: %s%s%s %s\n",
222                 prefix,
223                 condition_type_to_string(c->type),
224                 c->trigger ? "|" : "",
225                 c->negate ? "!" : "",
226                 c->parameter,
227                 CONDITION_STATE_IS_FAILED(c->state) ? "failed" : CONDITION_STATE_IS_SUCCEEDED(c->state) ? "succeeded" : "untested");
228 }
229
230 void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
231         Condition *c;
232
233         LIST_FOREACH(conditions, c, first)
234                 condition_dump(c, f, prefix);
235 }
236
237 static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
238         [CONDITION_PATH_EXISTS] = "ConditionPathExists",
239         [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob",
240         [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
241         [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink",
242         [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint",
243         [CONDITION_PATH_IS_READ_WRITE] = "ConditionPathIsReadWrite",
244         [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
245         [CONDITION_FILE_NOT_EMPTY] = "ConditionFileNotEmpty",
246         [CONDITION_FILE_IS_EXECUTABLE] = "ConditionFileIsExecutable",
247         [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
248         [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
249         [CONDITION_SECURITY] = "ConditionSecurity",
250         [CONDITION_CAPABILITY] = "ConditionCapability",
251         [CONDITION_HOST] = "ConditionHost",
252         [CONDITION_AC_POWER] = "ConditionACPower",
253         [CONDITION_ARCHITECTURE] = "ConditionArchitecture",
254         [CONDITION_NEEDS_UPDATE] = "ConditionNeedsUpdate",
255         [CONDITION_FIRST_BOOT] = "ConditionFirstBoot",
256         [CONDITION_NULL] = "ConditionNull"
257 };
258
259 DEFINE_STRING_TABLE_LOOKUP(condition_type, ConditionType);