chiark / gitweb /
condition: minor modernizations
[elogind.git] / src / core / condition.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/capability.h>
27 #include <sys/statvfs.h>
28 #include <fnmatch.h>
29
30 #include "sd-id128.h"
31 #include "util.h"
32 #include "condition.h"
33 #include "virt.h"
34 #include "path-util.h"
35 #include "fileio.h"
36 #include "unit.h"
37 #include "smack-util.h"
38 #include "apparmor-util.h"
39 #include "ima-util.h"
40 #include "selinux-util.h"
41
42 static bool condition_test_security(Condition *c) {
43         assert(c);
44         assert(c->parameter);
45         assert(c->type == CONDITION_SECURITY);
46
47         if (streq(c->parameter, "selinux"))
48                 return use_selinux() == !c->negate;
49         if (streq(c->parameter, "apparmor"))
50                 return use_apparmor() == !c->negate;
51         if (streq(c->parameter, "ima"))
52                 return use_ima() == !c->negate;
53         if (streq(c->parameter, "smack"))
54                 return use_smack() == !c->negate;
55
56         return c->negate;
57 }
58
59 static bool condition_test_capability(Condition *c) {
60         _cleanup_fclose_ FILE *f = NULL;
61         cap_value_t value;
62         char line[LINE_MAX];
63         unsigned long long capabilities = -1;
64
65         assert(c);
66         assert(c->parameter);
67         assert(c->type == CONDITION_CAPABILITY);
68
69         /* If it's an invalid capability, we don't have it */
70
71         if (cap_from_name(c->parameter, &value) < 0)
72                 return c->negate;
73
74         /* If it's a valid capability we default to assume
75          * that we have it */
76
77         f = fopen("/proc/self/status", "re");
78         if (!f)
79                 return !c->negate;
80
81         while (fgets(line, sizeof(line), f)) {
82                 truncate_nl(line);
83
84                 if (startswith(line, "CapBnd:")) {
85                         (void) sscanf(line+7, "%llx", &capabilities);
86                         break;
87                 }
88         }
89
90         return !!(capabilities & (1ULL << value)) == !c->negate;
91 }
92
93 static bool condition_test(Condition *c) {
94         assert(c);
95
96         switch(c->type) {
97
98         case CONDITION_PATH_EXISTS:
99                 return (access(c->parameter, F_OK) >= 0) == !c->negate;
100
101         case CONDITION_PATH_EXISTS_GLOB:
102                 return (glob_exists(c->parameter) > 0) == !c->negate;
103
104         case CONDITION_PATH_IS_DIRECTORY: {
105                 struct stat st;
106
107                 if (stat(c->parameter, &st) < 0)
108                         return c->negate;
109                 return S_ISDIR(st.st_mode) == !c->negate;
110         }
111
112         case CONDITION_PATH_IS_SYMBOLIC_LINK: {
113                 struct stat st;
114
115                 if (lstat(c->parameter, &st) < 0)
116                         return c->negate;
117                 return S_ISLNK(st.st_mode) == !c->negate;
118         }
119
120         case CONDITION_PATH_IS_MOUNT_POINT:
121                 return (path_is_mount_point(c->parameter, true) > 0) == !c->negate;
122
123         case CONDITION_PATH_IS_READ_WRITE:
124                 return (path_is_read_only_fs(c->parameter) > 0) == c->negate;
125
126         case CONDITION_DIRECTORY_NOT_EMPTY: {
127                 int k;
128
129                 k = dir_is_empty(c->parameter);
130                 return !(k == -ENOENT || k > 0) == !c->negate;
131         }
132
133         case CONDITION_FILE_NOT_EMPTY: {
134                 struct stat st;
135
136                 if (stat(c->parameter, &st) < 0)
137                         return c->negate;
138
139                 return (S_ISREG(st.st_mode) && st.st_size > 0) == !c->negate;
140         }
141
142         case CONDITION_FILE_IS_EXECUTABLE: {
143                 struct stat st;
144
145                 if (stat(c->parameter, &st) < 0)
146                         return c->negate;
147
148                 return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate;
149         }
150
151         case CONDITION_KERNEL_COMMAND_LINE:
152                 return condition_test_kernel_command_line(c);
153
154         case CONDITION_VIRTUALIZATION:
155                 return condition_test_virtualization(c);
156
157         case CONDITION_SECURITY:
158                 return condition_test_security(c);
159
160         case CONDITION_CAPABILITY:
161                 return condition_test_capability(c);
162
163         case CONDITION_HOST:
164                 return condition_test_host(c);
165
166         case CONDITION_AC_POWER:
167                 return condition_test_ac_power(c);
168
169         case CONDITION_ARCHITECTURE:
170                 return condition_test_architecture(c);
171
172         case CONDITION_NULL:
173                 return !c->negate;
174
175         default:
176                 assert_not_reached("Invalid condition type.");
177         }
178 }
179
180 bool condition_test_list(const char *unit, Condition *first) {
181         Condition *c;
182         int triggered = -1;
183
184         /* If the condition list is empty, then it is true */
185         if (!first)
186                 return true;
187
188         /* Otherwise, if all of the non-trigger conditions apply and
189          * if any of the trigger conditions apply (unless there are
190          * none) we return true */
191         LIST_FOREACH(conditions, c, first) {
192                 bool b;
193
194                 b = condition_test(c);
195                 if (unit)
196                         log_debug_unit(unit,
197                                        "%s=%s%s%s %s for %s.",
198                                        condition_type_to_string(c->type),
199                                        c->trigger ? "|" : "",
200                                        c->negate ? "!" : "",
201                                        c->parameter,
202                                        b ? "succeeded" : "failed",
203                                        unit);
204                 c->state = b ? 1 : -1;
205
206                 if (!c->trigger && !b)
207                         return false;
208
209                 if (c->trigger && triggered <= 0)
210                         triggered = b;
211         }
212
213         return triggered != 0;
214 }