]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path.c
e8844fd5ef4fc1178e92d269cdb9252f55192ac3
[thirdparty/systemd.git] / src / test / test-path.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <stdbool.h>
4 #include <stdio.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7
8 #include "alloc-util.h"
9 #include "all-units.h"
10 #include "fd-util.h"
11 #include "fs-util.h"
12 #include "macro.h"
13 #include "manager.h"
14 #include "mkdir.h"
15 #include "path-util.h"
16 #include "rm-rf.h"
17 #include "string-util.h"
18 #include "strv.h"
19 #include "tests.h"
20 #include "unit.h"
21 #include "util.h"
22
23 typedef void (*test_function_t)(Manager *m);
24
25 static int setup_test(Manager **m) {
26 char **tests_path = STRV_MAKE("exists", "existsglobFOOBAR", "changed", "modified", "unit",
27 "directorynotempty", "makedirectory");
28 char **test_path;
29 Manager *tmp = NULL;
30 int r;
31
32 assert_se(m);
33
34 r = enter_cgroup_subroot(NULL);
35 if (r == -ENOMEDIUM)
36 return log_tests_skipped("cgroupfs not available");
37
38 r = manager_new(UNIT_FILE_USER, MANAGER_TEST_RUN_BASIC, &tmp);
39 if (manager_errno_skip_test(r))
40 return log_tests_skipped_errno(r, "manager_new");
41 assert_se(r >= 0);
42 assert_se(manager_startup(tmp, NULL, NULL) >= 0);
43
44 STRV_FOREACH(test_path, tests_path) {
45 _cleanup_free_ char *p = NULL;
46
47 p = strjoin("/tmp/test-path_", *test_path);
48 assert_se(p);
49
50 (void) rm_rf(p, REMOVE_ROOT|REMOVE_PHYSICAL);
51 }
52
53 *m = tmp;
54
55 return 0;
56 }
57
58 static void shutdown_test(Manager *m) {
59 assert_se(m);
60
61 manager_free(m);
62 }
63
64 static Service *service_for_path(Manager *m, Path *path, const char *service_name) {
65 _cleanup_free_ char *tmp = NULL;
66 Unit *service_unit = NULL;
67
68 assert_se(m);
69 assert_se(path);
70
71 if (!service_name) {
72 assert_se(tmp = strreplace(UNIT(path)->id, ".path", ".service"));
73 service_unit = manager_get_unit(m, tmp);
74 } else
75 service_unit = manager_get_unit(m, service_name);
76 assert_se(service_unit);
77
78 return SERVICE(service_unit);
79 }
80
81 static void check_states(Manager *m, Path *path, Service *service, PathState path_state, ServiceState service_state) {
82 usec_t ts;
83 usec_t timeout = 2 * USEC_PER_SEC;
84
85 assert_se(m);
86 assert_se(service);
87
88 ts = now(CLOCK_MONOTONIC);
89
90 while (path->result != PATH_SUCCESS || service->result != SERVICE_SUCCESS ||
91 path->state != path_state || service->state != service_state) {
92 usec_t n;
93 int r;
94
95 r = sd_event_run(m->event, 100 * USEC_PER_MSEC);
96 assert_se(r >= 0);
97
98 printf("%s: state = %s; result = %s \n",
99 UNIT(path)->id,
100 path_state_to_string(path->state),
101 path_result_to_string(path->result));
102 printf("%s: state = %s; result = %s \n",
103 UNIT(service)->id,
104 service_state_to_string(service->state),
105 service_result_to_string(service->result));
106
107 n = now(CLOCK_MONOTONIC);
108 if (ts + timeout < n) {
109 log_error("Test timeout when testing %s", UNIT(path)->id);
110 exit(EXIT_FAILURE);
111 }
112 }
113 }
114
115 static void test_path_exists(Manager *m) {
116 const char *test_path = "/tmp/test-path_exists";
117 Unit *unit = NULL;
118 Path *path = NULL;
119 Service *service = NULL;
120
121 assert_se(m);
122
123 assert_se(manager_load_startable_unit_or_warn(m, "path-exists.path", NULL, &unit) >= 0);
124
125 path = PATH(unit);
126 service = service_for_path(m, path, NULL);
127
128 assert_se(unit_start(unit) >= 0);
129 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
130
131 assert_se(touch(test_path) >= 0);
132 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
133
134 /* Service restarts if file still exists */
135 assert_se(unit_stop(UNIT(service)) >= 0);
136 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
137
138 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
139 assert_se(unit_stop(UNIT(service)) >= 0);
140 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
141
142 assert_se(unit_stop(unit) >= 0);
143 }
144
145 static void test_path_existsglob(Manager *m) {
146 const char *test_path = "/tmp/test-path_existsglobFOOBAR";
147 Unit *unit = NULL;
148 Path *path = NULL;
149 Service *service = NULL;
150
151 assert_se(m);
152
153 assert_se(manager_load_startable_unit_or_warn(m, "path-existsglob.path", NULL, &unit) >= 0);
154
155 path = PATH(unit);
156 service = service_for_path(m, path, NULL);
157
158 assert_se(unit_start(unit) >= 0);
159 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
160
161 assert_se(touch(test_path) >= 0);
162 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
163
164 /* Service restarts if file still exists */
165 assert_se(unit_stop(UNIT(service)) >= 0);
166 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
167
168 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
169 assert_se(unit_stop(UNIT(service)) >= 0);
170 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
171
172 assert_se(unit_stop(unit) >= 0);
173 }
174
175 static void test_path_changed(Manager *m) {
176 const char *test_path = "/tmp/test-path_changed";
177 FILE *f;
178 Unit *unit = NULL;
179 Path *path = NULL;
180 Service *service = NULL;
181
182 assert_se(m);
183
184 assert_se(manager_load_startable_unit_or_warn(m, "path-changed.path", NULL, &unit) >= 0);
185
186 path = PATH(unit);
187 service = service_for_path(m, path, NULL);
188
189 assert_se(unit_start(unit) >= 0);
190 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
191
192 assert_se(touch(test_path) >= 0);
193 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
194
195 /* Service does not restart if file still exists */
196 assert_se(unit_stop(UNIT(service)) >= 0);
197 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
198
199 f = fopen(test_path, "w");
200 assert_se(f);
201 fclose(f);
202
203 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
204
205 assert_se(unit_stop(UNIT(service)) >= 0);
206 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
207
208 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
209 assert_se(unit_stop(unit) >= 0);
210 }
211
212 static void test_path_modified(Manager *m) {
213 _cleanup_fclose_ FILE *f = NULL;
214 const char *test_path = "/tmp/test-path_modified";
215 Unit *unit = NULL;
216 Path *path = NULL;
217 Service *service = NULL;
218
219 assert_se(m);
220
221 assert_se(manager_load_startable_unit_or_warn(m, "path-modified.path", NULL, &unit) >= 0);
222
223 path = PATH(unit);
224 service = service_for_path(m, path, NULL);
225
226 assert_se(unit_start(unit) >= 0);
227 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
228
229 assert_se(touch(test_path) >= 0);
230 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
231
232 /* Service does not restart if file still exists */
233 assert_se(unit_stop(UNIT(service)) >= 0);
234 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
235
236 f = fopen(test_path, "w");
237 assert_se(f);
238 fputs("test", f);
239
240 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
241
242 assert_se(unit_stop(UNIT(service)) >= 0);
243 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
244
245 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
246 assert_se(unit_stop(unit) >= 0);
247 }
248
249 static void test_path_unit(Manager *m) {
250 const char *test_path = "/tmp/test-path_unit";
251 Unit *unit = NULL;
252 Path *path = NULL;
253 Service *service = NULL;
254
255 assert_se(m);
256
257 assert_se(manager_load_startable_unit_or_warn(m, "path-unit.path", NULL, &unit) >= 0);
258
259 path = PATH(unit);
260 service = service_for_path(m, path, "path-mycustomunit.service");
261
262 assert_se(unit_start(unit) >= 0);
263 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
264
265 assert_se(touch(test_path) >= 0);
266 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
267
268 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
269 assert_se(unit_stop(UNIT(service)) >= 0);
270 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
271
272 assert_se(unit_stop(unit) >= 0);
273 }
274
275 static void test_path_directorynotempty(Manager *m) {
276 const char *test_path = "/tmp/test-path_directorynotempty/";
277 Unit *unit = NULL;
278 Path *path = NULL;
279 Service *service = NULL;
280
281 assert_se(m);
282
283 assert_se(manager_load_startable_unit_or_warn(m, "path-directorynotempty.path", NULL, &unit) >= 0);
284
285 path = PATH(unit);
286 service = service_for_path(m, path, NULL);
287
288 assert_se(access(test_path, F_OK) < 0);
289
290 assert_se(unit_start(unit) >= 0);
291 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
292
293 /* MakeDirectory default to no */
294 assert_se(access(test_path, F_OK) < 0);
295
296 assert_se(mkdir_p(test_path, 0755) >= 0);
297 assert_se(touch(strjoina(test_path, "test_file")) >= 0);
298 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
299
300 /* Service restarts if directory is still not empty */
301 assert_se(unit_stop(UNIT(service)) >= 0);
302 check_states(m, path, service, PATH_RUNNING, SERVICE_RUNNING);
303
304 assert_se(rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
305 assert_se(unit_stop(UNIT(service)) >= 0);
306 check_states(m, path, service, PATH_WAITING, SERVICE_DEAD);
307
308 assert_se(unit_stop(unit) >= 0);
309 }
310
311 static void test_path_makedirectory_directorymode(Manager *m) {
312 const char *test_path = "/tmp/test-path_makedirectory/";
313 Unit *unit = NULL;
314 struct stat s;
315
316 assert_se(m);
317
318 assert_se(manager_load_startable_unit_or_warn(m, "path-makedirectory.path", NULL, &unit) >= 0);
319
320 assert_se(access(test_path, F_OK) < 0);
321
322 assert_se(unit_start(unit) >= 0);
323
324 /* Check if the directory has been created */
325 assert_se(access(test_path, F_OK) >= 0);
326
327 /* Check the mode we specified with DirectoryMode=0744 */
328 assert_se(stat(test_path, &s) >= 0);
329 assert_se((s.st_mode & S_IRWXU) == 0700);
330 assert_se((s.st_mode & S_IRWXG) == 0040);
331 assert_se((s.st_mode & S_IRWXO) == 0004);
332
333 assert_se(unit_stop(unit) >= 0);
334 (void) rm_rf(test_path, REMOVE_ROOT|REMOVE_PHYSICAL);
335 }
336
337 int main(int argc, char *argv[]) {
338 static const test_function_t tests[] = {
339 test_path_exists,
340 test_path_existsglob,
341 test_path_changed,
342 test_path_modified,
343 test_path_unit,
344 test_path_directorynotempty,
345 test_path_makedirectory_directorymode,
346 NULL,
347 };
348
349 _cleanup_free_ char *test_path = NULL;
350 _cleanup_(rm_rf_physical_and_freep) char *runtime_dir = NULL;
351
352 umask(022);
353
354 test_setup_logging(LOG_INFO);
355
356 assert_se(get_testdata_dir("test-path", &test_path) >= 0);
357 assert_se(set_unit_path(test_path) >= 0);
358 assert_se(runtime_dir = setup_fake_runtime_dir());
359
360 for (const test_function_t *test = tests; test && *test; test++) {
361 Manager *m = NULL;
362 int r;
363
364 /* We create a clean environment for each test */
365 r = setup_test(&m);
366 if (r != 0)
367 return r;
368
369 (*test)(m);
370
371 shutdown_test(m);
372 }
373
374 return 0;
375 }