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