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