2013-04-03 19:04:03 +02:00
|
|
|
/***
|
|
|
|
This file is part of systemd.
|
|
|
|
|
|
|
|
Copyright 2013 Lennart Poettering
|
|
|
|
|
|
|
|
systemd is free software; you can redistribute it and/or modify it
|
|
|
|
under the terms of the GNU Lesser General Public License as published by
|
|
|
|
the Free Software Foundation; either version 2.1 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
systemd is distributed in the hope that it will be useful, but
|
|
|
|
WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Lesser General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Lesser General Public License
|
|
|
|
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
***/
|
|
|
|
|
|
|
|
#include <fcntl.h>
|
2015-11-16 22:09:36 +01:00
|
|
|
#include <stdio.h>
|
2013-04-03 19:04:03 +02:00
|
|
|
#include <unistd.h>
|
|
|
|
|
2015-10-27 03:01:06 +01:00
|
|
|
#include "alloc-util.h"
|
2013-09-19 23:22:59 +02:00
|
|
|
#include "ctype.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "def.h"
|
|
|
|
#include "env-util.h"
|
|
|
|
#include "fd-util.h"
|
|
|
|
#include "fileio.h"
|
2016-03-02 23:50:21 +01:00
|
|
|
#include "io-util.h"
|
2015-10-26 16:18:16 +01:00
|
|
|
#include "parse-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "process-util.h"
|
2015-10-24 22:58:24 +02:00
|
|
|
#include "string-util.h"
|
2015-10-25 13:14:12 +01:00
|
|
|
#include "strv.h"
|
|
|
|
#include "util.h"
|
2013-04-03 19:04:03 +02:00
|
|
|
|
|
|
|
static void test_parse_env_file(void) {
|
2013-07-30 01:49:55 +02:00
|
|
|
char t[] = "/tmp/test-fileio-in-XXXXXX",
|
|
|
|
p[] = "/tmp/test-fileio-out-XXXXXX";
|
2013-04-03 19:04:03 +02:00
|
|
|
int fd, r;
|
|
|
|
FILE *f;
|
2013-04-17 15:25:02 +02:00
|
|
|
_cleanup_free_ char *one = NULL, *two = NULL, *three = NULL, *four = NULL, *five = NULL,
|
|
|
|
*six = NULL, *seven = NULL, *eight = NULL, *nine = NULL, *ten = NULL;
|
2013-04-03 19:56:39 +02:00
|
|
|
_cleanup_strv_free_ char **a = NULL, **b = NULL;
|
2013-04-03 19:04:03 +02:00
|
|
|
char **i;
|
2013-04-03 19:56:39 +02:00
|
|
|
unsigned k;
|
2013-04-03 19:04:03 +02:00
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(p);
|
2013-12-12 00:06:30 +01:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
close(fd);
|
2013-07-30 01:49:55 +02:00
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(t);
|
2013-04-03 19:04:03 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
f = fdopen(fd, "w");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
fputs("one=BAR \n"
|
|
|
|
"# comment\n"
|
|
|
|
" # comment \n"
|
2013-04-18 10:15:25 +02:00
|
|
|
" ; comment \n"
|
2013-04-03 19:04:03 +02:00
|
|
|
" two = bar \n"
|
|
|
|
"invalid line\n"
|
2013-04-18 10:15:25 +02:00
|
|
|
"invalid line #comment\n"
|
2013-04-03 19:04:03 +02:00
|
|
|
"three = \"333\n"
|
|
|
|
"xxxx\"\n"
|
|
|
|
"four = \'44\\\"44\'\n"
|
|
|
|
"five = \'55\\\'55\' \"FIVE\" cinco \n"
|
|
|
|
"six = seis sechs\\\n"
|
|
|
|
" sis\n"
|
2013-04-18 10:15:25 +02:00
|
|
|
"seven=\"sevenval\" #nocomment\n"
|
|
|
|
"eight=eightval #nocomment\n"
|
2013-04-17 15:25:02 +02:00
|
|
|
"export nine=nineval\n"
|
env-util,fileio: immediately replace variables in load_env_file_push()
strv_env_replace was calling env_match(), which in effect allowed multiple
values for the same key to be inserted into the environment block. That's
pointless, because APIs to access variables only return a single value (the
latest entry), so it's better to keep the block clean, i.e. with just a single
entry for each key.
Add a new helper function that simply tests if the part before '=' is equal in
two strings and use that in strv_env_replace.
In load_env_file_push, use strv_env_replace to immediately replace the previous
assignment with a matching name.
Afaict, none of the callers are materially affected by this change, but it
seems like some pointless work was being done, if the same value was set
multiple times. We'd go through parsing and assigning the value for each
entry. With this change, we handle just the last one.
2017-02-11 05:08:53 +01:00
|
|
|
"ten=ignored\n"
|
|
|
|
"ten=ignored\n"
|
2013-04-17 15:25:02 +02:00
|
|
|
"ten=", f);
|
2013-04-03 19:04:03 +02:00
|
|
|
|
|
|
|
fflush(f);
|
|
|
|
fclose(f);
|
|
|
|
|
2014-07-03 17:50:55 +02:00
|
|
|
r = load_env_file(NULL, t, NULL, &a);
|
2013-04-17 15:25:02 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
STRV_FOREACH(i, a)
|
|
|
|
log_info("Got: <%s>", *i);
|
|
|
|
|
2013-12-12 23:08:47 +01:00
|
|
|
assert_se(streq_ptr(a[0], "one=BAR"));
|
|
|
|
assert_se(streq_ptr(a[1], "two=bar"));
|
|
|
|
assert_se(streq_ptr(a[2], "three=333\nxxxx"));
|
|
|
|
assert_se(streq_ptr(a[3], "four=44\"44"));
|
|
|
|
assert_se(streq_ptr(a[4], "five=55\'55FIVEcinco"));
|
|
|
|
assert_se(streq_ptr(a[5], "six=seis sechs sis"));
|
|
|
|
assert_se(streq_ptr(a[6], "seven=sevenval#nocomment"));
|
|
|
|
assert_se(streq_ptr(a[7], "eight=eightval #nocomment"));
|
|
|
|
assert_se(streq_ptr(a[8], "export nine=nineval"));
|
|
|
|
assert_se(streq_ptr(a[9], "ten="));
|
2013-04-17 15:25:02 +02:00
|
|
|
assert_se(a[10] == NULL);
|
|
|
|
|
2014-12-23 19:04:56 +01:00
|
|
|
strv_env_clean(a);
|
2013-04-17 15:25:02 +02:00
|
|
|
|
|
|
|
k = 0;
|
|
|
|
STRV_FOREACH(i, b) {
|
|
|
|
log_info("Got2: <%s>", *i);
|
|
|
|
assert_se(streq(*i, a[k++]));
|
|
|
|
}
|
|
|
|
|
2013-04-03 19:04:03 +02:00
|
|
|
r = parse_env_file(
|
|
|
|
t, NULL,
|
|
|
|
"one", &one,
|
|
|
|
"two", &two,
|
|
|
|
"three", &three,
|
|
|
|
"four", &four,
|
|
|
|
"five", &five,
|
|
|
|
"six", &six,
|
|
|
|
"seven", &seven,
|
2013-04-17 11:02:56 +02:00
|
|
|
"eight", &eight,
|
2013-04-17 15:25:02 +02:00
|
|
|
"export nine", &nine,
|
|
|
|
"ten", &ten,
|
2013-04-03 19:04:03 +02:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
log_info("one=[%s]", strna(one));
|
|
|
|
log_info("two=[%s]", strna(two));
|
|
|
|
log_info("three=[%s]", strna(three));
|
|
|
|
log_info("four=[%s]", strna(four));
|
|
|
|
log_info("five=[%s]", strna(five));
|
|
|
|
log_info("six=[%s]", strna(six));
|
|
|
|
log_info("seven=[%s]", strna(seven));
|
2013-04-17 11:02:56 +02:00
|
|
|
log_info("eight=[%s]", strna(eight));
|
2013-04-17 15:25:02 +02:00
|
|
|
log_info("export nine=[%s]", strna(nine));
|
|
|
|
log_info("ten=[%s]", strna(nine));
|
2013-04-03 19:04:03 +02:00
|
|
|
|
|
|
|
assert_se(streq(one, "BAR"));
|
|
|
|
assert_se(streq(two, "bar"));
|
|
|
|
assert_se(streq(three, "333\nxxxx"));
|
|
|
|
assert_se(streq(four, "44\"44"));
|
|
|
|
assert_se(streq(five, "55\'55FIVEcinco"));
|
|
|
|
assert_se(streq(six, "seis sechs sis"));
|
2013-04-18 10:15:25 +02:00
|
|
|
assert_se(streq(seven, "sevenval#nocomment"));
|
|
|
|
assert_se(streq(eight, "eightval #nocomment"));
|
2013-04-17 15:25:02 +02:00
|
|
|
assert_se(streq(nine, "nineval"));
|
|
|
|
assert_se(ten == NULL);
|
2013-04-03 19:04:03 +02:00
|
|
|
|
2013-07-30 01:49:55 +02:00
|
|
|
r = write_env_file(p, a);
|
2013-04-18 10:15:25 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2014-07-03 17:50:55 +02:00
|
|
|
r = load_env_file(NULL, p, NULL, &b);
|
2013-04-18 10:15:25 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2013-04-03 19:04:03 +02:00
|
|
|
unlink(t);
|
2013-07-30 01:49:55 +02:00
|
|
|
unlink(p);
|
2013-04-03 19:04:03 +02:00
|
|
|
}
|
|
|
|
|
2013-09-12 03:50:16 +02:00
|
|
|
static void test_parse_multiline_env_file(void) {
|
|
|
|
char t[] = "/tmp/test-fileio-in-XXXXXX",
|
|
|
|
p[] = "/tmp/test-fileio-out-XXXXXX";
|
|
|
|
int fd, r;
|
|
|
|
FILE *f;
|
|
|
|
_cleanup_strv_free_ char **a = NULL, **b = NULL;
|
|
|
|
char **i;
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(p);
|
2013-12-12 00:06:30 +01:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
close(fd);
|
2013-09-12 03:50:16 +02:00
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(t);
|
2013-09-12 03:50:16 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
f = fdopen(fd, "w");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
fputs("one=BAR\\\n"
|
|
|
|
" VAR\\\n"
|
|
|
|
"\tGAR\n"
|
|
|
|
"#comment\n"
|
|
|
|
"two=\"bar\\\n"
|
|
|
|
" var\\\n"
|
|
|
|
"\tgar\"\n"
|
|
|
|
"#comment\n"
|
|
|
|
"tri=\"bar \\\n"
|
|
|
|
" var \\\n"
|
|
|
|
"\tgar \"\n", f);
|
|
|
|
|
|
|
|
fflush(f);
|
|
|
|
fclose(f);
|
|
|
|
|
2014-07-03 17:50:55 +02:00
|
|
|
r = load_env_file(NULL, t, NULL, &a);
|
2013-09-12 03:50:16 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
STRV_FOREACH(i, a)
|
|
|
|
log_info("Got: <%s>", *i);
|
|
|
|
|
2013-12-12 23:08:47 +01:00
|
|
|
assert_se(streq_ptr(a[0], "one=BAR VAR\tGAR"));
|
|
|
|
assert_se(streq_ptr(a[1], "two=bar var\tgar"));
|
|
|
|
assert_se(streq_ptr(a[2], "tri=bar var \tgar "));
|
2013-09-12 03:50:16 +02:00
|
|
|
assert_se(a[3] == NULL);
|
|
|
|
|
|
|
|
r = write_env_file(p, a);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
2014-07-03 17:50:55 +02:00
|
|
|
r = load_env_file(NULL, p, NULL, &b);
|
2013-09-12 03:50:16 +02:00
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
unlink(t);
|
|
|
|
unlink(p);
|
|
|
|
}
|
|
|
|
|
2016-08-04 18:00:00 +02:00
|
|
|
static void test_merge_env_file(void) {
|
|
|
|
char t[] = "/tmp/test-fileio-XXXXXX";
|
|
|
|
int fd, r;
|
|
|
|
FILE *f;
|
|
|
|
_cleanup_strv_free_ char **a = NULL;
|
|
|
|
char **i;
|
|
|
|
|
|
|
|
fd = mkostemp_safe(t);
|
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
log_info("/* %s (%s) */", __func__, t);
|
|
|
|
|
|
|
|
f = fdopen(fd, "w");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
r = write_string_stream(f,
|
|
|
|
"one=1 \n"
|
|
|
|
"twelve=${one}2\n"
|
|
|
|
"twentyone=2${one}\n"
|
|
|
|
"one=2\n"
|
2017-02-11 20:05:10 +01:00
|
|
|
"twentytwo=2${one}\n"
|
|
|
|
"xxx_minus_three=$xxx - 3\n"
|
|
|
|
"xxx=0x$one$one$one\n"
|
2016-08-09 16:20:22 +02:00
|
|
|
"yyy=${one:-fallback}\n"
|
|
|
|
"zzz=${one:+replacement}\n"
|
|
|
|
"zzzz=${foobar:-${nothing}}\n"
|
|
|
|
"zzzzz=${nothing:+${nothing}}\n"
|
2017-02-11 20:05:10 +01:00
|
|
|
, false);
|
2016-08-04 18:00:00 +02:00
|
|
|
assert(r >= 0);
|
|
|
|
|
|
|
|
r = merge_env_file(&a, NULL, t);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
strv_sort(a);
|
|
|
|
|
|
|
|
STRV_FOREACH(i, a)
|
|
|
|
log_info("Got: <%s>", *i);
|
|
|
|
|
|
|
|
assert_se(streq(a[0], "one=2"));
|
|
|
|
assert_se(streq(a[1], "twelve=12"));
|
|
|
|
assert_se(streq(a[2], "twentyone=21"));
|
|
|
|
assert_se(streq(a[3], "twentytwo=22"));
|
2017-02-11 20:05:10 +01:00
|
|
|
assert_se(streq(a[4], "xxx=0x222"));
|
|
|
|
assert_se(streq(a[5], "xxx_minus_three= - 3"));
|
2016-08-09 16:20:22 +02:00
|
|
|
assert_se(streq(a[6], "yyy=2"));
|
|
|
|
assert_se(streq(a[7], "zzz=replacement"));
|
|
|
|
assert_se(streq(a[8], "zzzz="));
|
|
|
|
assert_se(streq(a[9], "zzzzz="));
|
|
|
|
assert_se(a[10] == NULL);
|
2016-08-04 18:00:00 +02:00
|
|
|
|
|
|
|
r = merge_env_file(&a, NULL, t);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
strv_sort(a);
|
|
|
|
|
|
|
|
STRV_FOREACH(i, a)
|
|
|
|
log_info("Got2: <%s>", *i);
|
|
|
|
|
|
|
|
assert_se(streq(a[0], "one=2"));
|
|
|
|
assert_se(streq(a[1], "twelve=12"));
|
|
|
|
assert_se(streq(a[2], "twentyone=21"));
|
|
|
|
assert_se(streq(a[3], "twentytwo=22"));
|
2017-02-11 20:05:10 +01:00
|
|
|
assert_se(streq(a[4], "xxx=0x222"));
|
|
|
|
assert_se(streq(a[5], "xxx_minus_three=0x222 - 3"));
|
2016-08-09 16:20:22 +02:00
|
|
|
assert_se(streq(a[6], "yyy=2"));
|
|
|
|
assert_se(streq(a[7], "zzz=replacement"));
|
|
|
|
assert_se(streq(a[8], "zzzz="));
|
|
|
|
assert_se(streq(a[9], "zzzzz="));
|
|
|
|
assert_se(a[10] == NULL);
|
2016-08-04 18:00:00 +02:00
|
|
|
}
|
2013-09-12 03:50:16 +02:00
|
|
|
|
2017-02-18 04:56:28 +01:00
|
|
|
static void test_merge_env_file_invalid(void) {
|
|
|
|
char t[] = "/tmp/test-fileio-XXXXXX";
|
|
|
|
int fd, r;
|
|
|
|
FILE *f;
|
|
|
|
_cleanup_strv_free_ char **a = NULL;
|
|
|
|
char **i;
|
|
|
|
|
|
|
|
fd = mkostemp_safe(t);
|
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
log_info("/* %s (%s) */", __func__, t);
|
|
|
|
|
|
|
|
f = fdopen(fd, "w");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
r = write_string_stream(f,
|
|
|
|
"unset one \n"
|
|
|
|
"unset one= \n"
|
|
|
|
"unset one=1 \n"
|
|
|
|
"one \n"
|
|
|
|
"one = \n"
|
|
|
|
"one two =\n"
|
|
|
|
"\x20two=\n"
|
|
|
|
"#comment=comment\n"
|
|
|
|
";comment2=comment2\n"
|
|
|
|
"#\n"
|
|
|
|
"\n\n" /* empty line */
|
|
|
|
, false);
|
|
|
|
assert(r >= 0);
|
|
|
|
|
|
|
|
r = merge_env_file(&a, NULL, t);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
STRV_FOREACH(i, a)
|
|
|
|
log_info("Got: <%s>", *i);
|
|
|
|
|
|
|
|
assert_se(strv_isempty(a));
|
|
|
|
}
|
|
|
|
|
2013-07-19 10:02:50 +02:00
|
|
|
static void test_executable_is_script(void) {
|
|
|
|
char t[] = "/tmp/test-executable-XXXXXX";
|
|
|
|
int fd, r;
|
|
|
|
FILE *f;
|
|
|
|
char *command;
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(t);
|
2013-07-19 10:02:50 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
f = fdopen(fd, "w");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
fputs("#! /bin/script -a -b \ngoo goo", f);
|
|
|
|
fflush(f);
|
|
|
|
|
|
|
|
r = executable_is_script(t, &command);
|
|
|
|
assert_se(r > 0);
|
|
|
|
assert_se(streq(command, "/bin/script"));
|
|
|
|
free(command);
|
|
|
|
|
|
|
|
r = executable_is_script("/bin/sh", &command);
|
|
|
|
assert_se(r == 0);
|
|
|
|
|
|
|
|
r = executable_is_script("/usr/bin/yum", &command);
|
|
|
|
assert_se(r > 0 || r == -ENOENT);
|
|
|
|
if (r > 0) {
|
|
|
|
assert_se(startswith(command, "/"));
|
|
|
|
free(command);
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose(f);
|
|
|
|
unlink(t);
|
|
|
|
}
|
|
|
|
|
2013-09-14 01:41:52 +02:00
|
|
|
static void test_status_field(void) {
|
2013-09-19 23:22:59 +02:00
|
|
|
_cleanup_free_ char *t = NULL, *p = NULL, *s = NULL, *z = NULL;
|
|
|
|
unsigned long long total = 0, buffers = 0;
|
2013-09-15 14:40:16 +02:00
|
|
|
int r;
|
2013-09-14 01:41:52 +02:00
|
|
|
|
2015-09-30 14:57:55 +02:00
|
|
|
assert_se(get_proc_field("/proc/self/status", "Threads", WHITESPACE, &t) == 0);
|
2013-09-14 01:41:52 +02:00
|
|
|
puts(t);
|
|
|
|
assert_se(streq(t, "1"));
|
|
|
|
|
2015-09-30 14:57:55 +02:00
|
|
|
r = get_proc_field("/proc/meminfo", "MemTotal", WHITESPACE, &p);
|
2013-09-19 23:22:59 +02:00
|
|
|
if (r != -ENOENT) {
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(r == 0);
|
2013-09-19 23:22:59 +02:00
|
|
|
puts(p);
|
|
|
|
assert_se(safe_atollu(p, &total) == 0);
|
|
|
|
}
|
2013-09-14 01:41:52 +02:00
|
|
|
|
2015-09-30 14:57:55 +02:00
|
|
|
r = get_proc_field("/proc/meminfo", "Buffers", WHITESPACE, &s);
|
2013-09-19 23:22:59 +02:00
|
|
|
if (r != -ENOENT) {
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(r == 0);
|
2013-09-19 23:22:59 +02:00
|
|
|
puts(s);
|
|
|
|
assert_se(safe_atollu(s, &buffers) == 0);
|
|
|
|
}
|
2013-09-14 01:41:52 +02:00
|
|
|
|
2014-09-30 23:37:10 +02:00
|
|
|
if (p)
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(buffers < total);
|
2013-09-19 23:22:59 +02:00
|
|
|
|
|
|
|
/* Seccomp should be a good test for field full of zeros. */
|
2015-09-30 14:57:55 +02:00
|
|
|
r = get_proc_field("/proc/meminfo", "Seccomp", WHITESPACE, &z);
|
2013-09-19 23:22:59 +02:00
|
|
|
if (r != -ENOENT) {
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(r == 0);
|
2013-09-19 23:22:59 +02:00
|
|
|
puts(z);
|
|
|
|
assert_se(safe_atollu(z, &buffers) == 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_capeff(void) {
|
|
|
|
int pid, p;
|
|
|
|
|
|
|
|
for (pid = 0; pid < 2; pid++) {
|
|
|
|
_cleanup_free_ char *capeff = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
r = get_process_capeff(0, &capeff);
|
|
|
|
log_info("capeff: '%s' (r=%d)", capeff, r);
|
|
|
|
|
|
|
|
if (r == -ENOENT || r == -EPERM)
|
|
|
|
return;
|
|
|
|
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(r == 0);
|
|
|
|
assert_se(*capeff);
|
2016-05-17 15:44:32 +02:00
|
|
|
p = capeff[strspn(capeff, HEXDIGITS)];
|
2014-10-04 23:51:45 +02:00
|
|
|
assert_se(!p || isspace(p));
|
2013-09-19 23:22:59 +02:00
|
|
|
}
|
2013-09-14 01:41:52 +02:00
|
|
|
}
|
|
|
|
|
2014-08-16 14:19:07 +02:00
|
|
|
static void test_write_string_stream(void) {
|
|
|
|
char fn[] = "/tmp/test-write_string_stream-XXXXXX";
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
int fd;
|
|
|
|
char buf[64];
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(fn);
|
2014-08-16 14:19:07 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
f = fdopen(fd, "r");
|
|
|
|
assert_se(f);
|
2015-07-06 23:31:44 +02:00
|
|
|
assert_se(write_string_stream(f, "boohoo", true) < 0);
|
2014-08-16 14:19:07 +02:00
|
|
|
|
2014-09-18 12:09:10 +02:00
|
|
|
f = freopen(fn, "r+", f);
|
2014-08-16 14:19:07 +02:00
|
|
|
assert_se(f);
|
|
|
|
|
2015-07-06 23:31:44 +02:00
|
|
|
assert_se(write_string_stream(f, "boohoo", true) == 0);
|
2014-08-16 14:19:07 +02:00
|
|
|
rewind(f);
|
|
|
|
|
|
|
|
assert_se(fgets(buf, sizeof(buf), f));
|
|
|
|
assert_se(streq(buf, "boohoo\n"));
|
|
|
|
|
2015-07-06 23:31:44 +02:00
|
|
|
f = freopen(fn, "w+", f);
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
assert_se(write_string_stream(f, "boohoo", false) == 0);
|
|
|
|
rewind(f);
|
|
|
|
|
|
|
|
assert_se(fgets(buf, sizeof(buf), f));
|
|
|
|
printf(">%s<", buf);
|
|
|
|
assert_se(streq(buf, "boohoo"));
|
|
|
|
|
2014-08-16 14:19:07 +02:00
|
|
|
unlink(fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_write_string_file(void) {
|
|
|
|
char fn[] = "/tmp/test-write_string_file-XXXXXX";
|
2014-09-18 12:09:10 +02:00
|
|
|
char buf[64] = {};
|
|
|
|
_cleanup_close_ int fd;
|
2014-08-16 14:19:07 +02:00
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(fn);
|
2014-08-16 14:19:07 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
2015-07-07 01:19:25 +02:00
|
|
|
assert_se(write_string_file(fn, "boohoo", WRITE_STRING_FILE_CREATE) == 0);
|
2014-08-16 14:19:07 +02:00
|
|
|
|
2014-09-16 21:59:50 +02:00
|
|
|
assert_se(read(fd, buf, sizeof(buf)) == 7);
|
2014-08-16 14:19:07 +02:00
|
|
|
assert_se(streq(buf, "boohoo\n"));
|
|
|
|
|
|
|
|
unlink(fn);
|
|
|
|
}
|
|
|
|
|
2014-09-02 18:55:31 +02:00
|
|
|
static void test_write_string_file_no_create(void) {
|
|
|
|
char fn[] = "/tmp/test-write_string_file_no_create-XXXXXX";
|
|
|
|
_cleanup_close_ int fd;
|
|
|
|
char buf[64] = {0};
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(fn);
|
2014-09-02 18:55:31 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
2015-07-07 01:19:25 +02:00
|
|
|
assert_se(write_string_file("/a/file/which/does/not/exists/i/guess", "boohoo", 0) < 0);
|
|
|
|
assert_se(write_string_file(fn, "boohoo", 0) == 0);
|
2014-09-02 18:55:31 +02:00
|
|
|
|
2014-11-04 16:19:26 +01:00
|
|
|
assert_se(read(fd, buf, sizeof(buf)) == strlen("boohoo\n"));
|
2014-09-02 18:55:31 +02:00
|
|
|
assert_se(streq(buf, "boohoo\n"));
|
|
|
|
|
|
|
|
unlink(fn);
|
|
|
|
}
|
|
|
|
|
2015-11-13 00:54:56 +01:00
|
|
|
static void test_write_string_file_verify(void) {
|
|
|
|
_cleanup_free_ char *buf = NULL, *buf2 = NULL;
|
|
|
|
int r;
|
|
|
|
|
|
|
|
assert_se(read_one_line_file("/proc/cmdline", &buf) >= 0);
|
2016-10-23 17:43:27 +02:00
|
|
|
assert_se((buf2 = strjoin(buf, "\n")));
|
2015-11-13 00:54:56 +01:00
|
|
|
|
|
|
|
r = write_string_file("/proc/cmdline", buf, 0);
|
|
|
|
assert_se(r == -EACCES || r == -EIO);
|
|
|
|
r = write_string_file("/proc/cmdline", buf2, 0);
|
|
|
|
assert_se(r == -EACCES || r == -EIO);
|
|
|
|
|
|
|
|
assert_se(write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
|
|
|
|
assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE) == 0);
|
|
|
|
|
|
|
|
r = write_string_file("/proc/cmdline", buf, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE);
|
|
|
|
assert_se(r == -EACCES || r == -EIO);
|
|
|
|
assert_se(write_string_file("/proc/cmdline", buf2, WRITE_STRING_FILE_VERIFY_ON_FAILURE|WRITE_STRING_FILE_AVOID_NEWLINE) == 0);
|
|
|
|
}
|
|
|
|
|
2014-09-02 18:55:31 +02:00
|
|
|
static void test_load_env_file_pairs(void) {
|
|
|
|
char fn[] = "/tmp/test-load_env_file_pairs-XXXXXX";
|
|
|
|
int fd;
|
|
|
|
int r;
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
_cleanup_strv_free_ char **l = NULL;
|
|
|
|
char **k, **v;
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(fn);
|
2014-09-02 18:55:31 +02:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
|
|
|
|
r = write_string_file(fn,
|
|
|
|
"NAME=\"Arch Linux\"\n"
|
|
|
|
"ID=arch\n"
|
|
|
|
"PRETTY_NAME=\"Arch Linux\"\n"
|
|
|
|
"ANSI_COLOR=\"0;36\"\n"
|
|
|
|
"HOME_URL=\"https://www.archlinux.org/\"\n"
|
|
|
|
"SUPPORT_URL=\"https://bbs.archlinux.org/\"\n"
|
2015-07-07 01:19:25 +02:00
|
|
|
"BUG_REPORT_URL=\"https://bugs.archlinux.org/\"\n",
|
|
|
|
WRITE_STRING_FILE_CREATE);
|
2014-09-02 18:55:31 +02:00
|
|
|
assert_se(r == 0);
|
|
|
|
|
|
|
|
f = fdopen(fd, "r");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
r = load_env_file_pairs(f, fn, NULL, &l);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
assert_se(strv_length(l) == 14);
|
|
|
|
STRV_FOREACH_PAIR(k, v, l) {
|
|
|
|
assert_se(STR_IN_SET(*k, "NAME", "ID", "PRETTY_NAME", "ANSI_COLOR", "HOME_URL", "SUPPORT_URL", "BUG_REPORT_URL"));
|
|
|
|
printf("%s=%s\n", *k, *v);
|
|
|
|
if (streq(*k, "NAME")) assert_se(streq(*v, "Arch Linux"));
|
|
|
|
if (streq(*k, "ID")) assert_se(streq(*v, "arch"));
|
|
|
|
if (streq(*k, "PRETTY_NAME")) assert_se(streq(*v, "Arch Linux"));
|
|
|
|
if (streq(*k, "ANSI_COLOR")) assert_se(streq(*v, "0;36"));
|
|
|
|
if (streq(*k, "HOME_URL")) assert_se(streq(*v, "https://www.archlinux.org/"));
|
|
|
|
if (streq(*k, "SUPPORT_URL")) assert_se(streq(*v, "https://bbs.archlinux.org/"));
|
|
|
|
if (streq(*k, "BUG_REPORT_URL")) assert_se(streq(*v, "https://bugs.archlinux.org/"));
|
|
|
|
}
|
|
|
|
|
|
|
|
unlink(fn);
|
|
|
|
}
|
|
|
|
|
2016-03-02 23:50:21 +01:00
|
|
|
static void test_search_and_fopen(void) {
|
|
|
|
const char *dirs[] = {"/tmp/foo/bar", "/tmp", NULL};
|
|
|
|
char name[] = "/tmp/test-search_and_fopen.XXXXXX";
|
|
|
|
int fd = -1;
|
|
|
|
int r;
|
|
|
|
FILE *f;
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(name);
|
2016-03-02 23:50:21 +01:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
r = search_and_fopen(name, "r", NULL, dirs, &f);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
r = search_and_fopen(basename(name), "r", "/", dirs, &f);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
r = search_and_fopen("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
|
|
|
|
r = unlink(name);
|
|
|
|
assert_se(r == 0);
|
|
|
|
|
|
|
|
r = search_and_fopen(basename(name), "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void test_search_and_fopen_nulstr(void) {
|
|
|
|
const char dirs[] = "/tmp/foo/bar\0/tmp\0";
|
|
|
|
char name[] = "/tmp/test-search_and_fopen.XXXXXX";
|
|
|
|
int fd = -1;
|
|
|
|
int r;
|
|
|
|
FILE *f;
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(name);
|
2016-03-02 23:50:21 +01:00
|
|
|
assert_se(fd >= 0);
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
r = search_and_fopen_nulstr(name, "r", NULL, dirs, &f);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
r = search_and_fopen_nulstr("/a/file/which/does/not/exist/i/guess", "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
r = search_and_fopen_nulstr("afilewhichdoesnotexistiguess", "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
|
|
|
|
r = unlink(name);
|
|
|
|
assert_se(r == 0);
|
|
|
|
|
|
|
|
r = search_and_fopen_nulstr(basename(name), "r", NULL, dirs, &f);
|
|
|
|
assert_se(r < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_writing_tmpfile(void) {
|
|
|
|
char name[] = "/tmp/test-systemd_writing_tmpfile.XXXXXX";
|
|
|
|
_cleanup_free_ char *contents = NULL;
|
|
|
|
size_t size;
|
|
|
|
int fd, r;
|
|
|
|
struct iovec iov[3];
|
|
|
|
|
|
|
|
IOVEC_SET_STRING(iov[0], "abc\n");
|
|
|
|
IOVEC_SET_STRING(iov[1], ALPHANUMERICAL "\n");
|
|
|
|
IOVEC_SET_STRING(iov[2], "");
|
|
|
|
|
2016-09-13 08:20:38 +02:00
|
|
|
fd = mkostemp_safe(name);
|
2016-03-02 23:50:21 +01:00
|
|
|
printf("tmpfile: %s", name);
|
|
|
|
|
|
|
|
r = writev(fd, iov, 3);
|
|
|
|
assert_se(r >= 0);
|
|
|
|
|
|
|
|
r = read_full_file(name, &contents, &size);
|
|
|
|
assert_se(r == 0);
|
|
|
|
printf("contents: %s", contents);
|
|
|
|
assert_se(streq(contents, "abc\n" ALPHANUMERICAL "\n"));
|
|
|
|
|
|
|
|
unlink(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void test_tempfn(void) {
|
|
|
|
char *ret = NULL, *p;
|
|
|
|
|
|
|
|
assert_se(tempfn_xxxxxx("/foo/bar/waldo", NULL, &ret) >= 0);
|
|
|
|
assert_se(streq_ptr(ret, "/foo/bar/.#waldoXXXXXX"));
|
|
|
|
free(ret);
|
|
|
|
|
|
|
|
assert_se(tempfn_xxxxxx("/foo/bar/waldo", "[miau]", &ret) >= 0);
|
|
|
|
assert_se(streq_ptr(ret, "/foo/bar/.#[miau]waldoXXXXXX"));
|
|
|
|
free(ret);
|
|
|
|
|
|
|
|
assert_se(tempfn_random("/foo/bar/waldo", NULL, &ret) >= 0);
|
|
|
|
assert_se(p = startswith(ret, "/foo/bar/.#waldo"));
|
|
|
|
assert_se(strlen(p) == 16);
|
|
|
|
assert_se(in_charset(p, "0123456789abcdef"));
|
|
|
|
free(ret);
|
|
|
|
|
|
|
|
assert_se(tempfn_random("/foo/bar/waldo", "[wuff]", &ret) >= 0);
|
|
|
|
assert_se(p = startswith(ret, "/foo/bar/.#[wuff]waldo"));
|
|
|
|
assert_se(strlen(p) == 16);
|
|
|
|
assert_se(in_charset(p, "0123456789abcdef"));
|
|
|
|
free(ret);
|
|
|
|
|
|
|
|
assert_se(tempfn_random_child("/foo/bar/waldo", NULL, &ret) >= 0);
|
|
|
|
assert_se(p = startswith(ret, "/foo/bar/waldo/.#"));
|
|
|
|
assert_se(strlen(p) == 16);
|
|
|
|
assert_se(in_charset(p, "0123456789abcdef"));
|
|
|
|
free(ret);
|
|
|
|
|
|
|
|
assert_se(tempfn_random_child("/foo/bar/waldo", "[kikiriki]", &ret) >= 0);
|
|
|
|
assert_se(p = startswith(ret, "/foo/bar/waldo/.#[kikiriki]"));
|
|
|
|
assert_se(strlen(p) == 16);
|
|
|
|
assert_se(in_charset(p, "0123456789abcdef"));
|
|
|
|
free(ret);
|
|
|
|
}
|
|
|
|
|
2017-09-22 17:55:53 +02:00
|
|
|
static void test_read_line(void) {
|
|
|
|
_cleanup_fclose_ FILE *f = NULL;
|
|
|
|
_cleanup_free_ char *line = NULL;
|
|
|
|
|
|
|
|
char buffer[] =
|
|
|
|
"Some test data\n"
|
|
|
|
"With newlines, and a NUL byte\0"
|
|
|
|
"\n"
|
|
|
|
"an empty line\n"
|
|
|
|
"an ignored line\n"
|
|
|
|
"and a very long line that is supposed to be truncated, because it is so long\n";
|
|
|
|
|
|
|
|
f = fmemopen(buffer, sizeof(buffer), "re");
|
|
|
|
assert_se(f);
|
|
|
|
|
|
|
|
assert_se(read_line(f, (size_t) -1, &line) == 15 && streq(line, "Some test data"));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 1024, &line) == 30 && streq(line, "With newlines, and a NUL byte"));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 1024, &line) == 14 && streq(line, "an empty line"));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, (size_t) -1, NULL) == 16);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 16, &line) == -ENOBUFS);
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
/* read_line() stopped when it hit the limit, that means when we continue reading we'll read at the first
|
|
|
|
* character after the previous limit. Let's make use of tha to continue our test. */
|
|
|
|
assert_se(read_line(f, 1024, &line) == 61 && streq(line, "line that is supposed to be truncated, because it is so long"));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 1024, &line) == 1 && streq(line, ""));
|
|
|
|
line = mfree(line);
|
|
|
|
|
|
|
|
assert_se(read_line(f, 1024, &line) == 0 && streq(line, ""));
|
|
|
|
}
|
|
|
|
|
2013-04-03 19:04:03 +02:00
|
|
|
int main(int argc, char *argv[]) {
|
2016-08-04 18:00:00 +02:00
|
|
|
log_set_max_level(LOG_DEBUG);
|
2013-09-19 23:22:59 +02:00
|
|
|
log_parse_environment();
|
|
|
|
log_open();
|
|
|
|
|
2013-04-03 19:04:03 +02:00
|
|
|
test_parse_env_file();
|
2013-09-12 03:50:16 +02:00
|
|
|
test_parse_multiline_env_file();
|
2016-08-04 18:00:00 +02:00
|
|
|
test_merge_env_file();
|
2017-02-18 04:56:28 +01:00
|
|
|
test_merge_env_file_invalid();
|
2013-07-19 10:02:50 +02:00
|
|
|
test_executable_is_script();
|
2013-09-14 01:41:52 +02:00
|
|
|
test_status_field();
|
2013-09-19 23:22:59 +02:00
|
|
|
test_capeff();
|
2014-08-16 14:19:07 +02:00
|
|
|
test_write_string_stream();
|
|
|
|
test_write_string_file();
|
2014-09-02 18:55:31 +02:00
|
|
|
test_write_string_file_no_create();
|
2015-11-13 00:54:56 +01:00
|
|
|
test_write_string_file_verify();
|
2014-09-02 18:55:31 +02:00
|
|
|
test_load_env_file_pairs();
|
2016-03-02 23:50:21 +01:00
|
|
|
test_search_and_fopen();
|
|
|
|
test_search_and_fopen_nulstr();
|
|
|
|
test_writing_tmpfile();
|
|
|
|
test_tempfn();
|
2017-09-22 17:55:53 +02:00
|
|
|
test_read_line();
|
2013-09-19 23:22:59 +02:00
|
|
|
|
2013-04-03 19:04:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|