diff options
author | Martin Pitt <martin.pitt@ubuntu.com> | 2015-02-17 11:22:16 +0100 |
---|---|---|
committer | Martin Pitt <martin.pitt@ubuntu.com> | 2015-02-17 11:22:16 +0100 |
commit | e735f4d4eafc8c8c296cefc8228cf91c3fcfe822 (patch) | |
tree | 6626785ac2b212cc52282387a0a0d8a20fee8db2 /src/test | |
parent | f47781d88ca6bf69d6b1dd0703b2b283482e5c09 (diff) | |
download | systemd-e735f4d4eafc8c8c296cefc8228cf91c3fcfe822.tar.gz |
Imported Upstream version 219
Diffstat (limited to 'src/test')
33 files changed, 1391 insertions, 152 deletions
diff --git a/src/test/test-async.c b/src/test/test-async.c index 401e68551e..abd36d693c 100644 --- a/src/test/test-async.c +++ b/src/test/test-async.c @@ -38,7 +38,9 @@ int main(int argc, char *argv[]) { fd = mkostemp_safe(name, O_RDWR|O_CLOEXEC); assert_se(fd >= 0); asynchronous_close(fd); + assert_se(asynchronous_job(async_func, NULL) >= 0); + assert_se(asynchronous_sync() >= 0); sleep(1); diff --git a/src/test/test-btrfs.c b/src/test/test-btrfs.c new file mode 100644 index 0000000000..150a32ad6f --- /dev/null +++ b/src/test/test-btrfs.c @@ -0,0 +1,106 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 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 <stdlib.h> +#include <fcntl.h> + +#include "log.h" +#include "fileio.h" +#include "util.h" +#include "btrfs-util.h" + +int main(int argc, char *argv[]) { + int r; + int fd; + + fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY); + if (fd < 0) + log_error_errno(errno, "Failed to open root directory: %m"); + else { + BtrfsSubvolInfo info; + BtrfsQuotaInfo quota; + char ts[FORMAT_TIMESTAMP_MAX], bs[FORMAT_BYTES_MAX]; + + r = btrfs_subvol_get_info_fd(fd, &info); + if (r < 0) + log_error_errno(r, "Failed to get subvolume info: %m"); + else { + log_info("otime: %s", format_timestamp(ts, sizeof(ts), info.otime)); + log_info("read-only (search): %s", yes_no(info.read_only)); + } + + r = btrfs_subvol_get_quota_fd(fd, "a); + if (r < 0) + log_error_errno(r, "Failed to get quota info: %m"); + else { + log_info("referred: %s", strna(format_bytes(bs, sizeof(bs), quota.referred))); + log_info("exclusive: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive))); + log_info("referred_max: %s", strna(format_bytes(bs, sizeof(bs), quota.referred_max))); + log_info("exclusive_max: %s", strna(format_bytes(bs, sizeof(bs), quota.exclusive_max))); + } + + r = btrfs_subvol_get_read_only_fd(fd); + if (r < 0) + log_error_errno(r, "Failed to get read only flag: %m"); + else + log_info("read-only (ioctl): %s", yes_no(r)); + + safe_close(fd); + } + + r = btrfs_subvol_make("/xxxtest"); + if (r < 0) + log_error_errno(r, "Failed to make subvolume: %m"); + + r = write_string_file("/xxxtest/afile", "ljsadhfljasdkfhlkjdsfha"); + if (r < 0) + log_error_errno(r, "Failed to write file: %m"); + + r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest2", false, false); + if (r < 0) + log_error_errno(r, "Failed to make snapshot: %m"); + + r = btrfs_subvol_snapshot("/xxxtest", "/xxxtest3", true, false); + if (r < 0) + log_error_errno(r, "Failed to make snapshot: %m"); + + r = btrfs_subvol_remove("/xxxtest"); + if (r < 0) + log_error_errno(r, "Failed to remove subvolume: %m"); + + r = btrfs_subvol_remove("/xxxtest2"); + if (r < 0) + log_error_errno(r, "Failed to remove subvolume: %m"); + + r = btrfs_subvol_remove("/xxxtest3"); + if (r < 0) + log_error_errno(r, "Failed to remove subvolume: %m"); + + r = btrfs_subvol_snapshot("/etc", "/etc2", true, true); + if (r < 0) + log_error_errno(r, "Failed to make snapshot: %m"); + + r = btrfs_subvol_remove("/etc2"); + if (r < 0) + log_error_errno(r, "Failed to remove subvolume: %m"); + + return 0; +} diff --git a/src/test/test-cap-list.c b/src/test/test-cap-list.c index dfa9a063c2..632d62ff8f 100644 --- a/src/test/test-cap-list.c +++ b/src/test/test-cap-list.c @@ -19,17 +19,21 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ +#include "util.h" #include "log.h" +#include "fileio.h" #include "cap-list.h" #include "capability.h" +#include <sys/prctl.h> -int main(int argc, char *argv[]) { +/* verify the capability parser */ +static void test_cap_list(void) { int i; assert_se(!capability_to_name(-1)); - assert_se(!capability_to_name(cap_last_cap()+1)); + assert_se(!capability_to_name(capability_list_length())); - for (i = 0; i <= (int) cap_last_cap(); i++) { + for (i = 0; i < capability_list_length(); i++) { const char *n; assert_se(n = capability_to_name(i)); @@ -39,9 +43,69 @@ int main(int argc, char *argv[]) { assert_se(capability_from_name("asdfbsd") == -EINVAL); assert_se(capability_from_name("CAP_AUDIT_READ") == CAP_AUDIT_READ); + assert_se(capability_from_name("cap_audit_read") == CAP_AUDIT_READ); + assert_se(capability_from_name("cAp_aUdIt_rEAd") == CAP_AUDIT_READ); assert_se(capability_from_name("0") == 0); assert_se(capability_from_name("15") == 15); assert_se(capability_from_name("-1") == -EINVAL); + for (i = 0; i < capability_list_length(); i++) { + _cleanup_cap_free_charp_ char *a = NULL; + const char *b; + unsigned u; + + assert_se(a = cap_to_name(i)); + + /* quit the loop as soon as libcap starts returning + * numeric ids, formatted as strings */ + if (safe_atou(a, &u) >= 0) + break; + + assert_se(b = capability_to_name(i)); + + printf("%s vs. %s\n", a, b); + + assert_se(strcasecmp(a, b) == 0); + } +} + +/* verify cap_last_cap() against /proc/sys/kernel/cap_last_cap */ +static void test_last_cap_file(void) { + _cleanup_free_ char *content = NULL; + unsigned long val = 0; + int r; + + r = read_one_line_file("/proc/sys/kernel/cap_last_cap", &content); + assert_se(r >= 0); + + r = safe_atolu(content, &val); + assert_se(r >= 0); + assert_se(val != 0); + assert_se(val == cap_last_cap()); +} + +/* verify cap_last_cap() against syscall probing */ +static void test_last_cap_probe(void) { + unsigned long p = (unsigned long)CAP_LAST_CAP; + + if (prctl(PR_CAPBSET_READ, p) < 0) { + for (p--; p > 0; p --) + if (prctl(PR_CAPBSET_READ, p) >= 0) + break; + } else { + for (;; p++) + if (prctl(PR_CAPBSET_READ, p+1) < 0) + break; + } + + assert_se(p != 0); + assert_se(p == cap_last_cap()); +} + +int main(int argc, char *argv[]) { + test_cap_list(); + test_last_cap_file(); + test_last_cap_probe(); + return 0; } diff --git a/src/test/test-cgroup-util.c b/src/test/test-cgroup-util.c index 58eb744277..67eeeb56b7 100644 --- a/src/test/test-cgroup-util.c +++ b/src/test/test-cgroup-util.c @@ -93,6 +93,7 @@ static void test_path_get_user_unit(void) { check_p_g_u_u("/meh.service", -ENOENT, NULL); check_p_g_u_u("/session-3.scope/_cpu.service", 0, "cpu.service"); check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/server.service", 0, "server.service"); + check_p_g_u_u("/user.slice/user-1000.slice/user@1000.service/foobar.slice/foobar@pie.service", 0, "foobar@pie.service"); check_p_g_u_u("/user.slice/user-1000.slice/user@.service/server.service", -ENOENT, NULL); } diff --git a/src/test/test-condition.c b/src/test/test-condition.c index 349c6470c3..88147c8e0a 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -23,8 +23,13 @@ #include "log.h" #include "architecture.h" #include "sd-id128.h" +#include "selinux-util.h" +#include "audit.h" +#include "ima-util.h" +#include "apparmor-util.h" +#include "smack-util.h" -static void test_condition_test_path_exists(void) { +static void test_condition_test_path(void) { Condition *condition; condition = condition_new(CONDITION_PATH_EXISTS, "/bin/sh", false, false); @@ -82,6 +87,14 @@ static void test_condition_test_path_exists(void) { condition = condition_new(CONDITION_PATH_IS_MOUNT_POINT, "/bin", false, false); assert_se(!condition_test(condition)); condition_free(condition); + + condition = condition_new(CONDITION_PATH_IS_READ_WRITE, "/tmp", false, false); + assert_se(condition_test(condition)); + condition_free(condition); + + condition = condition_new(CONDITION_PATH_IS_SYMBOLIC_LINK, "/dev/stdout", false, false); + assert_se(condition_test(condition)); + condition_free(condition); } static void test_condition_test_ac_power(void) { @@ -179,16 +192,46 @@ static void test_condition_test_null(void) { condition_free(condition); } +static void test_condition_test_security(void) { + Condition *condition; + + condition = condition_new(CONDITION_SECURITY, "garbage oifdsjfoidsjoj", false, false); + assert_se(!condition_test(condition)); + condition_free(condition); + + condition = condition_new(CONDITION_SECURITY, "selinux", false, true); + assert_se(condition_test(condition) != mac_selinux_use()); + condition_free(condition); + + condition = condition_new(CONDITION_SECURITY, "ima", false, false); + assert_se(condition_test(condition) == use_ima()); + condition_free(condition); + + condition = condition_new(CONDITION_SECURITY, "apparmor", false, false); + assert_se(condition_test(condition) == mac_apparmor_use()); + condition_free(condition); + + condition = condition_new(CONDITION_SECURITY, "smack", false, false); + assert_se(condition_test(condition) == mac_smack_use()); + condition_free(condition); + + condition = condition_new(CONDITION_SECURITY, "audit", false, false); + assert_se(condition_test(condition) == use_audit()); + condition_free(condition); +} + + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - test_condition_test_path_exists(); + test_condition_test_path(); test_condition_test_ac_power(); test_condition_test_host(); test_condition_test_architecture(); test_condition_test_kernel_command_line(); test_condition_test_null(); + test_condition_test_security(); return 0; } diff --git a/src/test/test-conf-files.c b/src/test/test-conf-files.c index 71cfc022dd..894c7f742f 100644 --- a/src/test/test-conf-files.c +++ b/src/test/test-conf-files.c @@ -59,12 +59,12 @@ static void test_conf_files_list(bool use_root) { search_2 = "/dir2"; } else { root_dir = NULL; - search_1 = strappenda(tmp_dir, "/dir1"); - search_2 = strappenda(tmp_dir, "/dir2"); + search_1 = strjoina(tmp_dir, "/dir1"); + search_2 = strjoina(tmp_dir, "/dir2"); } - expect_a = strappenda(tmp_dir, "/dir1/a.conf"); - expect_b = strappenda(tmp_dir, "/dir2/b.conf"); + expect_a = strjoina(tmp_dir, "/dir1/a.conf"); + expect_b = strjoina(tmp_dir, "/dir2/b.conf"); assert_se(conf_files_list(&found_files, ".conf", root_dir, search_1, search_2, NULL) == 0); strv_print(found_files); diff --git a/src/test/test-copy.c b/src/test/test-copy.c index d2cad08cb6..5c96f61005 100644 --- a/src/test/test-copy.c +++ b/src/test/test-copy.c @@ -44,7 +44,7 @@ static void test_copy_file(void) { assert_se(write_string_file(fn, "foo bar bar bar foo") == 0); - assert_se(copy_file(fn, fn_copy, 0, 0644) == 0); + assert_se(copy_file(fn, fn_copy, 0, 0644, 0) == 0); assert_se(read_full_file(fn_copy, &buf, &sz) == 0); assert_se(streq(buf, "foo bar bar bar foo\n")); @@ -67,8 +67,8 @@ static void test_copy_file_fd(void) { assert_se(out_fd >= 0); assert_se(write_string_file(in_fn, text) == 0); - assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd) < 0); - assert_se(copy_file_fd(in_fn, out_fd) >= 0); + assert_se(copy_file_fd("/a/file/which/does/not/exist/i/guess", out_fd, true) < 0); + assert_se(copy_file_fd(in_fn, out_fd, true) >= 0); assert_se(lseek(out_fd, SEEK_SET, 0) == 0); assert_se(read(out_fd, buf, sizeof(buf)) == sizeof(text) - 1); @@ -90,15 +90,15 @@ static void test_copy_tree(void) { rm_rf_dangerous(original_dir, false, true, false); STRV_FOREACH(p, files) { - char *f = strappenda(original_dir, *p); + char *f = strjoina(original_dir, *p); assert_se(mkdir_parents(f, 0755) >= 0); assert_se(write_string_file(f, "file") == 0); } STRV_FOREACH_PAIR(link, p, links) { - char *f = strappenda(original_dir, *p); - char *l = strappenda(original_dir, *link); + char *f = strjoina(original_dir, *p); + char *l = strjoina(original_dir, *link); assert_se(mkdir_parents(l, 0755) >= 0); assert_se(symlink(f, l) == 0); @@ -109,7 +109,7 @@ static void test_copy_tree(void) { STRV_FOREACH(p, files) { _cleanup_free_ char *buf = NULL; size_t sz = 0; - char *f = strappenda(copy_dir, *p); + char *f = strjoina(copy_dir, *p); assert_se(access(f, F_OK) == 0); assert_se(read_full_file(f, &buf, &sz) == 0); @@ -118,8 +118,8 @@ static void test_copy_tree(void) { STRV_FOREACH_PAIR(link, p, links) { _cleanup_free_ char *target = NULL; - char *f = strappenda(original_dir, *p); - char *l = strappenda(copy_dir, *link); + char *f = strjoina(original_dir, *p); + char *l = strjoina(copy_dir, *link); assert_se(readlink_and_canonicalize(l, &target) == 0); assert_se(path_equal(f, target)); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 60466f0d3f..91ccaf72b8 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -132,6 +132,11 @@ static void test_exec_environment(Manager *m) { test(m, "exec-environment-empty.service", 0, CLD_EXITED); } +static void test_exec_umask(Manager *m) { + test(m, "exec-umask-default.service", 0, CLD_EXITED); + test(m, "exec-umask-0177.service", 0, CLD_EXITED); +} + int main(int argc, char *argv[]) { test_function_t tests[] = { test_exec_workingdirectory, @@ -144,6 +149,7 @@ int main(int argc, char *argv[]) { test_exec_user, test_exec_group, test_exec_environment, + test_exec_umask, NULL, }; test_function_t *test = NULL; diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index cdf1973ea5..63e4a19b76 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -90,7 +90,7 @@ static void test_parse_env_file(void) { assert_se(streq_ptr(a[9], "ten=")); assert_se(a[10] == NULL); - strv_env_clean_log(a, NULL, "test"); + strv_env_clean(a); k = 0; STRV_FOREACH(i, b) { diff --git a/src/test/test-fstab-util.c b/src/test/test-fstab-util.c new file mode 100644 index 0000000000..50e5dee0a7 --- /dev/null +++ b/src/test/test-fstab-util.c @@ -0,0 +1,138 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 Zbigniew Jędrzejewski-Szmek + + 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 "fstab-util.h" +#include "util.h" +#include "log.h" + +/* +int fstab_filter_options(const char *opts, const char *names, + const char **namefound, char **value, char **filtered); +*/ + +static void do_fstab_filter_options(const char *opts, + const char *remove, + int r_expected, + const char *name_expected, + const char *value_expected, + const char *filtered_expected) { + + int r; + const char *name; + _cleanup_free_ char *value, *filtered; + + r = fstab_filter_options(opts, remove, &name, &value, &filtered); + log_info("\"%s\" → %d, \"%s\", \"%s\", \"%s\", expected %d, \"%s\", \"%s\", \"%s\"", + opts, r, name, value, filtered, + r_expected, name_expected, value_expected, filtered_expected ?: opts); + assert_se(r == r_expected); + assert_se(streq_ptr(name, name_expected)); + assert_se(streq_ptr(value, value_expected)); + assert_se(streq_ptr(filtered, filtered_expected ?: opts)); + + /* also test the malloc-less mode */ + r = fstab_filter_options(opts, remove, &name, NULL, NULL); + log_info("\"%s\" → %d, \"%s\", expected %d, \"%s\"", + opts, r, name, + r_expected, name_expected); + assert_se(r == r_expected); + assert_se(streq_ptr(name, name_expected)); +} + +static void test_fstab_filter_options(void) { + do_fstab_filter_options("opt=0", "opt\0x-opt\0", 1, "opt", "0", ""); + do_fstab_filter_options("opt=0", "x-opt\0opt\0", 1, "opt", "0", ""); + do_fstab_filter_options("opt", "opt\0x-opt\0", 1, "opt", NULL, ""); + do_fstab_filter_options("opt", "x-opt\0opt\0", 1, "opt", NULL, ""); + do_fstab_filter_options("x-opt", "x-opt\0opt\0", 1, "x-opt", NULL, ""); + + do_fstab_filter_options("opt=0,other", "opt\0x-opt\0", 1, "opt", "0", "other"); + do_fstab_filter_options("opt=0,other", "x-opt\0opt\0", 1, "opt", "0", "other"); + do_fstab_filter_options("opt,other", "opt\0x-opt\0", 1, "opt", NULL, "other"); + do_fstab_filter_options("opt,other", "x-opt\0opt\0", 1, "opt", NULL, "other"); + do_fstab_filter_options("x-opt,other", "opt\0x-opt\0", 1, "x-opt", NULL, "other"); + + do_fstab_filter_options("opto=0,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("x-opto,other", "opt\0x-opt\0", 0, NULL, NULL, NULL); + + do_fstab_filter_options("first,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first"); + do_fstab_filter_options("first=1,opt=0", "opt\0x-opt\0", 1, "opt", "0", "first=1"); + do_fstab_filter_options("first,opt=", "opt\0x-opt\0", 1, "opt", "", "first"); + do_fstab_filter_options("first=1,opt", "opt\0x-opt\0", 1, "opt", NULL, "first=1"); + do_fstab_filter_options("first=1,x-opt", "opt\0x-opt\0", 1, "x-opt", NULL, "first=1"); + + do_fstab_filter_options("first,opt=0,last=1", "opt\0x-opt\0", 1, "opt", "0", "first,last=1"); + do_fstab_filter_options("first=1,opt=0,last=2", "x-opt\0opt\0", 1, "opt", "0", "first=1,last=2"); + do_fstab_filter_options("first,opt,last", "opt\0", 1, "opt", NULL, "first,last"); + do_fstab_filter_options("first=1,opt,last", "x-opt\0opt\0", 1, "opt", NULL, "first=1,last"); + do_fstab_filter_options("first=,opt,last", "opt\0noopt\0", 1, "opt", NULL, "first=,last"); + + /* check repeated options */ + do_fstab_filter_options("first,opt=0,noopt=1,last=1", "opt\0noopt\0", 1, "noopt", "1", "first,last=1"); + do_fstab_filter_options("first=1,opt=0,last=2,opt=1", "opt\0", 1, "opt", "1", "first=1,last=2"); + do_fstab_filter_options("x-opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", ""); + do_fstab_filter_options("opt=0,x-opt=1", "opt\0x-opt\0", 1, "x-opt", "1", ""); + + /* check that semicolons are not misinterpreted */ + do_fstab_filter_options("opt=0;", "opt\0", 1, "opt", "0;", ""); + do_fstab_filter_options("opt;=0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options("opt;", "opt\0x-opt\0", 0, NULL, NULL, NULL); + + /* check that spaces are not misinterpreted */ + do_fstab_filter_options("opt=0 ", "opt\0", 1, "opt", "0 ", ""); + do_fstab_filter_options("opt =0", "x-opt\0opt\0noopt\0x-noopt\0", 0, NULL, NULL, NULL); + do_fstab_filter_options(" opt ", "opt\0x-opt\0", 0, NULL, NULL, NULL); + + /* check function will NULL args */ + do_fstab_filter_options(NULL, "opt\0", 0, NULL, NULL, ""); + do_fstab_filter_options("", "opt\0", 0, NULL, NULL, ""); +} + +static void test_fstab_find_pri(void) { + int pri = -1; + + assert_se(fstab_find_pri("pri", &pri) == 0); + assert_se(pri == -1); + + assert_se(fstab_find_pri("pri=11", &pri) == 1); + assert_se(pri == 11); + + assert_se(fstab_find_pri("opt,pri=12,opt", &pri) == 1); + assert_se(pri == 12); + + assert_se(fstab_find_pri("opt,opt,pri=12,pri=13", &pri) == 1); + assert_se(pri == 13); +} + +static void test_fstab_yes_no_option(void) { + assert_se(fstab_test_yes_no_option("nofail,fail,nofail", "nofail\0fail\0") == true); + assert_se(fstab_test_yes_no_option("nofail,nofail,fail", "nofail\0fail\0") == false); + assert_se(fstab_test_yes_no_option("abc,cde,afail", "nofail\0fail\0") == false); + assert_se(fstab_test_yes_no_option("nofail,fail=0,nofail=0", "nofail\0fail\0") == true); + assert_se(fstab_test_yes_no_option("nofail,nofail=0,fail=0", "nofail\0fail\0") == false); +} + +int main(void) { + test_fstab_filter_options(); + test_fstab_find_pri(); + test_fstab_yes_no_option(); +} diff --git a/src/test/test-fw-util.c b/src/test/test-fw-util.c new file mode 100644 index 0000000000..ab891aa0c4 --- /dev/null +++ b/src/test/test-fw-util.c @@ -0,0 +1,60 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2015 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 "log.h" +#include "fw-util.h" + +#define MAKE_IN_ADDR_UNION(a,b,c,d) (union in_addr_union) { .in.s_addr = htobe32((uint32_t) (a) << 24 | (uint32_t) (b) << 16 | (uint32_t) (c) << 8 | (uint32_t) (d))} + +int main(int argc, char *argv[]) { + int r; + log_set_max_level(LOG_DEBUG); + + r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_masquerade(true, AF_INET, 0, NULL, 0, "foobar", NULL, 0); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_masquerade(false, AF_INET, 0, NULL, 0, "foobar", NULL, 0); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 4), 815, NULL); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_local_dnat(true, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, &MAKE_IN_ADDR_UNION(1, 2, 3, 4)); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + r = fw_add_local_dnat(false, AF_INET, IPPROTO_TCP, NULL, NULL, 0, NULL, 0, 4711, &MAKE_IN_ADDR_UNION(1, 2, 3, 5), 815, NULL); + if (r < 0) + log_error_errno(r, "Failed to modify firewall: %m"); + + return 0; +} diff --git a/src/test/test-hashmap-plain.c b/src/test/test-hashmap-plain.c index 6f0910aae7..84b508f874 100644 --- a/src/test/test-hashmap-plain.c +++ b/src/test/test-hashmap-plain.c @@ -245,6 +245,8 @@ static void test_hashmap_put(void) { Hashmap *m = NULL; int valid_hashmap_put; void *val1 = (void*) "val 1"; + void *val2 = (void*) "val 2"; + _cleanup_free_ char* key1 = NULL; assert_se(hashmap_ensure_allocated(&m, &string_hash_ops) >= 0); assert_se(m); @@ -252,7 +254,10 @@ static void test_hashmap_put(void) { valid_hashmap_put = hashmap_put(m, "key 1", val1); assert_se(valid_hashmap_put == 1); assert_se(hashmap_put(m, "key 1", val1) == 0); - assert_se(hashmap_put(m, "key 1", (void *)"val 2") == -EEXIST); + assert_se(hashmap_put(m, "key 1", val2) == -EEXIST); + key1 = strdup("key 1"); + assert_se(hashmap_put(m, key1, val1) == 0); + assert_se(hashmap_put(m, key1, val2) == -EEXIST); hashmap_free(m); } diff --git a/src/test/test-json.c b/src/test/test-json.c new file mode 100644 index 0000000000..b09131891c --- /dev/null +++ b/src/test/test-json.c @@ -0,0 +1,107 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 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 <math.h> + +#include "log.h" +#include "util.h" +#include "json.h" + +static void test_one(const char *data, ...) { + void *state = NULL; + va_list ap; + + va_start(ap, data); + + for (;;) { + _cleanup_free_ char *str = NULL; + union json_value v = {}; + int t, tt; + + t = json_tokenize(&data, &str, &v, &state, NULL); + tt = va_arg(ap, int); + + assert_se(t == tt); + + if (t == JSON_END || t < 0) + break; + + else if (t == JSON_STRING) { + const char *nn; + + nn = va_arg(ap, const char *); + assert_se(streq_ptr(nn, str)); + + } else if (t == JSON_REAL) { + double d; + + d = va_arg(ap, double); + assert_se(fabs(d - v.real) < 0.001); + + } else if (t == JSON_INTEGER) { + intmax_t i; + + i = va_arg(ap, intmax_t); + assert_se(i == v.integer); + + } else if (t == JSON_BOOLEAN) { + bool b; + + b = va_arg(ap, int); + assert_se(b == v.boolean); + } + } + + va_end(ap); +} + +int main(int argc, char *argv[]) { + + test_one("x", -EINVAL); + test_one("", JSON_END); + test_one(" ", JSON_END); + test_one("0", JSON_INTEGER, (intmax_t) 0, JSON_END); + test_one("1234", JSON_INTEGER, (intmax_t) 1234, JSON_END); + test_one("3.141", JSON_REAL, 3.141, JSON_END); + test_one("0.0", JSON_REAL, 0.0, JSON_END); + test_one("7e3", JSON_REAL, 7e3, JSON_END); + test_one("-7e-3", JSON_REAL, -7e-3, JSON_END); + test_one("true", JSON_BOOLEAN, true, JSON_END); + test_one("false", JSON_BOOLEAN, false, JSON_END); + test_one("null", JSON_NULL, JSON_END); + test_one("{}", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); + test_one("\t {\n} \n", JSON_OBJECT_OPEN, JSON_OBJECT_CLOSE, JSON_END); + test_one("[]", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); + test_one("\t [] \n\n", JSON_ARRAY_OPEN, JSON_ARRAY_CLOSE, JSON_END); + test_one("\"\"", JSON_STRING, "", JSON_END); + test_one("\"foo\"", JSON_STRING, "foo", JSON_END); + test_one("\"foo\\nfoo\"", JSON_STRING, "foo\nfoo", JSON_END); + test_one("{\"foo\" : \"bar\"}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_STRING, "bar", JSON_OBJECT_CLOSE, JSON_END); + test_one("{\"foo\" : [true, false]}", JSON_OBJECT_OPEN, JSON_STRING, "foo", JSON_COLON, JSON_ARRAY_OPEN, JSON_BOOLEAN, true, JSON_COMMA, JSON_BOOLEAN, false, JSON_ARRAY_CLOSE, JSON_OBJECT_CLOSE, JSON_END); + test_one("\"\xef\xbf\xbd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); + test_one("\"\\ufffd\"", JSON_STRING, "\xef\xbf\xbd", JSON_END); + test_one("\"\\uf\"", -EINVAL); + test_one("\"\\ud800a\"", -EINVAL); + test_one("\"\\udc00\\udc00\"", -EINVAL); + test_one("\"\\ud801\\udc37\"", JSON_STRING, "\xf0\x90\x90\xb7", JSON_END); + + return 0; +} diff --git a/src/test/test-list.c b/src/test/test-list.c index fa52ad1db8..f6da1a7053 100644 --- a/src/test/test-list.c +++ b/src/test/test-list.c @@ -38,6 +38,27 @@ int main(int argc, const char *argv[]) { LIST_PREPEND(item, head, &items[i]); } + i = 0; + LIST_FOREACH_OTHERS(item, cursor, &items[2]) { + i++; + assert_se(cursor != &items[2]); + } + assert_se(i == ELEMENTSOF(items)-1); + + i = 0; + LIST_FOREACH_OTHERS(item, cursor, &items[0]) { + i++; + assert_se(cursor != &items[0]); + } + assert_se(i == ELEMENTSOF(items)-1); + + i = 0; + LIST_FOREACH_OTHERS(item, cursor, &items[3]) { + i++; + assert_se(cursor != &items[3]); + } + assert_se(i == ELEMENTSOF(items)-1); + assert_se(!LIST_JUST_US(item, head)); assert_se(items[0].item_next == NULL); @@ -105,5 +126,29 @@ int main(int argc, const char *argv[]) { LIST_REMOVE(item, head, &items[3]); assert_se(LIST_JUST_US(item, &items[3])); + assert_se(head == NULL); + + for (i = 0; i < ELEMENTSOF(items); i++) { + assert_se(LIST_JUST_US(item, &items[i])); + LIST_APPEND(item, head, &items[i]); + } + + assert_se(!LIST_JUST_US(item, head)); + + assert_se(items[0].item_next == &items[1]); + assert_se(items[1].item_next == &items[2]); + assert_se(items[2].item_next == &items[3]); + assert_se(items[3].item_next == NULL); + + assert_se(items[0].item_prev == NULL); + assert_se(items[1].item_prev == &items[0]); + assert_se(items[2].item_prev == &items[1]); + assert_se(items[3].item_prev == &items[2]); + + for (i = 0; i < ELEMENTSOF(items); i++) + LIST_REMOVE(item, head, &items[i]); + + assert_se(head == NULL); + return 0; } diff --git a/src/test/test-loopback.c b/src/test/test-loopback.c index ab330ac840..75fe053b63 100644 --- a/src/test/test-loopback.c +++ b/src/test/test-loopback.c @@ -25,11 +25,15 @@ #include <fcntl.h> #include "loopback-setup.h" +#include "log.h" #include "util.h" int main(int argc, char* argv[]) { int r; + log_open(); + log_parse_environment(); + if ((r = loopback_setup()) < 0) fprintf(stderr, "loopback: %s\n", strerror(-r)); diff --git a/src/test/test-namespace.c b/src/test/test-namespace.c index e74fd0c88a..2397db5fff 100644 --- a/src/test/test-namespace.c +++ b/src/test/test-namespace.c @@ -19,7 +19,6 @@ along with systemd; If not, see <http://www.gnu.org/licenses/>. ***/ -#include <libgen.h> #include <sys/socket.h> #include "namespace.h" @@ -43,8 +42,8 @@ static void test_tmpdir(const char *id, const char *A, const char *B) { assert_se((x.st_mode & 01777) == 0700); assert_se((y.st_mode & 01777) == 0700); - c = strappenda(a, "/tmp"); - d = strappenda(b, "/tmp"); + c = strjoina(a, "/tmp"); + d = strjoina(b, "/tmp"); assert_se(stat(c, &x) >= 0); assert_se(stat(d, &y) >= 0); diff --git a/src/test/test-path-lookup.c b/src/test/test-path-lookup.c new file mode 100644 index 0000000000..38e5c93df6 --- /dev/null +++ b/src/test/test-path-lookup.c @@ -0,0 +1,74 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 Zbigniew Jędrzejewski-Szmek + + 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 <sys/stat.h> +#include <sys/types.h> + +#include "path-lookup.h" +#include "log.h" +#include "strv.h" + +static void test_paths(SystemdRunningAs running_as, bool personal) { + char template[] = "/tmp/test-path-lookup.XXXXXXX"; + + _cleanup_lookup_paths_free_ LookupPaths lp = {}; + char *exists, *not; + + assert_se(mkdtemp(template)); + exists = strjoina(template, "/exists"); + assert_se(mkdir(exists, 0755) == 0); + not = strjoina(template, "/not"); + + assert_se(lookup_paths_init(&lp, running_as, personal, NULL, exists, not, not) == 0); + + assert_se(!strv_isempty(lp.unit_path)); + assert_se(strv_contains(lp.unit_path, exists)); + assert_se(strv_contains(lp.unit_path, not)); + + assert_se(rm_rf_dangerous(template, false, true, false) >= 0); +} + +static void print_generator_paths(SystemdRunningAs running_as) { + _cleanup_strv_free_ char **paths; + char **dir; + + log_info("Generators dirs (%s):", running_as == SYSTEMD_SYSTEM ? "system" : "user"); + + paths = generator_paths(running_as); + STRV_FOREACH(dir, paths) + log_info(" %s", *dir); +} + +int main(int argc, char **argv) { + log_set_max_level(LOG_DEBUG); + log_parse_environment(); + log_open(); + + test_paths(SYSTEMD_SYSTEM, false); + test_paths(SYSTEMD_SYSTEM, true); + test_paths(SYSTEMD_USER, false); + test_paths(SYSTEMD_USER, true); + + print_generator_paths(SYSTEMD_SYSTEM); + print_generator_paths(SYSTEMD_USER); + + return EXIT_SUCCESS; +} diff --git a/src/test/test-path-util.c b/src/test/test-path-util.c index 58b456a291..11aa52aaed 100644 --- a/src/test/test-path-util.c +++ b/src/test/test-path-util.c @@ -176,13 +176,13 @@ static void test_path_join(void) { test_join("/root", "/a/b", "/c", "/root/a/b/c"); test_join("/root", "a/b", "c", "/root/a/b/c"); test_join("/root", "/a/b", "c", "/root/a/b/c"); - test_join("/root", "/", "c", "/root//c"); + test_join("/root", "/", "c", "/root/c"); test_join("/root", "/", NULL, "/root/"); test_join(NULL, "/a/b", "/c", "/a/b/c"); test_join(NULL, "a/b", "c", "a/b/c"); test_join(NULL, "/a/b", "c", "/a/b/c"); - test_join(NULL, "/", "c", "//c"); + test_join(NULL, "/", "c", "/c"); test_join(NULL, "/", NULL, "/"); } diff --git a/src/test/test-path.c b/src/test/test-path.c index 18fcb575e6..4f9f5c1344 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -47,7 +47,7 @@ static int setup_test(Manager **m) { assert_se(manager_startup(tmp, NULL, NULL) >= 0); STRV_FOREACH(test_path, tests_path) { - rm_rf_dangerous(strappenda("/tmp/test-path_", *test_path), false, true, false); + rm_rf_dangerous(strjoina("/tmp/test-path_", *test_path), false, true, false); } *m = tmp; @@ -81,7 +81,7 @@ static void check_stop_unlink(Manager *m, Unit *unit, const char *test_path, con service = SERVICE(service_unit); ts = now(CLOCK_MONOTONIC); - /* We proces events until the service related to the path has been successfully started */ + /* We process events until the service related to the path has been successfully started */ while(service->result != SERVICE_SUCCESS || service->state != SERVICE_START) { usec_t n; int r; @@ -201,7 +201,7 @@ static void test_path_directorynotempty(Manager *m) { assert_se(access(test_path, F_OK) < 0); assert_se(mkdir_p(test_path, 0755) >= 0); - assert_se(touch(strappenda(test_path, "test_file")) >= 0); + assert_se(touch(strjoina(test_path, "test_file")) >= 0); check_stop_unlink(m, unit, test_path, NULL); } @@ -248,10 +248,6 @@ int main(int argc, char *argv[]) { log_parse_environment(); log_open(); - /* It is needed otherwise cgroup creation fails */ - if (getuid() != 0) - return EXIT_TEST_SKIP; - assert_se(set_unit_path(TEST_DIR ":") >= 0); for (test = tests; test && *test; test++) { diff --git a/src/test/test-pty.c b/src/test/test-pty.c index ed23e9f0f1..cab569a9da 100644 --- a/src/test/test-pty.c +++ b/src/test/test-pty.c @@ -100,7 +100,7 @@ static void test_pty(void) { Pty *pty; rcvsiz = 0; - memset(rcvbuf, 0, sizeof(rcvbuf)); + zero(rcvbuf); assert_se(sd_event_default(&event) >= 0); diff --git a/src/test/test-ring.c b/src/test/test-ring.c index 5e4efdbde9..a9dd01ca01 100644 --- a/src/test/test-ring.c +++ b/src/test/test-ring.c @@ -36,7 +36,7 @@ static void test_ring(void) { struct iovec vec[2]; int s; - memset(&r, 0, sizeof(r)); + zero(r); l = ring_peek(&r, vec); assert_se(l == 0); diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c new file mode 100644 index 0000000000..f5bae65bef --- /dev/null +++ b/src/test/test-sigbus.c @@ -0,0 +1,62 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2014 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 <sys/mman.h> + +#include "util.h" +#include "sigbus.h" + +int main(int argc, char *argv[]) { + _cleanup_close_ int fd = -1; + char template[] = "/tmp/sigbus-test-XXXXXX"; + void *addr = NULL; + uint8_t *p; + + sigbus_install(); + + assert_se(sigbus_pop(&addr) == 0); + + assert_se((fd = mkostemp(template, O_RDWR|O_CREAT|O_EXCL)) >= 0); + assert_se(unlink(template) >= 0); + assert_se(fallocate(fd, 0, 0, page_size() * 8) >= 0); + + p = mmap(NULL, page_size() * 16, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); + assert_se(p != MAP_FAILED); + + assert_se(sigbus_pop(&addr) == 0); + + p[0] = 0xFF; + assert_se(sigbus_pop(&addr) == 0); + + p[page_size()] = 0xFF; + assert_se(sigbus_pop(&addr) == 0); + + p[page_size()*8] = 0xFF; + p[page_size()*8+1] = 0xFF; + p[page_size()*10] = 0xFF; + assert_se(sigbus_pop(&addr) > 0); + assert_se(addr == p + page_size() * 8); + assert_se(sigbus_pop(&addr) > 0); + assert_se(addr == p + page_size() * 10); + assert_se(sigbus_pop(&addr) == 0); + + sigbus_reset(); +} diff --git a/src/test/test-strbuf.c b/src/test/test-strbuf.c index 43cb92b74b..4ec648ae66 100644 --- a/src/test/test-strbuf.c +++ b/src/test/test-strbuf.c @@ -48,7 +48,7 @@ static void test_strbuf(void) { /* check the content of the buffer directly */ l = strv_parse_nulstr(sb->buf, sb->len); - assert_se(streq(l[0], "")); /* root*/ + assert_se(streq(l[0], "")); /* root */ assert_se(streq(l[1], "waldo")); assert_se(streq(l[2], "foo")); assert_se(streq(l[3], "bar")); diff --git a/src/test/test-strv.c b/src/test/test-strv.c index 674c1b53fc..5ae929c3f8 100644 --- a/src/test/test-strv.c +++ b/src/test/test-strv.c @@ -175,7 +175,7 @@ static void test_strv_quote_unquote(const char* const *split, const char *quoted } } -static void test_strv_unquote(const char *quoted, const char **list) { +static void test_strv_unquote(const char *quoted, char **list) { _cleanup_strv_free_ char **s; _cleanup_free_ char *j; unsigned i = 0; @@ -470,6 +470,78 @@ static void test_strv_push(void) { assert_se(streq_ptr(a[3], NULL)); } +static void test_strv_equal(void) { + _cleanup_strv_free_ char **a = NULL; + _cleanup_strv_free_ char **b = NULL; + _cleanup_strv_free_ char **c = NULL; + + a = strv_new("one", "two", "three", NULL); + assert_se(a); + b = strv_new("one", "two", "three", NULL); + assert_se(a); + c = strv_new("one", "two", "three", "four", NULL); + assert_se(a); + + assert_se(strv_equal(a, a)); + assert_se(strv_equal(a, b)); + assert_se(strv_equal(NULL, NULL)); + + assert_se(!strv_equal(a, c)); + assert_se(!strv_equal(b, c)); + assert_se(!strv_equal(b, NULL)); +} + +static void test_strv_is_uniq(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + + a = strv_new(NULL, NULL); + assert_se(a); + assert_se(strv_is_uniq(a)); + + b = strv_new("foo", NULL); + assert_se(b); + assert_se(strv_is_uniq(b)); + + c = strv_new("foo", "bar", NULL); + assert_se(c); + assert_se(strv_is_uniq(c)); + + d = strv_new("foo", "bar", "waldo", "bar", "piep", NULL); + assert_se(d); + assert_se(!strv_is_uniq(d)); +} + +static void test_strv_reverse(void) { + _cleanup_strv_free_ char **a = NULL, **b = NULL, **c = NULL, **d = NULL; + + a = strv_new(NULL, NULL); + assert_se(a); + + strv_reverse(a); + assert_se(strv_isempty(a)); + + b = strv_new("foo", NULL); + assert_se(b); + strv_reverse(b); + assert_se(streq_ptr(b[0], "foo")); + assert_se(streq_ptr(b[1], NULL)); + + c = strv_new("foo", "bar", NULL); + assert_se(c); + strv_reverse(c); + assert_se(streq_ptr(c[0], "bar")); + assert_se(streq_ptr(c[1], "foo")); + assert_se(streq_ptr(c[2], NULL)); + + d = strv_new("foo", "bar", "waldo", NULL); + assert_se(d); + strv_reverse(d); + assert_se(streq_ptr(d[0], "waldo")); + assert_se(streq_ptr(d[1], "bar")); + assert_se(streq_ptr(d[2], "foo")); + assert_se(streq_ptr(d[3], NULL)); +} + int main(int argc, char *argv[]) { test_specifier_printf(); test_strv_foreach(); @@ -486,18 +558,22 @@ int main(int argc, char *argv[]) { test_strv_quote_unquote(input_table_quotes, QUOTES_STRING); test_strv_quote_unquote(input_table_spaces, SPACES_STRING); - test_strv_unquote(" foo=bar \"waldo\" zzz ", (const char*[]) { "foo=bar", "waldo", "zzz", NULL }); - test_strv_unquote("", (const char*[]) { NULL }); - test_strv_unquote(" ", (const char*[]) { NULL }); - test_strv_unquote(" ", (const char*[]) { NULL }); - test_strv_unquote(" x", (const char*[]) { "x", NULL }); - test_strv_unquote("x ", (const char*[]) { "x", NULL }); - test_strv_unquote(" x ", (const char*[]) { "x", NULL }); - test_strv_unquote(" \"x\" ", (const char*[]) { "x", NULL }); - test_strv_unquote(" 'x' ", (const char*[]) { "x", NULL }); - test_strv_unquote(" 'x\"' ", (const char*[]) { "x\"", NULL }); - test_strv_unquote(" \"x'\" ", (const char*[]) { "x'", NULL }); - test_strv_unquote("a '--b=c \"d e\"'", (const char*[]) { "a", "--b=c \"d e\"", NULL }); + test_strv_unquote(" foo=bar \"waldo\" zzz ", STRV_MAKE("foo=bar", "waldo", "zzz")); + test_strv_unquote("", STRV_MAKE_EMPTY); + test_strv_unquote(" ", STRV_MAKE_EMPTY); + test_strv_unquote(" ", STRV_MAKE_EMPTY); + test_strv_unquote(" x", STRV_MAKE("x")); + test_strv_unquote("x ", STRV_MAKE("x")); + test_strv_unquote(" x ", STRV_MAKE("x")); + test_strv_unquote(" \"x\" ", STRV_MAKE("x")); + test_strv_unquote(" 'x' ", STRV_MAKE("x")); + test_strv_unquote(" 'x\"' ", STRV_MAKE("x\"")); + test_strv_unquote(" \"x'\" ", STRV_MAKE("x'")); + test_strv_unquote("a '--b=c \"d e\"'", STRV_MAKE("a", "--b=c \"d e\"")); + + /* trailing backslashes */ + test_strv_unquote(" x\\\\", STRV_MAKE("x\\")); + test_invalid_unquote(" x\\"); test_invalid_unquote("a --b='c \"d e\"''"); test_invalid_unquote("a --b='c \"d e\" '\""); @@ -519,6 +595,9 @@ int main(int argc, char *argv[]) { test_strv_from_stdarg_alloca(); test_strv_push_prepend(); test_strv_push(); + test_strv_equal(); + test_strv_is_uniq(); + test_strv_reverse(); return 0; } diff --git a/src/test/test-strxcpyx.c b/src/test/test-strxcpyx.c index cb2309210f..a7c8e1267d 100644 --- a/src/test/test-strxcpyx.c +++ b/src/test/test-strxcpyx.c @@ -48,7 +48,7 @@ static void test_strpcpyf(void) { size_t space_left; space_left = sizeof(target); - space_left = strpcpyf(&s, space_left, "space left: %zd. ", space_left); + space_left = strpcpyf(&s, space_left, "space left: %zu. ", space_left); space_left = strpcpyf(&s, space_left, "foo%s", "bar"); assert_se(streq(target, "space left: 25. foobar")); diff --git a/src/test/test-tables.c b/src/test/test-tables.c index 97d5609adf..bda224bec6 100644 --- a/src/test/test-tables.c +++ b/src/test/test-tables.c @@ -46,7 +46,8 @@ #include "util.h" #include "architecture.h" #include "link-config.h" -#include "bus-policy.h" +#include "bus-xml-policy.h" +#include "busname.h" #include "journald-server.h" #include "locale-util.h" diff --git a/src/test/test-tmpfiles.c b/src/test/test-tmpfiles.c index 84050c6fa4..4b72c4a8fa 100644 --- a/src/test/test-tmpfiles.c +++ b/src/test/test-tmpfiles.c @@ -30,7 +30,7 @@ int main(int argc, char** argv) { const char *p = argv[1] ?: "/tmp"; - char *pattern = strappenda(p, "/systemd-test-XXXXXX"); + char *pattern = strjoina(p, "/systemd-test-XXXXXX"); _cleanup_close_ int fd, fd2; _cleanup_free_ char *cmd, *cmd2; diff --git a/src/test/test-udev.c b/src/test/test-udev.c index f2283ec7a7..b57d275efa 100644 --- a/src/test/test-udev.c +++ b/src/test/test-udev.c @@ -32,6 +32,7 @@ #include <sys/signalfd.h> #include "missing.h" +#include "selinux-util.h" #include "udev.h" #include "udev-util.h" diff --git a/src/test/test-unit-file.c b/src/test/test-unit-file.c index f31a1bbc9b..e517f571d6 100644 --- a/src/test/test-unit-file.c +++ b/src/test/test-unit-file.c @@ -71,89 +71,117 @@ static void check_execcommand(ExecCommand *c, const char* path, const char* argv0, const char* argv1, + const char* argv2, bool ignore) { + size_t n; + assert_se(c); - log_info("%s %s %s %s", - c->path, c->argv[0], c->argv[1], c->argv[2]); + log_info("expect: \"%s\" [\"%s\" \"%s\" \"%s\"]", + path, argv0 ?: path, argv1, argv2); + n = strv_length(c->argv); + log_info("actual: \"%s\" [\"%s\" \"%s\" \"%s\"]", + c->path, c->argv[0], n > 0 ? c->argv[1] : NULL, n > 1 ? c->argv[2] : NULL); assert_se(streq(c->path, path)); - assert_se(streq(c->argv[0], argv0)); - assert_se(streq(c->argv[1], argv1)); - assert_se(c->argv[2] == NULL); + assert_se(streq(c->argv[0], argv0 ?: path)); + if (n > 0) + assert_se(streq_ptr(c->argv[1], argv1)); + if (n > 1) + assert_se(streq_ptr(c->argv[2], argv2)); assert_se(c->ignore == ignore); } static void test_config_parse_exec(void) { - /* int config_parse_exec( */ - /* const char *filename, */ - /* unsigned line, */ - /* const char *section, */ - /* unsigned section_line, */ - /* const char *lvalue, */ - /* int ltype, */ - /* const char *rvalue, */ - /* void *data, */ - /* void *userdata) */ + /* int config_parse_exec( + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) */ int r; ExecCommand *c = NULL, *c1; + const char *ccc; - /* basic test */ + log_info("/* basic test */"); r = config_parse_exec(NULL, "fake", 1, "section", 1, "LValue", 0, "/RValue r1", &c, NULL); assert_se(r >= 0); - check_execcommand(c, "/RValue", "/RValue", "r1", false); + check_execcommand(c, "/RValue", "/RValue", "r1", NULL, false); r = config_parse_exec(NULL, "fake", 2, "section", 1, - "LValue", 0, "/RValue///slashes/// r1", + "LValue", 0, "/RValue///slashes r1///", &c, NULL); - /* test slashes */ + + log_info("/* test slashes */"); assert_se(r >= 0); c1 = c->command_next; - check_execcommand(c1, "/RValue/slashes", "/RValue///slashes///", - "r1", false); + check_execcommand(c1, "/RValue/slashes", "/RValue///slashes", "r1///", NULL, false); - /* honour_argv0 */ + log_info("/* trailing slash */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/RValue/ argv0 r1", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* honour_argv0 */"); r = config_parse_exec(NULL, "fake", 3, "section", 1, - "LValue", 0, "@/RValue///slashes2/// argv0 r1", + "LValue", 0, "@/RValue///slashes2 ///argv0 r1", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; - check_execcommand(c1, "/RValue/slashes2", "argv0", "r1", false); + check_execcommand(c1, "/RValue/slashes2", "///argv0", "r1", NULL, false); + + log_info("/* honour_argv0, no args */"); + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, "@/RValue", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); - /* ignore && honour_argv0 */ + log_info("/* no command, check for bad memory access */"); + r = config_parse_exec(NULL, "fake", 3, "section", 1, + "LValue", 0, " ", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + + log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "-@/RValue///slashes3/// argv0a r1", + "LValue", 0, "-@/RValue///slashes3 argv0a r1", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; - check_execcommand(c1, - "/RValue/slashes3", "argv0a", "r1", true); + check_execcommand(c1, "/RValue/slashes3", "argv0a", "r1", NULL, true); - /* ignore && honour_argv0 */ + log_info("/* ignore && honour_argv0 */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, - "LValue", 0, "@-/RValue///slashes4/// argv0b r1", + "LValue", 0, "@-/RValue///slashes4 argv0b r1", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; - check_execcommand(c1, - "/RValue/slashes4", "argv0b", "r1", true); + check_execcommand(c1, "/RValue/slashes4", "argv0b", "r1", NULL, true); - /* ignore && ignore */ + log_info("/* ignore && ignore */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "--/RValue argv0 r1", &c, NULL); assert_se(r == 0); assert_se(c1->command_next == NULL); - /* ignore && ignore */ + log_info("/* ignore && ignore (2) */"); r = config_parse_exec(NULL, "fake", 4, "section", 1, "LValue", 0, "-@-/RValue argv0 r1", &c, NULL); assert_se(r == 0); assert_se(c1->command_next == NULL); - /* semicolon */ + log_info("/* semicolon */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, "-@/RValue argv0 r1 ; " @@ -161,34 +189,119 @@ static void test_config_parse_exec(void) { &c, NULL); assert_se(r >= 0); c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + c1 = c1->command_next; + check_execcommand(c1, "/goo/goo", NULL, "boo", NULL, false); + + log_info("/* trailing semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "-@/RValue argv0 r1 ; ", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/RValue", "argv0", "r1", NULL, true); + + assert_se(c1->command_next == NULL); + + log_info("/* escaped semicolon */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/bin/find \\;", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/bin/find", NULL, ";", NULL, false); + + log_info("/* escaped semicolon with following arg */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "/sbin/find \\; x", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; check_execcommand(c1, - "/RValue", "argv0", "r1", true); + "/sbin/find", NULL, ";", "x", false); + log_info("/* spaces in the filename */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH WITH SPACES/daemon\" -1 -2", + &c, NULL); + assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, - "/goo/goo", "/goo/goo", "boo", false); + "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); - /* trailing semicolon */ + log_info("/* spaces in the filename, no args */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, - "-@/RValue argv0 r1 ; ", + "\"/PATH WITH SPACES/daemon -1 -2\"", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, - "/RValue", "argv0", "r1", true); + "/PATH WITH SPACES/daemon -1 -2", NULL, NULL, NULL, false); - assert_se(c1->command_next == NULL); + log_info("/* spaces in the filename, everything quoted */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH WITH SPACES/daemon\" \"-1\" '-2'", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1", "-2", false); - /* escaped semicolon */ + log_info("/* escaped spaces in the filename */"); r = config_parse_exec(NULL, "fake", 5, "section", 1, "LValue", 0, - "/usr/bin/find \\;", + "\"/PATH\\sWITH\\sSPACES/daemon\" '-1 -2'", &c, NULL); assert_se(r >= 0); c1 = c1->command_next; check_execcommand(c1, - "/usr/bin/find", "/usr/bin/find", ";", false); + "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); + + log_info("/* escaped spaces in the filename (2) */"); + r = config_parse_exec(NULL, "fake", 5, "section", 1, + "LValue", 0, + "\"/PATH\\x20WITH\\x20SPACES/daemon\" \"-1 -2\"", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, + "/PATH WITH SPACES/daemon", NULL, "-1 -2", NULL, false); + + for (ccc = "abfnrtv\\\'\"x"; *ccc; ccc++) { + /* \\x is an incomplete hexadecimal sequence, invalid because of the slash */ + char path[] = "/path\\X"; + path[sizeof(path) - 2] = *ccc; + + log_info("/* invalid character: \\%c */", *ccc); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, path, + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); + } + + log_info("/* valid character: \\s */"); + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path\\s", + &c, NULL); + assert_se(r >= 0); + c1 = c1->command_next; + check_execcommand(c1, "/path ", NULL, NULL, NULL, false); + + log_info("/* trailing backslash: \\ */"); + /* backslash is invalid */ + r = config_parse_exec(NULL, "fake", 4, "section", 1, + "LValue", 0, "/path\\", + &c, NULL); + assert_se(r == 0); + assert_se(c1->command_next == NULL); exec_command_free_list(c); } diff --git a/src/test/test-unit-name.c b/src/test/test-unit-name.c index ab6c488cff..5c7f8b40f7 100644 --- a/src/test/test-unit-name.c +++ b/src/test/test-unit-name.c @@ -159,6 +159,7 @@ static int test_unit_printf(void) { /* normal unit */ expect(u, "%n", "blah.service"); + expect(u, "%f", "/blah"); expect(u, "%N", "blah"); expect(u, "%p", "blah"); expect(u, "%P", "blah"); @@ -178,6 +179,7 @@ static int test_unit_printf(void) { expect(u2, "%n", "blah@foo-foo.service"); expect(u2, "%N", "blah@foo-foo"); + expect(u2, "%f", "/foo/foo"); expect(u2, "%p", "blah"); expect(u2, "%P", "blah"); expect(u2, "%i", "foo-foo"); @@ -191,6 +193,7 @@ static int test_unit_printf(void) { expect(u2, "%t", "/run/user/*"); manager_free(m); +#undef expect return 0; } @@ -260,6 +263,7 @@ static void test_unit_name_is_instance(void) { assert_se(unit_name_is_instance("a-c_c01Aj@b05Dii_-oioi.service")); assert_se(!unit_name_is_instance("a.service")); + assert_se(!unit_name_is_instance("a@.service")); assert_se(!unit_name_is_instance("junk")); assert_se(!unit_name_is_instance("")); } @@ -291,6 +295,11 @@ static void test_unit_name_to_instance(void) { assert_se(streq(instance, "bar")); free(instance); + r = unit_name_to_instance("foo@.service", &instance); + assert_se(r >= 0); + assert_se(streq(instance, "")); + free(instance); + r = unit_name_to_instance("fo0-stUff_b@b.e", &instance); assert_se(r >= 0); assert_se(streq(instance, "b")); @@ -302,6 +311,9 @@ static void test_unit_name_to_instance(void) { r = unit_name_to_instance("fooj@unk", &instance); assert_se(r < 0); + + r = unit_name_to_instance("foo@", &instance); + assert_se(r < 0); } static void test_unit_name_escape(void) { @@ -312,6 +324,29 @@ static void test_unit_name_escape(void) { assert_se(streq(r, "ab\\x2b\\x2dc.a-bc\\x40foo.service")); } +static void test_unit_name_template(void) { +#define expect(name, expected) \ + { \ + _cleanup_free_ char *f = NULL; \ + f = unit_name_template(name); \ + assert_se(f); \ + printf("got: %s, expected: %s\n", f, expected); \ + assert_se(streq(f, expected)); \ + } + expect("foo@bar.service", "foo@.service") + expect("foo.mount", "foo.mount") +#undef expect +} + +static void test_unit_name_is_template(void) { + assert_se(unit_name_is_template("foo@.service")); + assert_se(unit_name_is_template("bar@.path")); + + assert_se(!unit_name_is_template("bar@i.mount")); + assert_se(!unit_name_is_template("bar@foobbbb.service")); + assert_se(!unit_name_is_template("barfoo.service")); +} + int main(int argc, char* argv[]) { int rc = 0; test_replacements(); @@ -324,6 +359,8 @@ int main(int argc, char* argv[]) { test_build_subslice(); test_unit_name_to_instance(); test_unit_name_escape(); + test_unit_name_template(); + test_unit_name_is_template(); return rc; } diff --git a/src/test/test-utf8.c b/src/test/test-utf8.c index 3399f2ba9c..befa385754 100644 --- a/src/test/test-utf8.c +++ b/src/test/test-utf8.c @@ -93,6 +93,18 @@ static void test_utf8_escaping_printable(void) { assert_se(utf8_is_valid(p6)); } +static void test_utf16_to_utf8(void) { + char *a = NULL; + const uint16_t utf16[] = { 'a', 0xd800, 'b', 0xdc00, 'c', 0xd801, 0xdc37 }; + const char utf8[] = { 'a', 'b', 'c', 0xf0, 0x90, 0x90, 0xb7, 0 }; + + a = utf16_to_utf8(utf16, 14); + assert_se(a); + assert_se(streq(a, utf8)); + + free(a); +} + int main(int argc, char *argv[]) { test_utf8_is_valid(); test_utf8_is_printable(); @@ -100,6 +112,7 @@ int main(int argc, char *argv[]) { test_utf8_encoded_valid_unichar(); test_utf8_escaping(); test_utf8_escaping_printable(); + test_utf16_to_utf8(); return 0; } diff --git a/src/test/test-util.c b/src/test/test-util.c index fe54586eee..9515a8cbf1 100644 --- a/src/test/test-util.c +++ b/src/test/test-util.c @@ -145,6 +145,39 @@ static void test_alloca(void) { assert_se(!memcmp(t, zero, 997)); } +static void test_div_round_up(void) { + int div; + + /* basic tests */ + assert_se(DIV_ROUND_UP(0, 8) == 0); + assert_se(DIV_ROUND_UP(1, 8) == 1); + assert_se(DIV_ROUND_UP(8, 8) == 1); + assert_se(DIV_ROUND_UP(12, 8) == 2); + assert_se(DIV_ROUND_UP(16, 8) == 2); + + /* test multiple evaluation */ + div = 0; + assert_se(DIV_ROUND_UP(div++, 8) == 0 && div == 1); + assert_se(DIV_ROUND_UP(++div, 8) == 1 && div == 2); + assert_se(DIV_ROUND_UP(8, div++) == 4 && div == 3); + assert_se(DIV_ROUND_UP(8, ++div) == 2 && div == 4); + + /* overflow test with exact division */ + assert_se(sizeof(0U) == 4); + assert_se(0xfffffffaU % 10U == 0U); + assert_se(0xfffffffaU / 10U == 429496729U); + assert_se(DIV_ROUND_UP(0xfffffffaU, 10U) == 429496729U); + assert_se((0xfffffffaU + 10U - 1U) / 10U == 0U); + assert_se(0xfffffffaU / 10U + !!(0xfffffffaU % 10U) == 429496729U); + + /* overflow test with rounded division */ + assert_se(0xfffffffdU % 10U == 3U); + assert_se(0xfffffffdU / 10U == 429496729U); + assert_se(DIV_ROUND_UP(0xfffffffdU, 10U) == 429496730U); + assert_se((0xfffffffdU + 10U - 1U) / 10U == 0U); + assert_se(0xfffffffdU / 10U + !!(0xfffffffdU % 10U) == 429496730U); +} + static void test_first_word(void) { assert_se(first_word("Hello", "")); assert_se(first_word("Hello", "Hello")); @@ -383,8 +416,24 @@ static void test_cescape(void) { static void test_cunescape(void) { _cleanup_free_ char *unescaped; - assert_se(unescaped = cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00")); - assert_se(streq(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); + unescaped = cunescape("abc\\\\\\\"\\b\\f\\a\\n\\r\\t\\v\\003\\177\\234\\313\\000\\x00"); + assert_se(streq_ptr(unescaped, "abc\\\"\b\f\a\n\r\t\v\003\177\234\313\\000\\x00")); + + /* incomplete sequences */ + unescaped = cunescape("\\x0"); + assert_se(streq_ptr(unescaped, "\\x0")); + + unescaped = cunescape("\\x"); + assert_se(streq_ptr(unescaped, "\\x")); + + unescaped = cunescape("\\"); + assert_se(streq_ptr(unescaped, "\\")); + + unescaped = cunescape("\\11"); + assert_se(streq_ptr(unescaped, "\\11")); + + unescaped = cunescape("\\1"); + assert_se(streq_ptr(unescaped, "\\1")); } static void test_foreach_word(void) { @@ -406,28 +455,12 @@ static void test_foreach_word(void) { assert_se(strneq(expected[i++], word, l)); } -static void test_foreach_word_quoted(void) { +static void check(const char *test, char** expected, bool trailing) { const char *word, *state; size_t l; int i = 0; - const char test[] = "test a b c 'd' e '' '' hhh '' '' \"a b c\""; - const char * const expected[] = { - "test", - "a", - "b", - "c", - "d", - "e", - "", - "", - "hhh", - "", - "", - "a b c", - NULL - }; - printf("<%s>\n", test); + printf("<<<%s>>>\n", test); FOREACH_WORD_QUOTED(word, l, test, state) { _cleanup_free_ char *t = NULL; @@ -435,7 +468,34 @@ static void test_foreach_word_quoted(void) { assert_se(strneq(expected[i++], word, l)); printf("<%s>\n", t); } - assert_se(isempty(state)); + printf("<<<%s>>>\n", state); + assert_se(expected[i] == NULL); + assert_se(isempty(state) == !trailing); +} + +static void test_foreach_word_quoted(void) { + check("test a b c 'd' e '' '' hhh '' '' \"a b c\"", + STRV_MAKE("test", + "a", + "b", + "c", + "d", + "e", + "", + "", + "hhh", + "", + "", + "a b c"), + false); + + check("test \"xxx", + STRV_MAKE("test"), + true); + + check("test\\", + STRV_MAKE_EMPTY, + true); } static void test_default_term_for_tty(void) { @@ -543,7 +603,7 @@ static void test_get_process_comm(void) { r = get_process_environ(me, &env); assert_se(r >= 0 || r == -EACCES); - log_info("self strlen(environ): '%zd'", strlen(env)); + log_info("self strlen(environ): '%zu'", strlen(env)); if (!detect_container(NULL)) assert_se(get_ctty_devnr(1, &h) == -ENOENT); @@ -802,24 +862,24 @@ static void test_foreach_string(void) { assert_se(streq(x, "zzz")); } -static void test_filename_is_safe(void) { +static void test_filename_is_valid(void) { char foo[FILENAME_MAX+2]; int i; - assert_se(!filename_is_safe("")); - assert_se(!filename_is_safe("/bar/foo")); - assert_se(!filename_is_safe("/")); - assert_se(!filename_is_safe(".")); - assert_se(!filename_is_safe("..")); + assert_se(!filename_is_valid("")); + assert_se(!filename_is_valid("/bar/foo")); + assert_se(!filename_is_valid("/")); + assert_se(!filename_is_valid(".")); + assert_se(!filename_is_valid("..")); for (i=0; i<FILENAME_MAX+1; i++) foo[i] = 'a'; foo[FILENAME_MAX+1] = '\0'; - assert_se(!filename_is_safe(foo)); + assert_se(!filename_is_valid(foo)); - assert_se(filename_is_safe("foo_bar-333")); - assert_se(filename_is_safe("o.o")); + assert_se(filename_is_valid("foo_bar-333")); + assert_se(filename_is_valid("o.o")); } static void test_string_has_cc(void) { @@ -858,15 +918,15 @@ static void test_files_same(void) { } static void test_is_valid_documentation_url(void) { - assert_se(is_valid_documentation_url("http://www.freedesktop.org/wiki/Software/systemd")); - assert_se(is_valid_documentation_url("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); - assert_se(is_valid_documentation_url("file:foo")); - assert_se(is_valid_documentation_url("man:systemd.special(7)")); - assert_se(is_valid_documentation_url("info:bar")); + assert_se(documentation_url_is_valid("http://www.freedesktop.org/wiki/Software/systemd")); + assert_se(documentation_url_is_valid("https://www.kernel.org/doc/Documentation/binfmt_misc.txt")); + assert_se(documentation_url_is_valid("file:/foo/foo")); + assert_se(documentation_url_is_valid("man:systemd.special(7)")); + assert_se(documentation_url_is_valid("info:bar")); - assert_se(!is_valid_documentation_url("foo:")); - assert_se(!is_valid_documentation_url("info:")); - assert_se(!is_valid_documentation_url("")); + assert_se(!documentation_url_is_valid("foo:")); + assert_se(!documentation_url_is_valid("info:")); + assert_se(!documentation_url_is_valid("")); } static void test_file_in_same_dir(void) { @@ -1012,17 +1072,29 @@ static void test_strshorten(void) { assert_se(strlen(strshorten(s, 0)) == 0); } -static void test_strappenda(void) { +static void test_strjoina(void) { char *actual; - actual = strappenda("", "foo", "bar"); + actual = strjoina("", "foo", "bar"); assert_se(streq(actual, "foobar")); - actual = strappenda("foo", "bar", "baz"); + actual = strjoina("foo", "bar", "baz"); assert_se(streq(actual, "foobarbaz")); - actual = strappenda("foo", "", "bar", "baz"); + actual = strjoina("foo", "", "bar", "baz"); assert_se(streq(actual, "foobarbaz")); + + actual = strjoina("foo"); + assert_se(streq(actual, "foo")); + + actual = strjoina(NULL); + assert_se(streq(actual, "")); + + actual = strjoina(NULL, "foo"); + assert_se(streq(actual, "")); + + actual = strjoina("foo", NULL, "bar"); + assert_se(streq(actual, "foo")); } static void test_is_symlink(void) { @@ -1163,23 +1235,47 @@ static void test_glob_exists(void) { } static void test_execute_directory(void) { - char name[] = "/tmp/test-execute_directory/script1"; - char name2[] = "/tmp/test-execute_directory/script2"; - char name3[] = "/tmp/test-execute_directory/useless"; - char tempdir[] = "/tmp/test-execute_directory/"; - - assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid()) >= 0); - assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch /tmp/test-execute_directory/it_works") == 0); - assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch /tmp/test-execute_directory/it_works2") == 0); + char template_lo[] = "/tmp/test-readlink_and_make_absolute-lo.XXXXXXX"; + char template_hi[] = "/tmp/test-readlink_and_make_absolute-hi.XXXXXXX"; + const char * dirs[] = {template_hi, template_lo, NULL}; + const char *name, *name2, *name3, *overridden, *override, *masked, *mask; + + assert_se(mkdtemp(template_lo)); + assert_se(mkdtemp(template_hi)); + + name = strjoina(template_lo, "/script"); + name2 = strjoina(template_hi, "/script2"); + name3 = strjoina(template_lo, "/useless"); + overridden = strjoina(template_lo, "/overridden"); + override = strjoina(template_hi, "/overridden"); + masked = strjoina(template_lo, "/masked"); + mask = strjoina(template_hi, "/masked"); + + assert_se(write_string_file(name, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works") == 0); + assert_se(write_string_file(name2, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/it_works2") == 0); + assert_se(write_string_file(overridden, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0); + assert_se(write_string_file(override, "#!/bin/sh\necho 'Executing '$0") == 0); + assert_se(write_string_file(masked, "#!/bin/sh\necho 'Executing '$0\ntouch $(dirname $0)/failed") == 0); + assert_se(symlink("/dev/null", mask) == 0); assert_se(chmod(name, 0755) == 0); assert_se(chmod(name2, 0755) == 0); + assert_se(chmod(overridden, 0755) == 0); + assert_se(chmod(override, 0755) == 0); + assert_se(chmod(masked, 0755) == 0); assert_se(touch(name3) >= 0); - execute_directory(tempdir, NULL, DEFAULT_TIMEOUT_USEC, NULL); - assert_se(access("/tmp/test-execute_directory/it_works", F_OK) >= 0); - assert_se(access("/tmp/test-execute_directory/it_works2", F_OK) >= 0); + execute_directories(dirs, DEFAULT_TIMEOUT_USEC, NULL); + + assert_se(chdir(template_lo) == 0); + assert_se(access("it_works", F_OK) >= 0); + assert_se(access("failed", F_OK) < 0); - rm_rf_dangerous(tempdir, false, true, false); + assert_se(chdir(template_hi) == 0); + assert_se(access("it_works2", F_OK) >= 0); + assert_se(access("failed", F_OK) < 0); + + rm_rf_dangerous(template_lo, false, true, false); + rm_rf_dangerous(template_hi, false, true, false); } static void test_unquote_first_word(void) { @@ -1312,6 +1408,110 @@ static void test_parse_proc_cmdline(void) { assert_se(parse_proc_cmdline(parse_item) >= 0); } +static void test_raw_clone(void) { + pid_t parent, pid, pid2; + + parent = getpid(); + log_info("before clone: getpid()→"PID_FMT, parent); + assert_se(raw_getpid() == parent); + + pid = raw_clone(0, NULL); + assert_se(pid >= 0); + + pid2 = raw_getpid(); + log_info("raw_clone: "PID_FMT" getpid()→"PID_FMT" raw_getpid()→"PID_FMT, + pid, getpid(), pid2); + if (pid == 0) { + assert_se(pid2 != parent); + _exit(EXIT_SUCCESS); + } else { + int status; + + assert_se(pid2 == parent); + waitpid(pid, &status, __WCLONE); + assert_se(WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS); + } +} + +static void test_same_fd(void) { + _cleanup_close_pair_ int p[2] = { -1, -1 }; + _cleanup_close_ int a = -1, b = -1, c = -1; + + assert_se(pipe2(p, O_CLOEXEC) >= 0); + assert_se((a = dup(p[0])) >= 0); + assert_se((b = open("/dev/null", O_RDONLY|O_CLOEXEC)) >= 0); + assert_se((c = dup(a)) >= 0); + + assert_se(same_fd(p[0], p[0]) > 0); + assert_se(same_fd(p[1], p[1]) > 0); + assert_se(same_fd(a, a) > 0); + assert_se(same_fd(b, b) > 0); + + assert_se(same_fd(a, p[0]) > 0); + assert_se(same_fd(p[0], a) > 0); + assert_se(same_fd(c, p[0]) > 0); + assert_se(same_fd(p[0], c) > 0); + assert_se(same_fd(a, c) > 0); + assert_se(same_fd(c, a) > 0); + + assert_se(same_fd(p[0], p[1]) == 0); + assert_se(same_fd(p[1], p[0]) == 0); + assert_se(same_fd(p[0], b) == 0); + assert_se(same_fd(b, p[0]) == 0); + assert_se(same_fd(p[1], a) == 0); + assert_se(same_fd(a, p[1]) == 0); + assert_se(same_fd(p[1], b) == 0); + assert_se(same_fd(b, p[1]) == 0); + + assert_se(same_fd(a, b) == 0); + assert_se(same_fd(b, a) == 0); +} + +static void test_uid_ptr(void) { + + assert_se(UID_TO_PTR(0) != NULL); + assert_se(UID_TO_PTR(1000) != NULL); + + assert_se(PTR_TO_UID(UID_TO_PTR(0)) == 0); + assert_se(PTR_TO_UID(UID_TO_PTR(1000)) == 1000); +} + +static void test_sparse_write_one(int fd, const char *buffer, size_t n) { + char check[n]; + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(ftruncate(fd, 0) >= 0); + assert_se(sparse_write(fd, buffer, n, 4) == (ssize_t) n); + + assert_se(lseek(fd, 0, SEEK_CUR) == (off_t) n); + assert_se(ftruncate(fd, n) >= 0); + + assert_se(lseek(fd, 0, SEEK_SET) == 0); + assert_se(read(fd, check, n) == (ssize_t) n); + + assert_se(memcmp(buffer, check, n) == 0); +} + +static void test_sparse_write(void) { + const char test_a[] = "test"; + const char test_b[] = "\0\0\0\0test\0\0\0\0"; + const char test_c[] = "\0\0test\0\0\0\0"; + const char test_d[] = "\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0test\0\0\0test\0\0\0\0test\0\0\0\0\0\0\0\0"; + const char test_e[] = "test\0\0\0\0test"; + _cleanup_close_ int fd = -1; + char fn[] = "/tmp/sparseXXXXXX"; + + fd = mkostemp(fn, O_CLOEXEC); + assert_se(fd >= 0); + unlink(fn); + + test_sparse_write_one(fd, test_a, sizeof(test_a)); + test_sparse_write_one(fd, test_b, sizeof(test_b)); + test_sparse_write_one(fd, test_c, sizeof(test_c)); + test_sparse_write_one(fd, test_d, sizeof(test_d)); + test_sparse_write_one(fd, test_e, sizeof(test_e)); +} + int main(int argc, char *argv[]) { log_parse_environment(); log_open(); @@ -1321,6 +1521,7 @@ int main(int argc, char *argv[]) { test_max(); test_container_of(); test_alloca(); + test_div_round_up(); test_first_word(); test_close_many(); test_parse_boolean(); @@ -1360,7 +1561,7 @@ int main(int argc, char *argv[]) { test_hexdump(); test_log2i(); test_foreach_string(); - test_filename_is_safe(); + test_filename_is_valid(); test_string_has_cc(); test_ascii_strlower(); test_files_same(); @@ -1373,7 +1574,7 @@ int main(int argc, char *argv[]) { test_read_one_char(); test_ignore_signals(); test_strshorten(); - test_strappenda(); + test_strjoina(); test_is_symlink(); test_pid_is_unwaited(); test_pid_is_alive(); @@ -1384,6 +1585,10 @@ int main(int argc, char *argv[]) { test_unquote_first_word(); test_unquote_many_words(); test_parse_proc_cmdline(); + test_raw_clone(); + test_same_fd(); + test_uid_ptr(); + test_sparse_write(); return 0; } diff --git a/src/test/test-verbs.c b/src/test/test-verbs.c new file mode 100644 index 0000000000..0fcdd9e78d --- /dev/null +++ b/src/test/test-verbs.c @@ -0,0 +1,78 @@ +/*** + This file is part of systemd. + + Copyright 2014 systemd developers + + 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 "macro.h" +#include "strv.h" +#include "verbs.h" + +static int noop_dispatcher(int argc, char *argv[], void *userdata) { + return 0; +} + +#define test_dispatch_one(argv, verbs, expected) \ + optind = 0; \ + assert_se(dispatch_verb(strv_length(argv), argv, verbs, NULL) == expected); + +static void test_verbs(void) { + static const Verb verbs[] = { + { "help", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, + { "list-images", VERB_ANY, 1, 0, noop_dispatcher }, + { "list", VERB_ANY, 2, VERB_DEFAULT, noop_dispatcher }, + { "status", 2, VERB_ANY, 0, noop_dispatcher }, + { "show", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, + { "terminate", 2, VERB_ANY, 0, noop_dispatcher }, + { "login", 2, 2, 0, noop_dispatcher }, + { "copy-to", 3, 4, 0, noop_dispatcher }, + {} + }; + + /* not found */ + test_dispatch_one(STRV_MAKE("command-not-found"), verbs, -EINVAL); + + /* found */ + test_dispatch_one(STRV_MAKE("show"), verbs, 0); + + /* found, too few args */ + test_dispatch_one(STRV_MAKE("copy-to", "foo"), verbs, -EINVAL); + + /* found, meets min args */ + test_dispatch_one(STRV_MAKE("status", "foo", "bar"), verbs, 0); + + /* found, too many args */ + test_dispatch_one(STRV_MAKE("copy-to", "foo", "bar", "baz", "quux", "qaax"), verbs, -EINVAL); + + /* no verb, but a default is set */ + test_dispatch_one(STRV_MAKE_EMPTY, verbs, 0); +} + +static void test_verbs_no_default(void) { + static const Verb verbs[] = { + { "help", VERB_ANY, VERB_ANY, 0, noop_dispatcher }, + {}, + }; + + test_dispatch_one(STRV_MAKE(NULL), verbs, -EINVAL); +} + +int main(int argc, char *argv[]) { + test_verbs(); + test_verbs_no_default(); + + return 0; +} |