]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-fileio.c
Merge pull request #362 from d-hatayama/fix_selinux_unit_check_v2
[thirdparty/systemd.git] / src / test / test-fileio.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 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 <stdio.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25
26 #include "util.h"
27 #include "process-util.h"
28 #include "fileio.h"
29 #include "strv.h"
30 #include "env-util.h"
31 #include "def.h"
32 #include "ctype.h"
33
34 static void test_parse_env_file(void) {
35 char t[] = "/tmp/test-fileio-in-XXXXXX",
36 p[] = "/tmp/test-fileio-out-XXXXXX";
37 int fd, r;
38 FILE *f;
39 _cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL,
40 *six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL;
41 _cleanup_strv_free_ char **a = NULL, **b = NULL;
42 char **i;
43 unsigned k;
44
45 fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC);
46 assert_se(fd >= 0);
47 close(fd);
48
49 fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC);
50 assert_se(fd >= 0);
51
52 f = fdopen(fd, "w");
53 assert_se(f);
54
55 fputs("one=BAR \n"
56 "# comment\n"
57 " # comment \n"
58 " ; comment \n"
59 " two = bar \n"
60 "invalid line\n"
61 "invalid line #comment\n"
62 "three = \"333\n"
63 "xxxx\"\n"
64 "four = \'44\\\"44\'\n"
65 "five = \'55\\\'55\' \"FIVE\" cinco \n"
66 "six = seis sechs\\\n"
67 " sis\n"
68 "seven=\"sevenval\" #nocomment\n"
69 "eight=eightval #nocomment\n"
70 "export nine=nineval\n"
71 "ten=", f);
72
73 fflush(f);
74 fclose(f);
75
76 r = load_env_file(NULL, t, NULL, &a);
77 assert_se(r >= 0);
78
79 STRV_FOREACH(i, a)
80 log_info("Got: <%s>", *i);
81
82 assert_se(streq_ptr(a[0], "one=BAR"));
83 assert_se(streq_ptr(a[1], "two=bar"));
84 assert_se(streq_ptr(a[2], "three=333\nxxxx"));
85 assert_se(streq_ptr(a[3], "four=44\"44"));
86 assert_se(streq_ptr(a[4], "five=55\'55FIVEcinco"));
87 assert_se(streq_ptr(a[5], "six=seis sechs sis"));
88 assert_se(streq_ptr(a[6], "seven=sevenval#nocomment"));
89 assert_se(streq_ptr(a[7], "eight=eightval #nocomment"));
90 assert_se(streq_ptr(a[8], "export nine=nineval"));
91 assert_se(streq_ptr(a[9], "ten="));
92 assert_se(a[10] == NULL);
93
94 strv_env_clean(a);
95
96 k = 0;
97 STRV_FOREACH(i, b) {
98 log_info("Got2: <%s>", *i);
99 assert_se(streq(*i, a[k++]));
100 }
101
102 r = parse_env_file(
103 t, NULL,
104 "one", &one,
105 "two", &two,
106 "three", &three,
107 "four", &four,
108 "five", &five,
109 "six", &six,
110 "seven", &seven,
111 "eight", &eight,
112 "export nine", &nine,
113 "ten", &ten,
114 NULL);
115
116 assert_se(r >= 0);
117
118 log_info("one=[%s]", strna(one));
119 log_info("two=[%s]", strna(two));
120 log_info("three=[%s]", strna(three));
121 log_info("four=[%s]", strna(four));
122 log_info("five=[%s]", strna(five));
123 log_info("six=[%s]", strna(six));
124 log_info("seven=[%s]", strna(seven));
125 log_info("eight=[%s]", strna(eight));
126 log_info("export nine=[%s]", strna(nine));
127 log_info("ten=[%s]", strna(nine));
128
129 assert_se(streq(one, "BAR"));
130 assert_se(streq(two, "bar"));
131 assert_se(streq(three, "333\nxxxx"));
132 assert_se(streq(four, "44\"44"));
133 assert_se(streq(five, "55\'55FIVEcinco"));
134 assert_se(streq(six, "seis sechs sis"));
135 assert_se(streq(seven, "sevenval#nocomment"));
136 assert_se(streq(eight, "eightval #nocomment"));
137 assert_se(streq(nine, "nineval"));
138 assert_se(ten == NULL);
139
140 r = write_env_file(p, a);
141 assert_se(r >= 0);
142
143 r = load_env_file(NULL, p, NULL, &b);
144 assert_se(r >= 0);
145
146 unlink(t);
147 unlink(p);
148 }
149
150 static void test_parse_multiline_env_file(void) {
151 char t[] = "/tmp/test-fileio-in-XXXXXX",
152 p[] = "/tmp/test-fileio-out-XXXXXX";
153 int fd, r;
154 FILE *f;
155 _cleanup_strv_free_ char **a = NULL, **b = NULL;
156 char **i;
157
158 fd = mkostemp_safe(p, O_RDWR|O_CLOEXEC);
159 assert_se(fd >= 0);
160 close(fd);
161
162 fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC);
163 assert_se(fd >= 0);
164
165 f = fdopen(fd, "w");
166 assert_se(f);
167
168 fputs("one=BAR\\\n"
169 " VAR\\\n"
170 "\tGAR\n"
171 "#comment\n"
172 "two=\"bar\\\n"
173 " var\\\n"
174 "\tgar\"\n"
175 "#comment\n"
176 "tri=\"bar \\\n"
177 " var \\\n"
178 "\tgar \"\n", f);
179
180 fflush(f);
181 fclose(f);
182
183 r = load_env_file(NULL, t, NULL, &a);
184 assert_se(r >= 0);
185
186 STRV_FOREACH(i, a)
187 log_info("Got: <%s>", *i);
188
189 assert_se(streq_ptr(a[0], "one=BAR VAR\tGAR"));
190 assert_se(streq_ptr(a[1], "two=bar var\tgar"));
191 assert_se(streq_ptr(a[2], "tri=bar var \tgar "));
192 assert_se(a[3] == NULL);
193
194 r = write_env_file(p, a);
195 assert_se(r >= 0);
196
197 r = load_env_file(NULL, p, NULL, &b);
198 assert_se(r >= 0);
199
200 unlink(t);
201 unlink(p);
202 }
203
204
205 static void test_executable_is_script(void) {
206 char t[] = "/tmp/test-executable-XXXXXX";
207 int fd, r;
208 FILE *f;
209 char *command;
210
211 fd = mkostemp_safe(t, O_RDWR|O_CLOEXEC);
212 assert_se(fd >= 0);
213
214 f = fdopen(fd, "w");
215 assert_se(f);
216
217 fputs("#! /bin/script -a -b \ngoo goo", f);
218 fflush(f);
219
220 r = executable_is_script(t, &command);
221 assert_se(r > 0);
222 assert_se(streq(command, "/bin/script"));
223 free(command);
224
225 r = executable_is_script("/bin/sh", &command);
226 assert_se(r == 0);
227
228 r = executable_is_script("/usr/bin/yum", &command);
229 assert_se(r > 0 || r == -ENOENT);
230 if (r > 0) {
231 assert_se(startswith(command, "/"));
232 free(command);
233 }
234
235 fclose(f);
236 unlink(t);
237 }
238
239 static void test_status_field(void) {
240 _cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL;
241 unsigned long long total = 0, buffers = 0;
242 int r;
243
244 assert_se(get_status_field("/proc/self/status", "\nThreads:", &t) == 0);
245 puts(t);
246 assert_se(streq(t, "1"));
247
248 r = get_status_field("/proc/meminfo", "MemTotal:", &p);
249 if (r != -ENOENT) {
250 assert_se(r == 0);
251 puts(p);
252 assert_se(safe_atollu(p, &total) == 0);
253 }
254
255 r = get_status_field("/proc/meminfo", "\nBuffers:", &s);
256 if (r != -ENOENT) {
257 assert_se(r == 0);
258 puts(s);
259 assert_se(safe_atollu(s, &buffers) == 0);
260 }
261
262 if (p)
263 assert_se(buffers < total);
264
265 /* Seccomp should be a good test for field full of zeros. */
266 r = get_status_field("/proc/meminfo", "\nSeccomp:", &z);
267 if (r != -ENOENT) {
268 assert_se(r == 0);
269 puts(z);
270 assert_se(safe_atollu(z, &buffers) == 0);
271 }
272 }
273
274 static void test_capeff(void) {
275 int pid, p;
276
277 for (pid = 0; pid < 2; pid++) {
278 _cleanup_free_ char *capeff = NULL;
279 int r;
280
281 r = get_process_capeff(0, &capeff);
282 log_info("capeff: '%s' (r=%d)", capeff, r);
283
284 if (r == -ENOENT || r == -EPERM)
285 return;
286
287 assert_se(r == 0);
288 assert_se(*capeff);
289 p = capeff[strspn(capeff, DIGITS "abcdefABCDEF")];
290 assert_se(!p || isspace(p));
291 }
292 }
293
294 static void test_write_string_stream(void) {
295 char fn[] = "/tmp/test-write_string_stream-XXXXXX";
296 _cleanup_fclose_ FILE *f = NULL;
297 int fd;
298 char buf[64];
299
300 fd = mkostemp_safe(fn, O_RDWR);
301 assert_se(fd >= 0);
302
303 f = fdopen(fd, "r");
304 assert_se(f);
305 assert_se(write_string_stream(f, "boohoo", true) < 0);
306
307 f = freopen(fn, "r+", f);
308 assert_se(f);
309
310 assert_se(write_string_stream(f, "boohoo", true) == 0);
311 rewind(f);
312
313 assert_se(fgets(buf, sizeof(buf), f));
314 assert_se(streq(buf, "boohoo\n"));
315
316 f = freopen(fn, "w+", f);
317 assert_se(f);
318
319 assert_se(write_string_stream(f, "boohoo", false) == 0);
320 rewind(f);
321
322 assert_se(fgets(buf, sizeof(buf), f));
323 printf(">%s<", buf);
324 assert_se(streq(buf, "boohoo"));
325
326 unlink(fn);
327 }
328
329 static void test_write_string_file(void) {
330 char fn[] = "/tmp/test-write_string_file-XXXXXX";
331 char buf[64] = {};
332 _cleanup_close_ int fd;
333
334 fd = mkostemp_safe(fn, O_RDWR);
335 assert_se(fd >= 0);
336
337 assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
338
339 assert_se(read(fd, buf, sizeof(buf)) == 7);
340 assert_se(streq(buf, "boohoo\n"));
341
342 unlink(fn);
343 }
344
345 static void test_write_string_file_no_create(void) {
346 char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
347 _cleanup_close_ int fd;
348 char buf[64] = {0};
349
350 fd = mkostemp_safe(fn, O_RDWR);
351 assert_se(fd >= 0);
352
353 assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
354 assert_se(write_string_file(fn, "boohoo", 0) == 0);
355
356 assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n"));
357 assert_se(streq(buf, "boohoo\n"));
358
359 unlink(fn);
360 }
361
362 static void test_load_env_file_pairs(void) {
363 char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
364 int fd;
365 int r;
366 _cleanup_fclose_ FILE *f = NULL;
367 _cleanup_strv_free_ char **l = NULL;
368 char **k, **v;
369
370 fd = mkostemp_safe(fn, O_RDWR);
371 assert_se(fd >= 0);
372
373 r = write_string_file(fn,
374 "NAME=\"Arch Linux\"\n"
375 "ID=arch\n"
376 "PRETTY_NAME=\"Arch Linux\"\n"
377 "ANSI_COLOR=\"0;36\"\n"
378 "HOME_URL=\"https://www.archlinux.org/\"\n"
379 "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
380 "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
381 WRITE_STRING_FILE_CREATE);
382 assert_se(r == 0);
383
384 f = fdopen(fd, "r");
385 assert_se(f);
386
387 r = load_env_file_pairs(f, fn, NULL, &l);
388 assert_se(r >= 0);
389
390 assert_se(strv_length(l) == 14);
391 STRV_FOREACH_PAIR(k, v, l) {
392 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
393 printf("%s=%s\n", *k, *v);
394 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
395 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
396 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
397 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
398 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
399 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
400 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
401 }
402
403 unlink(fn);
404 }
405
406 int main(int argc, char *argv[]) {
407 log_parse_environment();
408 log_open();
409
410 test_parse_env_file();
411 test_parse_multiline_env_file();
412 test_executable_is_script();
413 test_status_field();
414 test_capeff();
415 test_write_string_stream();
416 test_write_string_file();
417 test_write_string_file_no_create();
418 test_load_env_file_pairs();
419
420 return 0;
421 }