chiark / gitweb /
test: add test for crash when adding a JOB_NOP
[elogind.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_load_env_file_pairs(void) {
352         char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
353         int fd;
354         int r;
355         _cleanup_fclose_ FILE *f = NULL;
356         _cleanup_strv_free_ char **l = NULL;
357         char **k, **v;
358
359         fd = mkostemp_safe(fn, O_RDWR);
360         assert_se(fd >= 0);
361
362         r = write_string_file(fn,
363                         "NAME=\"Arch Linux\"\n"
364                         "ID=arch\n"
365                         "PRETTY_NAME=\"Arch Linux\"\n"
366                         "ANSI_COLOR=\"0;36\"\n"
367                         "HOME_URL=\"https://www.archlinux.org/\"\n"
368                         "SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
369                         "BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n"
370                         );
371         assert_se(r == 0);
372
373         f = fdopen(fd, "r");
374         assert_se(f);
375
376         r = load_env_file_pairs(f, fn, NULL, &l);
377         assert_se(r >= 0);
378
379         assert_se(strv_length(l) == 14);
380         STRV_FOREACH_PAIR(k, v, l) {
381                 assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
382                 printf("%s=%s\n", *k, *v);
383                 if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
384                 if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
385                 if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
386                 if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
387                 if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
388                 if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
389                 if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
390         }
391
392         unlink(fn);
393 }
394
395 int main(int argc, char *argv[]) {
396         log_parse_environment();
397         log_open();
398
399         test_parse_env_file();
400         test_parse_multiline_env_file();
401         test_executable_is_script();
402         test_status_field();
403         test_capeff();
404         test_write_string_stream();
405         test_write_string_file();
406         test_write_string_file_no_create();
407         test_load_env_file_pairs();
408
409         return 0;
410 }