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