]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-util.c
tests: move io-util related tests to test-io-util
[thirdparty/systemd.git] / src / test / test-util.c
1 /***
2 This file is part of systemd.
3
4 Copyright 2010 Lennart Poettering
5 Copyright 2013 Thomas H.P. Andersen
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 <errno.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <sys/types.h>
25 #include <sys/wait.h>
26 #include <sys/xattr.h>
27 #include <unistd.h>
28
29 #include "alloc-util.h"
30 #include "def.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "fs-util.h"
34 #include "glob-util.h"
35 #include "mkdir.h"
36 #include "parse-util.h"
37 #include "path-util.h"
38 #include "process-util.h"
39 #include "rm-rf.h"
40 #include "special.h"
41 #include "string-util.h"
42 #include "strv.h"
43 #include "util.h"
44 #include "virt.h"
45 #include "xattr-util.h"
46
47 static void test_align_power2(void) {
48 unsigned long i, p2;
49
50 assert_se(ALIGN_POWER2(0) == 0);
51 assert_se(ALIGN_POWER2(1) == 1);
52 assert_se(ALIGN_POWER2(2) == 2);
53 assert_se(ALIGN_POWER2(3) == 4);
54 assert_se(ALIGN_POWER2(12) == 16);
55
56 assert_se(ALIGN_POWER2(ULONG_MAX) == 0);
57 assert_se(ALIGN_POWER2(ULONG_MAX - 1) == 0);
58 assert_se(ALIGN_POWER2(ULONG_MAX - 1024) == 0);
59 assert_se(ALIGN_POWER2(ULONG_MAX / 2) == ULONG_MAX / 2 + 1);
60 assert_se(ALIGN_POWER2(ULONG_MAX + 1) == 0);
61
62 for (i = 1; i < 131071; ++i) {
63 for (p2 = 1; p2 < i; p2 <<= 1)
64 /* empty */ ;
65
66 assert_se(ALIGN_POWER2(i) == p2);
67 }
68
69 for (i = ULONG_MAX - 1024; i < ULONG_MAX; ++i) {
70 for (p2 = 1; p2 && p2 < i; p2 <<= 1)
71 /* empty */ ;
72
73 assert_se(ALIGN_POWER2(i) == p2);
74 }
75 }
76
77 static void test_max(void) {
78 static const struct {
79 int a;
80 int b[CONST_MAX(10, 100)];
81 } val1 = {
82 .a = CONST_MAX(10, 100),
83 };
84 int d = 0;
85
86 assert_cc(sizeof(val1.b) == sizeof(int) * 100);
87
88 /* CONST_MAX returns (void) instead of a value if the passed arguments
89 * are not of the same type or not constant expressions. */
90 assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 10)), int));
91 assert_cc(__builtin_types_compatible_p(typeof(CONST_MAX(1, 1U)), void));
92
93 assert_se(val1.a == 100);
94 assert_se(MAX(++d, 0) == 1);
95 assert_se(d == 1);
96
97 assert_cc(MAXSIZE(char[3], uint16_t) == 3);
98 assert_cc(MAXSIZE(char[3], uint32_t) == 4);
99 assert_cc(MAXSIZE(char, long) == sizeof(long));
100
101 assert_se(MAX(-5, 5) == 5);
102 assert_se(MAX(5, 5) == 5);
103 assert_se(MAX(MAX(1, MAX(2, MAX(3, 4))), 5) == 5);
104 assert_se(MAX(MAX(1, MAX(2, MAX(3, 2))), 1) == 3);
105 assert_se(MAX(MIN(1, MIN(2, MIN(3, 4))), 5) == 5);
106 assert_se(MAX(MAX(1, MIN(2, MIN(3, 2))), 1) == 2);
107 assert_se(LESS_BY(8, 4) == 4);
108 assert_se(LESS_BY(8, 8) == 0);
109 assert_se(LESS_BY(4, 8) == 0);
110 assert_se(LESS_BY(16, LESS_BY(8, 4)) == 12);
111 assert_se(LESS_BY(4, LESS_BY(8, 4)) == 0);
112 assert_se(CLAMP(-5, 0, 1) == 0);
113 assert_se(CLAMP(5, 0, 1) == 1);
114 assert_se(CLAMP(5, -10, 1) == 1);
115 assert_se(CLAMP(5, -10, 10) == 5);
116 assert_se(CLAMP(CLAMP(0, -10, 10), CLAMP(-5, 10, 20), CLAMP(100, -5, 20)) == 10);
117 }
118
119 static void test_container_of(void) {
120 struct mytype {
121 uint8_t pad1[3];
122 uint64_t v1;
123 uint8_t pad2[2];
124 uint32_t v2;
125 } _packed_ myval = { };
126
127 assert_cc(sizeof(myval) == 17);
128 assert_se(container_of(&myval.v1, struct mytype, v1) == &myval);
129 assert_se(container_of(&myval.v2, struct mytype, v2) == &myval);
130 assert_se(container_of(&container_of(&myval.v2,
131 struct mytype,
132 v2)->v1,
133 struct mytype,
134 v1) == &myval);
135 }
136
137 static void test_div_round_up(void) {
138 int div;
139
140 /* basic tests */
141 assert_se(DIV_ROUND_UP(0, 8) == 0);
142 assert_se(DIV_ROUND_UP(1, 8) == 1);
143 assert_se(DIV_ROUND_UP(8, 8) == 1);
144 assert_se(DIV_ROUND_UP(12, 8) == 2);
145 assert_se(DIV_ROUND_UP(16, 8) == 2);
146
147 /* test multiple evaluation */
148 div = 0;
149 assert_se(DIV_ROUND_UP(div++, 8) == 0 && div == 1);
150 assert_se(DIV_ROUND_UP(++div, 8) == 1 && div == 2);
151 assert_se(DIV_ROUND_UP(8, div++) == 4 && div == 3);
152 assert_se(DIV_ROUND_UP(8, ++div) == 2 && div == 4);
153
154 /* overflow test with exact division */
155 assert_se(sizeof(0U) == 4);
156 assert_se(0xfffffffaU % 10U == 0U);
157 assert_se(0xfffffffaU / 10U == 429496729U);
158 assert_se(DIV_ROUND_UP(0xfffffffaU, 10U) == 429496729U);
159 assert_se((0xfffffffaU + 10U - 1U) / 10U == 0U);
160 assert_se(0xfffffffaU / 10U + !!(0xfffffffaU % 10U) == 429496729U);
161
162 /* overflow test with rounded division */
163 assert_se(0xfffffffdU % 10U == 3U);
164 assert_se(0xfffffffdU / 10U == 429496729U);
165 assert_se(DIV_ROUND_UP(0xfffffffdU, 10U) == 429496730U);
166 assert_se((0xfffffffdU + 10U - 1U) / 10U == 0U);
167 assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U);
168 }
169
170 static void test_u64log2(void) {
171 assert_se(u64log2(0) == 0);
172 assert_se(u64log2(8) == 3);
173 assert_se(u64log2(9) == 3);
174 assert_se(u64log2(15) == 3);
175 assert_se(u64log2(16) == 4);
176 assert_se(u64log2(1024*1024) == 20);
177 assert_se(u64log2(1024*1024+5) == 20);
178 }
179
180 static void test_protect_errno(void) {
181 errno = 12;
182 {
183 PROTECT_ERRNO;
184 errno = 11;
185 }
186 assert_se(errno == 12);
187 }
188
189 static void test_in_set(void) {
190 assert_se(IN_SET(1, 1));
191 assert_se(IN_SET(1, 1, 2, 3, 4));
192 assert_se(IN_SET(2, 1, 2, 3, 4));
193 assert_se(IN_SET(3, 1, 2, 3, 4));
194 assert_se(IN_SET(4, 1, 2, 3, 4));
195 assert_se(!IN_SET(0, 1));
196 assert_se(!IN_SET(0, 1, 2, 3, 4));
197 }
198
199 static void test_log2i(void) {
200 assert_se(log2i(1) == 0);
201 assert_se(log2i(2) == 1);
202 assert_se(log2i(3) == 1);
203 assert_se(log2i(4) == 2);
204 assert_se(log2i(32) == 5);
205 assert_se(log2i(33) == 5);
206 assert_se(log2i(63) == 5);
207 assert_se(log2i(INT_MAX) == sizeof(int)*8-2);
208 }
209
210 static void test_glob_exists(void) {
211 char name[] = "/tmp/test-glob_exists.XXXXXX";
212 int fd = -1;
213 int r;
214
215 fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC);
216 assert_se(fd >= 0);
217 close(fd);
218
219 r = glob_exists("/tmp/test-glob_exists*");
220 assert_se(r == 1);
221
222 r = unlink(name);
223 assert_se(r == 0);
224 r = glob_exists("/tmp/test-glob_exists*");
225 assert_se(r == 0);
226 }
227
228 static void test_execute_directory(void) {
229 char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX";
230 char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX";
231 const char * dirs[] = {template_hi, template_lo, NULL};
232 const char *name, *name2, *name3, *overridden, *override, *masked, *mask;
233
234 assert_se(mkdtemp(template_lo));
235 assert_se(mkdtemp(template_hi));
236
237 name = strjoina(template_lo, "/script");
238 name2 = strjoina(template_hi, "/script2");
239 name3 = strjoina(template_lo, "/useless");
240 overridden = strjoina(template_lo, "/overridden");
241 override = strjoina(template_hi, "/overridden");
242 masked = strjoina(template_lo, "/masked");
243 mask = strjoina(template_hi, "/masked");
244
245 assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works", WRITE_STRING_FILE_CREATE) == 0);
246 assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2", WRITE_STRING_FILE_CREATE) == 0);
247 assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0);
248 assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0", WRITE_STRING_FILE_CREATE) == 0);
249 assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed", WRITE_STRING_FILE_CREATE) == 0);
250 assert_se(symlink("/dev/null", mask) == 0);
251 assert_se(chmod(name, 0755) == 0);
252 assert_se(chmod(name2, 0755) == 0);
253 assert_se(chmod(overridden, 0755) == 0);
254 assert_se(chmod(override, 0755) == 0);
255 assert_se(chmod(masked, 0755) == 0);
256 assert_se(touch(name3) >= 0);
257
258 execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL);
259
260 assert_se(chdir(template_lo) == 0);
261 assert_se(access("it_works", F_OK) >= 0);
262 assert_se(access("failed", F_OK) < 0);
263
264 assert_se(chdir(template_hi) == 0);
265 assert_se(access("it_works2", F_OK) >= 0);
266 assert_se(access("failed", F_OK) < 0);
267
268 (void) rm_rf(template_lo, REMOVE_ROOT|REMOVE_PHYSICAL);
269 (void) rm_rf(template_hi, REMOVE_ROOT|REMOVE_PHYSICAL);
270 }
271
272 static void test_raw_clone(void) {
273 pid_t parent, pid, pid2;
274
275 parent = getpid();
276 log_info("before clone: getpid()→"PID_FMT, parent);
277 assert_se(raw_getpid() == parent);
278
279 pid = raw_clone(0, NULL);
280 assert_se(pid >= 0);
281
282 pid2 = raw_getpid();
283 log_info("raw_clone: "PID_FMT" getpid()→"PID_FMT" raw_getpid()→"PID_FMT,
284 pid, getpid(), pid2);
285 if (pid == 0) {
286 assert_se(pid2 != parent);
287 _exit(EXIT_SUCCESS);
288 } else {
289 int status;
290
291 assert_se(pid2 == parent);
292 waitpid(pid, &status, __WCLONE);
293 assert_se(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS);
294 }
295 }
296
297 static void test_fgetxattrat_fake(void) {
298 char t[] = "/var/tmp/xattrtestXXXXXX";
299 _cleanup_close_ int fd = -1;
300 const char *x;
301 char v[3] = {};
302 int r;
303
304 assert_se(mkdtemp(t));
305 x = strjoina(t, "/test");
306 assert_se(touch(x) >= 0);
307
308 r = setxattr(x, "user.foo", "bar", 3, 0);
309 if (r < 0 && errno == EOPNOTSUPP) /* no xattrs supported on /var/tmp... */
310 goto cleanup;
311 assert_se(r >= 0);
312
313 fd = open(t, O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
314 assert_se(fd >= 0);
315
316 assert_se(fgetxattrat_fake(fd, "test", "user.foo", v, 3, 0) >= 0);
317 assert_se(memcmp(v, "bar", 3) == 0);
318
319 safe_close(fd);
320 fd = open("/", O_RDONLY|O_DIRECTORY|O_CLOEXEC|O_NOCTTY);
321 assert_se(fd >= 0);
322 assert_se(fgetxattrat_fake(fd, "usr", "user.idontexist", v, 3, 0) == -ENODATA);
323
324 cleanup:
325 assert_se(unlink(x) >= 0);
326 assert_se(rmdir(t) >= 0);
327 }
328
329 int main(int argc, char *argv[]) {
330 log_parse_environment();
331 log_open();
332
333 test_align_power2();
334 test_max();
335 test_container_of();
336 test_div_round_up();
337 test_u64log2();
338 test_protect_errno();
339 test_in_set();
340 test_log2i();
341 test_glob_exists();
342 test_execute_directory();
343 test_raw_clone();
344 test_fgetxattrat_fake();
345
346 return 0;
347 }