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