]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-fileio.c
shared: add process-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 "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") < 0);
306
307 f = freopen(fn, "r+", f);
308 assert_se(f);
309
310 assert_se(write_string_stream(f, "boohoo") == 0);
311 rewind(f);
312
313 assert_se(fgets(buf, sizeof(buf), f));
314 assert_se(streq(buf, "boohoo\n"));
315
316 unlink(fn);
317 }
318
319 static void test_write_string_file(void) {
320 char fn[] = "/tmp/test-write_string_file-XXXXXX";
321 char buf[64] = {};
322 _cleanup_close_ int fd;
323
324 fd = mkostemp_safe(fn, O_RDWR);
325 assert_se(fd >= 0);
326
327 assert_se(write_string_file(fn, "boohoo") == 0);
328
329 assert_se(read(fd, buf, sizeof(buf)) == 7);
330 assert_se(streq(buf, "boohoo\n"));
331
332 unlink(fn);
333 }
334
335 static void test_write_string_file_no_create(void) {
336 char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
337 _cleanup_close_ int fd;
338 char buf[64] = {0};
339
340 fd = mkostemp_safe(fn, O_RDWR);
341 assert_se(fd >= 0);
342
343 assert_se(write_string_file_no_create("/a/file/which/does/not/exists/i/guess", "boohoo") < 0);
344 assert_se(write_string_file_no_create(fn, "boohoo") == 0);
345
346 assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n"));
347 assert_se(streq(buf, "boohoo\n"));
348
349 unlink(fn);
350 }
351
352 static void test_load_env_file_pairs(void) {
353 char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
354 int fd;
355 int r;
356 _cleanup_fclose_ FILE *f = NULL;
357 _cleanup_strv_free_ char **l = NULL;
358 char **k, **v;
359
360 fd = mkostemp_safe(fn, O_RDWR);
361 assert_se(fd >= 0);
362
363 r = write_string_file(fn,
364 "NAME=\"Arch Linux\"\n"
365 "ID=arch\n"
366 "PRETTY_NAME=\"Arch Linux\"\n"
367 "ANSI_COLOR=\"0;36\"\n"
368 "HOME_URL=\"https://www.archlinux.org/\"\n"
369 "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
370 "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n"
371 );
372 assert_se(r == 0);
373
374 f = fdopen(fd, "r");
375 assert_se(f);
376
377 r = load_env_file_pairs(f, fn, NULL, &l);
378 assert_se(r >= 0);
379
380 assert_se(strv_length(l) == 14);
381 STRV_FOREACH_PAIR(k, v, l) {
382 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
383 printf("%s=%s\n", *k, *v);
384 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
385 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
386 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
387 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
388 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
389 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
390 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
391 }
392
393 unlink(fn);
394 }
395
396 int main(int argc, char *argv[]) {
397 log_parse_environment();
398 log_open();
399
400 test_parse_env_file();
401 test_parse_multiline_env_file();
402 test_executable_is_script();
403 test_status_field();
404 test_capeff();
405 test_write_string_stream();
406 test_write_string_file();
407 test_write_string_file_no_create();
408 test_load_env_file_pairs();
409
410 return 0;
411 }