]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path.c
Merge pull request #8617 from keszybz/tmpfiles-relax
[thirdparty/systemd.git] / src / test / test-path.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Ronny Chevalier
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <stdbool.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25
26 #include "alloc-util.h"
27 #include "fd-util.h"
28 #include "fs-util.h"
29 #include "macro.h"
30 #include "manager.h"
31 #include "mkdir.h"
32 #include "rm-rf.h"
33 #include "string-util.h"
34 #include "strv.h"
35 #include "test-helper.h"
36 #include "tests.h"
37 #include "unit.h"
38 #include "util.h"
39
40 typedef void (*test_function_t)(Manager *m);
41
42 static int setup_test(Manager **m) {
43 char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
44 "directorynotempty", "makedirectory");
45 char **test_path;
46 Manager *tmp = NULL;
47 int r;
48
49 assert_se(m);
50
51 r = enter_cgroup_subroot();
52 if (r == -ENOMEDIUM) {
53 log_notice_errno(r, "Skipping test: cgroupfs not available");
54 return -EXIT_TEST_SKIP;
55 }
56
57 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
58 if (MANAGER_SKIP_TEST(r)) {
59 log_notice_errno(r, "Skipping test: manager_new: %m");
60 return -EXIT_TEST_SKIP;
61 }
62 assert_se(r >= 0);
63 assert_se(manager_startup(tmp, NULL, NULL) >= 0);
64
65 STRV_FOREACH(test_path, tests_path) {
66 _cleanup_free_ char *p = NULL;
67
68 p = strjoin("/tmp/test-path_", *test_path);
69 assert_se(p);
70
71 (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
72 }
73
74 *m = tmp;
75
76 return 0;
77 }
78
79 static void shutdown_test(Manager *m) {
80 assert_se(m);
81
82 manager_free(m);
83 }
84
85 static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, const char *service_name) {
86 _cleanup_free_ char *tmp = NULL;
87 Unit *service_unit = NULL;
88 Service *service = NULL;
89 usec_t ts;
90 usec_t timeout = 2 * USEC_PER_SEC;
91
92 assert_se(m);
93 assert_se(unit);
94 assert_se(test_path);
95
96 if (!service_name) {
97 assert_se(tmp = strreplace(unit->id, ".path", ".service"));
98 service_unit = manager_get_unit(m, tmp);
99 } else
100 service_unit = manager_get_unit(m, service_name);
101 assert_se(service_unit);
102 service = SERVICE(service_unit);
103
104 ts = now(CLOCK_MONOTONIC);
105 /* We process events until the service related to the path has been successfully started */
106 while (service->result != SERVICE_SUCCESS || service->state != SERVICE_START) {
107 usec_t n;
108 int r;
109
110 r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
111 assert_se(r >= 0);
112
113 printf("%s: state = %s; result = %s \n",
114 service_unit->id,
115 service_state_to_string(service->state),
116 service_result_to_string(service->result));
117
118
119 /* But we timeout if the service has not been started in the allocated time */
120 n = now(CLOCK_MONOTONIC);
121 if (ts + timeout < n) {
122 log_error("Test timeout when testing %s", unit->id);
123 exit(EXIT_FAILURE);
124 }
125 }
126
127 assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
128 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
129 }
130
131 static void test_path_exists(Manager *m) {
132 const char *test_path = "/tmp/test-path_exists";
133 Unit *unit = NULL;
134
135 assert_se(m);
136
137 assert_se(manager_load_unit(m, "path-exists.path", NULL, NULL, &unit) >= 0);
138 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
139
140 assert_se(touch(test_path) >= 0);
141
142 check_stop_unlink(m, unit, test_path, NULL);
143 }
144
145 static void test_path_existsglob(Manager *m) {
146 const char *test_path = "/tmp/test-path_existsglobFOOBAR";
147 Unit *unit = NULL;
148
149 assert_se(m);
150 assert_se(manager_load_unit(m, "path-existsglob.path", NULL, NULL, &unit) >= 0);
151 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
152
153 assert_se(touch(test_path) >= 0);
154
155 check_stop_unlink(m, unit, test_path, NULL);
156 }
157
158 static void test_path_changed(Manager *m) {
159 const char *test_path = "/tmp/test-path_changed";
160 FILE *f;
161 Unit *unit = NULL;
162
163 assert_se(m);
164
165 assert_se(touch(test_path) >= 0);
166
167 assert_se(manager_load_unit(m, "path-changed.path", NULL, NULL, &unit) >= 0);
168 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
169
170 f = fopen(test_path, "w");
171 assert_se(f);
172 fclose(f);
173
174 check_stop_unlink(m, unit, test_path, NULL);
175 }
176
177 static void test_path_modified(Manager *m) {
178 _cleanup_fclose_ FILE *f = NULL;
179 const char *test_path = "/tmp/test-path_modified";
180 Unit *unit = NULL;
181
182 assert_se(m);
183
184 assert_se(touch(test_path) >= 0);
185
186 assert_se(manager_load_unit(m, "path-modified.path", NULL, NULL, &unit) >= 0);
187 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
188
189 f = fopen(test_path, "w");
190 assert_se(f);
191 fputs("test", f);
192
193 check_stop_unlink(m, unit, test_path, NULL);
194 }
195
196 static void test_path_unit(Manager *m) {
197 const char *test_path = "/tmp/test-path_unit";
198 Unit *unit = NULL;
199
200 assert_se(m);
201
202 assert_se(manager_load_unit(m, "path-unit.path", NULL, NULL, &unit) >= 0);
203 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
204
205 assert_se(touch(test_path) >= 0);
206
207 check_stop_unlink(m, unit, test_path, "path-mycustomunit.service");
208 }
209
210 static void test_path_directorynotempty(Manager *m) {
211 const char *test_path = "/tmp/test-path_directorynotempty/";
212 Unit *unit = NULL;
213
214 assert_se(m);
215
216 assert_se(access(test_path, F_OK) < 0);
217
218 assert_se(manager_load_unit(m, "path-directorynotempty.path", NULL, NULL, &unit) >= 0);
219 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
220
221 /* MakeDirectory default to no */
222 assert_se(access(test_path, F_OK) < 0);
223
224 assert_se(mkdir_p(test_path, 0755) >= 0);
225 assert_se(touch(strjoina(test_path, "test_file")) >= 0);
226
227 check_stop_unlink(m, unit, test_path, NULL);
228 }
229
230 static void test_path_makedirectory_directorymode(Manager *m) {
231 const char *test_path = "/tmp/test-path_makedirectory/";
232 Unit *unit = NULL;
233 struct stat s;
234
235 assert_se(m);
236
237 assert_se(access(test_path, F_OK) < 0);
238
239 assert_se(manager_load_unit(m, "path-makedirectory.path", NULL, NULL, &unit) >= 0);
240 assert_se(UNIT_VTABLE(unit)->start(unit) >= 0);
241
242 /* Check if the directory has been created */
243 assert_se(access(test_path, F_OK) >= 0);
244
245 /* Check the mode we specified with DirectoryMode=0744 */
246 assert_se(stat(test_path, &s) >= 0);
247 assert_se((s.st_mode & S_IRWXU) == 0700);
248 assert_se((s.st_mode & S_IRWXG) == 0040);
249 assert_se((s.st_mode & S_IRWXO) == 0004);
250
251 assert_se(UNIT_VTABLE(unit)->stop(unit) >= 0);
252 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
253 }
254
255 int main(int argc, char *argv[]) {
256 static const test_function_t tests[] = {
257 test_path_exists,
258 test_path_existsglob,
259 test_path_changed,
260 test_path_modified,
261 test_path_unit,
262 test_path_directorynotempty,
263 test_path_makedirectory_directorymode,
264 NULL,
265 };
266
267 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
268 const test_function_t *test = NULL;
269 Manager *m = NULL;
270
271 umask(022);
272
273 log_parse_environment();
274 log_open();
275
276 assert_se(set_unit_path(get_testdata_dir("/test-path")) >= 0);
277 assert_se(runtime_dir = setup_fake_runtime_dir());
278
279 for (test = tests; test && *test; test++) {
280 int r;
281
282 /* We create a clean environment for each test */
283 r = setup_test(&m);
284 if (r < 0)
285 return -r;
286
287 (*test)(m);
288
289 shutdown_test(m);
290 }
291
292 return 0;
293 }